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)
103 {
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;
111 }
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)
116 {
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_DISPLAY_DELAY_AUTO;
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 /* XDM_MemoryType required by drm to allcoate buffer */
145 self->outBufs->descs[2].memType = XDM_MEMTYPE_RAW;
146 self->outBufs->descs[2].buf =
147 (XDAS_Int8 *) omap_bo_dmabuf (h264dec->bo_mberror);
148 self->outBufs->descs[2].bufSize.bytes = nmb + SIZE_OF_CONCEALMENT_DATA;
149 self->params->metadataType[0] = IVIDEO_METADATAPLANE_MBINFO;
150 /* need to lock the buffer to get the page pinned */
151 dce_buf_lock (1, (size_t *) & self->outBufs->descs[2].buf);
152 }
153 }
155 return ret;
156 }
158 static gint
159 gst_ducati_h264dec_handle_error (GstDucatiVidDec * self, gint ret,
160 gint extended_error, gint status_extended_error)
161 {
162 GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
163 const unsigned char *mberror, *mbcon;
164 unsigned mbw, mbh, nmb;
165 uint16_t mbwr, mbhr;
166 size_t n, nerr = 0;
167 char *line;
168 unsigned x, y;
170 if (h264dec->bo_mberror) {
171 mberror = omap_bo_map (h264dec->bo_mberror);
172 mbw = (self->width + 15) / 16;
173 mbh = (self->height + 15) / 16;
174 nmb = mbw * mbh;
175 mbcon = mberror + nmb;
176 mbwr = ((const uint16_t *) mbcon)[21]; /* not a public struct */
177 mbhr = ((const uint16_t *) mbcon)[22]; /* not a public struct */
178 if (nmb != mbwr * mbhr) {
179 GST_WARNING_OBJECT (self, "Failed to find MB size - "
180 "corruption might have happened");
181 } else {
182 for (n = 0; n < nmb; ++n) {
183 if (mberror[n])
184 ++nerr;
185 }
186 GST_INFO_OBJECT (self, "Frame has %zu MB errors over %zu (%u x %u) MBs",
187 nerr, nmb, mbwr, mbhr);
188 line = g_malloc (mbw + 1);
189 for (y = 0; y < mbh; y++) {
190 line[mbw] = 0;
191 for (x = 0; x < mbw; x++) {
192 line[x] = mberror[x + y * mbw] ? '!' : '.';
193 }
194 GST_INFO_OBJECT (self, "MB: %4u: %s", y, line);
195 }
196 g_free (line);
197 }
198 }
200 if (extended_error & 0x00000001) {
201 /* No valid slice. This seems to be bad enough that it's better to flush and
202 * skip to the next keyframe.
203 */
205 if (extended_error == 0x00000201) {
206 /* the codec doesn't unlock the input buffer in this case... */
207 gst_buffer_unref ((GstBuffer *) self->inArgs->inputID);
208 self->inArgs->inputID = 0;
209 }
211 self->needs_flushing = TRUE;
212 }
214 ret = parent_class->handle_error (self, ret, extended_error,
215 status_extended_error);
217 return ret;
218 }
220 static gboolean
221 gst_ducati_h264dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
222 gint64 diff)
223 {
224 gboolean is_bframe = GST_BUFFER_FLAG_IS_SET (buf,
225 GST_BUFFER_FLAG_B_FRAME);
227 if (diff >= 0 && is_bframe)
228 return TRUE;
230 return FALSE;
231 }
233 static gint
234 gst_ducati_h264dec_find_max_dpb_from_level (GstDucatiVidDec * self,
235 const char *level)
236 {
237 guint n;
239 for (n = 0; n < G_N_ELEMENTS (max_dpb_by_level); ++n)
240 if (!strcmp (level, max_dpb_by_level[n].level))
241 return max_dpb_by_level[n].kb;
243 GST_WARNING_OBJECT (self, "Max DBP not found for level %s", level);
244 return -1;
245 }
247 static gint
248 gst_ducati_h264dec_get_max_dpb_size (GstDucatiVidDec * self, GstCaps * caps)
249 {
250 gint wmb = (self->width + 15) / 16;
251 gint hmb = (self->height + 15) / 16;
252 gint max_dpb, max_dpb_size;
253 GstStructure *structure;
254 const char *level;
255 float chroma_factor = 1.5; /* We only support NV12, which is 4:2:0 */
257 /* Min( 1024 * MaxDPB / ( PicWidthInMbs * FrameHeightInMbs * 256 * ChromaFormatFactor ), 16 ) */
259 structure = gst_caps_get_structure (caps, 0);
260 if (!structure)
261 return -1;
263 level = gst_structure_get_string (structure, "level");
264 if (!level)
265 return -1;
267 max_dpb = gst_ducati_h264dec_find_max_dpb_from_level (self, level);
268 if (max_dpb < 0)
269 return -1;
271 max_dpb_size =
272 lrint (ceil (1024 * max_dpb / (wmb * hmb * 256 * chroma_factor)));
273 if (max_dpb_size > MAX_BACKLOG_FRAMES)
274 max_dpb_size = MAX_BACKLOG_FRAMES;
276 return max_dpb_size;
277 }
279 static gboolean
280 gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
281 {
282 GstStructure *structure;
284 GST_DEBUG_OBJECT (self, "set_sink_caps: %" GST_PTR_FORMAT, caps);
286 if (!GST_CALL_PARENT_WITH_DEFAULT (GST_DUCATIVIDDEC_CLASS, set_sink_caps,
287 (self, caps), TRUE))
288 return FALSE;
290 /* HW decoder fails in GETSTATUS */
291 #if 0
292 /* When we have the first decoded buffer, we ask the decoder for the
293 max number of frames needed to reorder */
294 int err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
295 self->dynParams, self->status);
296 if (!err) {
297 IH264VDEC_Status *s = (IH264VDEC_Status *) self->status;
298 if (s->spsMaxRefFrames > MAX_BACKLOG_FRAMES) {
299 h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
300 GST_WARNING_OBJECT (self,
301 "Stream needs %d frames for reordering, we can only accomodate %d",
302 s->spsMaxRefFrames, MAX_BACKLOG_FRAMES);
303 } else {
304 h264dec->backlog_maxframes = s->spsMaxRefFrames;
305 GST_INFO_OBJECT (self, "Num frames for reordering: %d",
306 h264dec->backlog_maxframes);
307 }
308 } else {
309 h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
310 GST_WARNING_OBJECT (self,
311 "Failed to request num frames for reordering, defaulting to %d",
312 h264dec->backlog_maxframes);
313 }
314 #endif
316 self->backlog_maxframes = -1;
318 structure = gst_caps_get_structure (caps, 0);
319 if (structure) {
320 gint num_ref_frames = -1, num_reorder_frames = -1;
321 const char *profile;
323 /* baseline profile does not use B frames (and I'll say constrained-baseline
324 is unlikely either from the name, it's not present in my H264 spec... */
325 profile = gst_structure_get_string (structure, "profile");
326 if (profile && (!strcmp (profile, "baseline")
327 || !strcmp (profile, "constrained-baseline"))) {
328 GST_DEBUG_OBJECT (self, "No need for reordering for %s profile", profile);
329 self->backlog_maxframes = 0;
330 goto no_b_frames;
331 }
334 if (gst_structure_get_int (structure, "num-ref-frames", &num_ref_frames)
335 && num_ref_frames >= 0) {
336 ((IH264VDEC_Params *) self->params)->dpbSizeInFrames = num_ref_frames;
337 }
338 if (gst_structure_get_int (structure, "num-reorder-frames",
339 &num_reorder_frames)
340 && num_reorder_frames >= 0) {
341 if (num_reorder_frames > MAX_BACKLOG_FRAMES) {
342 self->backlog_maxframes = MAX_BACKLOG_FRAMES;
343 GST_WARNING_OBJECT (self,
344 "Stream needs %d frames for reordering, we can only accomodate %d",
345 num_reorder_frames, MAX_BACKLOG_FRAMES);
346 } else {
347 self->backlog_maxframes = num_reorder_frames;
348 GST_INFO_OBJECT (self, "Num frames for reordering: %d",
349 self->backlog_maxframes);
350 }
351 }
352 }
354 /* If not present, use the spec forumula for a bound */
355 if (self->backlog_maxframes < 0) {
356 self->backlog_maxframes = gst_ducati_h264dec_get_max_dpb_size (self, caps);
357 if (self->backlog_maxframes >= 0) {
358 GST_WARNING_OBJECT (self,
359 "num-reorder-frames not found on caps, calculation from stream parameters gives %d",
360 self->backlog_maxframes);
361 } else {
362 self->backlog_maxframes = MAX_H264_BACKLOG_FRAMES;
363 }
364 }
365 if (self->backlog_maxframes > self->backlog_max_maxframes)
366 self->backlog_maxframes = self->backlog_max_maxframes;
367 GST_WARNING_OBJECT (self,
368 "Using %d frames for reordering", self->backlog_maxframes);
370 no_b_frames:
372 return TRUE;
373 }
375 /* GObject vmethod implementations */
377 static void
378 gst_ducati_h264dec_base_init (gpointer gclass)
379 {
380 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
382 gst_element_class_set_details_simple (element_class,
383 "DucatiH264Dec",
384 "Codec/Decoder/Video",
385 "Decodes video in H.264/bytestream format with ducati",
386 "Rob Clark <rob@ti.com>");
388 gst_element_class_add_pad_template (element_class,
389 gst_static_pad_template_get (&sink_factory));
390 }
392 static void
393 gst_ducati_h264dec_finalize (GObject * obj)
394 {
395 GstDucatiH264Dec *self = GST_DUCATIH264DEC (obj);
396 if (self->bo_mberror)
397 omap_bo_del (self->bo_mberror);
398 G_OBJECT_CLASS (parent_class)->finalize (obj);
399 }
401 static void
402 gst_ducati_h264dec_class_init (GstDucatiH264DecClass * klass)
403 {
404 GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
405 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
406 bclass->codec_name = "ivahd_h264dec";
407 bclass->update_buffer_size =
408 GST_DEBUG_FUNCPTR (gst_ducati_h264dec_update_buffer_size);
409 bclass->allocate_params =
410 GST_DEBUG_FUNCPTR (gst_ducati_h264dec_allocate_params);
411 bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_handle_error);
412 bclass->can_drop_frame =
413 GST_DEBUG_FUNCPTR (gst_ducati_h264dec_can_drop_frame);
414 bclass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_set_sink_caps);
415 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_finalize);
416 }
418 static void
419 gst_ducati_h264dec_init (GstDucatiH264Dec * self,
420 GstDucatiH264DecClass * gclass)
421 {
422 #ifndef GST_DISABLE_GST_DEBUG
423 GstDucatiVidDec *dec = GST_DUCATIVIDDEC (self);
425 dec->error_strings[0] = "no error-free slice";
426 dec->error_strings[1] = "error parsing SPS";
427 dec->error_strings[2] = "error parsing PPS";
428 dec->error_strings[3] = "error parsing slice header";
429 dec->error_strings[4] = "error parsing MB data";
430 dec->error_strings[5] = "unknown SPS";
431 dec->error_strings[6] = "unknown PPS";
432 dec->error_strings[7] = "invalid parameter";
433 dec->error_strings[16] = "unsupported feature";
434 dec->error_strings[17] = "SEI buffer overflow";
435 dec->error_strings[18] = "stream end";
436 dec->error_strings[19] = "no free buffers";
437 dec->error_strings[20] = "resolution change";
438 dec->error_strings[21] = "unsupported resolution";
439 dec->error_strings[22] = "invalid maxNumRefFrames";
440 dec->error_strings[23] = "invalid mbox message";
441 dec->error_strings[24] = "bad datasync input";
442 dec->error_strings[25] = "missing slice";
443 dec->error_strings[26] = "bad datasync param";
444 dec->error_strings[27] = "bad hw state";
445 dec->error_strings[28] = "temporal direct mode";
446 dec->error_strings[29] = "display width too small";
447 dec->error_strings[30] = "no SPS/PPS header";
448 dec->error_strings[31] = "gap in frame num";
449 #endif
450 }