Tizen 2.1 base
[profile/ivi/gst-openmax0.10.git] / 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 };
33
34 GSTOMX_BOILERPLATE (GstOmxH264Enc, gst_omx_h264enc, GstOmxBaseVideoEnc,
35     GST_OMX_BASE_VIDEOENC_TYPE);
36
37 /*
38  *  description : convert byte-stream format to packetized frame
39  *  params      : @self : GstOmxH264Enc, @buf: byte-stream buf, @sync: notify this buf is sync frame
40  *  return      : none
41  *  comments    :
42  */
43 static void
44 convert_to_packetized_frame (GstOmxH264Enc *self, GstBuffer **buf)
45 {
46   unsigned char *data = GST_BUFFER_DATA (*buf);
47   unsigned int size = GST_BUFFER_SIZE(*buf);
48   int idx = 0;
49   gint start_idx = -1;
50   unsigned char *nalu_start = NULL;
51   GstOmxBaseFilter *omx_base = GST_OMX_BASE_FILTER(self);
52
53   GST_LOG_OBJECT (self, "convert_to_packtized format. size=%d sliceMode=%d",
54       GST_BUFFER_SIZE(*buf), self->slice_fmo.eSliceMode);
55
56   if (omx_base->gomx->component_vendor == GOMX_VENDOR_SLSI &&
57     self->slice_fmo.eSliceMode == OMX_VIDEO_SLICEMODE_AVCDefault) { /* 1 slice per frame */
58     GST_LOG_OBJECT (self, " handle single NALU per buffer");
59     while (idx < size - GSTOMX_H264_NAL_START_LEN) {
60       if (((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x00)&& (data[idx+3] == 0x01)) ||
61         ((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x01))) {
62         if (data[idx+2] == 0x01) {
63           GST_ERROR_OBJECT (self, "ERROR : NALU header is 3-bytes, yet to support !!");
64         } else {
65           GSTOMX_H264_WB32(data + idx, size - idx - GSTOMX_H264_NAL_START_LEN);
66           return;
67         }
68       }
69       idx++;
70     } /* while */
71   } else { /* handle multiple NALUs in one buffer */
72     GST_LOG_OBJECT (self, " handle multiple NALUs per buffer");
73     while (idx < size - GSTOMX_H264_NAL_START_LEN) {
74       if (((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x00)&& (data[idx+3] == 0x01)) ||
75         ((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x01))) {
76         if (data[idx+2] == 0x01) {
77           GST_ERROR_OBJECT (self, "ERROR : NALU header is 3-bytes, yet to support !!");
78         } else {
79           if (start_idx >= 0) {
80             if (idx <= start_idx) {
81               GST_ERROR_OBJECT (self, "ERROR : idx <= start_idx !!");
82               return;
83             }
84             GST_LOG_OBJECT (self, "size of current nal unit = %d", idx-start_idx);
85             GSTOMX_H264_WB32(nalu_start, idx - start_idx - GSTOMX_H264_NAL_START_LEN);
86           }
87           start_idx = idx;
88           nalu_start = data + idx;
89           idx++;
90         }
91       }
92       idx++;
93     } /* while */
94     idx += GSTOMX_H264_NAL_START_LEN;
95
96     /* converting last nal unit */
97     if (start_idx >= 0) {
98       GST_LOG_OBJECT (self, "size of current nal unit = %d", idx-start_idx);
99       GSTOMX_H264_WB32(nalu_start, idx - start_idx - GSTOMX_H264_NAL_START_LEN);
100     }
101   }
102 }
103
104 /*
105  *  description : convert byte-stream codec data to packtized codec_data
106  *  params      : @self : GstOmxH264Enc, @inbuf: byte-stream codec data (omx buf), @outbuf: packetized codec_data
107  *  return      : true on successes / false on failure
108  *  comments    :
109  */
110 static gboolean
111 convert_to_packetized_dci (GstOmxH264Enc *self, unsigned char *nalu_dci, unsigned nalu_dci_len,
112     GstBuffer **packetized_dci, gint *out_sps_cnt, gint *out_pps_cnt)
113 {
114   gint idx = 0;
115   gint sps_cnt = 0;
116   gint pps_cnt = 0;
117   GQueue *sps_queue = 0;
118   GQueue *pps_queue = 0;
119   unsigned char *packet_dci = NULL;
120   gint prev_nalu_start = 0;
121   gint prev_nalu_type = GSTOMX_H264_NUT_UNKNOWN;
122   gint sps_size = 0;
123   gint pps_size = 0;
124   GstBuffer *sps_data = NULL;
125   GstBuffer *pps_data = NULL;
126   GstBuffer *queue_data = NULL;
127   gint nal_type = GSTOMX_H264_NUT_UNKNOWN;
128   unsigned char profile = 0;
129   unsigned char level = 0;
130   unsigned char profile_comp = 0;
131   gboolean bret = TRUE;
132   gboolean single_sps_pps = FALSE; /* if there is only 1 sps, pps set, */
133
134   sps_queue = g_queue_new ();
135   pps_queue = g_queue_new ();
136
137   /* find no.of SPS & PPS units */
138   while (idx < nalu_dci_len) {
139     if ((nalu_dci[idx] == 0x00) && (nalu_dci[idx+1] == 0x00) && (nalu_dci[idx+2] == 0x01)) {
140       /* copy previous nal unit */
141       if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_SPS) {
142         if (nalu_dci[idx -1] == 0x00) {
143           sps_size = idx -1 - prev_nalu_start;
144         } else {
145           sps_size = idx - prev_nalu_start;
146         }
147         sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
148         if (!sps_data) {
149           GST_ERROR_OBJECT (self, "failed to allocate memory..");
150           bret = FALSE;
151           goto exit;
152         }
153         GSTOMX_H264_WB16(GST_BUFFER_DATA(sps_data), sps_size);
154         memcpy (GST_BUFFER_DATA(sps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, sps_size);
155         g_queue_push_tail (sps_queue, sps_data);
156       } else if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_PPS) {
157         if (nalu_dci[idx -1] == 0x00) {
158           pps_size = idx -1 - prev_nalu_start;
159         } else {
160           pps_size = idx - prev_nalu_start;
161         }
162         pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
163         if (!pps_data) {
164           GST_ERROR_OBJECT (self, "failed to allocate memory..");
165           bret = FALSE;
166           goto exit;
167         }
168         GSTOMX_H264_WB16(GST_BUFFER_DATA(pps_data), pps_size);
169         memcpy (GST_BUFFER_DATA(pps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, pps_size);
170         g_queue_push_tail (pps_queue, pps_data);
171       }
172       /* present nalu type */
173       nal_type = nalu_dci[idx+3] & 0x1f;
174
175       if (nal_type == GSTOMX_H264_NUT_SPS) {
176         sps_cnt++;
177         prev_nalu_start = idx + 3;
178         prev_nalu_type =GSTOMX_H264_NUT_SPS;
179         profile = nalu_dci[idx+4];
180         level = nalu_dci[idx+6];
181         GST_INFO_OBJECT (self, "Profile Number = %d and Level = %d...", nalu_dci[idx+4], level);
182         GST_INFO_OBJECT (self, "Profile is %s", (profile == 66) ? "BaseLine Profile": (profile == 77)? "Main Profile": profile==88 ?
183                   "Extended Profile": profile==100 ? "High Profile": "Not Supported codec");
184       } else if ((nalu_dci[idx+3] & 0x1f) == GSTOMX_H264_NUT_PPS) {
185         pps_cnt++;
186         prev_nalu_start = idx + 3;
187         prev_nalu_type = GSTOMX_H264_NUT_PPS;
188       }
189     }
190     idx++;
191   }
192
193   /* copy previous nal unit */
194   if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_SPS) {
195     sps_size = idx - prev_nalu_start;
196
197     sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
198     if (!sps_data) {
199       GST_ERROR_OBJECT (self, "failed to allocate memory..");
200       bret = FALSE;
201       goto exit;
202     }
203
204     GSTOMX_H264_WB16(GST_BUFFER_DATA(sps_data), sps_size);
205     memcpy (GST_BUFFER_DATA(sps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, sps_size);
206     g_queue_push_tail (sps_queue, sps_data);
207
208   } else if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_PPS) {
209     pps_size = idx - prev_nalu_start;
210
211     pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
212     if (!pps_data) {
213       GST_ERROR_OBJECT (self, "failed to allocate memory..");
214       bret = FALSE;
215       goto exit;
216     }
217
218     GSTOMX_H264_WB16(GST_BUFFER_DATA(pps_data), pps_size);
219     memcpy (GST_BUFFER_DATA(pps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, pps_size);
220     g_queue_push_tail (pps_queue, pps_data);
221   }
222
223   /* make packetized codec data */
224   if (sps_cnt == 1 && pps_cnt == 1) {
225     single_sps_pps = TRUE;
226     *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);
227     GST_LOG_OBJECT(self, "allocate packetized_dci in case of single sps, pps. (size=%d)",  GST_BUFFER_SIZE(*packetized_dci));
228   } else {
229     *packetized_dci = gst_buffer_new_and_alloc(GSTOMX_H264_MDATA);
230     GST_LOG_OBJECT(self, "allocate packetized_dci in case of multi sps, pps");
231   }
232
233   if (*packetized_dci == NULL) {
234     GST_ERROR_OBJECT (self, "Failed to allocate memory..");
235     bret = FALSE;
236     goto exit;
237   }
238
239   packet_dci = GST_BUFFER_DATA(*packetized_dci);
240   packet_dci[0] = 0x01; /* configurationVersion */
241   packet_dci[1] = profile; /* AVCProfileIndication */
242   packet_dci[2] = profile_comp; /* profile_compatibility*/
243   packet_dci[3] = level;  /* AVCLevelIndication */
244   packet_dci[4] = 0xff; /* Reserver (6bits.111111) + LengthSizeMinusOne (2bits). lengthoflength = 4 for present */
245   packet_dci[5] = 0xe0 | sps_cnt; /* Reserver (3bits. 111) + numOfSequenceParameterSets (5bits) */
246
247   /* copy SPS sets */
248   while (!g_queue_is_empty (sps_queue)) {
249     sps_data = g_queue_pop_head (sps_queue);
250
251     if (TRUE == single_sps_pps) {
252       memcpy(packet_dci + GSTOMX_H264_MDATA, GST_BUFFER_DATA(sps_data), GST_BUFFER_SIZE(sps_data));
253       gst_buffer_unref(sps_data);
254       sps_data = NULL;
255     } else {
256       *packetized_dci = gst_buffer_join(*packetized_dci, sps_data);
257     }
258   }
259
260   /* add number of PPS sets (1byte)*/
261   if (TRUE == single_sps_pps) {
262     packet_dci[GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size] = pps_cnt;
263   } else {
264     GstBuffer *next_data = gst_buffer_new_and_alloc(GSTOMX_H264_CNT_LEN);
265     if (!next_data) {
266       GST_ERROR_OBJECT (self, "Failed to allocate memory..");
267       bret = FALSE;
268       goto exit;
269     }
270     GST_BUFFER_DATA(next_data)[0] = pps_cnt;
271     *packetized_dci = gst_buffer_join(*packetized_dci, next_data);
272   }
273
274   /* copy PPS sets */
275   while (!g_queue_is_empty (pps_queue)) {
276     pps_data = g_queue_pop_head (pps_queue);
277
278     if (TRUE == single_sps_pps) {
279       memcpy(packet_dci + GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size + GSTOMX_H264_CNT_LEN,
280                       GST_BUFFER_DATA(pps_data), GST_BUFFER_SIZE(pps_data));
281       gst_buffer_unref(pps_data);
282       pps_data = NULL;
283     } else {
284       *packetized_dci = gst_buffer_join(*packetized_dci, pps_data);
285     }
286   }
287
288 exit:
289   while (!g_queue_is_empty (sps_queue)) {
290     queue_data = g_queue_pop_head (sps_queue);
291     gst_buffer_unref (queue_data);
292     queue_data = NULL;
293   }
294   g_queue_free (sps_queue);
295
296   while (!g_queue_is_empty (pps_queue)) {
297     queue_data = g_queue_pop_head (pps_queue);
298     gst_buffer_unref (queue_data);
299     queue_data = NULL;
300   }
301   g_queue_free (pps_queue);
302
303   *out_sps_cnt = sps_cnt;
304   *out_pps_cnt = sps_cnt;
305
306   return bret;
307 }
308
309 /*
310  *  description : resotre packtized dci (codec_data)
311  *  params      : @self : GstOmxH264Enc, @inbuf: codec data, @outbuf: h264enc->dci
312  *  return      : none
313  *  comments    :
314  *    from original packetized codec_data: METADATA(6) + SPS_CNT(0) + {SPS_SIZE(2)+SPS_DATA(sps_size)}*n +
315                                                              PPS_CNT(1) + {PPS_SIZE(2)+PPS_DATA(pps_size)}*n
316  *    to estore packetized dci: {SPS_SIZE(4)+SPS_DATA(sps_size)}*n + {PPS_SIZE(4)+PPS_DATA(pps_size)}*n
317  */
318 static gboolean
319 restore_packetized_dci (GstOmxH264Enc *self, GstBuffer *inbuf, GstBuffer **outbuf, gint sps_cnt, gint pps_cnt)
320 {
321   unsigned char *indata = GST_BUFFER_DATA(inbuf);
322   guint sps_size =0;
323   guint pps_size =0;
324   gint i = 0;
325   GstBuffer *next_data = NULL;
326
327   GST_INFO_OBJECT (self, "restore_packetized_dci. sps_cnt=%d, pps_cnt=%d", sps_cnt, pps_cnt);
328
329   if (sps_cnt == 1 && pps_cnt == 1) {
330     sps_size = GSTOMX_H264_RB16(indata + GSTOMX_H264_MDATA);
331     pps_size = GSTOMX_H264_RB16(indata + GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size + GSTOMX_H264_CNT_LEN);
332
333     *outbuf = gst_buffer_new_and_alloc (GSTOMX_H264_A_DCI_LEN + sps_size + GSTOMX_H264_A_DCI_LEN + pps_size);
334     if (!*outbuf) {
335       GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
336       goto error_exit;
337     }
338
339     GSTOMX_H264_WB32(GST_BUFFER_DATA(*outbuf), sps_size);
340     indata += GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN;
341     memcpy (GST_BUFFER_DATA(*outbuf) + GSTOMX_H264_A_DCI_LEN, indata, sps_size);
342     indata += sps_size;
343
344     GSTOMX_H264_WB32(GST_BUFFER_DATA(*outbuf) + GSTOMX_H264_A_DCI_LEN + sps_size, pps_size);
345     indata += GSTOMX_H264_CNT_LEN + GSTOMX_H264_C_DCI_LEN;
346     memcpy (GST_BUFFER_DATA(*outbuf) + GSTOMX_H264_A_DCI_LEN + sps_size + GSTOMX_H264_A_DCI_LEN, indata, pps_size);
347     indata += pps_size;
348   } else {
349     /* in this case, dci has multi nalu. ex) sps + sps + sps + pps + pps */
350     indata += GSTOMX_H264_MDATA;
351     *outbuf = gst_buffer_new ();
352
353     for (i = 0; i < sps_cnt; i++) {
354       sps_size = GSTOMX_H264_RB16(indata); /* metadata(6) */
355
356       next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + sps_size);
357       if (!next_data) {
358         GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
359         goto error_exit;
360       }
361       GSTOMX_H264_WB32(GST_BUFFER_DATA(next_data), sps_size);
362       indata += GSTOMX_H264_C_DCI_LEN; /* sps size field (2 byte) */
363       memcpy (GST_BUFFER_DATA(next_data) + GSTOMX_H264_A_DCI_LEN, indata, sps_size);
364
365       *outbuf = gst_buffer_join(*outbuf, next_data);
366       indata += sps_size;
367     }
368     indata += GSTOMX_H264_CNT_LEN; /* pps cnt field (1 byte) */
369
370     for (i = 0; i < pps_cnt; i++) {
371       pps_size = GSTOMX_H264_RB16(indata);
372
373       next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + pps_size);
374       if (!next_data) {
375         GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
376         goto error_exit;
377       }
378       GSTOMX_H264_WB32(GST_BUFFER_DATA(next_data), pps_size);
379       indata += GSTOMX_H264_C_DCI_LEN;
380       memcpy (GST_BUFFER_DATA(next_data) + GSTOMX_H264_A_DCI_LEN, indata, pps_size);
381
382       *outbuf = gst_buffer_join(*outbuf, next_data);
383       indata += pps_size;
384     }
385   }
386
387   return TRUE;
388
389 error_exit:
390   if (*outbuf) {
391     gst_buffer_unref(*outbuf);
392     *outbuf = NULL;
393   }
394   return FALSE;
395 }
396
397 /*
398  *  description : set sync frame. if needed, convert output to packetized format, append dci every I frame.
399  *  params      : @self : GstOmxBaseFilter, @buf: encoder output frame, @omx_buffer: omx_buffer
400  *  return      : none
401  *  comments    :
402  */
403 static GstOmxReturn
404 process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
405 {
406   GstOmxH264Enc *self;
407   self = GST_OMX_H264ENC (omx_base);
408
409   if (!self->byte_stream) { /* Packtized Format */
410     convert_to_packetized_frame (self, buf); /* convert byte stream to packetized stream */
411     GST_LOG_OBJECT (self, "output buffer is converted to Packtized format.");
412   } else {
413     GST_LOG_OBJECT (self, "output buffer is Byte-stream format.");
414   }
415
416   if ((self->first_frame) ||(self->append_dci && omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
417     GstBuffer *newbuf = NULL;
418     GST_LOG_OBJECT (self, "append dci at %s by gst-openmax.", (self->first_frame == TRUE) ? "first frame": "every I frame");
419
420     if (self->dci == NULL) {
421       GST_ERROR_OBJECT (self, "dci is null. can not append dci.");
422       self->append_dci = FALSE;
423     } else {
424       newbuf = gst_buffer_merge (self->dci, *buf);
425       if (newbuf == NULL) {
426         GST_ERROR_OBJECT (self, "Failed to gst_buffer_merge.");
427         return GSTOMX_RETURN_ERROR;
428       }
429       gst_buffer_copy_metadata(newbuf, *buf, GST_BUFFER_COPY_ALL);
430       gst_buffer_unref(*buf);
431       *buf = newbuf;
432       }
433     }
434
435   if (self->first_frame == TRUE)
436     self->first_frame = FALSE;
437
438   /* Set sync frame info while encoding */
439   if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
440     GST_BUFFER_FLAG_UNSET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
441   } else {
442     GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
443   }
444
445   return GSTOMX_RETURN_OK;
446 }
447
448 /*
449  *  description : if needed, convert byte-stream codec_data to packetized format, save dci.
450  *  params      : @self : GstOmxBaseFilter, @omx_buffer: omx_buffer
451  *  return      : none
452  *  comments    :
453  */
454 static void
455 process_output_caps(GstOmxBaseFilter * base, OMX_BUFFERHEADERTYPE *omx_buffer)
456 {
457   GstOmxH264Enc *h264enc;
458   gboolean ret = FALSE;
459
460   h264enc = GST_OMX_H264ENC (base);
461
462   if (!h264enc->byte_stream) { /* Packtized Format */
463     GstCaps *caps = NULL;
464     GstStructure *structure;
465     GstBuffer *codec_data = NULL;
466     gint sps_cnt = 0;
467     gint pps_cnt = 0;
468     GValue value = { 0, {{0}
469         }
470     };
471     g_value_init (&value, GST_TYPE_BUFFER);
472
473     GST_INFO_OBJECT (h264enc, "Packtized Format: set src caps with codec-data");
474
475     /* convert codec_data to packtized format.. (metadata(cnt) + sps_size + sps + cnt + pps_size + pps) */
476     ret = convert_to_packetized_dci (h264enc, omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen,
477         &codec_data, &sps_cnt, &pps_cnt);
478
479     if (FALSE == ret) {
480       GST_ERROR_OBJECT (h264enc, "ERROR: convert to packetized dci");
481       if (codec_data) {
482         gst_buffer_unref(codec_data);
483         codec_data = NULL;
484       }
485       return;
486     }
487
488     /* restore packtized format sps, pps */
489     ret = restore_packetized_dci (h264enc, codec_data, &h264enc->dci, sps_cnt, pps_cnt);
490     if (ret == FALSE) {
491       GST_ERROR_OBJECT (h264enc, "ERROR: restore packetized dci");
492       return;
493     }
494
495     GST_DEBUG_OBJECT (h264enc, "adding codec_data in caps");
496     caps = gst_pad_get_negotiated_caps (base->srcpad);
497     caps = gst_caps_make_writable (caps);
498     structure = gst_caps_get_structure (caps, 0);
499
500     /* packetized format, set codec_data field in caps */
501     gst_value_set_buffer (&value,codec_data);
502     gst_buffer_unref (codec_data);
503     codec_data = NULL;
504     gst_structure_set_value (structure, "codec_data", &value);
505     g_value_unset (&value);
506
507     gst_pad_set_caps (base->srcpad, caps);
508     gst_caps_unref (caps);
509   } else {
510     /* byte-stream format */
511     GST_INFO_OBJECT (h264enc, "Byte-stream Format");
512     h264enc->dci = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
513     if (!h264enc->dci) {
514       GST_ERROR_OBJECT (h264enc, "failed to allocate memory...");
515       return;
516     }
517     memcpy (GST_BUFFER_DATA (h264enc->dci),
518         omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
519   }
520 }
521
522 static void
523 finalize (GObject * obj)
524 {
525   GstOmxH264Enc *h264enc;
526   h264enc = GST_OMX_H264ENC (obj);
527
528   GST_LOG_OBJECT (h264enc, "h264enc finalize enter");
529
530   if (h264enc->dci) {
531     gst_buffer_unref(h264enc->dci);
532     h264enc->dci = NULL;
533   }
534   G_OBJECT_CLASS (parent_class)->finalize (obj);
535 }
536
537 static void
538 type_base_init (gpointer g_class)
539 {
540   GstElementClass *element_class;
541
542   element_class = GST_ELEMENT_CLASS (g_class);
543
544   gst_element_class_set_details_simple (element_class,
545       "OpenMAX IL H.264/AVC video encoder",
546       "Codec/Encoder/Video",
547       "Encodes video in H.264/AVC format with OpenMAX IL", "Felipe Contreras");
548
549   gst_element_class_add_pad_template (element_class,
550       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
551           gstomx_template_caps (G_TYPE_FROM_CLASS (g_class), "sink")));
552
553   gst_element_class_add_pad_template (element_class,
554       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
555           gstomx_template_caps (G_TYPE_FROM_CLASS (g_class), "src")));
556 }
557
558 static void
559 set_property (GObject * obj,
560     guint prop_id, const GValue * value, GParamSpec * pspec)
561 {
562   GstOmxH264Enc *self;
563   GstOmxBaseFilter *omx_base;
564
565   self = GST_OMX_H264ENC (obj);
566   omx_base = GST_OMX_BASE_FILTER (obj);
567
568   switch (prop_id) {
569     case ARG_APPEND_DCI:
570       self->append_dci = g_value_get_boolean (value);
571       GST_INFO_OBJECT (self, "set Appending dci = %d", self->append_dci);
572       break;
573
574     case ARG_BYTE_STREAM:
575       self->byte_stream = g_value_get_boolean (value);
576       GST_INFO_OBJECT (self, "set Byte stream = %d", self->byte_stream);
577       break;
578
579     case ARG_SLICE_MODE:
580       {
581         OMX_VIDEO_PARAM_AVCSLICEFMO param;
582         OMX_ERRORTYPE ret;
583
584         self->slice_fmo.eSliceMode = g_value_get_uint (value);
585
586         G_OMX_INIT_PARAM (param);
587         param.nPortIndex = omx_base->out_port->port_index;
588         OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoSliceFMO, &param);
589
590         param.eSliceMode = self->slice_fmo.eSliceMode;
591         param.nNumSliceGroups = 1;
592         param.nSliceGroupMapType = 1;
593         ret = OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoSliceFMO, &param);
594         if (ret != OMX_ErrorNone)
595           GST_ERROR_OBJECT (self, "failed to set eSliceMode = %d", self->slice_fmo.eSliceMode);
596         else
597           GST_INFO_OBJECT (self, "set eSliceMode = %d", self->slice_fmo.eSliceMode);
598       }
599       break;
600
601     case ARG_SLICE_SIZE:
602       {
603         OMX_VIDEO_PARAM_AVCTYPE param;
604         OMX_ERRORTYPE ret;
605
606         self->h264type.nSliceHeaderSpacing = g_value_get_uint (value);
607
608         G_OMX_INIT_PARAM (param);
609         param.nPortIndex = omx_base->out_port->port_index;
610         OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, &param);
611
612         param.nSliceHeaderSpacing = self->h264type.nSliceHeaderSpacing;
613         ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, &param);
614         if (ret != OMX_ErrorNone)
615           GST_ERROR_OBJECT (self, "failed to set nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
616         else
617           GST_INFO_OBJECT (self, "nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
618       }
619       break;
620
621     default:
622       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
623       break;
624   }
625 }
626
627 static void
628 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
629 {
630   GstOmxH264Enc *self;
631
632   self = GST_OMX_H264ENC (obj);
633
634   switch (prop_id) {
635     case ARG_APPEND_DCI:
636       g_value_set_boolean (value, self->append_dci);
637       break;
638     case ARG_BYTE_STREAM:
639       g_value_set_boolean (value, self->byte_stream);
640       break;
641     case ARG_SLICE_MODE:
642       g_value_set_int (value, self->slice_fmo.eSliceMode);
643       break;
644     case ARG_SLICE_SIZE:
645       g_value_set_uint (value, self->h264type.nSliceHeaderSpacing);
646       break;
647
648     default:
649       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
650       break;
651   }
652 }
653
654 static void
655 type_class_init (gpointer g_class, gpointer class_data)
656 {
657   GObjectClass *gobject_class;
658   GstOmxBaseFilterClass *basefilter_class;
659
660   gobject_class = G_OBJECT_CLASS (g_class);
661   basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
662
663   {
664     gobject_class->set_property = set_property;
665     gobject_class->get_property = get_property;
666
667     g_object_class_install_property (gobject_class, ARG_APPEND_DCI,
668         g_param_spec_boolean ("append-dci", "append codec_data with every key frame for byte-stream format",
669             "append codec_data with every key frame for byte-stream format",
670             FALSE,
671             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
672
673     g_object_class_install_property (gobject_class, ARG_BYTE_STREAM,
674         g_param_spec_boolean ("byte-stream", "Output stream format",
675             "output stream format whether byte-stream format (TRUE) or packetized (FALSE)",
676             FALSE,
677             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
678
679     g_object_class_install_property (gobject_class, ARG_SLICE_MODE,
680         g_param_spec_int ("slice-mode", "H264 encoder slice mode",
681             "slice mode: 0-Disable, 1-Fixed MB num slice, 2-Fixed bit num slice",
682             0, 4, 0,
683             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
684
685     g_object_class_install_property (gobject_class, ARG_SLICE_SIZE,
686         g_param_spec_uint ("slice-size", "H264 encoder slice size",
687             "MB or bit num: MB number:1 ~ (MBCnt-1), Bit number: 1900 (bit) ~",
688             0, G_MAXUINT, 0,
689             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
690   }
691
692   basefilter_class->process_output_buf = process_output_buf;
693   basefilter_class->process_output_caps = process_output_caps;
694
695   gobject_class->finalize = finalize;
696
697 }
698
699 static void
700 settings_changed_cb (GOmxCore * core)
701 {
702   GstOmxBaseVideoEnc *omx_base;
703   GstOmxBaseFilter *omx_base_filter;
704   GstOmxH264Enc *self;
705
706   guint width;
707   guint height;
708
709   omx_base_filter = core->object;
710   omx_base = GST_OMX_BASE_VIDEOENC (omx_base_filter);
711   self = GST_OMX_H264ENC (omx_base_filter);
712
713   GST_DEBUG_OBJECT (omx_base, "settings changed");
714
715   {
716     OMX_PARAM_PORTDEFINITIONTYPE param;
717
718     G_OMX_INIT_PARAM (param);
719
720     param.nPortIndex = omx_base_filter->out_port->port_index;
721     OMX_GetParameter (core->omx_handle, OMX_IndexParamPortDefinition, &param);
722
723     width = param.format.video.nFrameWidth;
724     height = param.format.video.nFrameHeight;
725   }
726
727   {
728     GstCaps *new_caps, *peer_caps;
729     gchar *format ;
730     int i =0;
731
732     new_caps = gst_caps_new_simple ("video/x-h264",
733         "width", G_TYPE_INT, width,
734         "height", G_TYPE_INT, height,
735         "framerate", GST_TYPE_FRACTION,
736         omx_base->framerate_num, omx_base->framerate_denom, NULL);
737
738     /* get peer pad caps */
739     peer_caps = gst_pad_peer_get_caps(omx_base_filter->srcpad);
740     if (peer_caps) {
741       GST_LOG_OBJECT (omx_base, "peer caps : %s\n", gst_caps_to_string(peer_caps));
742
743       for (i = 0; i < peer_caps->structs->len; i++) {
744         GstStructure *s;
745         s = gst_caps_get_structure (peer_caps, i);
746
747         if (g_strrstr (gst_structure_get_name (s), "video/x-h264")) {
748           if (!gst_structure_get (s, "stream-format", G_TYPE_STRING, &format, NULL)) {
749             GST_WARNING_OBJECT (self, "Failed to get stream-format from peer caps...");
750           } else {
751             GST_INFO_OBJECT (self, "format : %s", format);
752             gst_caps_set_simple (new_caps, "stream-format", G_TYPE_STRING, format, NULL);
753             if (g_strrstr(format, "byte-stream")) {
754               GST_INFO_OBJECT (self, "Mandatory BYTE_STREAM");
755               self->byte_stream = TRUE;
756             } else if (g_strrstr(format, "avc")){
757               GST_INFO_OBJECT (self, "Mandatory PACKETIZED");
758               self->byte_stream = FALSE;
759             } else {
760               GST_INFO_OBJECT (self, "Nothing mentioned about stream-format... use byte_stream property to decide");
761               if (self->byte_stream) {
762                 GST_INFO_OBJECT (self, "Is in BYTE_STREAM");
763               } else {
764                 GST_INFO_OBJECT (self, "Is in PACKETIZED");
765               }
766             }
767           }
768         }
769       }
770     }
771
772     GST_INFO_OBJECT (omx_base, "caps are: %" GST_PTR_FORMAT, new_caps);
773     gst_pad_set_caps (omx_base_filter->srcpad, new_caps);
774   }
775 }
776
777 static void
778 type_instance_init (GTypeInstance * instance, gpointer g_class)
779 {
780   GstOmxBaseFilter *omx_base_filter;
781   GstOmxBaseVideoEnc *omx_base;
782   GstOmxH264Enc *self;
783
784   omx_base_filter = GST_OMX_BASE_FILTER (instance);
785   omx_base = GST_OMX_BASE_VIDEOENC (instance);
786   self = GST_OMX_H264ENC (instance);
787
788   self->byte_stream = FALSE;
789   self->append_dci = FALSE;
790   self->first_frame = TRUE;
791   self->dci = NULL;
792   self->slice_fmo.eSliceMode = OMX_VIDEO_SLICEMODE_AVCLevelMax;
793
794   omx_base->compression_format = OMX_VIDEO_CodingAVC;
795
796   omx_base_filter->gomx->settings_changed_cb = settings_changed_cb;
797 }