Realigned code on new Ducati header files
[glsdk/gst-plugin-ducati.git] / src / gstducatih264dec.c
1 /*
2  * GStreamer
3  * Copyright (c) 2010, Texas Instruments Incorporated
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation
8  * version 2.1 of the License.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
20 /**
21  * SECTION:element-ducatih264dec
22  *
23  * FIXME:Describe ducatih264dec here.
24  *
25  * <refsect2>
26  * <title>Example launch line</title>
27  * |[
28  * gst-launch -v -m fakesrc ! ducatih264dec ! fakesink silent=TRUE
29  * ]|
30  * </refsect2>
31  */
33 #ifdef HAVE_CONFIG_H
34 #  include <config.h>
35 #endif
37 #include <math.h>
38 #include "gstducatih264dec.h"
41 #define GST_BUFFER_FLAG_B_FRAME (GST_BUFFER_FLAG_LAST << 0)
42 #define PADX  32
43 #define PADY  24
45 /* This structure is not public, this should be replaced by
46    sizeof(sErrConcealLayerStr) when it is made so. */
47 #define SIZE_OF_CONCEALMENT_DATA 65536
50 GST_BOILERPLATE (GstDucatiH264Dec, gst_ducati_h264dec, GstDucatiVidDec,
51     GST_TYPE_DUCATIVIDDEC);
53 /* *INDENT-OFF* */
54 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
55     GST_PAD_SINK,
56     GST_PAD_ALWAYS,
57     GST_STATIC_CAPS ("video/x-h264, "
58         "stream-format = byte-stream, "   /* only byte-stream */
59         "alignment = au, "          /* only entire frames */
60         "width = (int)[ 16, 2048 ], "
61         "height = (int)[ 16, 2048 ], "
62         "framerate = (fraction)[ 0, max ],"
63         "profile = (string){constrained-baseline, baseline, main, extended};"
64         "video/x-h264, "
65         "stream-format = byte-stream, "   /* only byte-stream */
66         "alignment = au, "          /* only entire frames */
67         "width = (int)[ 16, 2048 ], "
68         "height = (int)[ 16, 2048 ], "
69         "framerate = (fraction)[ 0, max ],"
70         "profile = (string) {high, high-10-intra, high-10, high-4:2:2-intra, "
71         "high-4:2:2, high-4:4:4-intra, high-4:4:4, cavlc-4:4:4-intra}, "
72         "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};")
73     );
75 static const struct
76 {
77   const char *level;
78   gint kb;
79 } max_dpb_by_level[] = {
80   { "1", 149 },
81   { "1b", 149 }, /* That one's not in the spec ?? */
82   { "1.1", 338 },
83   { "1.2", 891 },
84   { "1.3", 891 },
85   { "2", 891 },
86   { "2.1", 1782 },
87   { "2.2", 3038 },
88   { "3", 3038 },
89   { "3.1", 6750 },
90   { "3.2", 7680 },
91   { "4", 12288 },
92   { "4.1", 12288 },
93   { "4.2", 12288 },
94   { "5", 41400 },
95   { "5.1", 69120 },
96 };
97 /* *INDENT-ON* */
99 /* GstDucatiVidDec vmethod implementations */
101 static void
102 gst_ducati_h264dec_update_buffer_size (GstDucatiVidDec * self)
104   gint w = self->width;
105   gint h = self->height;
107   /* calculate output buffer parameters: */
108   self->padded_width = ALIGN2 (w + (2 * PADX), 7);
109   self->padded_height = h + 4 * PADY;
110   self->min_buffers = MIN (16, 32768 / ((w / 16) * (h / 16))) + 3;
113 static gboolean
114 gst_ducati_h264dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
115     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
117   gboolean ret = parent_class->allocate_params (self,
118       sizeof (IH264VDEC_Params), sizeof (IH264VDEC_DynamicParams),
119       sizeof (IH264VDEC_Status), sizeof (IH264VDEC_InArgs),
120       sizeof (IH264VDEC_OutArgs));
122   if (ret) {
123     IH264VDEC_Params *params = (IH264VDEC_Params *) self->params;
125     self->params->displayDelay = IVIDDEC3_DECODE_ORDER;
126     params->dpbSizeInFrames = IH264VDEC_DPB_NUMFRAMES_AUTO;
127     params->pConstantMemory = 0;
128     params->presetLevelIdc = IH264VDEC_LEVEL41;
129     params->errConcealmentMode = IH264VDEC_APPLY_CONCEALMENT;
130     params->temporalDirModePred = TRUE;
132     if (self->codec_debug_info) {
133       /* We must allocate a byte per MB, plus the size of some struture which
134          is not public. Place this in the first metadata buffer slot, and ask
135          for MBINFO metadata for it. */
136       GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
137       unsigned mbw = (self->width + 15) / 16;
138       unsigned mbh = (self->height + 15) / 16;
139       unsigned nmb = mbw * mbh;
141       h264dec->bo_mberror =
142           omap_bo_new (self->device, nmb + SIZE_OF_CONCEALMENT_DATA,
143           OMAP_BO_WC);
144       self->outBufs->descs[2].memType = XDM_MEMTYPE_BO;
145       self->outBufs->descs[2].buf =
146           (XDAS_Int8 *) omap_bo_handle (h264dec->bo_mberror);
147       self->outBufs->descs[2].bufSize.bytes = nmb + SIZE_OF_CONCEALMENT_DATA;
148       self->params->metadataType[0] = IVIDEO_METADATAPLANE_MBINFO;
149     }
150   }
152   return ret;
155 static gint
156 gst_ducati_h264dec_handle_error (GstDucatiVidDec * self, gint ret,
157     gint extended_error, gint status_extended_error)
159   GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
160   const unsigned char *mberror, *mbcon;
161   unsigned mbw, mbh, nmb;
162   uint16_t mbwr, mbhr;
163   size_t n, nerr = 0;
164   char *line;
165   unsigned x, y;
167   if (h264dec->bo_mberror) {
168     mberror = omap_bo_map (h264dec->bo_mberror);
169     mbw = (self->width + 15) / 16;
170     mbh = (self->height + 15) / 16;
171     nmb = mbw * mbh;
172     mbcon = mberror + nmb;
173     mbwr = ((const uint16_t *) mbcon)[21];      /* not a public struct */
174     mbhr = ((const uint16_t *) mbcon)[22];      /* not a public struct */
175     if (nmb != mbwr * mbhr) {
176       GST_WARNING_OBJECT (self, "Failed to find MB size - "
177           "corruption might have happened");
178     } else {
179       for (n = 0; n < nmb; ++n) {
180         if (mberror[n])
181           ++nerr;
182       }
183       GST_INFO_OBJECT (self, "Frame has %zu MB errors over %zu (%u x %u) MBs",
184           nerr, nmb, mbwr, mbhr);
185       line = g_malloc (mbw + 1);
186       for (y = 0; y < mbh; y++) {
187         line[mbw] = 0;
188         for (x = 0; x < mbw; x++) {
189           line[x] = mberror[x + y * mbw] ? '!' : '.';
190         }
191         GST_INFO_OBJECT (self, "MB: %4u: %s", y, line);
192       }
193       g_free (line);
194     }
195   }
197   if (extended_error & 0x00000001) {
198     /* No valid slice. This seems to be bad enough that it's better to flush and
199      * skip to the next keyframe.
200      */
202     if (extended_error == 0x00000201) {
203       /* the codec doesn't unlock the input buffer in this case... */
204       gst_buffer_unref ((GstBuffer *) self->inArgs->inputID);
205       self->inArgs->inputID = 0;
206     }
208     self->needs_flushing = TRUE;
209   }
211   ret = parent_class->handle_error (self, ret, extended_error,
212       status_extended_error);
214   return ret;
217 static gboolean
218 gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
219     GstQuery * query, gboolean * forward)
221   GstDucatiH264Dec *self = GST_DUCATIH264DEC (vdec);
222   gboolean res = TRUE;
224   switch (GST_QUERY_TYPE (query)) {
225     case GST_QUERY_LATENCY:
226     {
227       gboolean live;
228       GstClockTime min, max, latency;
230       if (vdec->fps_d == 0) {
231         GST_INFO_OBJECT (self, "not ready to report latency");
232         res = FALSE;
233         break;
234       }
236       gst_query_parse_latency (query, &live, &min, &max);
237       if (vdec->fps_n != 0)
238         latency = gst_util_uint64_scale (GST_SECOND, vdec->fps_d, vdec->fps_n);
239       else
240         latency = 0;
242       /* Take into account the backlog frames for reordering */
243       latency *= (vdec->backlog_maxframes + 1);
245       if (min == GST_CLOCK_TIME_NONE)
246         min = latency;
247       else
248         min += latency;
250       if (max != GST_CLOCK_TIME_NONE)
251         max += latency;
253       GST_INFO_OBJECT (self,
254           "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
255           GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
256       gst_query_set_latency (query, live, min, max);
257       break;
258     }
259     default:
260       break;
261   }
263   if (res)
264     res = parent_class->query (vdec, pad, query, forward);
266   return res;
269 static gboolean
270 gst_ducati_h264dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
271     gint64 diff)
273   gboolean is_bframe = GST_BUFFER_FLAG_IS_SET (buf,
274       GST_BUFFER_FLAG_B_FRAME);
276   if (diff >= 0 && is_bframe)
277     return TRUE;
279   return FALSE;
282 static gint
283 gst_ducati_h264dec_find_max_dpb_from_level (GstDucatiVidDec * self,
284     const char *level)
286   guint n;
288   for (n = 0; n < G_N_ELEMENTS (max_dpb_by_level); ++n)
289     if (!strcmp (level, max_dpb_by_level[n].level))
290       return max_dpb_by_level[n].kb;
292   GST_WARNING_OBJECT (self, "Max DBP not found for level %s", level);
293   return -1;
296 static gint
297 gst_ducati_h264dec_get_max_dpb_size (GstDucatiVidDec * self, GstCaps * caps)
299   gint wmb = (self->width + 15) / 16;
300   gint hmb = (self->height + 15) / 16;
301   gint max_dpb, max_dpb_size;
302   GstStructure *structure;
303   const char *level;
304   float chroma_factor = 1.5;    /* We only support NV12, which is 4:2:0 */
306   /* Min( 1024 * MaxDPB / ( PicWidthInMbs * FrameHeightInMbs * 256 * ChromaFormatFactor ), 16 ) */
308   structure = gst_caps_get_structure (caps, 0);
309   if (!structure)
310     return -1;
312   level = gst_structure_get_string (structure, "level");
313   if (!level)
314     return -1;
316   max_dpb = gst_ducati_h264dec_find_max_dpb_from_level (self, level);
317   if (max_dpb < 0)
318     return -1;
320   max_dpb_size =
321       lrint (ceil (1024 * max_dpb / (wmb * hmb * 256 * chroma_factor)));
322   if (max_dpb_size > MAX_BACKLOG_FRAMES)
323     max_dpb_size = MAX_BACKLOG_FRAMES;
325   return max_dpb_size;
328 static gboolean
329 gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
331   GstStructure *structure;
333   GST_DEBUG_OBJECT (self, "set_sink_caps: %" GST_PTR_FORMAT, caps);
335   if (!GST_CALL_PARENT_WITH_DEFAULT (GST_DUCATIVIDDEC_CLASS, set_sink_caps,
336           (self, caps), TRUE))
337     return FALSE;
339   /* HW decoder fails in GETSTATUS */
340 #if 0
341   /* When we have the first decoded buffer, we ask the decoder for the
342      max number of frames needed to reorder */
343   int err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
344       self->dynParams, self->status);
345   if (!err) {
346     IH264VDEC_Status *s = (IH264VDEC_Status *) self->status;
347     if (s->spsMaxRefFrames > MAX_BACKLOG_FRAMES) {
348       h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
349       GST_WARNING_OBJECT (self,
350           "Stream needs %d frames for reordering, we can only accomodate %d",
351           s->spsMaxRefFrames, MAX_BACKLOG_FRAMES);
352     } else {
353       h264dec->backlog_maxframes = s->spsMaxRefFrames;
354       GST_INFO_OBJECT (self, "Num frames for reordering: %d",
355           h264dec->backlog_maxframes);
356     }
357   } else {
358     h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
359     GST_WARNING_OBJECT (self,
360         "Failed to request num frames for reordering, defaulting to %d",
361         h264dec->backlog_maxframes);
362   }
363 #endif
365   self->backlog_maxframes = -1;
367   structure = gst_caps_get_structure (caps, 0);
368   if (structure) {
369     gint num_ref_frames = -1, num_reorder_frames = -1;
370     const char *profile;
372     /* baseline profile does not use B frames (and I'll say constrained-baseline
373        is unlikely either from the name, it's not present in my H264 spec... */
374     profile = gst_structure_get_string (structure, "profile");
375     if (profile && (!strcmp (profile, "baseline")
376             || !strcmp (profile, "constrained-baseline"))) {
377       GST_DEBUG_OBJECT (self, "No need for reordering for %s profile", profile);
378       self->backlog_maxframes = 0;
379       goto no_b_frames;
380     }
383     if (gst_structure_get_int (structure, "num-ref-frames", &num_ref_frames)
384         && num_ref_frames >= 0) {
385       ((IH264VDEC_Params *) self->params)->dpbSizeInFrames = num_ref_frames;
386     }
387     if (gst_structure_get_int (structure, "num-reorder-frames",
388             &num_reorder_frames)
389         && num_reorder_frames >= 0) {
390       if (num_reorder_frames > MAX_BACKLOG_FRAMES) {
391         self->backlog_maxframes = MAX_BACKLOG_FRAMES;
392         GST_WARNING_OBJECT (self,
393             "Stream needs %d frames for reordering, we can only accomodate %d",
394             num_reorder_frames, MAX_BACKLOG_FRAMES);
395       } else {
396         self->backlog_maxframes = num_reorder_frames;
397         GST_INFO_OBJECT (self, "Num frames for reordering: %d",
398             self->backlog_maxframes);
399       }
400     }
401   }
403   /* If not present, use the spec forumula for a bound */
404   if (self->backlog_maxframes < 0) {
405     self->backlog_maxframes = gst_ducati_h264dec_get_max_dpb_size (self, caps);
406     if (self->backlog_maxframes >= 0) {
407       GST_WARNING_OBJECT (self,
408           "num-reorder-frames not found on caps, calculation from stream parameters gives %d",
409           self->backlog_maxframes);
410     } else {
411       self->backlog_maxframes = MAX_H264_BACKLOG_FRAMES;
412     }
413   }
414   if (self->backlog_maxframes > self->backlog_max_maxframes)
415     self->backlog_maxframes = self->backlog_max_maxframes;
416   GST_WARNING_OBJECT (self,
417       "Using %d frames for reordering", self->backlog_maxframes);
419 no_b_frames:
421   return TRUE;
424 /* GObject vmethod implementations */
426 static void
427 gst_ducati_h264dec_base_init (gpointer gclass)
429   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
431   gst_element_class_set_details_simple (element_class,
432       "DucatiH264Dec",
433       "Codec/Decoder/Video",
434       "Decodes video in H.264/bytestream format with ducati",
435       "Rob Clark <rob@ti.com>");
437   gst_element_class_add_pad_template (element_class,
438       gst_static_pad_template_get (&sink_factory));
441 static void
442 gst_ducati_h264dec_finalize (GObject * obj)
444   GstDucatiH264Dec *self = GST_DUCATIH264DEC (obj);
445   if (self->bo_mberror)
446     omap_bo_del (self->bo_mberror);
447   G_OBJECT_CLASS (parent_class)->finalize (obj);
450 static void
451 gst_ducati_h264dec_class_init (GstDucatiH264DecClass * klass)
453   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
454   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
455   bclass->codec_name = "ivahd_h264dec";
456   bclass->update_buffer_size =
457       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_update_buffer_size);
458   bclass->allocate_params =
459       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_allocate_params);
460   bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_handle_error);
461   bclass->can_drop_frame =
462       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_can_drop_frame);
463   bclass->query = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_query);
464   bclass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_set_sink_caps);
465   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_finalize);
468 static void
469 gst_ducati_h264dec_init (GstDucatiH264Dec * self,
470     GstDucatiH264DecClass * gclass)
472 #ifndef GST_DISABLE_GST_DEBUG
473   GstDucatiVidDec *dec = GST_DUCATIVIDDEC (self);
475   dec->error_strings[0] = "no error-free slice";
476   dec->error_strings[1] = "error parsing SPS";
477   dec->error_strings[2] = "error parsing PPS";
478   dec->error_strings[3] = "error parsing slice header";
479   dec->error_strings[4] = "error parsing MB data";
480   dec->error_strings[5] = "unknown SPS";
481   dec->error_strings[6] = "unknown PPS";
482   dec->error_strings[7] = "invalid parameter";
483   dec->error_strings[16] = "unsupported feature";
484   dec->error_strings[17] = "SEI buffer overflow";
485   dec->error_strings[18] = "stream end";
486   dec->error_strings[19] = "no free buffers";
487   dec->error_strings[20] = "resolution change";
488   dec->error_strings[21] = "unsupported resolution";
489   dec->error_strings[22] = "invalid maxNumRefFrames";
490   dec->error_strings[23] = "invalid mbox message";
491   dec->error_strings[24] = "bad datasync input";
492   dec->error_strings[25] = "missing slice";
493   dec->error_strings[26] = "bad datasync param";
494   dec->error_strings[27] = "bad hw state";
495   dec->error_strings[28] = "temporal direct mode";
496   dec->error_strings[29] = "display width too small";
497   dec->error_strings[30] = "no SPS/PPS header";
498   dec->error_strings[31] = "gap in frame num";
499 #endif