diff --git a/src/gstducatih264dec.c b/src/gstducatih264dec.c
index d1abc9872509b54fd7478775c15bd9ef5a8e13b7..05e1c94d491376ac94347b1e06325e441a064ce0 100644 (file)
--- a/src/gstducatih264dec.c
+++ b/src/gstducatih264dec.c
#define PADX 32
#define PADY 24
+/* This structure is not public, this should be replaced by
+ sizeof(sErrConcealLayerStr) when it is made so. */
+#define SIZE_OF_CONCEALMENT_DATA 65536
+
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, 5.1};")
);
-/* *INDENT-OFF* */
static const struct
{
const char *level;
if (ret) {
IH264VDEC_Params *params = (IH264VDEC_Params *) self->params;
+
self->params->displayDelay = IVIDDEC3_DECODE_ORDER;
- params->maxNumRefFrames = IH264VDEC_NUM_REFFRAMES_AUTO;
+ params->dpbSizeInFrames = IH264VDEC_DPB_NUMFRAMES_AUTO;
params->pConstantMemory = 0;
params->presetLevelIdc = IH264VDEC_LEVEL41;
params->errConcealmentMode = IH264VDEC_APPLY_CONCEALMENT;
params->temporalDirModePred = TRUE;
+
+ if (self->codec_debug_info) {
+ /* We must allocate a byte per MB, plus the size of some struture which
+ is not public. Place this in the first metadata buffer slot, and ask
+ for MBINFO metadata for it. */
+ GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
+ unsigned mbw = (self->width + 15) / 16;
+ unsigned mbh = (self->height + 15) / 16;
+ unsigned nmb = mbw * mbh;
+
+ h264dec->bo_mberror =
+ omap_bo_new (self->device, nmb + SIZE_OF_CONCEALMENT_DATA,
+ OMAP_BO_WC);
+ self->outBufs->descs[2].memType = XDM_MEMTYPE_BO;
+ self->outBufs->descs[2].buf =
+ (XDAS_Int8 *) omap_bo_handle (h264dec->bo_mberror);
+ self->outBufs->descs[2].bufSize.bytes = nmb + SIZE_OF_CONCEALMENT_DATA;
+ self->params->metadataType[0] = IVIDEO_METADATAPLANE_MBINFO;
+ }
}
return ret;
gst_ducati_h264dec_handle_error (GstDucatiVidDec * self, gint ret,
gint extended_error, gint status_extended_error)
{
+ GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
+ const unsigned char *mberror, *mbcon;
+ unsigned mbw, mbh, nmb;
+ uint16_t mbwr, mbhr;
+ size_t n, nerr = 0;
+ char *line;
+ unsigned x, y;
+
+ if (h264dec->bo_mberror) {
+ mberror = omap_bo_map (h264dec->bo_mberror);
+ mbw = (self->width + 15) / 16;
+ mbh = (self->height + 15) / 16;
+ nmb = mbw * mbh;
+ mbcon = mberror + nmb;
+ mbwr = ((const uint16_t *) mbcon)[21]; /* not a public struct */
+ mbhr = ((const uint16_t *) mbcon)[22]; /* not a public struct */
+ if (nmb != mbwr * mbhr) {
+ GST_WARNING_OBJECT (self, "Failed to find MB size - "
+ "corruption might have happened");
+ } else {
+ for (n = 0; n < nmb; ++n) {
+ if (mberror[n])
+ ++nerr;
+ }
+ GST_INFO_OBJECT (self, "Frame has %zu MB errors over %zu (%u x %u) MBs",
+ nerr, nmb, mbwr, mbhr);
+ line = g_malloc (mbw + 1);
+ for (y = 0; y < mbh; y++) {
+ line[mbw] = 0;
+ for (x = 0; x < mbw; x++) {
+ line[x] = mberror[x + y * mbw] ? '!' : '.';
+ }
+ GST_INFO_OBJECT (self, "MB: %4u: %s", y, line);
+ }
+ g_free (line);
+ }
+ }
+
if (extended_error & 0x00000001) {
/* No valid slice. This seems to be bad enough that it's better to flush and
* skip to the next keyframe.
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 *= (self->backlog_maxframes + 1);
+ latency *= (vdec->backlog_maxframes + 1);
if (min == GST_CLOCK_TIME_NONE)
min = latency;
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;
structure = gst_caps_get_structure (caps, 0);
if (!structure)
- return 16;
+ return -1;
level = gst_structure_get_string (structure, "level");
if (!level)
- return 16;
+ return -1;
max_dpb = gst_ducati_h264dec_find_max_dpb_from_level (self, level);
if (max_dpb < 0)
- return 16;
+ return -1;
max_dpb_size =
lrint (ceil (1024 * max_dpb / (wmb * hmb * 256 * chroma_factor)));
- if (max_dpb_size > 16)
- max_dpb_size = 16;
+ if (max_dpb_size > MAX_BACKLOG_FRAMES)
+ max_dpb_size = MAX_BACKLOG_FRAMES;
return max_dpb_size;
}
static gboolean
gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
{
- GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
GstStructure *structure;
GST_DEBUG_OBJECT (self, "set_sink_caps: %" GST_PTR_FORMAT, caps);
}
#endif
- h264dec->backlog_maxframes = -1;
+ self->backlog_maxframes = -1;
structure = gst_caps_get_structure (caps, 0);
if (structure) {
- gint num_ref_frames = -1;
+ 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) {
- if (num_ref_frames > MAX_BACKLOG_FRAMES) {
- h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
+ ((IH264VDEC_Params *) self->params)->dpbSizeInFrames = 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_ref_frames, MAX_BACKLOG_FRAMES);
+ num_reorder_frames, MAX_BACKLOG_FRAMES);
} else {
- h264dec->backlog_maxframes = num_ref_frames;
+ self->backlog_maxframes = num_reorder_frames;
GST_INFO_OBJECT (self, "Num frames for reordering: %d",
- h264dec->backlog_maxframes);
+ self->backlog_maxframes);
}
}
}
/* If not present, use the spec forumula for a bound */
- if (h264dec->backlog_maxframes < 0) {
- h264dec->backlog_maxframes =
- gst_ducati_h264dec_get_max_dpb_size (self, caps);
- GST_WARNING_OBJECT (self,
- "num-ref-frames not found on caps, defaulting to %d",
- h264dec->backlog_maxframes);
- }
-
- return TRUE;
-}
-
-/* The following few functions reorder buffers by timestamp, on the
- assumption that buffers are properly timestamped by presentation
- time, but pushed in any (but presumably decode) order.
- They also assume all incoming buffers have a valid timestamp.
- */
-
-static GstFlowReturn
-gst_ducati_h264dec_push_earliest (GstDucatiH264Dec * self)
-{
- GstClockTime earliest_ts = GST_CLOCK_TIME_NONE;
- guint earliest_index = 0, i;
- GstBuffer *buf;
-
- if (self->backlog_nframes == 0)
- return GST_FLOW_OK;
-
- /* work out which frame has the earliest ts */
- for (i = 0; i < self->backlog_nframes; i++) {
- GstClockTime ts = GST_BUFFER_TIMESTAMP (self->backlog_frames[i]);
- if (earliest_ts == GST_CLOCK_TIME_NONE || ts < earliest_ts) {
- earliest_ts = ts;
- earliest_index = i;
+ if (self->backlog_maxframes < 0) {
+ self->backlog_maxframes = gst_ducati_h264dec_get_max_dpb_size (self, caps);
+ if (self->backlog_maxframes >= 0) {
+ GST_WARNING_OBJECT (self,
+ "num-reorder-frames not found on caps, calculation from stream parameters gives %d",
+ self->backlog_maxframes);
+ } else {
+ self->backlog_maxframes = MAX_H264_BACKLOG_FRAMES;
}
}
+ if (self->backlog_maxframes > self->backlog_max_maxframes)
+ self->backlog_maxframes = self->backlog_max_maxframes;
+ GST_WARNING_OBJECT (self,
+ "Using %d frames for reordering", self->backlog_maxframes);
- /* send it, giving away the ref */
- buf = self->backlog_frames[earliest_index];
- self->backlog_frames[earliest_index] =
- self->backlog_frames[--self->backlog_nframes];
- GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
- buf);
- return gst_pad_push (GST_DUCATIVIDDEC (self)->srcpad, buf);
-}
-
-static GstFlowReturn
-gst_ducati_h264dec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
-{
- GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
- GstFlowReturn ret = GST_FLOW_OK;
-
- /* add the frame to the list, the array will own the ref */
- GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
- h264dec->backlog_frames[h264dec->backlog_nframes++] = buf;
-
- /* push till we have no more than the max needed, or error */
- while (h264dec->backlog_nframes > h264dec->backlog_maxframes) {
- ret = gst_ducati_h264dec_push_earliest (h264dec);
- if (ret != GST_FLOW_OK)
- break;
- }
-
- return ret;
-}
+no_b_frames:
-static void
-gst_ducati_h264dec_on_flush (GstDucatiVidDec * self, gboolean eos)
-{
- GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
-
- /* push everything on the backlog, ignoring errors */
- while (h264dec->backlog_nframes > 0) {
- gst_ducati_h264dec_push_earliest (h264dec);
- }
+ return TRUE;
}
/* GObject vmethod implementations */
gst_static_pad_template_get (&sink_factory));
}
+static void
+gst_ducati_h264dec_finalize (GObject * obj)
+{
+ GstDucatiH264Dec *self = GST_DUCATIH264DEC (obj);
+ if (self->bo_mberror)
+ omap_bo_del (self->bo_mberror);
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
static void
gst_ducati_h264dec_class_init (GstDucatiH264DecClass * klass)
{
GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
bclass->codec_name = "ivahd_h264dec";
bclass->update_buffer_size =
GST_DEBUG_FUNCPTR (gst_ducati_h264dec_update_buffer_size);
bclass->can_drop_frame =
GST_DEBUG_FUNCPTR (gst_ducati_h264dec_can_drop_frame);
bclass->query = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_query);
- bclass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_push_output);
- bclass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_on_flush);
bclass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_set_sink_caps);
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_finalize);
}
static void
gst_ducati_h264dec_init (GstDucatiH264Dec * self,
GstDucatiH264DecClass * gclass)
{
- self->backlog_maxframes = 0;
- self->backlog_nframes = 0;
+#ifndef GST_DISABLE_GST_DEBUG
+ GstDucatiVidDec *dec = GST_DUCATIVIDDEC (self);
+
+ dec->error_strings[0] = "no error-free slice";
+ dec->error_strings[1] = "error parsing SPS";
+ dec->error_strings[2] = "error parsing PPS";
+ dec->error_strings[3] = "error parsing slice header";
+ dec->error_strings[4] = "error parsing MB data";
+ dec->error_strings[5] = "unknown SPS";
+ dec->error_strings[6] = "unknown PPS";
+ dec->error_strings[7] = "invalid parameter";
+ dec->error_strings[16] = "unsupported feature";
+ dec->error_strings[17] = "SEI buffer overflow";
+ dec->error_strings[18] = "stream end";
+ dec->error_strings[19] = "no free buffers";
+ dec->error_strings[20] = "resolution change";
+ dec->error_strings[21] = "unsupported resolution";
+ dec->error_strings[22] = "invalid maxNumRefFrames";
+ dec->error_strings[23] = "invalid mbox message";
+ dec->error_strings[24] = "bad datasync input";
+ dec->error_strings[25] = "missing slice";
+ dec->error_strings[26] = "bad datasync param";
+ dec->error_strings[27] = "bad hw state";
+ dec->error_strings[28] = "temporal direct mode";
+ dec->error_strings[29] = "display width too small";
+ dec->error_strings[30] = "no SPS/PPS header";
+ dec->error_strings[31] = "gap in frame num";
+#endif
}