9b553505bcf599c3eee66ef2359767fdb43807e1
[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
46 GST_BOILERPLATE (GstDucatiH264Dec, gst_ducati_h264dec, GstDucatiVidDec,
47     GST_TYPE_DUCATIVIDDEC);
49 /* *INDENT-OFF* */
50 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
51     GST_PAD_SINK,
52     GST_PAD_ALWAYS,
53     GST_STATIC_CAPS ("video/x-h264, "
54         "stream-format = byte-stream, "   /* only byte-stream */
55         "alignment = au, "          /* only entire frames */
56         "width = (int)[ 16, 2048 ], "
57         "height = (int)[ 16, 2048 ], "
58         "framerate = (fraction)[ 0, max ],"
59         "profile = (string){constrained-baseline, baseline, main, extended};"
60         "video/x-h264, "
61         "stream-format = byte-stream, "   /* only byte-stream */
62         "alignment = au, "          /* only entire frames */
63         "width = (int)[ 16, 2048 ], "
64         "height = (int)[ 16, 2048 ], "
65         "framerate = (fraction)[ 0, max ],"
66         "profile = (string) {high, high-10-intra, high-10, high-4:2:2-intra, "
67         "high-4:2:2, high-4:4:4-intra, high-4:4:4, cavlc-4:4:4-intra}, "
68         "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};")
69     );
71 static const struct
72 {
73   const char *level;
74   gint kb;
75 } max_dpb_by_level[] = {
76   { "1", 149 },
77   { "1b", 149 }, /* That one's not in the spec ?? */
78   { "1.1", 338 },
79   { "1.2", 891 },
80   { "1.3", 891 },
81   { "2", 891 },
82   { "2.1", 1782 },
83   { "2.2", 3038 },
84   { "3", 3038 },
85   { "3.1", 6750 },
86   { "3.2", 7680 },
87   { "4", 12288 },
88   { "4.1", 12288 },
89   { "4.2", 12288 },
90   { "5", 41400 },
91   { "5.1", 69120 },
92 };
93 /* *INDENT-ON* */
95 /* GstDucatiVidDec vmethod implementations */
97 static void
98 gst_ducati_h264dec_update_buffer_size (GstDucatiVidDec * self)
99 {
100   gint w = self->width;
101   gint h = self->height;
103   /* calculate output buffer parameters: */
104   self->padded_width = ALIGN2 (w + (2 * PADX), 7);
105   self->padded_height = h + 4 * PADY;
106   self->min_buffers = MIN (16, 32768 / ((w / 16) * (h / 16))) + 3;
109 static gboolean
110 gst_ducati_h264dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
111     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
113   gboolean ret = parent_class->allocate_params (self,
114       sizeof (IH264VDEC_Params), sizeof (IH264VDEC_DynamicParams),
115       sizeof (IH264VDEC_Status), sizeof (IH264VDEC_InArgs),
116       sizeof (IH264VDEC_OutArgs));
118   if (ret) {
119     IH264VDEC_Params *params = (IH264VDEC_Params *) self->params;
121     self->params->displayDelay = IVIDDEC3_DECODE_ORDER;
122     params->maxNumRefFrames = IH264VDEC_NUM_REFFRAMES_AUTO;
123     params->pConstantMemory = 0;
124     params->presetLevelIdc = IH264VDEC_LEVEL41;
125     params->errConcealmentMode = IH264VDEC_APPLY_CONCEALMENT;
126     params->temporalDirModePred = TRUE;
127   }
129   return ret;
132 static gint
133 gst_ducati_h264dec_handle_error (GstDucatiVidDec * self, gint ret,
134     gint extended_error, gint status_extended_error)
136   if (extended_error & 0x00000001) {
137     /* No valid slice. This seems to be bad enough that it's better to flush and
138      * skip to the next keyframe.
139      */
141     if (extended_error == 0x00000201) {
142       /* the codec doesn't unlock the input buffer in this case... */
143       gst_buffer_unref ((GstBuffer *) self->inArgs->inputID);
144       self->inArgs->inputID = 0;
145     }
147     self->needs_flushing = TRUE;
148   }
150   ret = parent_class->handle_error (self, ret, extended_error,
151       status_extended_error);
153   return ret;
156 static gboolean
157 gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
158     GstQuery * query, gboolean * forward)
160   GstDucatiH264Dec *self = GST_DUCATIH264DEC (vdec);
161   gboolean res = TRUE;
163   switch (GST_QUERY_TYPE (query)) {
164     case GST_QUERY_LATENCY:
165     {
166       gboolean live;
167       GstClockTime min, max, latency;
169       if (vdec->fps_d == 0) {
170         GST_INFO_OBJECT (self, "not ready to report latency");
171         res = FALSE;
172         break;
173       }
175       gst_query_parse_latency (query, &live, &min, &max);
176       if (vdec->fps_n != 0)
177         latency = gst_util_uint64_scale (GST_SECOND, vdec->fps_d, vdec->fps_n);
178       else
179         latency = 0;
181       /* Take into account the backlog frames for reordering */
182       latency *= (self->backlog_maxframes + 1);
184       if (min == GST_CLOCK_TIME_NONE)
185         min = latency;
186       else
187         min += latency;
189       if (max != GST_CLOCK_TIME_NONE)
190         max += latency;
192       GST_INFO_OBJECT (self,
193           "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
194           GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
195       gst_query_set_latency (query, live, min, max);
196       break;
197     }
198     default:
199       break;
200   }
202   if (res)
203     res = parent_class->query (vdec, pad, query, forward);
205   return res;
208 static gboolean
209 gst_ducati_h264dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
210     gint64 diff)
212   gboolean is_bframe = GST_BUFFER_FLAG_IS_SET (buf,
213       GST_BUFFER_FLAG_B_FRAME);
215   if (diff >= 0 && is_bframe)
216     return TRUE;
218   return FALSE;
221 static gint
222 gst_ducati_h264dec_find_max_dpb_from_level (GstDucatiVidDec * self,
223     const char *level)
225   guint n;
227   for (n = 0; n < G_N_ELEMENTS (max_dpb_by_level); ++n)
228     if (!strcmp (level, max_dpb_by_level[n].level))
229       return max_dpb_by_level[n].kb;
231   GST_WARNING_OBJECT (self, "Max DBP not found for level %s", level);
232   return -1;
235 static gint
236 gst_ducati_h264dec_get_max_dpb_size (GstDucatiVidDec * self, GstCaps * caps)
238   gint wmb = (self->width + 15) / 16;
239   gint hmb = (self->height + 15) / 16;
240   gint max_dpb, max_dpb_size;
241   GstStructure *structure;
242   const char *level;
243   float chroma_factor = 1.5;    /* We only support NV12, which is 4:2:0 */
245   /* Min( 1024 * MaxDPB / ( PicWidthInMbs * FrameHeightInMbs * 256 * ChromaFormatFactor ), 16 ) */
247   structure = gst_caps_get_structure (caps, 0);
248   if (!structure)
249     return 16;
251   level = gst_structure_get_string (structure, "level");
252   if (!level)
253     return 16;
255   max_dpb = gst_ducati_h264dec_find_max_dpb_from_level (self, level);
256   if (max_dpb < 0)
257     return 16;
259   max_dpb_size =
260       lrint (ceil (1024 * max_dpb / (wmb * hmb * 256 * chroma_factor)));
261   if (max_dpb_size > 16)
262     max_dpb_size = 16;
264   return max_dpb_size;
267 static gboolean
268 gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
270   GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
271   GstStructure *structure;
273   GST_DEBUG_OBJECT (self, "set_sink_caps: %" GST_PTR_FORMAT, caps);
275   if (!GST_CALL_PARENT_WITH_DEFAULT (GST_DUCATIVIDDEC_CLASS, set_sink_caps,
276           (self, caps), TRUE))
277     return FALSE;
279   /* HW decoder fails in GETSTATUS */
280 #if 0
281   /* When we have the first decoded buffer, we ask the decoder for the
282      max number of frames needed to reorder */
283   int err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
284       self->dynParams, self->status);
285   if (!err) {
286     IH264VDEC_Status *s = (IH264VDEC_Status *) self->status;
287     if (s->spsMaxRefFrames > MAX_BACKLOG_FRAMES) {
288       h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
289       GST_WARNING_OBJECT (self,
290           "Stream needs %d frames for reordering, we can only accomodate %d",
291           s->spsMaxRefFrames, MAX_BACKLOG_FRAMES);
292     } else {
293       h264dec->backlog_maxframes = s->spsMaxRefFrames;
294       GST_INFO_OBJECT (self, "Num frames for reordering: %d",
295           h264dec->backlog_maxframes);
296     }
297   } else {
298     h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
299     GST_WARNING_OBJECT (self,
300         "Failed to request num frames for reordering, defaulting to %d",
301         h264dec->backlog_maxframes);
302   }
303 #endif
305   h264dec->backlog_maxframes = -1;
307   structure = gst_caps_get_structure (caps, 0);
308   if (structure) {
309     gint num_ref_frames = -1, num_reorder_frames = -1;
310     if (gst_structure_get_int (structure, "num-ref-frames", &num_ref_frames)
311         && num_ref_frames >= 0) {
312       ((IH264VDEC_Params *) self->params)->maxNumRefFrames = num_ref_frames;
313     }
314     if (gst_structure_get_int (structure, "num-reorder-frames",
315             &num_reorder_frames)
316         && num_reorder_frames >= 0) {
317       if (num_reorder_frames > MAX_BACKLOG_FRAMES) {
318         h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
319         GST_WARNING_OBJECT (self,
320             "Stream needs %d frames for reordering, we can only accomodate %d",
321             num_reorder_frames, MAX_BACKLOG_FRAMES);
322       } else {
323         h264dec->backlog_maxframes = num_reorder_frames;
324         GST_INFO_OBJECT (self, "Num frames for reordering: %d",
325             h264dec->backlog_maxframes);
326       }
327     }
328   }
330   /* If not present, use the spec forumula for a bound */
331   if (h264dec->backlog_maxframes < 0) {
332     h264dec->backlog_maxframes =
333         gst_ducati_h264dec_get_max_dpb_size (self, caps);
334     GST_WARNING_OBJECT (self,
335         "num-reorder-frames not found on caps, defaulting to %d",
336         h264dec->backlog_maxframes);
337   }
339   return TRUE;
342 /* The following few functions reorder buffers by "picture order
343    count", which is passed through OFFSET_END by h264parse.
344  */
346 static GstFlowReturn
347 gst_ducati_h264dec_push_earliest (GstDucatiH264Dec * self)
349   guint64 earliest_poc = G_MAXUINT64;
350   guint earliest_index = 0, i;
351   GstBuffer *buf;
353   if (self->backlog_nframes == 0)
354     return GST_FLOW_OK;
356   /* work out which frame has the earliest poc */
357   for (i = 0; i < self->backlog_nframes; i++) {
358     guint64 poc = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
359     if (earliest_poc == G_MAXUINT64 || poc < earliest_poc) {
360       earliest_poc = poc;
361       earliest_index = i;
362     }
363   }
365   /* send it, giving away the ref */
366   buf = self->backlog_frames[earliest_index];
367   self->backlog_frames[earliest_index] =
368       self->backlog_frames[--self->backlog_nframes];
369   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
370       buf);
371   return gst_pad_push (GST_DUCATIVIDDEC (self)->srcpad, buf);
374 static GstBuffer *
375 gst_ducati_h264dec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
377   GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
379   /* If we're about to push an IDR frame, then we can flush all the frames
380      we currently have queued. This is necessary as picture order count
381      is local to each IDR + set of non IDR frames, so will restart at 0
382      when next IDR frames comes in. */
383   if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
384     GST_DEBUG_OBJECT (self, "Got keyframe, pushing %u frames",
385         h264dec->backlog_nframes);
386     while (h264dec->backlog_nframes > 0) {
387       gst_ducati_h264dec_push_earliest (h264dec);
388     }
389   }
391   return parent_class->push_input (self, buf);
394 static GstFlowReturn
395 gst_ducati_h264dec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
397   GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
398   GstFlowReturn ret = GST_FLOW_OK;
400   /* add the frame to the list, the array will own the ref */
401   GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
402   h264dec->backlog_frames[h264dec->backlog_nframes++] = buf;
404   /* push till we have no more than the max needed, or error */
405   while (h264dec->backlog_nframes > h264dec->backlog_maxframes) {
406     ret = gst_ducati_h264dec_push_earliest (h264dec);
407     if (ret != GST_FLOW_OK)
408       break;
409   }
411   return ret;
414 static void
415 gst_ducati_h264dec_on_flush (GstDucatiVidDec * self, gboolean eos)
417   GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
419   /* push everything on the backlog, ignoring errors */
420   while (h264dec->backlog_nframes > 0) {
421     gst_ducati_h264dec_push_earliest (h264dec);
422   }
425 /* GObject vmethod implementations */
427 static void
428 gst_ducati_h264dec_base_init (gpointer gclass)
430   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
432   gst_element_class_set_details_simple (element_class,
433       "DucatiH264Dec",
434       "Codec/Decoder/Video",
435       "Decodes video in H.264/bytestream format with ducati",
436       "Rob Clark <rob@ti.com>");
438   gst_element_class_add_pad_template (element_class,
439       gst_static_pad_template_get (&sink_factory));
442 static void
443 gst_ducati_h264dec_class_init (GstDucatiH264DecClass * klass)
445   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
446   bclass->codec_name = "ivahd_h264dec";
447   bclass->update_buffer_size =
448       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_update_buffer_size);
449   bclass->allocate_params =
450       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_allocate_params);
451   bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_handle_error);
452   bclass->can_drop_frame =
453       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_can_drop_frame);
454   bclass->query = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_query);
455   bclass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_push_input);
456   bclass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_push_output);
457   bclass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_on_flush);
458   bclass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_set_sink_caps);
461 static void
462 gst_ducati_h264dec_init (GstDucatiH264Dec * self,
463     GstDucatiH264DecClass * gclass)
465   self->backlog_maxframes = 0;
466   self->backlog_nframes = 0;