2 * Copyright (C) 2007-2009 Nokia Corporation.
4 * Author: Felipe Contreras <felipe.contreras@nokia.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "gstomx_h264dec.h"
25 GSTOMX_BOILERPLATE (GstOmxH264Dec, gst_omx_h264dec, GstOmxBaseVideoDec,
26 GST_OMX_BASE_VIDEODEC_TYPE);
28 static void instance_init (GstElement * element);
31 * description : find stream format(3gpp or nalu)
32 * params : @self : GstOmxH264Dec, @buf: input gstbuffer in pad_chain
34 * comments : finding whether the stream format of input buf is 3GPP or Elementary Stream(nalu)
37 check_frame (GstOmxH264Dec *self, GstBuffer * buf)
39 guint buf_size = GST_BUFFER_SIZE (buf);
40 guint8 *buf_data = GST_BUFFER_DATA (buf);
42 guint forbidden_zero_bit = 0;
45 if (buf_data == NULL || buf_size < GSTOMX_H264_NAL_START_LEN + 1) {
46 self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
47 GST_WARNING_OBJECT(self, "H264 format is unknown");
51 self->h264Format = GSTOMX_H264_FORMAT_PACKETIZED;
53 if ((buf_data[0] == 0x00)&&(buf_data[1] == 0x00)&&
54 ((buf_data[2] == 0x01)||((buf_data[2] == 0x00)&&(buf_data[3] == 0x01)))) {
55 check_byte = (buf_data[2] == 0x01) ? 3 : 4;
57 nal_type = (guint)(buf_data[check_byte] & 0x1f);
58 forbidden_zero_bit = (guint)(buf_data[check_byte] & 0x80);
59 GST_LOG_OBJECT(self, "check first frame: nal_type=%d, forbidden_zero_bit=%d", nal_type, forbidden_zero_bit);
61 if (forbidden_zero_bit == 0) {
62 /* check nal_unit_type is invaild value: ex) slice, DPA,DPB... */
63 if ((0 < nal_type && nal_type <= 15) || nal_type == 19 || nal_type == 20) {
64 GST_INFO_OBJECT(self, "H264 format is Byte-stream format");
65 self->h264Format = GSTOMX_H264_FORMAT_BYTE_STREAM;
70 if (self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED)
71 GST_INFO_OBJECT(self, "H264 format is Packetized format");
75 * description : convert input 3gpp buffer to nalu based buffer
76 * params : @self : GstOmxH264Dec, @buf: buffer to be converted
81 convert_frame (GstOmxH264Dec *self, GstBuffer **buf)
85 OMX_U32 cumulSize = 0;
87 OMX_U32 nalHeaderSize = 0;
89 OMX_U8 *frame_3gpp = GST_BUFFER_DATA(*buf);
90 OMX_U32 frame_3gpp_size = GST_BUFFER_SIZE(*buf);
91 GstBuffer *nalu_next_buf = NULL;
92 GstBuffer *nalu_buf = NULL;
95 /* get NAL Length based on length of length*/
96 if (self->h264NalLengthSize == 1) {
97 nalSize = frame_3gpp[0];
98 } else if (self->h264NalLengthSize == 2) {
99 nalSize = GSTOMX_H264_RB16(frame_3gpp);
101 nalSize = GSTOMX_H264_RB32(frame_3gpp);
104 GST_LOG_OBJECT(self, "packetized frame size = %d", nalSize);
106 frame_3gpp += self->h264NalLengthSize;
108 /* Checking frame type */
109 frameType = *frame_3gpp & 0x1f;
113 case GSTOMX_H264_NUT_SLICE:
114 GST_LOG_OBJECT(self, "Frame is non-IDR frame...");
116 case GSTOMX_H264_NUT_IDR:
117 GST_LOG_OBJECT(self, "Frame is an IDR frame...");
119 case GSTOMX_H264_NUT_SEI:
120 GST_LOG_OBJECT(self, "Found SEI Data...");
122 case GSTOMX_H264_NUT_SPS:
123 GST_LOG_OBJECT(self, "Found SPS data...");
125 case GSTOMX_H264_NUT_PPS:
126 GST_LOG_OBJECT(self, "Found PPS data...");
128 case GSTOMX_H264_NUT_EOSEQ:
129 GST_LOG_OBJECT(self, "End of sequence...");
131 case GSTOMX_H264_NUT_EOSTREAM:
132 GST_LOG_OBJECT(self, "End of stream...");
134 case GSTOMX_H264_NUT_DPA:
135 case GSTOMX_H264_NUT_DPB:
136 case GSTOMX_H264_NUT_DPC:
137 case GSTOMX_H264_NUT_AUD:
138 case GSTOMX_H264_NUT_FILL:
139 case GSTOMX_H264_NUT_MIXED:
142 GST_INFO_OBJECT(self, "Unknown Frame type: %d. do check_frame one more time with next frame.", frameType);
143 self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
147 /* if nal size is same, we can change only start code */
148 if((nalSize + GSTOMX_H264_NAL_START_LEN) == frame_3gpp_size) {
149 GST_LOG_OBJECT(self, "only change start code");
150 *buf = gst_buffer_make_writable(*buf); /* make writable to support memsrc */
151 GSTOMX_H264_WB32(GST_BUFFER_DATA(*buf), 1);
155 /* Convert 3GPP Frame to NALU Frame */
157 nalHeaderSize = offset ? 3 : 4;
159 outSize += nalSize + nalHeaderSize;
161 if (nalSize > frame_3gpp_size) {
162 GST_ERROR_OBJECT(self, "out of bounds Error. frame_nalu_size=%d", outSize);
167 nalu_next_buf= gst_buffer_new_and_alloc(nalSize + nalHeaderSize);
168 if (nalu_next_buf == NULL) {
169 GST_ERROR_OBJECT(self, "gst_buffer_new_and_alloc failed.(nalu_next_buf)");
173 nalu_buf = gst_buffer_new_and_alloc(outSize);
176 if (nalu_buf == NULL) {
177 GST_ERROR_OBJECT(self, "gst_buffer_new_and_alloc failed.(nalu_buf)");
182 memcpy(GST_BUFFER_DATA(nalu_buf)+nalHeaderSize, frame_3gpp, nalSize);
183 GSTOMX_H264_WB32(GST_BUFFER_DATA(nalu_buf), 1);
186 GstBuffer *nalu_joined_buf = gst_buffer_join(nalu_buf,nalu_next_buf);
187 nalu_buf = nalu_joined_buf;
188 nalu_next_buf = NULL;
190 memcpy(GST_BUFFER_DATA(nalu_buf)+nalHeaderSize+offset, frame_3gpp, nalSize);
191 (GST_BUFFER_DATA(nalu_buf)+offset)[0] = (GST_BUFFER_DATA(nalu_buf)+offset)[1] = 0;
192 (GST_BUFFER_DATA(nalu_buf)+offset)[2] = 1;
195 frame_3gpp += nalSize;
196 cumulSize += nalSize + self->h264NalLengthSize;
197 GST_LOG_OBJECT(self, "frame_3gpp_size = %d => frame_nalu_size=%d", frame_3gpp_size, outSize);
198 } while (cumulSize < frame_3gpp_size);
200 gst_buffer_copy_metadata(nalu_buf, *buf, GST_BUFFER_COPY_ALL);
202 gst_buffer_unref (*buf);
208 if (nalu_buf) { gst_buffer_unref (nalu_buf); }
209 GST_ERROR_OBJECT(self, "converting frame error.");
215 * description : convert input 3gpp buffer(codec data) to nalu based buffer
216 * params : @self : GstOmxH264Dec, @buf: buffer to be converted, @dci_nalu: converted buffer
217 * return : true on successes / false on failure
221 convert_dci (GstOmxH264Dec *self, GstBuffer *buf, GstBuffer **dci_nalu)
223 gboolean ret = FALSE;
225 OMX_U16 unitSize = 0;
226 OMX_U32 totalSize = 0;
230 OMX_U8 *pInputStream = GST_BUFFER_DATA(buf);
231 OMX_U32 pBuffSize = GST_BUFFER_SIZE(buf);
233 const OMX_U8 *extraData = (guchar*)pInputStream + 4;
234 static const OMX_U8 naluHeader[GSTOMX_H264_NAL_START_LEN] = {0, 0, 0, 1};
236 if (pInputStream != NULL) {
237 /* retrieve Length of Length*/
238 self->h264NalLengthSize = (*extraData++ & 0x03) + 1;
239 GST_INFO("Length Of Length is %d", self->h264NalLengthSize);
240 if (self->h264NalLengthSize == 3)
242 GST_INFO("LengthOfLength is WRONG...");
245 /* retrieve sps and pps unit(s) */
246 unitNb = *extraData++ & 0x1f;
247 GST_INFO("No. of SPS units = %u", unitNb);
249 GST_INFO("SPS is not present...");
254 /* get SPS/PPS data Length*/
255 unitSize = GSTOMX_H264_RB16(extraData);
257 /* Extra 4 bytes for adding delimiter */
258 totalSize += unitSize + GSTOMX_H264_NAL_START_LEN;
260 /* Check if SPS/PPS Data Length crossed buffer Length */
261 if ((extraData + 2 + unitSize) > (pInputStream + pBuffSize)) {
262 GST_INFO("SPS length is wrong in DCI...");
267 out = g_realloc(out, totalSize);
269 out = g_malloc(totalSize);
272 GST_INFO("realloc failed...");
276 /* Copy NALU header */
277 memcpy(out + totalSize - unitSize - GSTOMX_H264_NAL_START_LEN,
278 naluHeader, GSTOMX_H264_NAL_START_LEN);
280 /* Copy SPS/PPS Length and data */
281 memcpy(out + totalSize - unitSize, extraData + GSTOMX_H264_SPSPPS_LEN, unitSize);
283 extraData += (GSTOMX_H264_SPSPPS_LEN + unitSize);
285 if (!unitNb && !spsDone++)
287 /* Completed reading SPS data, now read PPS data */
288 unitNb = *extraData++; /* number of pps unit(s) */
289 GST_INFO( "No. of PPS units = %d", unitNb);
293 *dci_nalu = gst_buffer_new_and_alloc(totalSize);
294 if (*dci_nalu == NULL) {
295 GST_ERROR_OBJECT(self, " gst_buffer_new_and_alloc failed...\n");
299 memcpy(GST_BUFFER_DATA(*dci_nalu), out, totalSize);
300 GST_INFO( "Total SPS+PPS size = %d", totalSize);
314 process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
316 GstOmxH264Dec *h264_self;
318 h264_self = GST_OMX_H264DEC (omx_base_filter);
320 if (h264_self->h264Format == GSTOMX_H264_FORMAT_UNKNOWN) {
321 check_frame(h264_self, *buf);
324 if (h264_self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED) {
326 if (omx_base_filter->last_pad_push_return != GST_FLOW_OK ||
327 !(omx_base_filter->gomx->omx_state == OMX_StateExecuting ||
328 omx_base_filter->gomx->omx_state == OMX_StatePause)) {
329 GST_LOG_OBJECT(h264_self, "this frame will not be converted and go to out_flushing");
330 return GSTOMX_RETURN_OK;
333 GST_LOG_OBJECT(h264_self, "H264 format is Packetized format. convert to Byte-stream format");
334 convert_frame(h264_self, buf);
337 /* if you want to use commonly for videodec input, use this */
338 /* GST_OMX_BASE_FILTER_CLASS (parent_class)->process_input_buf (omx_base_filter, buf); */
340 return GSTOMX_RETURN_OK;
345 type_base_init (gpointer g_class)
347 GstElementClass *element_class;
349 element_class = GST_ELEMENT_CLASS (g_class);
351 gst_element_class_set_details_simple (element_class,
352 "OpenMAX IL H.264/AVC video decoder",
353 "Codec/Decoder/Video",
354 "Decodes video in H.264/AVC format with OpenMAX IL", "Felipe Contreras");
356 gst_element_class_add_pad_template (element_class,
357 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
358 gstomx_template_caps (G_TYPE_FROM_CLASS (g_class), "sink")));
360 gst_element_class_add_pad_template (element_class,
361 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
362 gstomx_template_caps (G_TYPE_FROM_CLASS (g_class), "src")));
366 type_class_init (gpointer g_class, gpointer class_data)
368 GstOmxBaseFilterClass *basefilter_class;
370 GST_WARNING("h264 dec type_class_init");
371 basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
373 basefilter_class->process_input_buf = process_input_buf;
374 basefilter_class->instance_init = instance_init;
377 /* h264 dec has its own sink_setcaps for supporting nalu convert codec data */
379 sink_setcaps (GstPad * pad, GstCaps * caps)
381 GstStructure *structure;
382 GstOmxBaseVideoDec *self;
383 GstOmxH264Dec *h264_self;
384 GstOmxBaseFilter *omx_base;
388 gboolean hls_streaming = FALSE;
390 self = GST_OMX_BASE_VIDEODEC (GST_PAD_PARENT (pad));
391 h264_self = GST_OMX_H264DEC (GST_PAD_PARENT (pad));
392 omx_base = GST_OMX_BASE_FILTER (self);
394 g_return_val_if_fail (gst_caps_get_size (caps) == 1, FALSE);
396 GST_WARNING_OBJECT (self, "setcaps (sink)(h264): %" GST_PTR_FORMAT, caps);
398 gomx = (GOmxCore *) omx_base->gomx;
400 structure = gst_caps_get_structure (caps, 0);
402 if(gst_structure_has_field(structure, "max-width") &&
403 gst_structure_has_field(structure, "max-height")) {
404 gst_structure_get_int (structure, "max-width", &width);
405 gst_structure_get_int (structure, "max-height", &height);
407 gst_structure_get_int (structure, "width", &width);
408 gst_structure_get_int (structure, "height", &height);
412 const GValue *framerate = NULL;
413 framerate = gst_structure_get_value (structure, "framerate");
415 self->framerate_num = gst_value_get_fraction_numerator (framerate);
416 self->framerate_denom = gst_value_get_fraction_denominator (framerate);
418 omx_base->duration = gst_util_uint64_scale_int (GST_SECOND, self->framerate_denom, self->framerate_num);
419 GST_INFO_OBJECT (self, "set average duration= %"GST_TIME_FORMAT, GST_TIME_ARGS (omx_base->duration));
422 if (gomx == NULL && omx_base->use_state_tuning == FALSE)
424 GST_ERROR_OBJECT(self, "GOmxCore is NULL! sink_setcaps return FALSE");
425 return FALSE; /* we can do this only for B2. */
428 if (gomx->omx_handle == NULL && omx_base->use_state_tuning == FALSE)
430 GST_ERROR_OBJECT(self, "omx_handle is NULL! sink_setcaps return FALSE");
431 return FALSE; /* we can do this only for B2 */
434 if ((width <= 0 || height <=0) && omx_base->use_state_tuning == FALSE)
436 GST_ERROR_OBJECT(self, "we got invalid width or height. sink_setcaps return FALSE");
437 return FALSE; /* we can do this only for B2 */
441 const GValue *codec_data;
443 gboolean ret = FALSE;
444 guint8 *buf_data = NULL;
446 codec_data = gst_structure_get_value (structure, "codec_data");
448 buffer = gst_value_get_buffer (codec_data);
450 buf_data = GST_BUFFER_DATA(buffer);
452 if (GST_BUFFER_SIZE(buffer) <= GSTOMX_H264_NAL_START_LEN) {
453 GST_ERROR("codec data size (%d) is less than start code length.", GST_BUFFER_SIZE(buffer));
455 if ((buf_data[0] == 0x00)&&(buf_data[1] == 0x00)&&
456 ((buf_data[2] == 0x01)||((buf_data[2] == 0x00)&&(buf_data[3] == 0x01)))) {
457 h264_self->h264Format = GSTOMX_H264_FORMAT_BYTE_STREAM;
458 GST_INFO_OBJECT(self, "H264 codec_data format is Byte-stream.");
460 h264_self->h264Format = GSTOMX_H264_FORMAT_PACKETIZED;
461 GST_INFO_OBJECT(self, "H264 codec_data format is Packetized.");
464 /* if codec data is 3gpp format, convert nalu format */
465 if(h264_self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED) {
466 GstBuffer *nalu_dci = NULL;
468 ret = convert_dci(h264_self, buffer, &nalu_dci);
470 omx_base->codec_data = nalu_dci;
472 GST_ERROR_OBJECT(h264_self, "converting dci error.");
474 gst_buffer_unref (nalu_dci);
477 omx_base->codec_data = buffer;
478 gst_buffer_ref (buffer);
481 } else { /* not 3GPP format */
482 omx_base->codec_data = buffer;
483 gst_buffer_ref (buffer);
486 h264_self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
490 gst_structure_get_boolean (structure, "hls_streaming", &hls_streaming);
492 gomx->hls_streaming = hls_streaming;
494 if (gomx->component_vendor == GOMX_VENDOR_SLSI_SEC || gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS)
496 /* MODIFICATION: if avi demuxer can not handle b-frame ts reorder */
497 gboolean need_ts_reorder = FALSE;
498 gst_structure_get_boolean(structure, "ts-linear", &need_ts_reorder);
500 if (need_ts_reorder) {
501 OMX_ERRORTYPE err = OMX_ErrorNone;
502 OMX_INDEXTYPE index = OMX_IndexComponentStartUnused;
504 err = OMX_GetExtensionIndex(gomx->omx_handle, "OMX.SEC.index.enableTimestampReorder", &index);
506 if (err == OMX_ErrorNone && index != OMX_IndexComponentStartUnused)
508 EnableTimestampReorderParams param;
509 G_OMX_INIT_PARAM (param);
511 GST_INFO_OBJECT(self, "set OMX_IndexParamEnableTimestampReorder");
513 param.bEnable = OMX_TRUE;
514 err = OMX_SetParameter(gomx->omx_handle, index, ¶m);
515 if (err != OMX_ErrorNone)
517 GST_ERROR_OBJECT(self, "setParam OMX_IndexParamEnableTimestampReorder failed with error (0x%x)", err);
522 GST_ERROR_OBJECT(self, "caps has ts-linear but can not set OMX_IndexParamEnableTimestampReorder");
527 /* Input port configuration. */
529 OMX_PARAM_PORTDEFINITIONTYPE param;
530 G_OMX_INIT_PARAM (param);
532 param.nPortIndex = omx_base->in_port->port_index;
533 OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
535 param.format.video.nFrameWidth = width;
536 param.format.video.nFrameHeight = height;
539 param.format.video.nFrameWidth = HLS_MAX_WIDTH;
540 param.format.video.nFrameHeight = HLS_MAX_HEIGHT;
542 GST_WARNING_OBJECT(self, "set output buffer resolution to 720p to handle DRC switch in HLS");
545 OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
547 return gst_pad_set_caps (pad, caps);
551 instance_private_value_init(GstElement * element)
553 GstOmxBaseVideoDec *omx_base;
554 GstOmxBaseFilter *omx_base_filter;
556 omx_base_filter = GST_OMX_BASE_FILTER (element);
557 omx_base = GST_OMX_BASE_VIDEODEC (element);
559 omx_base->compression_format = OMX_VIDEO_CodingAVC;
560 omx_base_filter->gomx->compression_format = OMX_VIDEO_CodingAVC;
564 instance_init (GstElement * element)
566 GST_OMX_BASE_FILTER_CLASS (parent_class)->instance_init(element);
568 instance_private_value_init(element);
572 type_instance_init (GTypeInstance * instance, gpointer g_class)
574 GstOmxBaseFilter *omx_base_filter;
576 GST_WARNING("h264 dec begin");
577 omx_base_filter = GST_OMX_BASE_FILTER (instance);
579 instance_private_value_init(GST_ELEMENT(instance));
581 gst_pad_set_setcaps_function (omx_base_filter->sinkpad, sink_setcaps);