d7149fbef30582d80b1285fe0cc1dce81a3d975a
[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;
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;
314       if (num_ref_frames > MAX_BACKLOG_FRAMES) {
315         h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
316         GST_WARNING_OBJECT (self,
317             "Stream needs %d frames for reordering, we can only accomodate %d",
318             num_ref_frames, MAX_BACKLOG_FRAMES);
319       } else {
320         h264dec->backlog_maxframes = num_ref_frames;
321         GST_INFO_OBJECT (self, "Num frames for reordering: %d",
322             h264dec->backlog_maxframes);
323       }
324     }
325   }
327   /* If not present, use the spec forumula for a bound */
328   if (h264dec->backlog_maxframes < 0) {
329     h264dec->backlog_maxframes =
330         gst_ducati_h264dec_get_max_dpb_size (self, caps);
331     GST_WARNING_OBJECT (self,
332         "num-ref-frames not found on caps, defaulting to %d",
333         h264dec->backlog_maxframes);
334   }
336   return TRUE;
339 /* The following few functions reorder buffers by "picture order
340    count", which is passed through OFFSET_END by h264parse.
341  */
343 static GstFlowReturn
344 gst_ducati_h264dec_push_earliest (GstDucatiH264Dec * self)
346   guint64 earliest_poc = G_MAXUINT64;
347   guint earliest_index = 0, i;
348   GstBuffer *buf;
350   if (self->backlog_nframes == 0)
351     return GST_FLOW_OK;
353   /* work out which frame has the earliest poc */
354   for (i = 0; i < self->backlog_nframes; i++) {
355     guint64 poc = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
356     if (earliest_poc == G_MAXUINT64 || poc < earliest_poc) {
357       earliest_poc = poc;
358       earliest_index = i;
359     }
360   }
362   /* send it, giving away the ref */
363   buf = self->backlog_frames[earliest_index];
364   self->backlog_frames[earliest_index] =
365       self->backlog_frames[--self->backlog_nframes];
366   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
367       buf);
368   return gst_pad_push (GST_DUCATIVIDDEC (self)->srcpad, buf);
371 static GstBuffer *
372 gst_ducati_h264dec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
374   GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
376   /* If we're about to push an IDR frame, then we can flush all the frames
377      we currently have queued. This is necessary as picture order count
378      is local to each IDR + set of non IDR frames, so will restart at 0
379      when next IDR frames comes in. */
380   if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
381     GST_DEBUG_OBJECT (self, "Got keyframe, pushing %u frames",
382         h264dec->backlog_nframes);
383     while (h264dec->backlog_nframes > 0) {
384       gst_ducati_h264dec_push_earliest (h264dec);
385     }
386   }
388   return parent_class->push_input (self, buf);
391 static GstFlowReturn
392 gst_ducati_h264dec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
394   GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
395   GstFlowReturn ret = GST_FLOW_OK;
397   /* add the frame to the list, the array will own the ref */
398   GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
399   h264dec->backlog_frames[h264dec->backlog_nframes++] = buf;
401   /* push till we have no more than the max needed, or error */
402   while (h264dec->backlog_nframes > h264dec->backlog_maxframes) {
403     ret = gst_ducati_h264dec_push_earliest (h264dec);
404     if (ret != GST_FLOW_OK)
405       break;
406   }
408   return ret;
411 static void
412 gst_ducati_h264dec_on_flush (GstDucatiVidDec * self, gboolean eos)
414   GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
416   /* push everything on the backlog, ignoring errors */
417   while (h264dec->backlog_nframes > 0) {
418     gst_ducati_h264dec_push_earliest (h264dec);
419   }
422 /* GObject vmethod implementations */
424 static void
425 gst_ducati_h264dec_base_init (gpointer gclass)
427   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
429   gst_element_class_set_details_simple (element_class,
430       "DucatiH264Dec",
431       "Codec/Decoder/Video",
432       "Decodes video in H.264/bytestream format with ducati",
433       "Rob Clark <rob@ti.com>");
435   gst_element_class_add_pad_template (element_class,
436       gst_static_pad_template_get (&sink_factory));
439 static void
440 gst_ducati_h264dec_class_init (GstDucatiH264DecClass * klass)
442   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
443   bclass->codec_name = "ivahd_h264dec";
444   bclass->update_buffer_size =
445       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_update_buffer_size);
446   bclass->allocate_params =
447       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_allocate_params);
448   bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_handle_error);
449   bclass->can_drop_frame =
450       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_can_drop_frame);
451   bclass->query = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_query);
452   bclass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_push_input);
453   bclass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_push_output);
454   bclass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_on_flush);
455   bclass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_set_sink_caps);
458 static void
459 gst_ducati_h264dec_init (GstDucatiH264Dec * self,
460     GstDucatiH264DecClass * gclass)
462   self->backlog_maxframes = 0;
463   self->backlog_nframes = 0;