diff --git a/src/gstducatih264dec.c b/src/gstducatih264dec.c
index fa8a8c1da13ecba1c861da3adf01103a4ca4a88b..e5eeba07a49321db6115cf3afd0cfa3bf9634c4e 100644 (file)
--- a/src/gstducatih264dec.c
+++ b/src/gstducatih264dec.c
# include <config.h>
#endif
+#include <math.h>
#include "gstducatih264dec.h"
GST_BOILERPLATE (GstDucatiH264Dec, gst_ducati_h264dec, GstDucatiVidDec,
GST_TYPE_DUCATIVIDDEC);
+/* *INDENT-OFF* */
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-h264, "
"stream-format = byte-stream, " /* only byte-stream */
- "align = au, " /* only entire frames */
+ "alignment = au, " /* only entire frames */
"width = (int)[ 16, 2048 ], "
"height = (int)[ 16, 2048 ], "
"framerate = (fraction)[ 0, max ],"
"profile = (string){constrained-baseline, baseline, main, extended};"
"video/x-h264, "
"stream-format = byte-stream, " /* only byte-stream */
- "align = au, " /* only entire frames */
+ "alignment = au, " /* only entire frames */
"width = (int)[ 16, 2048 ], "
"height = (int)[ 16, 2048 ], "
"framerate = (fraction)[ 0, max ],"
"profile = (string) {high, high-10-intra, high-10, high-4:2:2-intra, "
"high-4:2:2, high-4:4:4-intra, high-4:4:4, cavlc-4:4:4-intra}, "
- "level = (string) {1, 1b, 1.1, 1.2, 1.3, 2, 2.1, 2.2, 3, 3.1, 3.2, 4, 4.1, 4.2};"
- )
+ "level = (string) {1, 1b, 1.1, 1.2, 1.3, 2, 2.1, 2.2, 3, 3.1, 3.2, 4, 4.1, 4.2};")
);
+static const struct
+{
+ const char *level;
+ gint kb;
+} max_dpb_by_level[] = {
+ { "1", 149 },
+ { "1b", 149 }, /* That one's not in the spec ?? */
+ { "1.1", 338 },
+ { "1.2", 891 },
+ { "1.3", 891 },
+ { "2", 891 },
+ { "2.1", 1782 },
+ { "2.2", 3038 },
+ { "3", 3038 },
+ { "3.1", 6750 },
+ { "3.2", 7680 },
+ { "4", 12288 },
+ { "4.1", 12288 },
+ { "4.2", 12288 },
+ { "5", 41400 },
+ { "5.1", 69120 },
+};
+/* *INDENT-ON* */
+
/* GstDucatiVidDec vmethod implementations */
static void
if (ret) {
IH264VDEC_Params *params = (IH264VDEC_Params *) self->params;
- self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_1;
+
+ self->params->displayDelay = IVIDDEC3_DECODE_ORDER;
params->maxNumRefFrames = IH264VDEC_NUM_REFFRAMES_AUTO;
params->pConstantMemory = 0;
params->presetLevelIdc = IH264VDEC_LEVEL41;
self->inArgs->inputID = 0;
}
- gst_ducati_viddec_codec_flush (self, FALSE);
+ self->needs_flushing = TRUE;
}
ret = parent_class->handle_error (self, ret, extended_error,
gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
GstQuery * query, gboolean * forward)
{
- GstDucatiH264Dec * self = GST_DUCATIH264DEC (vdec);
+ GstDucatiH264Dec *self = GST_DUCATIH264DEC (vdec);
gboolean res = TRUE;
switch (GST_QUERY_TYPE (query)) {
gst_query_parse_latency (query, &live, &min, &max);
if (vdec->fps_n != 0)
- latency = gst_util_uint64_scale (GST_SECOND,
- vdec->fps_d, vdec->fps_n);
+ latency = gst_util_uint64_scale (GST_SECOND, vdec->fps_d, vdec->fps_n);
else
latency = 0;
+ /* Take into account the backlog frames for reordering */
+ latency *= (vdec->backlog_maxframes + 1);
+
if (min == GST_CLOCK_TIME_NONE)
min = latency;
else
if (max != GST_CLOCK_TIME_NONE)
max += latency;
- GST_INFO_OBJECT (self, "latency %"GST_TIME_FORMAT " ours %"GST_TIME_FORMAT,
+ GST_INFO_OBJECT (self,
+ "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
gst_query_set_latency (query, live, min, max);
break;
}
static gboolean
-gst_ducati_h264dec_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
+gst_ducati_h264dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
gint64 diff)
{
gboolean is_bframe = GST_BUFFER_FLAG_IS_SET (buf,
return FALSE;
}
+static gint
+gst_ducati_h264dec_find_max_dpb_from_level (GstDucatiVidDec * self,
+ const char *level)
+{
+ guint n;
+
+ for (n = 0; n < G_N_ELEMENTS (max_dpb_by_level); ++n)
+ if (!strcmp (level, max_dpb_by_level[n].level))
+ return max_dpb_by_level[n].kb;
+
+ GST_WARNING_OBJECT (self, "Max DBP not found for level %s", level);
+ return -1;
+}
+
+static gint
+gst_ducati_h264dec_get_max_dpb_size (GstDucatiVidDec * self, GstCaps * caps)
+{
+ gint wmb = (self->width + 15) / 16;
+ gint hmb = (self->height + 15) / 16;
+ gint max_dpb, max_dpb_size;
+ GstStructure *structure;
+ const char *level;
+ float chroma_factor = 1.5; /* We only support NV12, which is 4:2:0 */
+
+ /* Min( 1024 * MaxDPB / ( PicWidthInMbs * FrameHeightInMbs * 256 * ChromaFormatFactor ), 16 ) */
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!structure)
+ return 16;
+
+ level = gst_structure_get_string (structure, "level");
+ if (!level)
+ return 16;
+
+ max_dpb = gst_ducati_h264dec_find_max_dpb_from_level (self, level);
+ if (max_dpb < 0)
+ return 16;
+
+ max_dpb_size =
+ lrint (ceil (1024 * max_dpb / (wmb * hmb * 256 * chroma_factor)));
+ if (max_dpb_size > 16)
+ max_dpb_size = 16;
+
+ return max_dpb_size;
+}
+
+static gboolean
+gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
+{
+ GstStructure *structure;
+
+ GST_DEBUG_OBJECT (self, "set_sink_caps: %" GST_PTR_FORMAT, caps);
+
+ if (!GST_CALL_PARENT_WITH_DEFAULT (GST_DUCATIVIDDEC_CLASS, set_sink_caps,
+ (self, caps), TRUE))
+ return FALSE;
+
+ /* HW decoder fails in GETSTATUS */
+#if 0
+ /* When we have the first decoded buffer, we ask the decoder for the
+ max number of frames needed to reorder */
+ int err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
+ self->dynParams, self->status);
+ if (!err) {
+ IH264VDEC_Status *s = (IH264VDEC_Status *) self->status;
+ if (s->spsMaxRefFrames > MAX_BACKLOG_FRAMES) {
+ h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
+ GST_WARNING_OBJECT (self,
+ "Stream needs %d frames for reordering, we can only accomodate %d",
+ s->spsMaxRefFrames, MAX_BACKLOG_FRAMES);
+ } else {
+ h264dec->backlog_maxframes = s->spsMaxRefFrames;
+ GST_INFO_OBJECT (self, "Num frames for reordering: %d",
+ h264dec->backlog_maxframes);
+ }
+ } else {
+ h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
+ GST_WARNING_OBJECT (self,
+ "Failed to request num frames for reordering, defaulting to %d",
+ h264dec->backlog_maxframes);
+ }
+#endif
+
+ self->backlog_maxframes = -1;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (structure) {
+ gint num_ref_frames = -1, num_reorder_frames = -1;
+ const char *profile;
+
+ /* baseline profile does not use B frames (and I'll say constrained-baseline
+ is unlikely either from the name, it's not present in my H264 spec... */
+ profile = gst_structure_get_string (structure, "profile");
+ if (profile && (!strcmp (profile, "baseline")
+ || !strcmp (profile, "constrained-baseline"))) {
+ GST_DEBUG_OBJECT (self, "No need for reordering for %s profile", profile);
+ self->backlog_maxframes = 0;
+ goto no_b_frames;
+ }
+
+
+ if (gst_structure_get_int (structure, "num-ref-frames", &num_ref_frames)
+ && num_ref_frames >= 0) {
+ ((IH264VDEC_Params *) self->params)->maxNumRefFrames = num_ref_frames;
+ }
+ if (gst_structure_get_int (structure, "num-reorder-frames",
+ &num_reorder_frames)
+ && num_reorder_frames >= 0) {
+ if (num_reorder_frames > MAX_BACKLOG_FRAMES) {
+ self->backlog_maxframes = MAX_BACKLOG_FRAMES;
+ GST_WARNING_OBJECT (self,
+ "Stream needs %d frames for reordering, we can only accomodate %d",
+ num_reorder_frames, MAX_BACKLOG_FRAMES);
+ } else {
+ self->backlog_maxframes = num_reorder_frames;
+ GST_INFO_OBJECT (self, "Num frames for reordering: %d",
+ self->backlog_maxframes);
+ }
+ }
+ }
+
+ /* If not present, use the spec forumula for a bound */
+ if (self->backlog_maxframes < 0) {
+ self->backlog_maxframes = gst_ducati_h264dec_get_max_dpb_size (self, caps);
+ GST_WARNING_OBJECT (self,
+ "num-reorder-frames not found on caps, defaulting to %d",
+ self->backlog_maxframes);
+ }
+
+no_b_frames:
+
+ return TRUE;
+}
+
/* GObject vmethod implementations */
static void
bclass->allocate_params =
GST_DEBUG_FUNCPTR (gst_ducati_h264dec_allocate_params);
bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_handle_error);
- bclass->drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_drop_frame);
+ bclass->can_drop_frame =
+ GST_DEBUG_FUNCPTR (gst_ducati_h264dec_can_drop_frame);
bclass->query = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_query);
+ bclass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_set_sink_caps);
}
static void