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;
107 }
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)
112 {
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;
130 }
132 static gint
133 gst_ducati_h264dec_handle_error (GstDucatiVidDec * self, gint ret,
134 gint extended_error, gint status_extended_error)
135 {
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;
154 }
156 static gboolean
157 gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
158 GstQuery * query, gboolean * forward)
159 {
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 *= (vdec->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;
206 }
208 static gboolean
209 gst_ducati_h264dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
210 gint64 diff)
211 {
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;
219 }
221 static gint
222 gst_ducati_h264dec_find_max_dpb_from_level (GstDucatiVidDec * self,
223 const char *level)
224 {
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;
233 }
235 static gint
236 gst_ducati_h264dec_get_max_dpb_size (GstDucatiVidDec * self, GstCaps * caps)
237 {
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 -1;
251 level = gst_structure_get_string (structure, "level");
252 if (!level)
253 return -1;
255 max_dpb = gst_ducati_h264dec_find_max_dpb_from_level (self, level);
256 if (max_dpb < 0)
257 return -1;
259 max_dpb_size =
260 lrint (ceil (1024 * max_dpb / (wmb * hmb * 256 * chroma_factor)));
261 if (max_dpb_size > MAX_BACKLOG_FRAMES)
262 max_dpb_size = MAX_BACKLOG_FRAMES;
264 return max_dpb_size;
265 }
267 static gboolean
268 gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
269 {
270 GstStructure *structure;
272 GST_DEBUG_OBJECT (self, "set_sink_caps: %" GST_PTR_FORMAT, caps);
274 if (!GST_CALL_PARENT_WITH_DEFAULT (GST_DUCATIVIDDEC_CLASS, set_sink_caps,
275 (self, caps), TRUE))
276 return FALSE;
278 /* HW decoder fails in GETSTATUS */
279 #if 0
280 /* When we have the first decoded buffer, we ask the decoder for the
281 max number of frames needed to reorder */
282 int err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
283 self->dynParams, self->status);
284 if (!err) {
285 IH264VDEC_Status *s = (IH264VDEC_Status *) self->status;
286 if (s->spsMaxRefFrames > MAX_BACKLOG_FRAMES) {
287 h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
288 GST_WARNING_OBJECT (self,
289 "Stream needs %d frames for reordering, we can only accomodate %d",
290 s->spsMaxRefFrames, MAX_BACKLOG_FRAMES);
291 } else {
292 h264dec->backlog_maxframes = s->spsMaxRefFrames;
293 GST_INFO_OBJECT (self, "Num frames for reordering: %d",
294 h264dec->backlog_maxframes);
295 }
296 } else {
297 h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
298 GST_WARNING_OBJECT (self,
299 "Failed to request num frames for reordering, defaulting to %d",
300 h264dec->backlog_maxframes);
301 }
302 #endif
304 self->backlog_maxframes = -1;
306 structure = gst_caps_get_structure (caps, 0);
307 if (structure) {
308 gint num_ref_frames = -1, num_reorder_frames = -1;
309 const char *profile;
311 /* baseline profile does not use B frames (and I'll say constrained-baseline
312 is unlikely either from the name, it's not present in my H264 spec... */
313 profile = gst_structure_get_string (structure, "profile");
314 if (profile && (!strcmp (profile, "baseline")
315 || !strcmp (profile, "constrained-baseline"))) {
316 GST_DEBUG_OBJECT (self, "No need for reordering for %s profile", profile);
317 self->backlog_maxframes = 0;
318 goto no_b_frames;
319 }
322 if (gst_structure_get_int (structure, "num-ref-frames", &num_ref_frames)
323 && num_ref_frames >= 0) {
324 ((IH264VDEC_Params *) self->params)->maxNumRefFrames = num_ref_frames;
325 }
326 if (gst_structure_get_int (structure, "num-reorder-frames",
327 &num_reorder_frames)
328 && num_reorder_frames >= 0) {
329 if (num_reorder_frames > MAX_BACKLOG_FRAMES) {
330 self->backlog_maxframes = MAX_BACKLOG_FRAMES;
331 GST_WARNING_OBJECT (self,
332 "Stream needs %d frames for reordering, we can only accomodate %d",
333 num_reorder_frames, MAX_BACKLOG_FRAMES);
334 } else {
335 self->backlog_maxframes = num_reorder_frames;
336 GST_INFO_OBJECT (self, "Num frames for reordering: %d",
337 self->backlog_maxframes);
338 }
339 }
340 }
342 /* If not present, use the spec forumula for a bound */
343 if (self->backlog_maxframes < 0) {
344 self->backlog_maxframes = gst_ducati_h264dec_get_max_dpb_size (self, caps);
345 GST_WARNING_OBJECT (self,
346 "num-reorder-frames not found on caps, calculation from stream parameters gives %d",
347 self->backlog_maxframes);
348 }
349 if (self->backlog_maxframes > self->backlog_max_maxframes)
350 self->backlog_maxframes = self->backlog_max_maxframes;
351 GST_WARNING_OBJECT (self,
352 "Using %d frames for reordering", self->backlog_maxframes);
354 no_b_frames:
356 return TRUE;
357 }
359 /* GObject vmethod implementations */
361 static void
362 gst_ducati_h264dec_base_init (gpointer gclass)
363 {
364 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
366 gst_element_class_set_details_simple (element_class,
367 "DucatiH264Dec",
368 "Codec/Decoder/Video",
369 "Decodes video in H.264/bytestream format with ducati",
370 "Rob Clark <rob@ti.com>");
372 gst_element_class_add_pad_template (element_class,
373 gst_static_pad_template_get (&sink_factory));
374 }
376 static void
377 gst_ducati_h264dec_class_init (GstDucatiH264DecClass * klass)
378 {
379 GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
380 bclass->codec_name = "ivahd_h264dec";
381 bclass->update_buffer_size =
382 GST_DEBUG_FUNCPTR (gst_ducati_h264dec_update_buffer_size);
383 bclass->allocate_params =
384 GST_DEBUG_FUNCPTR (gst_ducati_h264dec_allocate_params);
385 bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_handle_error);
386 bclass->can_drop_frame =
387 GST_DEBUG_FUNCPTR (gst_ducati_h264dec_can_drop_frame);
388 bclass->query = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_query);
389 bclass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_set_sink_caps);
390 }
392 static void
393 gst_ducati_h264dec_init (GstDucatiH264Dec * self,
394 GstDucatiH264DecClass * gclass)
395 {
396 }