Initialize Tizen 2.3
[framework/multimedia/gst-openmax.git] / wearable / omx / gstomx_h264enc.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_h264enc.h"
23 #include "gstomx.h"
24
25 enum
26 {
27   ARG_0,
28   ARG_APPEND_DCI,
29   ARG_BYTE_STREAM,
30   ARG_SLICE_MODE,
31   ARG_SLICE_SIZE,
32   ARG_PHYSICAL_OUTPUT,
33   ARG_ENCODER_LEVEL,
34   ARG_ENCODER_PROFILE,
35 };
36
37 GSTOMX_BOILERPLATE (GstOmxH264Enc, gst_omx_h264enc, GstOmxBaseVideoEnc,
38     GST_OMX_BASE_VIDEOENC_TYPE);
39
40
41 static void instance_init (GstElement * element);
42 static void instance_deinit (GstElement * element);
43 static void instance_private_value_init(GstElement * element);
44
45
46 /*
47  *  description : convert byte-stream format to packetized frame
48  *  params      : @self : GstOmxH264Enc, @buf: byte-stream buf, @sync: notify this buf is sync frame
49  *  return      : none
50  *  comments    :
51  */
52 static void
53 convert_to_packetized_frame (GstOmxH264Enc *self, GstBuffer **buf)
54 {
55   unsigned char *data = GST_BUFFER_DATA (*buf);
56   unsigned int size = GST_BUFFER_SIZE(*buf);
57   unsigned char *buf_pos, *end_pos;
58   int idx = 0;
59   gint start_idx = -1;
60   unsigned char *nalu_start = NULL;
61   GstOmxBaseFilter *omx_base = GST_OMX_BASE_FILTER(self);
62
63   GST_LOG_OBJECT (self, "convert_to_packtized format. size=%d sliceMode=%d",
64       GST_BUFFER_SIZE(*buf), self->slice_fmo.eSliceMode);
65
66   if ((omx_base->gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS ||
67     omx_base->gomx->component_vendor == GOMX_VENDOR_SLSI_SEC) &&
68       self->slice_fmo.eSliceMode == OMX_VIDEO_SLICEMODE_AVCDefault) { /* 1 slice per frame */
69     GST_LOG_OBJECT (self, " handle single NALU per buffer");
70     while (idx < size - GSTOMX_H264_NAL_START_LEN) {
71       if (((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x00)&& (data[idx+3] == 0x01)) ||
72         ((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x01))) {
73         if (data[idx+2] == 0x01) {
74           GST_ERROR_OBJECT (self, "ERROR : NALU header is 3-bytes, yet to support !!");
75         } else {
76           GSTOMX_H264_WB32(data + idx, size - idx - GSTOMX_H264_NAL_START_LEN);
77           return;
78         }
79       }
80       idx++;
81     } /* while */
82
83 #if 0 /* Deprecated : It consumes power because lots of memory accessing time */
84   } else { /* handle multiple NALUs in one buffer */
85     GST_LOG_OBJECT (self, " handle multiple NALUs per buffer");
86     while (idx < size - GSTOMX_H264_NAL_START_LEN) {
87       if (((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x00)&& (data[idx+3] == 0x01)) ||
88         ((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x01))) {
89         if (data[idx+2] == 0x01) {
90           GST_ERROR_OBJECT (self, "ERROR : NALU header is 3-bytes, yet to support !!");
91         } else {
92           if (start_idx >= 0) {
93             if (idx <= start_idx) {
94               GST_ERROR_OBJECT (self, "ERROR : idx <= start_idx !!");
95               return;
96             }
97             GST_LOG_OBJECT (self, "size of current nal unit = %d", idx-start_idx);
98             GSTOMX_H264_WB32(nalu_start, idx - start_idx - GSTOMX_H264_NAL_START_LEN);
99           }
100           start_idx = idx;
101           nalu_start = data + idx;
102           idx++;
103         }
104       }
105       idx++;
106     } /* while */
107     idx += GSTOMX_H264_NAL_START_LEN;
108 #endif
109
110    } else { /* handle multiple NALUs in one buffer */
111     GST_LOG_OBJECT (self, " handle multiple NALUs per buffer");
112
113     buf_pos = data;
114     end_pos = buf_pos + size;
115
116     /* Reading 8byte per loop (for efficiency) and determines whether NAL starting point is contained or not */
117     for (end_pos -= 7; buf_pos < end_pos; buf_pos += 4) {
118         int idx_flag = 0;
119         unsigned int value0 = *((unsigned int*)buf_pos);
120         unsigned int value1 = *((unsigned int*)buf_pos + 1);
121
122         if (!(value0 & 0xFF000000)) {    /* |XXX0| */
123             if ( !(value0 & 0xFFFFFF00) && ((value1 & 0x000000FF) == 0x00000001)) {
124                 /* |X000|1 */
125                 /* found */
126                 idx = buf_pos+1 - data;
127                 idx_flag = 1;
128                 goto out;
129
130             } else if ( !(value0 & 0xFFFF0000) && ((value1 & 0x0000FFFF) == 0x00000100)) {
131                 /* XX00|01*/
132                 /* found */
133                 idx = buf_pos+2 - data;
134                 idx_flag = 1;
135                 goto out;
136
137             } else if ((value1 & 0x00FFFFFF) == 0x00010000) {
138                 /* XXX0|001 */
139                 /* found */
140                 idx = buf_pos+3 - data;
141                 idx_flag = 1;
142                 goto out;
143             } else if (!(value0&0xFFFF0000)&&((value1&0x000000FF)==0x00000001)) {
144                 /* XX00|1*/
145                 goto err;
146             } else if ((value1&0x0000FFFF)==0x00000100) {
147                 /* XXX0|01 */
148                 goto err;
149             }
150
151         } else if (value0 == 0x01000000) {
152             /* found */
153             idx = buf_pos - data;
154             idx_flag = 1;
155             goto out;
156         } else if ((value0 & 0x00FFFFFF)==0x00010000) {
157             /* |001X| */
158             goto err;
159         } else if ((value0 & 0xFFFFFF00)==0x01000000) {
160             /* |X001| */
161     err:
162             GST_ERROR_OBJECT (self, "ERROR : NALU header is 3-bytes, yet to support !!");
163             continue;
164         }
165
166     out:
167         if (idx_flag) {
168             if (start_idx >= 0) {
169                 if (idx <= start_idx) {
170                     GST_ERROR_OBJECT (self, "ERROR : idx <= start_idx !!");
171                     return;
172                 }
173                 GST_LOG_OBJECT (self, "size of current nal unit = %d", idx-start_idx);
174                 GSTOMX_H264_WB32(nalu_start, idx - start_idx - GSTOMX_H264_NAL_START_LEN);
175             }
176             start_idx = idx;
177             nalu_start = data + idx;
178         }
179     }
180     idx = size;
181     /* converting last nal unit */
182     if (start_idx >= 0) {
183       GST_LOG_OBJECT (self, "size of current nal unit = %d", idx-start_idx);
184       GSTOMX_H264_WB32(nalu_start, idx - start_idx - GSTOMX_H264_NAL_START_LEN);
185     }
186   }
187 }
188
189 /*
190  *  description : convert byte-stream codec data to packtized codec_data
191  *  params      : @self : GstOmxH264Enc, @inbuf: byte-stream codec data (omx buf), @outbuf: packetized codec_data
192  *  return      : true on successes / false on failure
193  *  comments    :
194  */
195 static gboolean
196 convert_to_packetized_dci (GstOmxH264Enc *self, unsigned char *nalu_dci, unsigned nalu_dci_len,
197     GstBuffer **packetized_dci, gint *out_sps_cnt, gint *out_pps_cnt)
198 {
199   gint idx = 0;
200   gint sps_cnt = 0;
201   gint pps_cnt = 0;
202   GQueue *sps_queue = 0;
203   GQueue *pps_queue = 0;
204   unsigned char *packet_dci = NULL;
205   gint prev_nalu_start = 0;
206   gint prev_nalu_type = GSTOMX_H264_NUT_UNKNOWN;
207   gint sps_size = 0;
208   gint pps_size = 0;
209   GstBuffer *sps_data = NULL;
210   GstBuffer *pps_data = NULL;
211   GstBuffer *queue_data = NULL;
212   gint nal_type = GSTOMX_H264_NUT_UNKNOWN;
213   unsigned char profile = 0;
214   unsigned char level = 0;
215   unsigned char profile_comp = 0;
216   gboolean bret = TRUE;
217   gboolean single_sps_pps = FALSE; /* if there is only 1 sps, pps set, */
218
219   sps_queue = g_queue_new ();
220   pps_queue = g_queue_new ();
221
222   /* find no.of SPS & PPS units */
223   while (idx < nalu_dci_len) {
224     if ((nalu_dci[idx] == 0x00) && (nalu_dci[idx+1] == 0x00) && (nalu_dci[idx+2] == 0x01)) {
225       /* copy previous nal unit */
226       if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_SPS) {
227         if (nalu_dci[idx -1] == 0x00) {
228           sps_size = idx -1 - prev_nalu_start;
229         } else {
230           sps_size = idx - prev_nalu_start;
231         }
232         sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
233         if (!sps_data) {
234           GST_ERROR_OBJECT (self, "failed to allocate memory..");
235           bret = FALSE;
236           goto exit;
237         }
238         GSTOMX_H264_WB16(GST_BUFFER_DATA(sps_data), sps_size);
239         memcpy (GST_BUFFER_DATA(sps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, sps_size);
240         g_queue_push_tail (sps_queue, sps_data);
241       } else if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_PPS) {
242         if (nalu_dci[idx -1] == 0x00) {
243           pps_size = idx -1 - prev_nalu_start;
244         } else {
245           pps_size = idx - prev_nalu_start;
246         }
247         pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
248         if (!pps_data) {
249           GST_ERROR_OBJECT (self, "failed to allocate memory..");
250           bret = FALSE;
251           goto exit;
252         }
253         GSTOMX_H264_WB16(GST_BUFFER_DATA(pps_data), pps_size);
254         memcpy (GST_BUFFER_DATA(pps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, pps_size);
255         g_queue_push_tail (pps_queue, pps_data);
256       }
257       /* present nalu type */
258       nal_type = nalu_dci[idx+3] & 0x1f;
259
260       if (nal_type == GSTOMX_H264_NUT_SPS) {
261         sps_cnt++;
262         prev_nalu_start = idx + 3;
263         prev_nalu_type =GSTOMX_H264_NUT_SPS;
264         profile = nalu_dci[idx+4];
265         level = nalu_dci[idx+6];
266         GST_INFO_OBJECT (self, "Profile Number = %d and Level = %d...", nalu_dci[idx+4], level);
267         GST_INFO_OBJECT (self, "Profile is %s", (profile == 66) ? "BaseLine Profile": (profile == 77)? "Main Profile": profile==88 ?
268                   "Extended Profile": profile==100 ? "High Profile": "Not Supported codec");
269       } else if ((nalu_dci[idx+3] & 0x1f) == GSTOMX_H264_NUT_PPS) {
270         pps_cnt++;
271         prev_nalu_start = idx + 3;
272         prev_nalu_type = GSTOMX_H264_NUT_PPS;
273       }
274     }
275     idx++;
276   }
277
278   /* copy previous nal unit */
279   if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_SPS) {
280     sps_size = idx - prev_nalu_start;
281
282     sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
283     if (!sps_data) {
284       GST_ERROR_OBJECT (self, "failed to allocate memory..");
285       bret = FALSE;
286       goto exit;
287     }
288
289     GSTOMX_H264_WB16(GST_BUFFER_DATA(sps_data), sps_size);
290     memcpy (GST_BUFFER_DATA(sps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, sps_size);
291     g_queue_push_tail (sps_queue, sps_data);
292
293   } else if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_PPS) {
294     pps_size = idx - prev_nalu_start;
295
296     pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
297     if (!pps_data) {
298       GST_ERROR_OBJECT (self, "failed to allocate memory..");
299       bret = FALSE;
300       goto exit;
301     }
302
303     GSTOMX_H264_WB16(GST_BUFFER_DATA(pps_data), pps_size);
304     memcpy (GST_BUFFER_DATA(pps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, pps_size);
305     g_queue_push_tail (pps_queue, pps_data);
306   }
307
308   /* make packetized codec data */
309   if (sps_cnt == 1 && pps_cnt == 1) {
310     single_sps_pps = TRUE;
311     *packetized_dci = gst_buffer_new_and_alloc(GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size + GSTOMX_H264_CNT_LEN + GSTOMX_H264_C_DCI_LEN + pps_size);
312     GST_LOG_OBJECT(self, "allocate packetized_dci in case of single sps, pps. (size=%d)",  GST_BUFFER_SIZE(*packetized_dci));
313   } else {
314     *packetized_dci = gst_buffer_new_and_alloc(GSTOMX_H264_MDATA);
315     GST_LOG_OBJECT(self, "allocate packetized_dci in case of multi sps, pps");
316   }
317
318   if (*packetized_dci == NULL) {
319     GST_ERROR_OBJECT (self, "Failed to allocate memory..");
320     bret = FALSE;
321     goto exit;
322   }
323
324   packet_dci = GST_BUFFER_DATA(*packetized_dci);
325   packet_dci[0] = 0x01; /* configurationVersion */
326   packet_dci[1] = profile; /* AVCProfileIndication */
327   packet_dci[2] = profile_comp; /* profile_compatibility*/
328   packet_dci[3] = level;  /* AVCLevelIndication */
329   packet_dci[4] = 0xff; /* Reserver (6bits.111111) + LengthSizeMinusOne (2bits). lengthoflength = 4 for present */
330   packet_dci[5] = 0xe0 | sps_cnt; /* Reserver (3bits. 111) + numOfSequenceParameterSets (5bits) */
331
332   /* copy SPS sets */
333   while (!g_queue_is_empty (sps_queue)) {
334     sps_data = g_queue_pop_head (sps_queue);
335
336     if (TRUE == single_sps_pps) {
337       memcpy(packet_dci + GSTOMX_H264_MDATA, GST_BUFFER_DATA(sps_data), GST_BUFFER_SIZE(sps_data));
338       gst_buffer_unref(sps_data);
339       sps_data = NULL;
340     } else {
341       *packetized_dci = gst_buffer_join(*packetized_dci, sps_data);
342     }
343   }
344
345   /* add number of PPS sets (1byte)*/
346   if (TRUE == single_sps_pps) {
347     packet_dci[GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size] = pps_cnt;
348   } else {
349     GstBuffer *next_data = gst_buffer_new_and_alloc(GSTOMX_H264_CNT_LEN);
350     if (!next_data) {
351       GST_ERROR_OBJECT (self, "Failed to allocate memory..");
352       bret = FALSE;
353       goto exit;
354     }
355     GST_BUFFER_DATA(next_data)[0] = pps_cnt;
356     *packetized_dci = gst_buffer_join(*packetized_dci, next_data);
357   }
358
359   /* copy PPS sets */
360   while (!g_queue_is_empty (pps_queue)) {
361     pps_data = g_queue_pop_head (pps_queue);
362
363     if (TRUE == single_sps_pps) {
364       memcpy(packet_dci + GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size + GSTOMX_H264_CNT_LEN,
365                       GST_BUFFER_DATA(pps_data), GST_BUFFER_SIZE(pps_data));
366       gst_buffer_unref(pps_data);
367       pps_data = NULL;
368     } else {
369       *packetized_dci = gst_buffer_join(*packetized_dci, pps_data);
370     }
371   }
372
373 exit:
374   while (!g_queue_is_empty (sps_queue)) {
375     queue_data = g_queue_pop_head (sps_queue);
376     gst_buffer_unref (queue_data);
377     queue_data = NULL;
378   }
379   g_queue_free (sps_queue);
380
381   while (!g_queue_is_empty (pps_queue)) {
382     queue_data = g_queue_pop_head (pps_queue);
383     gst_buffer_unref (queue_data);
384     queue_data = NULL;
385   }
386   g_queue_free (pps_queue);
387
388   *out_sps_cnt = sps_cnt;
389   *out_pps_cnt = sps_cnt;
390
391   return bret;
392 }
393
394 /*
395  *  description : resotre packtized dci (codec_data)
396  *  params      : @self : GstOmxH264Enc, @inbuf: codec data, @outbuf: h264enc->dci
397  *  return      : none
398  *  comments    :
399  *    from original packetized codec_data: METADATA(6) + SPS_CNT(0) + {SPS_SIZE(2)+SPS_DATA(sps_size)}*n +
400                                                              PPS_CNT(1) + {PPS_SIZE(2)+PPS_DATA(pps_size)}*n
401  *    to estore packetized dci: {SPS_SIZE(4)+SPS_DATA(sps_size)}*n + {PPS_SIZE(4)+PPS_DATA(pps_size)}*n
402  */
403 static gboolean
404 restore_packetized_dci (GstOmxH264Enc *self, GstBuffer *inbuf, GstBuffer **outbuf, gint sps_cnt, gint pps_cnt)
405 {
406   unsigned char *indata = GST_BUFFER_DATA(inbuf);
407   guint sps_size =0;
408   guint pps_size =0;
409   gint i = 0;
410   GstBuffer *next_data = NULL;
411
412   GST_INFO_OBJECT (self, "restore_packetized_dci. sps_cnt=%d, pps_cnt=%d", sps_cnt, pps_cnt);
413
414   if (sps_cnt == 1 && pps_cnt == 1) {
415     sps_size = GSTOMX_H264_RB16(indata + GSTOMX_H264_MDATA);
416     pps_size = GSTOMX_H264_RB16(indata + GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size + GSTOMX_H264_CNT_LEN);
417
418     *outbuf = gst_buffer_new_and_alloc (GSTOMX_H264_A_DCI_LEN + sps_size + GSTOMX_H264_A_DCI_LEN + pps_size);
419     if (!*outbuf) {
420       GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
421       goto error_exit;
422     }
423
424     GSTOMX_H264_WB32(GST_BUFFER_DATA(*outbuf), sps_size);
425     indata += GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN;
426     memcpy (GST_BUFFER_DATA(*outbuf) + GSTOMX_H264_A_DCI_LEN, indata, sps_size);
427     indata += sps_size;
428
429     GSTOMX_H264_WB32(GST_BUFFER_DATA(*outbuf) + GSTOMX_H264_A_DCI_LEN + sps_size, pps_size);
430     indata += GSTOMX_H264_CNT_LEN + GSTOMX_H264_C_DCI_LEN;
431     memcpy (GST_BUFFER_DATA(*outbuf) + GSTOMX_H264_A_DCI_LEN + sps_size + GSTOMX_H264_A_DCI_LEN, indata, pps_size);
432     indata += pps_size;
433   } else {
434     /* in this case, dci has multi nalu. ex) sps + sps + sps + pps + pps */
435     indata += GSTOMX_H264_MDATA;
436     *outbuf = gst_buffer_new ();
437
438     for (i = 0; i < sps_cnt; i++) {
439       sps_size = GSTOMX_H264_RB16(indata); /* metadata(6) */
440
441       next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + sps_size);
442       if (!next_data) {
443         GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
444         goto error_exit;
445       }
446       GSTOMX_H264_WB32(GST_BUFFER_DATA(next_data), sps_size);
447       indata += GSTOMX_H264_C_DCI_LEN; /* sps size field (2 byte) */
448       memcpy (GST_BUFFER_DATA(next_data) + GSTOMX_H264_A_DCI_LEN, indata, sps_size);
449
450       *outbuf = gst_buffer_join(*outbuf, next_data);
451       indata += sps_size;
452     }
453     indata += GSTOMX_H264_CNT_LEN; /* pps cnt field (1 byte) */
454
455     for (i = 0; i < pps_cnt; i++) {
456       pps_size = GSTOMX_H264_RB16(indata);
457
458       next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + pps_size);
459       if (!next_data) {
460         GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
461         goto error_exit;
462       }
463       GSTOMX_H264_WB32(GST_BUFFER_DATA(next_data), pps_size);
464       indata += GSTOMX_H264_C_DCI_LEN;
465       memcpy (GST_BUFFER_DATA(next_data) + GSTOMX_H264_A_DCI_LEN, indata, pps_size);
466
467       *outbuf = gst_buffer_join(*outbuf, next_data);
468       indata += pps_size;
469     }
470   }
471
472   return TRUE;
473
474 error_exit:
475   if (*outbuf) {
476     gst_buffer_unref(*outbuf);
477     *outbuf = NULL;
478   }
479   return FALSE;
480 }
481
482 static void
483 set_apppend_dci(GstOmxBaseFilter * self)
484 {
485   OMX_INDEXTYPE index = OMX_IndexComponentStartUnused;
486   OMX_ERRORTYPE err = OMX_ErrorNone;
487   PrependSPSPPSToIDRFramesParams params;
488   GOmxCore *gomx = self->gomx;
489
490   GST_LOG_OBJECT(self, "set_apppend_dci enter");
491
492
493   if(gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS || gomx->component_vendor == GOMX_VENDOR_SLSI_SEC)
494     err = OMX_GetExtensionIndex(gomx->omx_handle, "OMX.SEC.index.prependSPSPPSToIDRFrames", &index);
495
496   if (err != OMX_ErrorNone || index == OMX_IndexComponentStartUnused) {
497       GST_INFO_OBJECT(self, "can not get index for OMX_GetExtensionIndex OMX_IndexParamPrependSPSPPSToIDR");
498       return;
499   }
500
501   G_OMX_INIT_PARAM(params);
502   params.bEnable = OMX_TRUE;
503
504   err = OMX_SetParameter(gomx->omx_handle, index, &params);
505   if (err == OMX_ErrorNone) {
506     GST_WARNING_OBJECT(self, "set_apppend_dci (prependSPSPPSToIDRFrames) Success.");
507   } else {
508     GST_ERROR_OBJECT(self, "set OMX_IndexParamPrependSPSPPSToIDR failed with error %d (0x%08x)", err, err);
509   }
510
511   return;
512 }
513
514 static void
515 set_physical_output(GstOmxBaseFilter * self)
516 {
517   OMX_INDEXTYPE index = OMX_IndexComponentStartUnused;
518   OMX_ERRORTYPE err = OMX_ErrorNone;
519   PhysicalOutputParams params;
520   GOmxCore *gomx = self->gomx;
521
522   GST_LOG_OBJECT(self, "set_physical_output enter");
523
524   err = OMX_GetExtensionIndex(gomx->omx_handle, "OMX.SEC.index.encoderSharedOutputFD", &index);
525   if (err != OMX_ErrorNone || index == OMX_IndexComponentStartUnused) {
526       GST_INFO_OBJECT(self, "can not get index for OMX_GetExtensionIndex OMX_IndexParamSharedOutputFD");
527       return;
528   }
529
530   G_OMX_INIT_PARAM(params);
531   params.bEnable = OMX_TRUE;
532
533   err = OMX_SetParameter(gomx->omx_handle, index, &params);
534   if (err == OMX_ErrorNone) {
535     GST_INFO_OBJECT(self, "set_physical_output success.");
536   } else {
537     GST_ERROR_OBJECT(self, "set OMX_IndexParamPhysicalOutput failed with error %d (0x%08x)", err, err);
538     return;
539   }
540
541   return;
542 }
543
544
545 /*
546  *  description : set sync frame. if needed, convert output to packetized format, append dci every I frame.
547  *  params      : @self : GstOmxBaseFilter, @buf: encoder output frame, @omx_buffer: omx_buffer
548  *  return      : none
549  *  comments    :
550  */
551 static GstOmxReturn
552 process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
553 {
554   GstOmxH264Enc *self;
555   self = GST_OMX_H264ENC (omx_base);
556
557   if (!omx_base->bPhysicalOutput) {
558     if (!self->byte_stream) { /* Packtized Format */
559       convert_to_packetized_frame (self, buf); /* convert byte stream to packetized stream */
560       GST_LOG_OBJECT (self, "output buffer is converted to Packtized format.");
561     } else {
562       GST_LOG_OBJECT (self, "output buffer is Byte-stream format.");
563     }
564   }
565
566   if ((self->first_frame) ||(self->append_dci && omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
567
568     if (omx_base->gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS ||
569       omx_base->gomx->component_vendor == GOMX_VENDOR_SLSI_SEC) {
570       GST_LOG_OBJECT (self, "append dci at %s by MFC.", (self->first_frame == TRUE) ? "first frame": "every I frame");
571       goto exit;
572     }
573
574     GST_LOG_OBJECT (self, "append dci at %s by gst-openmax.", (self->first_frame == TRUE) ? "first frame": "every I frame");
575
576     if (self->dci == NULL) {
577       GST_ERROR_OBJECT (self, "dci is null. can not append dci.");
578       self->append_dci = FALSE;
579     } else {
580       GstBuffer *newbuf = NULL;
581       newbuf = gst_buffer_merge (self->dci, *buf);
582       if (newbuf == NULL) {
583         GST_ERROR_OBJECT (self, "Failed to gst_buffer_merge.");
584         return GSTOMX_RETURN_ERROR;
585       }
586       gst_buffer_copy_metadata(newbuf, *buf, GST_BUFFER_COPY_ALL);
587       gst_buffer_unref(*buf);
588       *buf = newbuf;
589       }
590     }
591
592 exit:
593
594   if (self->first_frame == TRUE)
595     self->first_frame = FALSE;
596
597   /* Set sync frame info while encoding */
598   if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
599     GST_BUFFER_FLAG_UNSET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
600   } else {
601     GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
602   }
603
604   return GSTOMX_RETURN_OK;
605 }
606
607 /*
608  *  description : if needed, convert byte-stream codec_data to packetized format, save dci.
609  *  params      : @self : GstOmxBaseFilter, @omx_buffer: omx_buffer
610  *  return      : none
611  *  comments    :
612  */
613 static void
614 process_output_caps(GstOmxBaseFilter * base, OMX_BUFFERHEADERTYPE *omx_buffer)
615 {
616   GstOmxH264Enc *h264enc;
617   gboolean ret = FALSE;
618
619   h264enc = GST_OMX_H264ENC (base);
620
621   if (!h264enc->byte_stream) { /* Packtized Format */
622     GstCaps *caps = NULL;
623     GstStructure *structure;
624     GstBuffer *codec_data = NULL;
625     gint sps_cnt = 0;
626     gint pps_cnt = 0;
627     GValue value = { 0, {{0}
628         }
629     };
630     g_value_init (&value, GST_TYPE_BUFFER);
631
632     GST_INFO_OBJECT (h264enc, "Packtized Format: set src caps with codec-data");
633
634     /* convert codec_data to packtized format.. (metadata(cnt) + sps_size + sps + cnt + pps_size + pps) */
635     ret = convert_to_packetized_dci (h264enc, omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen,
636         &codec_data, &sps_cnt, &pps_cnt);
637
638     if (FALSE == ret) {
639       GST_ERROR_OBJECT (h264enc, "ERROR: convert to packetized dci");
640       if (codec_data) {
641         gst_buffer_unref(codec_data);
642         codec_data = NULL;
643       }
644       return;
645     }
646
647     /* restore packtized format sps, pps */
648     ret = restore_packetized_dci (h264enc, codec_data, &h264enc->dci, sps_cnt, pps_cnt);
649     if (ret == FALSE) {
650       GST_ERROR_OBJECT (h264enc, "ERROR: restore packetized dci");
651       return;
652     }
653
654     GST_DEBUG_OBJECT (h264enc, "adding codec_data in caps");
655     caps = gst_pad_get_negotiated_caps (base->srcpad);
656     caps = gst_caps_make_writable (caps);
657     structure = gst_caps_get_structure (caps, 0);
658
659     /* packetized format, set codec_data field in caps */
660     gst_value_set_buffer (&value,codec_data);
661     gst_buffer_unref (codec_data);
662     codec_data = NULL;
663     gst_structure_set_value (structure, "codec_data", &value);
664     g_value_unset (&value);
665
666     gst_pad_set_caps (base->srcpad, caps);
667     gst_caps_unref (caps);
668   } else {
669     /* byte-stream format */
670     GST_INFO_OBJECT (h264enc, "Byte-stream Format");
671     h264enc->dci = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
672     if (!h264enc->dci) {
673       GST_ERROR_OBJECT (h264enc, "failed to allocate memory...");
674       return;
675     }
676     memcpy (GST_BUFFER_DATA (h264enc->dci),
677         omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
678   }
679 }
680
681 static void
682 instance_deinit (GstElement * element)
683 {
684   GstOmxH264Enc *h264enc;
685   h264enc = GST_OMX_H264ENC (element);
686
687   GST_WARNING_OBJECT (h264enc, "h264 enc deinit");
688
689   if (h264enc->dci) {
690     gst_buffer_unref(h264enc->dci);
691     h264enc->dci = NULL;
692   }
693
694   GST_OMX_BASE_FILTER_CLASS (parent_class)->instance_deinit(element);
695   GST_WARNING_OBJECT (h264enc, "h264 enc end");
696 }
697
698 static void
699 finalize (GObject * obj)
700 {
701   GstOmxH264Enc *h264enc;
702   h264enc = GST_OMX_H264ENC (obj);
703
704   GST_LOG_OBJECT (h264enc, "h264enc finalize enter");
705
706   G_OBJECT_CLASS (parent_class)->finalize (obj);
707 }
708
709 static void
710 type_base_init (gpointer g_class)
711 {
712   GstElementClass *element_class;
713
714   element_class = GST_ELEMENT_CLASS (g_class);
715
716   gst_element_class_set_details_simple (element_class,
717       "OpenMAX IL H.264/AVC video encoder",
718       "Codec/Encoder/Video",
719       "Encodes video in H.264/AVC format with OpenMAX IL", "Felipe Contreras");
720
721   gst_element_class_add_pad_template (element_class,
722       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
723           gstomx_template_caps (G_TYPE_FROM_CLASS (g_class), "sink")));
724
725   gst_element_class_add_pad_template (element_class,
726       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
727           gstomx_template_caps (G_TYPE_FROM_CLASS (g_class), "src")));
728 }
729
730 static void
731 set_property (GObject * obj,
732     guint prop_id, const GValue * value, GParamSpec * pspec)
733 {
734   GstOmxH264Enc *self;
735   GstOmxBaseFilter *omx_base;
736
737   self = GST_OMX_H264ENC (obj);
738   omx_base = GST_OMX_BASE_FILTER (obj);
739
740   switch (prop_id) {
741     case ARG_APPEND_DCI:
742       self->append_dci = g_value_get_boolean (value);
743       GST_WARNING_OBJECT (self, "set Appending dci = %d", self->append_dci);
744       if (self->append_dci == TRUE)
745         set_apppend_dci (omx_base);
746       break;
747
748     case ARG_BYTE_STREAM:
749       self->byte_stream = g_value_get_boolean (value);
750       GST_INFO_OBJECT (self, "set Byte stream = %d", self->byte_stream);
751       break;
752
753     case ARG_SLICE_MODE:
754       {
755         OMX_VIDEO_PARAM_AVCSLICEFMO param;
756         OMX_ERRORTYPE ret;
757
758         self->slice_fmo.eSliceMode = g_value_get_int (value);
759         if (omx_base->gomx->component_vendor  == GOMX_VENDOR_SLSI_EXYNOS) {
760           G_OMX_INIT_PARAM (param);
761           param.nPortIndex = omx_base->out_port->port_index;
762           OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoSliceFMO, &param);
763
764           param.eSliceMode = self->slice_fmo.eSliceMode;
765           param.nNumSliceGroups = 1;
766           param.nSliceGroupMapType = 1;
767           ret = OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoSliceFMO, &param);
768           if (ret != OMX_ErrorNone)
769             GST_ERROR_OBJECT (self, "failed to set eSliceMode = %d", self->slice_fmo.eSliceMode);
770           else
771             GST_INFO_OBJECT (self, "set eSliceMode = %d", self->slice_fmo.eSliceMode);
772         }
773       }
774       break;
775
776     case ARG_SLICE_SIZE:
777       {
778         OMX_VIDEO_PARAM_AVCTYPE param;
779         OMX_ERRORTYPE ret;
780
781         self->h264type.nSliceHeaderSpacing = g_value_get_uint (value);
782
783         if (omx_base->gomx->component_vendor  == GOMX_VENDOR_SLSI_EXYNOS) {
784             self->h264type.nSliceHeaderSpacing = self->h264type.nSliceHeaderSpacing / 8;
785
786           G_OMX_INIT_PARAM (param);
787           param.nPortIndex = omx_base->out_port->port_index;
788           OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, &param);
789
790           param.nSliceHeaderSpacing = self->h264type.nSliceHeaderSpacing;
791           ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, &param);
792           if (ret != OMX_ErrorNone)
793             GST_ERROR_OBJECT (self, "failed to set nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
794           else
795             GST_INFO_OBJECT (self, "nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
796         }
797       }
798       break;
799
800 case ARG_PHYSICAL_OUTPUT:
801       omx_base->bPhysicalOutput = g_value_get_boolean (value);
802       GST_WARNING_OBJECT (self, "set Physical output = %d", omx_base->bPhysicalOutput);
803       if ((omx_base->bPhysicalOutput == TRUE) &&
804         (omx_base->gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS ||
805           omx_base->gomx->component_vendor == GOMX_VENDOR_SLSI_SEC)) {
806         set_physical_output (omx_base);
807       }
808       break;
809
810     case ARG_ENCODER_LEVEL:
811     {
812         OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
813         OMX_ERRORTYPE ret;
814
815         omx_base->encoder_level =g_value_get_int (value);
816         G_OMX_INIT_PARAM (param);
817
818         param.nPortIndex = omx_base->out_port->port_index;
819         OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoProfileLevelCurrent, &param);
820
821         GST_WARNING_OBJECT (self, "Set parameter level from %d to %d", param.eLevel ,omx_base->encoder_level);
822
823         param.eLevel = omx_base->encoder_level;
824         ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoProfileLevelCurrent, &param);
825         if (ret != OMX_ErrorNone)
826         GST_ERROR_OBJECT (self, "failed to set encoder level = %d", param.eLevel);
827         else
828         GST_INFO_OBJECT (self, "encoder level changed to = %d", param.eLevel);
829     }
830        break;
831     case ARG_ENCODER_PROFILE:
832     {
833         OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
834         OMX_ERRORTYPE ret;
835
836         omx_base->encoder_profile=g_value_get_int (value);
837         G_OMX_INIT_PARAM (param);
838
839         param.nPortIndex = omx_base->out_port->port_index;
840         OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoProfileLevelCurrent, &param);
841
842         GST_WARNING_OBJECT (self, "Set parameter profile from %d to %d", param.eProfile ,omx_base->encoder_profile);
843
844         param.eProfile = omx_base->encoder_profile;
845         ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoProfileLevelCurrent, &param);
846         if (ret != OMX_ErrorNone)
847           GST_ERROR_OBJECT (self, "failed to set encoder profile = %d", param.eProfile);
848         else
849           GST_INFO_OBJECT (self, "encoder profile changed to = %d", param.eProfile);
850     }
851        break;
852     default:
853       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
854       break;
855   }
856 }
857
858 static void
859 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
860 {
861   GstOmxH264Enc *self;
862   GstOmxBaseFilter *omx_base;
863
864   self = GST_OMX_H264ENC (obj);
865   omx_base = GST_OMX_BASE_FILTER (obj);
866
867   switch (prop_id) {
868     case ARG_APPEND_DCI:
869       g_value_set_boolean (value, self->append_dci);
870       break;
871     case ARG_BYTE_STREAM:
872       g_value_set_boolean (value, self->byte_stream);
873       break;
874     case ARG_SLICE_MODE:
875       g_value_set_int (value, self->slice_fmo.eSliceMode);
876       break;
877     case ARG_SLICE_SIZE:
878       g_value_set_uint (value, self->h264type.nSliceHeaderSpacing);
879       break;
880     case ARG_PHYSICAL_OUTPUT:
881       g_value_set_boolean (value, omx_base->bPhysicalOutput);
882       break;
883     case ARG_ENCODER_LEVEL:
884       g_value_set_int (value, omx_base->encoder_level);
885       break;
886     case ARG_ENCODER_PROFILE:
887       g_value_set_int (value, omx_base->encoder_profile);
888       break;
889     default:
890       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
891       break;
892   }
893 }
894
895 static void
896 type_class_init (gpointer g_class, gpointer class_data)
897 {
898   GObjectClass *gobject_class;
899   GstOmxBaseFilterClass *basefilter_class;
900
901   gobject_class = G_OBJECT_CLASS (g_class);
902   basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
903
904   {
905     gobject_class->set_property = set_property;
906     gobject_class->get_property = get_property;
907
908     GST_WARNING("h264 enc  type_class_init");
909     g_object_class_install_property (gobject_class, ARG_APPEND_DCI,
910         g_param_spec_boolean ("append-dci", "append codec_data with every key frame for byte-stream format",
911             "append codec_data with every key frame for byte-stream format",
912             FALSE,
913             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
914
915     g_object_class_install_property (gobject_class, ARG_BYTE_STREAM,
916         g_param_spec_boolean ("byte-stream", "Output stream format",
917             "output stream format whether byte-stream format (TRUE) or packetized (FALSE)",
918             FALSE,
919             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
920
921     g_object_class_install_property (gobject_class, ARG_SLICE_MODE,
922         g_param_spec_int ("slice-mode", "H264 encoder slice mode",
923             "slice mode: 0-Disable, 1-Fixed MB num slice, 2-Fixed bit num slice",
924             0, 4, 0,
925             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
926
927     g_object_class_install_property (gobject_class, ARG_SLICE_SIZE,
928         g_param_spec_uint ("slice-size", "H264 encoder slice size",
929             "MB or bit num: MB number:1 ~ (MBCnt-1), Bit number: 1900 (bit) ~",
930             0, G_MAXUINT, 0,
931             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
932
933     g_object_class_install_property (gobject_class, ARG_PHYSICAL_OUTPUT,
934         g_param_spec_boolean ("physical-output", "set physical-output",
935             "Whether or not to use physical_output",
936             FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
937
938     g_object_class_install_property (gobject_class, ARG_ENCODER_LEVEL,
939         g_param_spec_int ("encoder-level", "set encoder-level",
940             "set encoder-level",
941             0, 32768, 512,
942             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
943
944     g_object_class_install_property (gobject_class, ARG_ENCODER_PROFILE,
945         g_param_spec_int ("encoder-profile", "set encoder-profile",
946             "set encoder-profile",
947             0, 32768, 512,
948             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
949   }
950
951   basefilter_class->process_output_buf = process_output_buf;
952   basefilter_class->process_output_caps = process_output_caps;
953   basefilter_class->instance_init = instance_init;
954   basefilter_class->instance_deinit = instance_deinit;
955
956   gobject_class->finalize = finalize;
957
958 }
959
960 static void
961 settings_changed_cb (GOmxCore * core)
962 {
963   GstOmxBaseVideoEnc *omx_base;
964   GstOmxBaseFilter *omx_base_filter;
965   GstOmxH264Enc *self;
966
967   guint width;
968   guint height;
969
970   omx_base_filter = core->object;
971   omx_base = GST_OMX_BASE_VIDEOENC (omx_base_filter);
972   self = GST_OMX_H264ENC (omx_base_filter);
973
974   GST_DEBUG_OBJECT (omx_base, "settings changed");
975
976   {
977     OMX_PARAM_PORTDEFINITIONTYPE param;
978
979     G_OMX_INIT_PARAM (param);
980
981     param.nPortIndex = omx_base_filter->out_port->port_index;
982     OMX_GetParameter (core->omx_handle, OMX_IndexParamPortDefinition, &param);
983
984     width = param.format.video.nFrameWidth;
985     height = param.format.video.nFrameHeight;
986   }
987
988   {
989     GstCaps *new_caps, *peer_caps;
990     gchar *format ;
991     int i =0;
992
993     new_caps = gst_caps_new_simple ("video/x-h264",
994         "width", G_TYPE_INT, width,
995         "height", G_TYPE_INT, height,
996         "framerate", GST_TYPE_FRACTION,
997         omx_base->framerate_num, omx_base->framerate_denom, NULL);
998
999     /* get peer pad caps */
1000     peer_caps = gst_pad_peer_get_caps(omx_base_filter->srcpad);
1001     if (peer_caps) {
1002       GST_LOG_OBJECT (omx_base, "peer caps : %" GST_PTR_FORMAT, peer_caps);
1003
1004       for (i = 0; i < peer_caps->structs->len; i++) {
1005         GstStructure *s;
1006         s = gst_caps_get_structure (peer_caps, i);
1007
1008         if (g_strrstr (gst_structure_get_name (s), "video/x-h264")) {
1009           if (!gst_structure_get (s, "stream-format", G_TYPE_STRING, &format, NULL)) {
1010             GST_WARNING_OBJECT (self, "Failed to get stream-format from peer caps...");
1011           } else {
1012             GST_INFO_OBJECT (self, "format : %s", format);
1013             gst_caps_set_simple (new_caps, "stream-format", G_TYPE_STRING, format, NULL);
1014             if (g_strrstr(format, "byte-stream")) {
1015               GST_INFO_OBJECT (self, "Mandatory BYTE_STREAM");
1016               self->byte_stream = TRUE;
1017             } else if (g_strrstr(format, "avc")){
1018               GST_INFO_OBJECT (self, "Mandatory PACKETIZED");
1019               self->byte_stream = FALSE;
1020             } else {
1021               GST_INFO_OBJECT (self, "Nothing mentioned about stream-format... use byte_stream property to decide");
1022               if (self->byte_stream) {
1023                 GST_INFO_OBJECT (self, "Is in BYTE_STREAM");
1024               } else {
1025                 GST_INFO_OBJECT (self, "Is in PACKETIZED");
1026               }
1027             }
1028           }
1029         }
1030       }
1031
1032       gst_caps_unref(peer_caps);
1033     }
1034
1035     GST_INFO_OBJECT (omx_base, "caps are: %" GST_PTR_FORMAT, new_caps);
1036     gst_pad_set_caps (omx_base_filter->srcpad, new_caps);
1037     gst_caps_unref(new_caps);
1038   }
1039 }
1040
1041 static void
1042 instance_private_value_init(GstElement * element)
1043 {
1044   GstOmxBaseFilter *omx_base_filter;
1045   GstOmxBaseVideoEnc *omx_base;
1046   GstOmxH264Enc *self;
1047
1048   omx_base_filter = GST_OMX_BASE_FILTER (element);
1049   omx_base = GST_OMX_BASE_VIDEOENC (element);
1050   self = GST_OMX_H264ENC (element);
1051
1052   self->byte_stream = FALSE;
1053   self->append_dci = FALSE;
1054   self->first_frame = TRUE;
1055   self->dci = NULL;
1056   self->slice_fmo.eSliceMode = OMX_VIDEO_SLICEMODE_AVCLevelMax;
1057   omx_base_filter->bPhysicalOutput = FALSE;
1058
1059   omx_base->compression_format = OMX_VIDEO_CodingAVC;
1060
1061   omx_base_filter->gomx->settings_changed_cb = settings_changed_cb;
1062 }
1063
1064 static void
1065 instance_init (GstElement * element)
1066 {
1067   GST_OMX_BASE_FILTER_CLASS (parent_class)->instance_init(element);
1068
1069   instance_private_value_init(element);
1070 }
1071
1072 static void
1073 type_instance_init (GTypeInstance * instance, gpointer g_class)
1074 {
1075   instance_private_value_init(GST_ELEMENT(instance));
1076 }