Initialize Tizen 2.3
[framework/multimedia/gst-openmax.git] / wearable / omx / gstomx_h264dec.c
1 /*
2  * Copyright (C) 2007-2009 Nokia Corporation.
3  *
4  * Author: Felipe Contreras <felipe.contreras@nokia.com>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "gstomx_h264dec.h"
23 #include "gstomx.h"
24
25 GSTOMX_BOILERPLATE (GstOmxH264Dec, gst_omx_h264dec, GstOmxBaseVideoDec,
26     GST_OMX_BASE_VIDEODEC_TYPE);
27
28 static void instance_init (GstElement * element);
29
30 /*
31  *  description : find stream format(3gpp or nalu)
32  *  params      : @self : GstOmxH264Dec, @buf: input gstbuffer in pad_chain
33  *  return      : none
34  *  comments    : finding whether the stream format of input buf is 3GPP or Elementary Stream(nalu)
35  */
36 static void
37 check_frame (GstOmxH264Dec *self, GstBuffer * buf)
38 {
39   guint buf_size = GST_BUFFER_SIZE (buf);
40   guint8 *buf_data = GST_BUFFER_DATA (buf);
41   guint nal_type = 0;
42   guint forbidden_zero_bit = 0;
43   guint check_byte= 0;
44
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");
48     return;
49   }
50
51   self->h264Format = GSTOMX_H264_FORMAT_PACKETIZED;
52
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;
56
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);
60
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;
66       }
67     }
68   }
69
70   if (self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED)
71     GST_INFO_OBJECT(self, "H264 format is Packetized format");
72 }
73
74 /*
75  *  description : convert input 3gpp buffer to nalu based buffer
76  *  params      : @self : GstOmxH264Dec, @buf: buffer to be converted
77  *  return      : none
78  *  comments    : none
79  */
80 static void
81 convert_frame (GstOmxH264Dec *self, GstBuffer **buf)
82 {
83   OMX_U8 frameType;
84   OMX_U32 nalSize = 0;
85   OMX_U32 cumulSize = 0;
86   OMX_U32 offset = 0;
87   OMX_U32 nalHeaderSize = 0;
88   OMX_U32 outSize = 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;
93
94   do {
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);
100       } else {
101           nalSize = GSTOMX_H264_RB32(frame_3gpp);
102       }
103
104       GST_LOG_OBJECT(self, "packetized frame size = %d", nalSize);
105
106       frame_3gpp += self->h264NalLengthSize;
107
108       /* Checking frame type */
109       frameType = *frame_3gpp & 0x1f;
110
111       switch (frameType)
112       {
113           case GSTOMX_H264_NUT_SLICE:
114              GST_LOG_OBJECT(self, "Frame is non-IDR frame...");
115               break;
116           case GSTOMX_H264_NUT_IDR:
117              GST_LOG_OBJECT(self, "Frame is an IDR frame...");
118               break;
119           case GSTOMX_H264_NUT_SEI:
120              GST_LOG_OBJECT(self, "Found SEI Data...");
121               break;
122           case GSTOMX_H264_NUT_SPS:
123              GST_LOG_OBJECT(self, "Found SPS data...");
124               break;
125           case GSTOMX_H264_NUT_PPS:
126              GST_LOG_OBJECT(self, "Found PPS data...");
127               break;
128           case GSTOMX_H264_NUT_EOSEQ:
129              GST_LOG_OBJECT(self, "End of sequence...");
130               break;
131           case GSTOMX_H264_NUT_EOSTREAM:
132              GST_LOG_OBJECT(self, "End of stream...");
133               break;
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:
140               break;
141           default:
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;
144               goto EXIT;
145       }
146
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);
152           return;
153       }
154
155       /* Convert 3GPP Frame to NALU Frame */
156       offset = outSize;
157       nalHeaderSize = offset ? 3 : 4;
158
159       outSize += nalSize + nalHeaderSize;
160
161       if (nalSize > frame_3gpp_size) {
162           GST_ERROR_OBJECT(self, "out of bounds Error. frame_nalu_size=%d", outSize);
163           goto EXIT;
164       }
165
166       if (nalu_buf) {
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)");
170               goto EXIT;
171           }
172       } else {
173           nalu_buf = gst_buffer_new_and_alloc(outSize);
174       }
175
176       if (nalu_buf == NULL) {
177           GST_ERROR_OBJECT(self, "gst_buffer_new_and_alloc failed.(nalu_buf)");
178           goto EXIT;
179       }
180
181       if (!offset) {
182           memcpy(GST_BUFFER_DATA(nalu_buf)+nalHeaderSize, frame_3gpp, nalSize);
183           GSTOMX_H264_WB32(GST_BUFFER_DATA(nalu_buf), 1);
184       } else {
185           if (nalu_next_buf) {
186               GstBuffer *nalu_joined_buf = gst_buffer_join(nalu_buf,nalu_next_buf);
187               nalu_buf = nalu_joined_buf;
188               nalu_next_buf = NULL;
189           }
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;
193       }
194
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);
199
200   gst_buffer_copy_metadata(nalu_buf, *buf, GST_BUFFER_COPY_ALL);
201
202   gst_buffer_unref (*buf);
203   *buf = nalu_buf;
204
205   return;
206
207 EXIT:
208   if (nalu_buf) { gst_buffer_unref (nalu_buf); }
209   GST_ERROR_OBJECT(self, "converting frame error.");
210
211   return;
212 }
213
214 /*
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
218  *  comments  : none
219  */
220 static gboolean
221 convert_dci (GstOmxH264Dec *self, GstBuffer *buf, GstBuffer **dci_nalu)
222 {
223   gboolean ret = FALSE;
224   OMX_U8 *out = NULL;
225   OMX_U16 unitSize = 0;
226   OMX_U32 totalSize = 0;
227   OMX_U8 unitNb = 0;
228   OMX_U8 spsDone = 0;
229
230   OMX_U8 *pInputStream = GST_BUFFER_DATA(buf);
231   OMX_U32 pBuffSize = GST_BUFFER_SIZE(buf);
232
233   const OMX_U8 *extraData = (guchar*)pInputStream + 4;
234   static const OMX_U8 naluHeader[GSTOMX_H264_NAL_START_LEN] = {0, 0, 0, 1};
235
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)
241       {
242           GST_INFO("LengthOfLength is WRONG...");
243           goto EXIT;
244       }
245      /* retrieve sps and pps unit(s) */
246       unitNb = *extraData++ & 0x1f;
247       GST_INFO("No. of SPS units = %u", unitNb);
248       if (!unitNb) {
249           GST_INFO("SPS is not present...");
250           goto EXIT;
251       }
252
253       while (unitNb--) {
254           /* get SPS/PPS data Length*/
255           unitSize = GSTOMX_H264_RB16(extraData);
256
257           /* Extra 4 bytes for adding delimiter */
258           totalSize += unitSize + GSTOMX_H264_NAL_START_LEN;
259
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...");
263               goto EXIT;
264           }
265
266           if (out)
267             out = g_realloc(out, totalSize);
268           else
269             out = g_malloc(totalSize);
270
271           if (!out) {
272               GST_INFO("realloc failed...");
273               goto EXIT;
274           }
275
276           /* Copy NALU header */
277           memcpy(out + totalSize - unitSize - GSTOMX_H264_NAL_START_LEN,
278               naluHeader, GSTOMX_H264_NAL_START_LEN);
279
280           /* Copy SPS/PPS Length and data */
281           memcpy(out + totalSize - unitSize, extraData + GSTOMX_H264_SPSPPS_LEN, unitSize);
282
283           extraData += (GSTOMX_H264_SPSPPS_LEN + unitSize);
284
285           if (!unitNb && !spsDone++)
286           {
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);
290           }
291       }
292
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");
296           goto EXIT;
297       }
298
299       memcpy(GST_BUFFER_DATA(*dci_nalu), out, totalSize);
300       GST_INFO( "Total SPS+PPS size = %d", totalSize);
301   }
302
303   ret = TRUE;
304
305 EXIT:
306   if (out) {
307       g_free(out);
308   }
309   return ret;
310 }
311
312
313 static GstOmxReturn
314 process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
315 {
316   GstOmxH264Dec *h264_self;
317
318   h264_self = GST_OMX_H264DEC (omx_base_filter);
319
320   if (h264_self->h264Format == GSTOMX_H264_FORMAT_UNKNOWN) {
321     check_frame(h264_self, *buf);
322   }
323
324   if (h264_self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED) {
325
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;
331     }
332
333     GST_LOG_OBJECT(h264_self, "H264 format is Packetized format. convert to Byte-stream format");
334     convert_frame(h264_self, buf);
335   }
336
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); */
339
340   return GSTOMX_RETURN_OK;
341 }
342
343
344 static void
345 type_base_init (gpointer g_class)
346 {
347   GstElementClass *element_class;
348
349   element_class = GST_ELEMENT_CLASS (g_class);
350
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");
355
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")));
359
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")));
363 }
364
365 static void
366 type_class_init (gpointer g_class, gpointer class_data)
367 {
368   GstOmxBaseFilterClass *basefilter_class;
369
370   GST_WARNING("h264 dec  type_class_init");
371   basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
372
373   basefilter_class->process_input_buf = process_input_buf;
374   basefilter_class->instance_init = instance_init;
375 }
376
377 /* h264 dec has its own sink_setcaps for supporting nalu convert codec data */
378 static gboolean
379 sink_setcaps (GstPad * pad, GstCaps * caps)
380 {
381   GstStructure *structure;
382   GstOmxBaseVideoDec *self;
383   GstOmxH264Dec *h264_self;
384   GstOmxBaseFilter *omx_base;
385   GOmxCore *gomx;
386   gint width = 0;
387   gint height = 0;
388   gboolean hls_streaming = FALSE;
389
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);
393
394   g_return_val_if_fail (gst_caps_get_size (caps) == 1, FALSE);
395
396   GST_WARNING_OBJECT (self, "setcaps (sink)(h264): %" GST_PTR_FORMAT, caps);
397
398   gomx = (GOmxCore *) omx_base->gomx;
399
400   structure = gst_caps_get_structure (caps, 0);
401
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);
406   } else {
407     gst_structure_get_int (structure, "width", &width);
408     gst_structure_get_int (structure, "height", &height);
409   }
410
411   {
412     const GValue *framerate = NULL;
413     framerate = gst_structure_get_value (structure, "framerate");
414     if (framerate) {
415       self->framerate_num = gst_value_get_fraction_numerator (framerate);
416       self->framerate_denom = gst_value_get_fraction_denominator (framerate);
417     }
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));
420   }
421
422   if (gomx == NULL && omx_base->use_state_tuning == FALSE)
423   {
424     GST_ERROR_OBJECT(self, "GOmxCore is NULL! sink_setcaps return FALSE");
425     return FALSE; /* we can do this only for B2.  */
426   }
427
428   if (gomx->omx_handle == NULL && omx_base->use_state_tuning == FALSE)
429   {
430     GST_ERROR_OBJECT(self, "omx_handle is NULL! sink_setcaps return FALSE");
431     return FALSE; /* we can do this only for B2 */
432   }
433
434   if ((width <= 0 || height <=0) && omx_base->use_state_tuning == FALSE)
435   {
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 */
438   }
439
440   {
441     const GValue *codec_data;
442     GstBuffer *buffer;
443     gboolean ret = FALSE;
444     guint8 *buf_data = NULL;
445
446     codec_data = gst_structure_get_value (structure, "codec_data");
447     if (codec_data) {
448       buffer = gst_value_get_buffer (codec_data);
449
450       buf_data = GST_BUFFER_DATA(buffer);
451
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));
454       } else {
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.");
459         } else {
460            h264_self->h264Format = GSTOMX_H264_FORMAT_PACKETIZED;
461            GST_INFO_OBJECT(self, "H264 codec_data format is Packetized.");
462         }
463
464         /* if codec data is 3gpp format, convert nalu format */
465         if(h264_self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED) {
466           GstBuffer *nalu_dci = NULL;
467
468           ret = convert_dci(h264_self, buffer, &nalu_dci);
469           if (ret) {
470             omx_base->codec_data = nalu_dci;
471           } else {
472             GST_ERROR_OBJECT(h264_self, "converting dci error.");
473             if (nalu_dci) {
474               gst_buffer_unref (nalu_dci);
475               nalu_dci = NULL;
476             }
477             omx_base->codec_data = buffer;
478             gst_buffer_ref (buffer);
479           }
480
481         } else { /* not 3GPP format */
482           omx_base->codec_data = buffer;
483           gst_buffer_ref (buffer);
484         }
485       }
486       h264_self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
487     }
488   }
489
490   gst_structure_get_boolean (structure, "hls_streaming", &hls_streaming);
491
492   gomx->hls_streaming = hls_streaming;
493
494   if (gomx->component_vendor == GOMX_VENDOR_SLSI_SEC || gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS)
495   {
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);
499
500     if (need_ts_reorder) {
501       OMX_ERRORTYPE err = OMX_ErrorNone;
502       OMX_INDEXTYPE index = OMX_IndexComponentStartUnused;
503
504       err = OMX_GetExtensionIndex(gomx->omx_handle, "OMX.SEC.index.enableTimestampReorder", &index);
505
506       if (err == OMX_ErrorNone && index != OMX_IndexComponentStartUnused)
507       {
508         EnableTimestampReorderParams param;
509         G_OMX_INIT_PARAM (param);
510
511         GST_INFO_OBJECT(self, "set OMX_IndexParamEnableTimestampReorder");
512
513         param.bEnable = OMX_TRUE;
514         err = OMX_SetParameter(gomx->omx_handle, index, &param);
515         if (err != OMX_ErrorNone)
516         {
517           GST_ERROR_OBJECT(self, "setParam OMX_IndexParamEnableTimestampReorder failed with error (0x%x)", err);
518         }
519       }
520       else
521       {
522         GST_ERROR_OBJECT(self, "caps has ts-linear but can not set OMX_IndexParamEnableTimestampReorder");
523       }
524     }
525   }
526
527   /* Input port configuration. */
528   {
529     OMX_PARAM_PORTDEFINITIONTYPE param;
530     G_OMX_INIT_PARAM (param);
531
532     param.nPortIndex = omx_base->in_port->port_index;
533     OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
534
535     param.format.video.nFrameWidth = width;
536     param.format.video.nFrameHeight = height;
537
538     if(hls_streaming) {
539       param.format.video.nFrameWidth = HLS_MAX_WIDTH;
540       param.format.video.nFrameHeight = HLS_MAX_HEIGHT;
541
542       GST_WARNING_OBJECT(self, "set output buffer resolution to 720p to handle DRC switch in HLS");
543     }
544
545     OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
546   }
547   return gst_pad_set_caps (pad, caps);
548 }
549
550 static void
551 instance_private_value_init(GstElement * element)
552 {
553   GstOmxBaseVideoDec *omx_base;
554   GstOmxBaseFilter *omx_base_filter;
555
556   omx_base_filter = GST_OMX_BASE_FILTER (element);
557   omx_base = GST_OMX_BASE_VIDEODEC (element);
558
559   omx_base->compression_format = OMX_VIDEO_CodingAVC;
560   omx_base_filter->gomx->compression_format = OMX_VIDEO_CodingAVC;
561 }
562
563 static void
564 instance_init (GstElement * element)
565 {
566   GST_OMX_BASE_FILTER_CLASS (parent_class)->instance_init(element);
567
568   instance_private_value_init(element);
569 }
570
571 static void
572 type_instance_init (GTypeInstance * instance, gpointer g_class)
573 {
574   GstOmxBaseFilter *omx_base_filter;
575
576   GST_WARNING("h264 dec  begin");
577   omx_base_filter = GST_OMX_BASE_FILTER (instance);
578
579   instance_private_value_init(GST_ELEMENT(instance));
580
581   gst_pad_set_setcaps_function (omx_base_filter->sinkpad, sink_setcaps);
582 }