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);
29 * description : find stream format(3gpp or nalu)
30 * params : @self : GstOmxH264Dec, @buf: input gstbuffer in pad_chain
32 * comments : finding whether the stream format of input buf is 3GPP or Elementary Stream(nalu)
35 check_frame (GstOmxH264Dec *self, GstBuffer * buf)
37 guint buf_size = GST_BUFFER_SIZE (buf);
38 guint8 *buf_data = GST_BUFFER_DATA (buf);
40 guint forbidden_zero_bit = 0;
43 if (buf_data == NULL || buf_size < GSTOMX_H264_NAL_START_LEN + 1) {
44 self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
45 GST_WARNING_OBJECT(self, "H264 format is unknown");
49 self->h264Format = GSTOMX_H264_FORMAT_PACKETIZED;
51 if ((buf_data[0] == 0x00)&&(buf_data[1] == 0x00)&&
52 ((buf_data[2] == 0x01)||((buf_data[2] == 0x00)&&(buf_data[3] == 0x01)))) {
53 check_byte = (buf_data[2] == 0x01) ? 3 : 4;
55 nal_type = (guint)(buf_data[check_byte] & 0x1f);
56 forbidden_zero_bit = (guint)(buf_data[check_byte] & 0x80);
57 GST_LOG_OBJECT(self, "check first frame: nal_type=%d, forbidden_zero_bit=%d", nal_type, forbidden_zero_bit);
59 if (forbidden_zero_bit == 0) {
60 /* check nal_unit_type is invaild value: ex) slice, DPA,DPB... */
61 if ((0 < nal_type && nal_type <= 15) || nal_type == 19 || nal_type == 20) {
62 GST_INFO_OBJECT(self, "H264 format is Byte-stream format");
63 self->h264Format = GSTOMX_H264_FORMAT_BYTE_STREAM;
68 if (self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED)
69 GST_INFO_OBJECT(self, "H264 format is Packetized format");
73 * description : convert input 3gpp buffer to nalu based buffer
74 * params : @self : GstOmxH264Dec, @buf: buffer to be converted
79 convert_frame (GstOmxH264Dec *self, GstBuffer **buf)
83 OMX_U32 cumulSize = 0;
85 OMX_U32 nalHeaderSize = 0;
87 OMX_U8 *frame_3gpp = GST_BUFFER_DATA(*buf);
88 OMX_U32 frame_3gpp_size = GST_BUFFER_SIZE(*buf);
89 GstBuffer *nalu_next_buf = NULL;
90 GstBuffer *nalu_buf = NULL;
93 /* get NAL Length based on length of length*/
94 if (self->h264NalLengthSize == 1) {
95 nalSize = frame_3gpp[0];
96 } else if (self->h264NalLengthSize == 2) {
97 nalSize = GSTOMX_H264_RB16(frame_3gpp);
99 nalSize = GSTOMX_H264_RB32(frame_3gpp);
102 GST_LOG_OBJECT(self, "packetized frame size = %d", nalSize);
104 frame_3gpp += self->h264NalLengthSize;
106 /* Checking frame type */
107 frameType = *frame_3gpp & 0x1f;
111 case GSTOMX_H264_NUT_SLICE:
112 GST_LOG_OBJECT(self, "Frame is non-IDR frame...");
114 case GSTOMX_H264_NUT_IDR:
115 GST_LOG_OBJECT(self, "Frame is an IDR frame...");
117 case GSTOMX_H264_NUT_SEI:
118 GST_LOG_OBJECT(self, "Found SEI Data...");
120 case GSTOMX_H264_NUT_SPS:
121 GST_LOG_OBJECT(self, "Found SPS data...");
123 case GSTOMX_H264_NUT_PPS:
124 GST_LOG_OBJECT(self, "Found PPS data...");
126 case GSTOMX_H264_NUT_EOSEQ:
127 GST_LOG_OBJECT(self, "End of sequence...");
129 case GSTOMX_H264_NUT_EOSTREAM:
130 GST_LOG_OBJECT(self, "End of stream...");
132 case GSTOMX_H264_NUT_DPA:
133 case GSTOMX_H264_NUT_DPB:
134 case GSTOMX_H264_NUT_DPC:
135 case GSTOMX_H264_NUT_AUD:
136 case GSTOMX_H264_NUT_FILL:
137 case GSTOMX_H264_NUT_MIXED:
140 GST_INFO_OBJECT(self, "Unknown Frame type: %d. do check_frame one more time with next frame.", frameType);
141 self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
145 /* if nal size is same, we can change only start code */
146 if((nalSize + GSTOMX_H264_NAL_START_LEN) == frame_3gpp_size) {
147 GST_LOG_OBJECT(self, "only change start code");
148 *buf = gst_buffer_make_writable(*buf); /* make writable to support memsrc */
149 GSTOMX_H264_WB32(GST_BUFFER_DATA(*buf), 1);
153 /* Convert 3GPP Frame to NALU Frame */
155 nalHeaderSize = offset ? 3 : 4;
157 outSize += nalSize + nalHeaderSize;
159 if (nalSize > frame_3gpp_size) {
160 GST_ERROR_OBJECT(self, "out of bounds Error. frame_nalu_size=%d", outSize);
165 nalu_next_buf= gst_buffer_new_and_alloc(nalSize + nalHeaderSize);
166 if (nalu_next_buf == NULL) {
167 GST_ERROR_OBJECT(self, "gst_buffer_new_and_alloc failed.(nalu_next_buf)");
171 nalu_buf = gst_buffer_new_and_alloc(outSize);
174 if (nalu_buf == NULL) {
175 GST_ERROR_OBJECT(self, "gst_buffer_new_and_alloc failed.(nalu_buf)");
180 memcpy(GST_BUFFER_DATA(nalu_buf)+nalHeaderSize, frame_3gpp, nalSize);
181 GSTOMX_H264_WB32(GST_BUFFER_DATA(nalu_buf), 1);
184 GstBuffer *nalu_joined_buf = gst_buffer_join(nalu_buf,nalu_next_buf);
185 nalu_buf = nalu_joined_buf;
186 nalu_next_buf = NULL;
188 memcpy(GST_BUFFER_DATA(nalu_buf)+nalHeaderSize+offset, frame_3gpp, nalSize);
189 (GST_BUFFER_DATA(nalu_buf)+offset)[0] = (GST_BUFFER_DATA(nalu_buf)+offset)[1] = 0;
190 (GST_BUFFER_DATA(nalu_buf)+offset)[2] = 1;
193 frame_3gpp += nalSize;
194 cumulSize += nalSize + self->h264NalLengthSize;
195 GST_LOG_OBJECT(self, "frame_3gpp_size = %d => frame_nalu_size=%d", frame_3gpp_size, outSize);
196 } while (cumulSize < frame_3gpp_size);
198 gst_buffer_copy_metadata(nalu_buf, *buf, GST_BUFFER_COPY_ALL);
200 gst_buffer_unref (*buf);
206 if (nalu_buf) { gst_buffer_unref (nalu_buf); }
207 GST_ERROR_OBJECT(self, "converting frame error.");
213 * description : convert input 3gpp buffer(codec data) to nalu based buffer
214 * params : @self : GstOmxH264Dec, @buf: buffer to be converted, @dci_nalu: converted buffer
215 * return : true on successes / false on failure
219 convert_dci (GstOmxH264Dec *self, GstBuffer *buf, GstBuffer **dci_nalu)
221 gboolean ret = FALSE;
223 OMX_U16 unitSize = 0;
224 OMX_U32 totalSize = 0;
228 OMX_U8 *pInputStream = GST_BUFFER_DATA(buf);
229 OMX_U32 pBuffSize = GST_BUFFER_SIZE(buf);
231 const OMX_U8 *extraData = (guchar*)pInputStream + 4;
232 static const OMX_U8 naluHeader[GSTOMX_H264_NAL_START_LEN] = {0, 0, 0, 1};
234 if (pInputStream != NULL) {
235 /* retrieve Length of Length*/
236 self->h264NalLengthSize = (*extraData++ & 0x03) + 1;
237 GST_INFO("Length Of Length is %d", self->h264NalLengthSize);
238 if (self->h264NalLengthSize == 3)
240 GST_INFO("LengthOfLength is WRONG...");
243 /* retrieve sps and pps unit(s) */
244 unitNb = *extraData++ & 0x1f;
245 GST_INFO("No. of SPS units = %u", unitNb);
247 GST_INFO("SPS is not present...");
252 /* get SPS/PPS data Length*/
253 unitSize = GSTOMX_H264_RB16(extraData);
255 /* Extra 4 bytes for adding delimiter */
256 totalSize += unitSize + GSTOMX_H264_NAL_START_LEN;
258 /* Check if SPS/PPS Data Length crossed buffer Length */
259 if ((extraData + 2 + unitSize) > (pInputStream + pBuffSize)) {
260 GST_INFO("SPS length is wrong in DCI...");
265 out = g_realloc(out, totalSize);
267 out = g_malloc(totalSize);
270 GST_INFO("realloc failed...");
274 /* Copy NALU header */
275 memcpy(out + totalSize - unitSize - GSTOMX_H264_NAL_START_LEN,
276 naluHeader, GSTOMX_H264_NAL_START_LEN);
278 /* Copy SPS/PPS Length and data */
279 memcpy(out + totalSize - unitSize, extraData + GSTOMX_H264_SPSPPS_LEN, unitSize);
281 extraData += (GSTOMX_H264_SPSPPS_LEN + unitSize);
283 if (!unitNb && !spsDone++)
285 /* Completed reading SPS data, now read PPS data */
286 unitNb = *extraData++; /* number of pps unit(s) */
287 GST_INFO( "No. of PPS units = %d", unitNb);
291 *dci_nalu = gst_buffer_new_and_alloc(totalSize);
292 if (*dci_nalu == NULL) {
293 GST_ERROR_OBJECT(self, " gst_buffer_new_and_alloc failed...\n");
297 memcpy(GST_BUFFER_DATA(*dci_nalu), out, totalSize);
298 GST_INFO( "Total SPS+PPS size = %d", totalSize);
312 process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
314 GstOmxH264Dec *h264_self;
316 h264_self = GST_OMX_H264DEC (omx_base_filter);
318 if (h264_self->h264Format == GSTOMX_H264_FORMAT_UNKNOWN) {
319 check_frame(h264_self, *buf);
322 if (h264_self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED) {
324 if (omx_base_filter->last_pad_push_return != GST_FLOW_OK ||
325 !(omx_base_filter->gomx->omx_state == OMX_StateExecuting ||
326 omx_base_filter->gomx->omx_state == OMX_StatePause)) {
327 GST_LOG_OBJECT(h264_self, "this frame will not be converted and go to out_flushing");
328 return GSTOMX_RETURN_OK;
331 GST_LOG_OBJECT(h264_self, "H264 format is Packetized format. convert to Byte-stream format");
332 convert_frame(h264_self, buf);
335 /* if you want to use commonly for videodec input, use this */
336 /* GST_OMX_BASE_FILTER_CLASS (parent_class)->process_input_buf (omx_base_filter, buf); */
338 return GSTOMX_RETURN_OK;
342 type_base_init (gpointer g_class)
344 GstElementClass *element_class;
346 element_class = GST_ELEMENT_CLASS (g_class);
348 gst_element_class_set_details_simple (element_class,
349 "OpenMAX IL H.264/AVC video decoder",
350 "Codec/Decoder/Video",
351 "Decodes video in H.264/AVC format with OpenMAX IL", "Felipe Contreras");
353 gst_element_class_add_pad_template (element_class,
354 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
355 gstomx_template_caps (G_TYPE_FROM_CLASS (g_class), "sink")));
357 gst_element_class_add_pad_template (element_class,
358 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
359 gstomx_template_caps (G_TYPE_FROM_CLASS (g_class), "src")));
363 type_class_init (gpointer g_class, gpointer class_data)
365 GstOmxBaseFilterClass *basefilter_class;
367 basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
369 basefilter_class->process_input_buf = process_input_buf;
372 /* h264 dec has its own sink_setcaps for supporting nalu convert codec data */
374 sink_setcaps (GstPad * pad, GstCaps * caps)
376 GstStructure *structure;
377 GstOmxBaseVideoDec *self;
378 GstOmxH264Dec *h264_self;
379 GstOmxBaseFilter *omx_base;
381 OMX_PARAM_PORTDEFINITIONTYPE param;
385 self = GST_OMX_BASE_VIDEODEC (GST_PAD_PARENT (pad));
386 h264_self = GST_OMX_H264DEC (GST_PAD_PARENT (pad));
387 omx_base = GST_OMX_BASE_FILTER (self);
389 gomx = (GOmxCore *) omx_base->gomx;
391 GST_INFO_OBJECT (self, "setcaps (sink)(h264): %" GST_PTR_FORMAT, caps);
393 g_return_val_if_fail (gst_caps_get_size (caps) == 1, FALSE);
395 structure = gst_caps_get_structure (caps, 0);
397 gst_structure_get_int (structure, "width", &width);
398 gst_structure_get_int (structure, "height", &height);
401 const GValue *framerate = NULL;
402 framerate = gst_structure_get_value (structure, "framerate");
404 self->framerate_num = gst_value_get_fraction_numerator (framerate);
405 self->framerate_denom = gst_value_get_fraction_denominator (framerate);
407 omx_base->duration = gst_util_uint64_scale_int (GST_SECOND, self->framerate_denom, self->framerate_num);
408 GST_INFO_OBJECT (self, "set average duration= %"GST_TIME_FORMAT, GST_TIME_ARGS (omx_base->duration));
411 G_OMX_INIT_PARAM (param);
414 const GValue *codec_data;
416 gboolean ret = FALSE;
417 guint8 *buf_data = NULL;
419 codec_data = gst_structure_get_value (structure, "codec_data");
421 buffer = gst_value_get_buffer (codec_data);
423 buf_data = GST_BUFFER_DATA(buffer);
425 if (GST_BUFFER_SIZE(buffer) <= GSTOMX_H264_NAL_START_LEN) {
426 GST_ERROR("codec data size (%d) is less than start code length.", GST_BUFFER_SIZE(buffer));
428 if ((buf_data[0] == 0x00)&&(buf_data[1] == 0x00)&&
429 ((buf_data[2] == 0x01)||((buf_data[2] == 0x00)&&(buf_data[3] == 0x01)))) {
430 h264_self->h264Format = GSTOMX_H264_FORMAT_BYTE_STREAM;
431 GST_INFO_OBJECT(self, "H264 codec_data format is Byte-stream.");
433 h264_self->h264Format = GSTOMX_H264_FORMAT_PACKETIZED;
434 GST_INFO_OBJECT(self, "H264 codec_data format is Packetized.");
437 /* if codec data is 3gpp format, convert nalu format */
438 if(h264_self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED) {
439 GstBuffer *nalu_dci = NULL;
441 ret = convert_dci(h264_self, buffer, &nalu_dci);
443 omx_base->codec_data = nalu_dci;
445 GST_ERROR_OBJECT(h264_self, "converting dci error.");
447 gst_buffer_unref (nalu_dci);
450 omx_base->codec_data = buffer;
451 gst_buffer_ref (buffer);
454 } else { /* not 3GPP format */
455 omx_base->codec_data = buffer;
456 gst_buffer_ref (buffer);
459 h264_self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
462 /* Input port configuration. */
464 param.nPortIndex = omx_base->in_port->port_index;
465 OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
467 param.format.video.nFrameWidth = width;
468 param.format.video.nFrameHeight = height;
470 OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
472 return gst_pad_set_caps (pad, caps);
476 type_instance_init (GTypeInstance * instance, gpointer g_class)
478 GstOmxBaseVideoDec *omx_base;
479 GstOmxBaseFilter *omx_base_filter;
481 omx_base = GST_OMX_BASE_VIDEODEC (instance);
482 omx_base_filter = GST_OMX_BASE_FILTER (instance);
484 omx_base->compression_format = OMX_VIDEO_CodingAVC;
486 gst_pad_set_setcaps_function (omx_base_filter->sinkpad, sink_setcaps);