Port DucatiVidDec to the Gstreamer 1.0 API
[gstreamer-omap:gst-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  */
19
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  */
32
33 #ifdef HAVE_CONFIG_H
34 #  include <config.h>
35 #endif
36
37 #include <math.h>
38 #include "gstducatih264dec.h"
39
40
41 #define GST_BUFFER_FLAG_B_FRAME (GST_BUFFER_FLAG_LAST << 0)
42 #define PADX  32
43 #define PADY  24
44
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
48
49 #define gst_ducati_h264dec_parent_class parent_class
50 G_DEFINE_TYPE (GstDucatiH264Dec, gst_ducati_h264dec, GST_TYPE_DUCATIVIDDEC);
51
52 /* *INDENT-OFF* */
53 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
54     GST_PAD_SINK,
55     GST_PAD_ALWAYS,
56     GST_STATIC_CAPS ("video/x-h264, "
57         "stream-format = byte-stream, "   /* only byte-stream */
58         "alignment = au, "          /* only entire frames */
59         "width = (int)[ 16, 2048 ], "
60         "height = (int)[ 16, 2048 ], "
61         "framerate = (fraction)[ 0, max ],"
62         "profile = (string){constrained-baseline, baseline, main, extended};"
63         "video/x-h264, "
64         "stream-format = byte-stream, "   /* only byte-stream */
65         "alignment = au, "          /* only entire frames */
66         "width = (int)[ 16, 2048 ], "
67         "height = (int)[ 16, 2048 ], "
68         "framerate = (fraction)[ 0, max ],"
69         "profile = (string) {high, high-10-intra, high-10, high-4:2:2-intra, "
70         "high-4:2:2, high-4:4:4-intra, high-4:4:4, cavlc-4:4:4-intra}, "
71         "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};")
72     );
73
74 static const struct
75 {
76   const char *level;
77   gint kb;
78 } max_dpb_by_level[] = {
79   { "1", 149 },
80   { "1b", 149 }, /* That one's not in the spec ?? */
81   { "1.1", 338 },
82   { "1.2", 891 },
83   { "1.3", 891 },
84   { "2", 891 },
85   { "2.1", 1782 },
86   { "2.2", 3038 },
87   { "3", 3038 },
88   { "3.1", 6750 },
89   { "3.2", 7680 },
90   { "4", 12288 },
91   { "4.1", 12288 },
92   { "4.2", 12288 },
93   { "5", 41400 },
94   { "5.1", 69120 },
95 };
96 /* *INDENT-ON* */
97
98 /* GstDucatiVidDec vmethod implementations */
99
100 static void
101 gst_ducati_h264dec_update_buffer_size (GstDucatiVidDec * self)
102 {
103   gint w = self->width;
104   gint h = self->height;
105
106   /* calculate output buffer parameters: */
107   self->padded_width = ALIGN2 (w + (2 * PADX), 7);
108   self->padded_height = h + 4 * PADY;
109   self->min_buffers = MIN (16, 32768 / ((w / 16) * (h / 16))) + 3;
110 }
111
112 static gboolean
113 gst_ducati_h264dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
114     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
115 {
116   gboolean ret = GST_DUCATIVIDDEC_CLASS (parent_class)->allocate_params (self,
117       sizeof (IH264VDEC_Params), sizeof (IH264VDEC_DynamicParams),
118       sizeof (IH264VDEC_Status), sizeof (IH264VDEC_InArgs),
119       sizeof (IH264VDEC_OutArgs));
120
121   if (ret) {
122     IH264VDEC_Params *params = (IH264VDEC_Params *) self->params;
123
124     params->dpbSizeInFrames = IH264VDEC_DPB_NUMFRAMES_AUTO;
125     params->pConstantMemory = 0;
126     params->presetLevelIdc = IH264VDEC_LEVEL41;
127     params->errConcealmentMode = IH264VDEC_APPLY_CONCEALMENT;
128     params->temporalDirModePred = TRUE;
129
130     if (self->codec_debug_info) {
131       /* We must allocate a byte per MB, plus the size of some struture which
132          is not public. Place this in the first metadata buffer slot, and ask
133          for MBINFO metadata for it. */
134       GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
135       unsigned mbw = (self->width + 15) / 16;
136       unsigned mbh = (self->height + 15) / 16;
137       unsigned nmb = mbw * mbh;
138
139       h264dec->bo_mberror =
140           omap_bo_new (self->device, nmb + SIZE_OF_CONCEALMENT_DATA,
141           OMAP_BO_WC);
142       self->outBufs->descs[2].memType = XDM_MEMTYPE_BO;
143       self->outBufs->descs[2].buf =
144           (XDAS_Int8 *) omap_bo_handle (h264dec->bo_mberror);
145       self->outBufs->descs[2].bufSize.bytes = nmb + SIZE_OF_CONCEALMENT_DATA;
146       self->params->metadataType[0] = IVIDEO_METADATAPLANE_MBINFO;
147     }
148   }
149
150   return ret;
151 }
152
153 static gint
154 gst_ducati_h264dec_handle_error (GstDucatiVidDec * self, gint ret,
155     gint extended_error, gint status_extended_error)
156 {
157   GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
158   const unsigned char *mberror, *mbcon;
159   unsigned mbw, mbh, nmb;
160   uint16_t mbwr, mbhr;
161   size_t n, nerr = 0;
162   char *line;
163   unsigned x, y;
164
165   if (h264dec->bo_mberror) {
166     mberror = omap_bo_map (h264dec->bo_mberror);
167     mbw = (self->width + 15) / 16;
168     mbh = (self->height + 15) / 16;
169     nmb = mbw * mbh;
170     mbcon = mberror + nmb;
171     mbwr = ((const uint16_t *) mbcon)[21];      /* not a public struct */
172     mbhr = ((const uint16_t *) mbcon)[22];      /* not a public struct */
173     if (nmb != mbwr * mbhr) {
174       GST_WARNING_OBJECT (self, "Failed to find MB size - "
175           "corruption might have happened");
176     } else {
177       for (n = 0; n < nmb; ++n) {
178         if (mberror[n])
179           ++nerr;
180       }
181       GST_INFO_OBJECT (self, "Frame has %zu MB errors over %zu (%u x %u) MBs",
182           nerr, nmb, mbwr, mbhr);
183       line = g_malloc (mbw + 1);
184       for (y = 0; y < mbh; y++) {
185         line[mbw] = 0;
186         for (x = 0; x < mbw; x++) {
187           line[x] = mberror[x + y * mbw] ? '!' : '.';
188         }
189         GST_INFO_OBJECT (self, "MB: %4u: %s", y, line);
190       }
191       g_free (line);
192     }
193   }
194
195   if (extended_error & 0x00000001) {
196     GST_WARNING_OBJECT (self,
197         "No valid slice... got to flush and skip to next KeyFrame");
198     /* No valid slice. This seems to be bad enough that it's better to flush and
199      * skip to the next keyframe.
200      */
201
202     if (extended_error == 0x00000201) {
203       /* the codec doesn't unlock the input buffer in this case... */
204       gst_video_codec_frame_unref ((GstVideoCodecFrame *) self->inArgs->
205           inputID);
206       self->inArgs->inputID = 0;
207     }
208
209     self->needs_flushing = TRUE;
210   }
211
212   ret =
213       GST_DUCATIVIDDEC_CLASS (parent_class)->handle_error (self, ret,
214       extended_error, status_extended_error);
215
216   return ret;
217 }
218
219 static gboolean
220 gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
221     GstQuery * query, gboolean * forward)
222 {
223   GstDucatiH264Dec *self = GST_DUCATIH264DEC (vdec);
224   gboolean res = TRUE;
225
226   switch (GST_QUERY_TYPE (query)) {
227     case GST_QUERY_LATENCY:
228     {
229       gboolean live;
230       GstClockTime min, max, latency;
231
232       if (vdec->input_state->info.fps_d == 0) {
233         GST_INFO_OBJECT (self, "not ready to report latency");
234         res = FALSE;
235         break;
236       }
237
238       gst_query_parse_latency (query, &live, &min, &max);
239       if (vdec->input_state->info.fps_n != 0)
240         latency = gst_util_uint64_scale (GST_SECOND,
241             vdec->input_state->info.fps_d, vdec->input_state->info.fps_n);
242       else
243         latency = 0;
244
245       /* FIXME: How do we get that info from the decoder?
246        *
247        * Take into account the backlog frames for reordering
248        * latency *= (vdec->backlog_maxframes + 1);
249        */
250
251       if (min == GST_CLOCK_TIME_NONE)
252         min = latency;
253       else
254         min += latency;
255
256       if (max != GST_CLOCK_TIME_NONE)
257         max += latency;
258
259       GST_INFO_OBJECT (self,
260           "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
261           GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
262       gst_query_set_latency (query, live, min, max);
263       break;
264     }
265     default:
266       break;
267   }
268
269   if (res)
270     res =
271         GST_DUCATIVIDDEC_CLASS (parent_class)->query (vdec, pad, query,
272         forward);
273   return res;
274 }
275
276 /* GObject vmethod implementations */
277
278 static void
279 gst_ducati_h264dec_finalize (GObject * obj)
280 {
281   GstDucatiH264Dec *self = GST_DUCATIH264DEC (obj);
282   if (self->bo_mberror)
283     omap_bo_del (self->bo_mberror);
284   G_OBJECT_CLASS (parent_class)->finalize (obj);
285 }
286
287
288 static void
289 gst_ducati_h264dec_class_init (GstDucatiH264DecClass * klass)
290 {
291   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
292   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
293   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
294
295   gst_element_class_set_static_metadata (element_class,
296       "DucatiH264Dec", "Codec/Decoder/Video",
297       "Decodes video in H.264/bytestream format with ducati",
298       "Rob Clark <rob@ti.com>");
299
300   gst_element_class_add_pad_template (element_class,
301       gst_static_pad_template_get (&sink_factory));
302
303   bclass->codec_name = "ivahd_h264dec";
304   bclass->update_buffer_size =
305       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_update_buffer_size);
306   bclass->allocate_params =
307       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_allocate_params);
308   bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_handle_error);
309   bclass->query = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_query);
310   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_finalize);
311 }
312
313 static void
314 gst_ducati_h264dec_init (GstDucatiH264Dec * self)
315 {
316 #ifndef GST_DISABLE_GST_DEBUG
317   GstDucatiVidDec *dec = GST_DUCATIVIDDEC (self);
318
319   dec->error_strings[0] = "no error-free slice";
320   dec->error_strings[1] = "error parsing SPS";
321   dec->error_strings[2] = "error parsing PPS";
322   dec->error_strings[3] = "error parsing slice header";
323   dec->error_strings[4] = "error parsing MB data";
324   dec->error_strings[5] = "unknown SPS";
325   dec->error_strings[6] = "unknown PPS";
326   dec->error_strings[7] = "invalid parameter";
327   dec->error_strings[16] = "unsupported feature";
328   dec->error_strings[17] = "SEI buffer overflow";
329   dec->error_strings[18] = "stream end";
330   dec->error_strings[19] = "no free buffers";
331   dec->error_strings[20] = "resolution change";
332   dec->error_strings[21] = "unsupported resolution";
333   dec->error_strings[22] = "invalid maxNumRefFrames";
334   dec->error_strings[23] = "invalid mbox message";
335   dec->error_strings[24] = "bad datasync input";
336   dec->error_strings[25] = "missing slice";
337   dec->error_strings[26] = "bad datasync param";
338   dec->error_strings[27] = "bad hw state";
339   dec->error_strings[28] = "temporal direct mode";
340   dec->error_strings[29] = "display width too small";
341   dec->error_strings[30] = "no SPS/PPS header";
342   dec->error_strings[31] = "gap in frame num";
343 #endif
344 }