mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 11:45:25 +00:00
applemedia: vtdec: set reorder queue length to the max DPB length
Set reorder_queue_frame_delay from the DPB size (in frames). Still not optimal, as the DPB size is larger than the max bframe forward prediction length, but I don't know how to compute the latter without parsing every group of pictures.
This commit is contained in:
parent
8cca2d55f5
commit
733a780e9d
1 changed files with 133 additions and 12 deletions
|
@ -72,6 +72,8 @@ static void gst_vtdec_session_output_callback (void
|
||||||
*decompression_output_ref_con, void *source_frame_ref_con, OSStatus status,
|
*decompression_output_ref_con, void *source_frame_ref_con, OSStatus status,
|
||||||
VTDecodeInfoFlags info_flags, CVImageBufferRef image_buffer, CMTime pts,
|
VTDecodeInfoFlags info_flags, CVImageBufferRef image_buffer, CMTime pts,
|
||||||
CMTime duration);
|
CMTime duration);
|
||||||
|
static gboolean compute_h264_decode_picture_buffer_length (GstVtdec * vtdec,
|
||||||
|
GstBuffer * codec_data, int *length);
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_vtdec_sink_template =
|
static GstStaticPadTemplate gst_vtdec_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
|
@ -183,7 +185,15 @@ gst_vtdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
|
||||||
|
|
||||||
structure = gst_caps_get_structure (state->caps, 0);
|
structure = gst_caps_get_structure (state->caps, 0);
|
||||||
caps_name = gst_structure_get_name (structure);
|
caps_name = gst_structure_get_name (structure);
|
||||||
if (!strcmp (caps_name, "video/x-h264") && state->codec_data == NULL) {
|
if (!strcmp (caps_name, "video/x-h264")) {
|
||||||
|
cm_format = kCMVideoCodecType_H264;
|
||||||
|
} else if (!strcmp (caps_name, "video/mpeg")) {
|
||||||
|
cm_format = kCMVideoCodecType_MPEG2Video;
|
||||||
|
} else if (!strcmp (caps_name, "image/jpeg")) {
|
||||||
|
cm_format = kCMVideoCodecType_JPEG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cm_format == kCMVideoCodecType_H264 && state->codec_data == NULL) {
|
||||||
GST_INFO_OBJECT (vtdec, "no codec data, wait for one");
|
GST_INFO_OBJECT (vtdec, "no codec data, wait for one");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -191,19 +201,17 @@ gst_vtdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
|
||||||
if (vtdec->session)
|
if (vtdec->session)
|
||||||
gst_vtdec_invalidate_session (vtdec);
|
gst_vtdec_invalidate_session (vtdec);
|
||||||
|
|
||||||
vtdec->reorder_queue_frame_delay = 0;
|
|
||||||
|
|
||||||
if (!strcmp (caps_name, "video/x-h264")) {
|
|
||||||
cm_format = kCMVideoCodecType_H264;
|
|
||||||
vtdec->reorder_queue_frame_delay = 16;
|
|
||||||
} else if (!strcmp (caps_name, "video/mpeg")) {
|
|
||||||
cm_format = kCMVideoCodecType_MPEG2Video;
|
|
||||||
} else if (!strcmp (caps_name, "image/jpeg")) {
|
|
||||||
cm_format = kCMVideoCodecType_JPEG;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_video_info_from_caps (&vtdec->video_info, state->caps);
|
gst_video_info_from_caps (&vtdec->video_info, state->caps);
|
||||||
|
|
||||||
|
if (cm_format == kCMVideoCodecType_H264) {
|
||||||
|
if (!compute_h264_decode_picture_buffer_length (vtdec, state->codec_data,
|
||||||
|
&vtdec->reorder_queue_frame_delay)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vtdec->reorder_queue_frame_delay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (state->codec_data) {
|
if (state->codec_data) {
|
||||||
format_description = create_format_description_from_codec_data (vtdec,
|
format_description = create_format_description_from_codec_data (vtdec,
|
||||||
cm_format, state->codec_data);
|
cm_format, state->codec_data);
|
||||||
|
@ -558,3 +566,116 @@ gst_vtdec_push_frames_if_needed (GstVtdec * vtdec, gboolean drain,
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
parse_h264_profile_and_level_from_codec_data (GstVtdec * vtdec,
|
||||||
|
GstBuffer * codec_data, int *profile, int *level)
|
||||||
|
{
|
||||||
|
GstMapInfo map;
|
||||||
|
guint8 *data;
|
||||||
|
gint size;
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
|
||||||
|
gst_buffer_map (codec_data, &map, GST_MAP_READ);
|
||||||
|
data = map.data;
|
||||||
|
size = map.size;
|
||||||
|
|
||||||
|
/* parse the avcC data */
|
||||||
|
if (size < 7)
|
||||||
|
goto avcc_too_small;
|
||||||
|
|
||||||
|
/* parse the version, this must be 1 */
|
||||||
|
if (data[0] != 1)
|
||||||
|
goto wrong_version;
|
||||||
|
|
||||||
|
/* AVCProfileIndication */
|
||||||
|
/* profile_compat */
|
||||||
|
/* AVCLevelIndication */
|
||||||
|
if (profile)
|
||||||
|
*profile = data[1];
|
||||||
|
|
||||||
|
if (level)
|
||||||
|
*level = data[3];
|
||||||
|
|
||||||
|
out:
|
||||||
|
gst_buffer_unmap (codec_data, &map);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
avcc_too_small:
|
||||||
|
GST_ELEMENT_ERROR (vtdec, STREAM, DECODE, (NULL),
|
||||||
|
("invalid codec_data buffer length"));
|
||||||
|
ret = FALSE;
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
wrong_version:
|
||||||
|
GST_ELEMENT_ERROR (vtdec, STREAM, DECODE, (NULL),
|
||||||
|
("wrong avcC version in codec_data"));
|
||||||
|
ret = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_dpb_max_mb_s_from_level (int level)
|
||||||
|
{
|
||||||
|
switch (level) {
|
||||||
|
case 10:
|
||||||
|
/* 1b?? */
|
||||||
|
return 396;
|
||||||
|
case 11:
|
||||||
|
return 900;
|
||||||
|
case 12:
|
||||||
|
case 13:
|
||||||
|
case 20:
|
||||||
|
return 2376;
|
||||||
|
case 21:
|
||||||
|
return 4752;
|
||||||
|
case 22:
|
||||||
|
return 8100;
|
||||||
|
case 31:
|
||||||
|
return 18000;
|
||||||
|
case 32:
|
||||||
|
return 20480;
|
||||||
|
case 40:
|
||||||
|
case 41:
|
||||||
|
return 32768;
|
||||||
|
case 42:
|
||||||
|
return 34816;
|
||||||
|
case 50:
|
||||||
|
return 110400;
|
||||||
|
case 51:
|
||||||
|
case 52:
|
||||||
|
return 184320;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
compute_h264_decode_picture_buffer_length (GstVtdec * vtdec,
|
||||||
|
GstBuffer * codec_data, int *length)
|
||||||
|
{
|
||||||
|
int profile, level;
|
||||||
|
int dpb_mb_size = 16;
|
||||||
|
int max_dpb_size_frames = 16;
|
||||||
|
int max_dpb_mb_s = -1;
|
||||||
|
int width_in_mb_s = vtdec->video_info.width / dpb_mb_size;
|
||||||
|
int height_in_mb_s = vtdec->video_info.height / dpb_mb_size;
|
||||||
|
|
||||||
|
if (!parse_h264_profile_and_level_from_codec_data (vtdec, codec_data,
|
||||||
|
&profile, &level))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
max_dpb_mb_s = get_dpb_max_mb_s_from_level (level);
|
||||||
|
if (max_dpb_mb_s == -1) {
|
||||||
|
GST_ELEMENT_ERROR (vtdec, STREAM, DECODE, (NULL),
|
||||||
|
("invalid level in codec_data, could not compute max_dpb_mb_s"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this formula is specified in sections A.3.1.h and A.3.2.f of the 2009
|
||||||
|
* edition of the standard */
|
||||||
|
*length = MIN (floor (max_dpb_mb_s / (width_in_mb_s * height_in_mb_s)),
|
||||||
|
max_dpb_size_frames);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue