2 * Copyright (C) 2007-2009 Nokia Corporation.
4 * Author: Felipe Contreras <felipe.contreras@nokia.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "gstomx_h264enc.h"
37 GSTOMX_BOILERPLATE (GstOmxH264Enc, gst_omx_h264enc, GstOmxBaseVideoEnc,
38 GST_OMX_BASE_VIDEOENC_TYPE);
41 static void instance_init (GstElement * element);
42 static void instance_deinit (GstElement * element);
43 static void instance_private_value_init(GstElement * element);
47 * description : convert byte-stream format to packetized frame
48 * params : @self : GstOmxH264Enc, @buf: byte-stream buf, @sync: notify this buf is sync frame
53 convert_to_packetized_frame (GstOmxH264Enc *self, GstBuffer **buf)
55 unsigned char *data = GST_BUFFER_DATA (*buf);
56 unsigned int size = GST_BUFFER_SIZE(*buf);
57 unsigned char *buf_pos, *end_pos;
60 unsigned char *nalu_start = NULL;
61 GstOmxBaseFilter *omx_base = GST_OMX_BASE_FILTER(self);
63 GST_LOG_OBJECT (self, "convert_to_packtized format. size=%d sliceMode=%d",
64 GST_BUFFER_SIZE(*buf), self->slice_fmo.eSliceMode);
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 !!");
76 GSTOMX_H264_WB32(data + idx, size - idx - GSTOMX_H264_NAL_START_LEN);
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 !!");
93 if (idx <= start_idx) {
94 GST_ERROR_OBJECT (self, "ERROR : idx <= start_idx !!");
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);
101 nalu_start = data + idx;
107 idx += GSTOMX_H264_NAL_START_LEN;
110 } else { /* handle multiple NALUs in one buffer */
111 GST_LOG_OBJECT (self, " handle multiple NALUs per buffer");
114 end_pos = buf_pos + size;
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) {
119 unsigned int value0 = *((unsigned int*)buf_pos);
120 unsigned int value1 = *((unsigned int*)buf_pos + 1);
122 if (!(value0 & 0xFF000000)) { /* |XXX0| */
123 if ( !(value0 & 0xFFFFFF00) && ((value1 & 0x000000FF) == 0x00000001)) {
126 idx = buf_pos+1 - data;
130 } else if ( !(value0 & 0xFFFF0000) && ((value1 & 0x0000FFFF) == 0x00000100)) {
133 idx = buf_pos+2 - data;
137 } else if ((value1 & 0x00FFFFFF) == 0x00010000) {
140 idx = buf_pos+3 - data;
143 } else if (!(value0&0xFFFF0000)&&((value1&0x000000FF)==0x00000001)) {
146 } else if ((value1&0x0000FFFF)==0x00000100) {
151 } else if (value0 == 0x01000000) {
153 idx = buf_pos - data;
156 } else if ((value0 & 0x00FFFFFF)==0x00010000) {
159 } else if ((value0 & 0xFFFFFF00)==0x01000000) {
162 GST_ERROR_OBJECT (self, "ERROR : NALU header is 3-bytes, yet to support !!");
168 if (start_idx >= 0) {
169 if (idx <= start_idx) {
170 GST_ERROR_OBJECT (self, "ERROR : idx <= start_idx !!");
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);
177 nalu_start = data + idx;
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);
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
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)
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;
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, */
219 sps_queue = g_queue_new ();
220 pps_queue = g_queue_new ();
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;
230 sps_size = idx - prev_nalu_start;
232 sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
234 GST_ERROR_OBJECT (self, "failed to allocate memory..");
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;
245 pps_size = idx - prev_nalu_start;
247 pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
249 GST_ERROR_OBJECT (self, "failed to allocate memory..");
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);
257 /* present nalu type */
258 nal_type = nalu_dci[idx+3] & 0x1f;
260 if (nal_type == GSTOMX_H264_NUT_SPS) {
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) {
271 prev_nalu_start = idx + 3;
272 prev_nalu_type = GSTOMX_H264_NUT_PPS;
278 /* copy previous nal unit */
279 if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_SPS) {
280 sps_size = idx - prev_nalu_start;
282 sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
284 GST_ERROR_OBJECT (self, "failed to allocate memory..");
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);
293 } else if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_PPS) {
294 pps_size = idx - prev_nalu_start;
296 pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
298 GST_ERROR_OBJECT (self, "failed to allocate memory..");
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);
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));
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");
318 if (*packetized_dci == NULL) {
319 GST_ERROR_OBJECT (self, "Failed to allocate memory..");
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) */
333 while (!g_queue_is_empty (sps_queue)) {
334 sps_data = g_queue_pop_head (sps_queue);
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);
341 *packetized_dci = gst_buffer_join(*packetized_dci, sps_data);
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;
349 GstBuffer *next_data = gst_buffer_new_and_alloc(GSTOMX_H264_CNT_LEN);
351 GST_ERROR_OBJECT (self, "Failed to allocate memory..");
355 GST_BUFFER_DATA(next_data)[0] = pps_cnt;
356 *packetized_dci = gst_buffer_join(*packetized_dci, next_data);
360 while (!g_queue_is_empty (pps_queue)) {
361 pps_data = g_queue_pop_head (pps_queue);
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);
369 *packetized_dci = gst_buffer_join(*packetized_dci, pps_data);
374 while (!g_queue_is_empty (sps_queue)) {
375 queue_data = g_queue_pop_head (sps_queue);
376 gst_buffer_unref (queue_data);
379 g_queue_free (sps_queue);
381 while (!g_queue_is_empty (pps_queue)) {
382 queue_data = g_queue_pop_head (pps_queue);
383 gst_buffer_unref (queue_data);
386 g_queue_free (pps_queue);
388 *out_sps_cnt = sps_cnt;
389 *out_pps_cnt = sps_cnt;
395 * description : resotre packtized dci (codec_data)
396 * params : @self : GstOmxH264Enc, @inbuf: codec data, @outbuf: h264enc->dci
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
404 restore_packetized_dci (GstOmxH264Enc *self, GstBuffer *inbuf, GstBuffer **outbuf, gint sps_cnt, gint pps_cnt)
406 unsigned char *indata = GST_BUFFER_DATA(inbuf);
410 GstBuffer *next_data = NULL;
412 GST_INFO_OBJECT (self, "restore_packetized_dci. sps_cnt=%d, pps_cnt=%d", sps_cnt, pps_cnt);
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);
418 *outbuf = gst_buffer_new_and_alloc (GSTOMX_H264_A_DCI_LEN + sps_size + GSTOMX_H264_A_DCI_LEN + pps_size);
420 GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
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);
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);
434 /* in this case, dci has multi nalu. ex) sps + sps + sps + pps + pps */
435 indata += GSTOMX_H264_MDATA;
436 *outbuf = gst_buffer_new ();
438 for (i = 0; i < sps_cnt; i++) {
439 sps_size = GSTOMX_H264_RB16(indata); /* metadata(6) */
441 next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + sps_size);
443 GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
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);
450 *outbuf = gst_buffer_join(*outbuf, next_data);
453 indata += GSTOMX_H264_CNT_LEN; /* pps cnt field (1 byte) */
455 for (i = 0; i < pps_cnt; i++) {
456 pps_size = GSTOMX_H264_RB16(indata);
458 next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + pps_size);
460 GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
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);
467 *outbuf = gst_buffer_join(*outbuf, next_data);
476 gst_buffer_unref(*outbuf);
483 set_apppend_dci(GstOmxBaseFilter * self)
485 OMX_INDEXTYPE index = OMX_IndexComponentStartUnused;
486 OMX_ERRORTYPE err = OMX_ErrorNone;
487 PrependSPSPPSToIDRFramesParams params;
488 GOmxCore *gomx = self->gomx;
490 GST_LOG_OBJECT(self, "set_apppend_dci enter");
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);
496 if (err != OMX_ErrorNone || index == OMX_IndexComponentStartUnused) {
497 GST_INFO_OBJECT(self, "can not get index for OMX_GetExtensionIndex OMX_IndexParamPrependSPSPPSToIDR");
501 G_OMX_INIT_PARAM(params);
502 params.bEnable = OMX_TRUE;
504 err = OMX_SetParameter(gomx->omx_handle, index, ¶ms);
505 if (err == OMX_ErrorNone) {
506 GST_WARNING_OBJECT(self, "set_apppend_dci (prependSPSPPSToIDRFrames) Success.");
508 GST_ERROR_OBJECT(self, "set OMX_IndexParamPrependSPSPPSToIDR failed with error %d (0x%08x)", err, err);
515 set_physical_output(GstOmxBaseFilter * self)
517 OMX_INDEXTYPE index = OMX_IndexComponentStartUnused;
518 OMX_ERRORTYPE err = OMX_ErrorNone;
519 PhysicalOutputParams params;
520 GOmxCore *gomx = self->gomx;
522 GST_LOG_OBJECT(self, "set_physical_output enter");
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");
530 G_OMX_INIT_PARAM(params);
531 params.bEnable = OMX_TRUE;
533 err = OMX_SetParameter(gomx->omx_handle, index, ¶ms);
534 if (err == OMX_ErrorNone) {
535 GST_INFO_OBJECT(self, "set_physical_output success.");
537 GST_ERROR_OBJECT(self, "set OMX_IndexParamPhysicalOutput failed with error %d (0x%08x)", err, err);
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
552 process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
555 self = GST_OMX_H264ENC (omx_base);
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.");
562 GST_LOG_OBJECT (self, "output buffer is Byte-stream format.");
566 if ((self->first_frame) ||(self->append_dci && omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
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");
574 GST_LOG_OBJECT (self, "append dci at %s by gst-openmax.", (self->first_frame == TRUE) ? "first frame": "every I frame");
576 if (self->dci == NULL) {
577 GST_ERROR_OBJECT (self, "dci is null. can not append dci.");
578 self->append_dci = FALSE;
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;
586 gst_buffer_copy_metadata(newbuf, *buf, GST_BUFFER_COPY_ALL);
587 gst_buffer_unref(*buf);
594 if (self->first_frame == TRUE)
595 self->first_frame = FALSE;
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);
601 GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
604 return GSTOMX_RETURN_OK;
608 * description : if needed, convert byte-stream codec_data to packetized format, save dci.
609 * params : @self : GstOmxBaseFilter, @omx_buffer: omx_buffer
614 process_output_caps(GstOmxBaseFilter * base, OMX_BUFFERHEADERTYPE *omx_buffer)
616 GstOmxH264Enc *h264enc;
617 gboolean ret = FALSE;
619 h264enc = GST_OMX_H264ENC (base);
621 if (!h264enc->byte_stream) { /* Packtized Format */
622 GstCaps *caps = NULL;
623 GstStructure *structure;
624 GstBuffer *codec_data = NULL;
627 GValue value = { 0, {{0}
630 g_value_init (&value, GST_TYPE_BUFFER);
632 GST_INFO_OBJECT (h264enc, "Packtized Format: set src caps with codec-data");
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);
639 GST_ERROR_OBJECT (h264enc, "ERROR: convert to packetized dci");
641 gst_buffer_unref(codec_data);
647 /* restore packtized format sps, pps */
648 ret = restore_packetized_dci (h264enc, codec_data, &h264enc->dci, sps_cnt, pps_cnt);
650 GST_ERROR_OBJECT (h264enc, "ERROR: restore packetized dci");
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);
659 /* packetized format, set codec_data field in caps */
660 gst_value_set_buffer (&value,codec_data);
661 gst_buffer_unref (codec_data);
663 gst_structure_set_value (structure, "codec_data", &value);
664 g_value_unset (&value);
666 gst_pad_set_caps (base->srcpad, caps);
667 gst_caps_unref (caps);
669 /* byte-stream format */
670 GST_INFO_OBJECT (h264enc, "Byte-stream Format");
671 h264enc->dci = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
673 GST_ERROR_OBJECT (h264enc, "failed to allocate memory...");
676 memcpy (GST_BUFFER_DATA (h264enc->dci),
677 omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
682 instance_deinit (GstElement * element)
684 GstOmxH264Enc *h264enc;
685 h264enc = GST_OMX_H264ENC (element);
687 GST_WARNING_OBJECT (h264enc, "h264 enc deinit");
690 gst_buffer_unref(h264enc->dci);
694 GST_OMX_BASE_FILTER_CLASS (parent_class)->instance_deinit(element);
695 GST_WARNING_OBJECT (h264enc, "h264 enc end");
699 finalize (GObject * obj)
701 GstOmxH264Enc *h264enc;
702 h264enc = GST_OMX_H264ENC (obj);
704 GST_LOG_OBJECT (h264enc, "h264enc finalize enter");
706 G_OBJECT_CLASS (parent_class)->finalize (obj);
710 type_base_init (gpointer g_class)
712 GstElementClass *element_class;
714 element_class = GST_ELEMENT_CLASS (g_class);
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");
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")));
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")));
731 set_property (GObject * obj,
732 guint prop_id, const GValue * value, GParamSpec * pspec)
735 GstOmxBaseFilter *omx_base;
737 self = GST_OMX_H264ENC (obj);
738 omx_base = GST_OMX_BASE_FILTER (obj);
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);
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);
755 OMX_VIDEO_PARAM_AVCSLICEFMO param;
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, ¶m);
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, ¶m);
768 if (ret != OMX_ErrorNone)
769 GST_ERROR_OBJECT (self, "failed to set eSliceMode = %d", self->slice_fmo.eSliceMode);
771 GST_INFO_OBJECT (self, "set eSliceMode = %d", self->slice_fmo.eSliceMode);
778 OMX_VIDEO_PARAM_AVCTYPE param;
781 self->h264type.nSliceHeaderSpacing = g_value_get_uint (value);
783 if (omx_base->gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS) {
784 self->h264type.nSliceHeaderSpacing = self->h264type.nSliceHeaderSpacing / 8;
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, ¶m);
790 param.nSliceHeaderSpacing = self->h264type.nSliceHeaderSpacing;
791 ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, ¶m);
792 if (ret != OMX_ErrorNone)
793 GST_ERROR_OBJECT (self, "failed to set nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
795 GST_INFO_OBJECT (self, "nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
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);
810 case ARG_ENCODER_LEVEL:
812 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
815 omx_base->encoder_level =g_value_get_int (value);
816 G_OMX_INIT_PARAM (param);
818 param.nPortIndex = omx_base->out_port->port_index;
819 OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoProfileLevelCurrent, ¶m);
821 GST_WARNING_OBJECT (self, "Set parameter level from %d to %d", param.eLevel ,omx_base->encoder_level);
823 param.eLevel = omx_base->encoder_level;
824 ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoProfileLevelCurrent, ¶m);
825 if (ret != OMX_ErrorNone)
826 GST_ERROR_OBJECT (self, "failed to set encoder level = %d", param.eLevel);
828 GST_INFO_OBJECT (self, "encoder level changed to = %d", param.eLevel);
831 case ARG_ENCODER_PROFILE:
833 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
836 omx_base->encoder_profile=g_value_get_int (value);
837 G_OMX_INIT_PARAM (param);
839 param.nPortIndex = omx_base->out_port->port_index;
840 OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoProfileLevelCurrent, ¶m);
842 GST_WARNING_OBJECT (self, "Set parameter profile from %d to %d", param.eProfile ,omx_base->encoder_profile);
844 param.eProfile = omx_base->encoder_profile;
845 ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoProfileLevelCurrent, ¶m);
846 if (ret != OMX_ErrorNone)
847 GST_ERROR_OBJECT (self, "failed to set encoder profile = %d", param.eProfile);
849 GST_INFO_OBJECT (self, "encoder profile changed to = %d", param.eProfile);
853 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
859 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
862 GstOmxBaseFilter *omx_base;
864 self = GST_OMX_H264ENC (obj);
865 omx_base = GST_OMX_BASE_FILTER (obj);
869 g_value_set_boolean (value, self->append_dci);
871 case ARG_BYTE_STREAM:
872 g_value_set_boolean (value, self->byte_stream);
875 g_value_set_int (value, self->slice_fmo.eSliceMode);
878 g_value_set_uint (value, self->h264type.nSliceHeaderSpacing);
880 case ARG_PHYSICAL_OUTPUT:
881 g_value_set_boolean (value, omx_base->bPhysicalOutput);
883 case ARG_ENCODER_LEVEL:
884 g_value_set_int (value, omx_base->encoder_level);
886 case ARG_ENCODER_PROFILE:
887 g_value_set_int (value, omx_base->encoder_profile);
890 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
896 type_class_init (gpointer g_class, gpointer class_data)
898 GObjectClass *gobject_class;
899 GstOmxBaseFilterClass *basefilter_class;
901 gobject_class = G_OBJECT_CLASS (g_class);
902 basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
905 gobject_class->set_property = set_property;
906 gobject_class->get_property = get_property;
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",
913 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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)",
919 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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",
925 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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) ~",
931 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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));
938 g_object_class_install_property (gobject_class, ARG_ENCODER_LEVEL,
939 g_param_spec_int ("encoder-level", "set encoder-level",
942 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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",
948 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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;
956 gobject_class->finalize = finalize;
961 settings_changed_cb (GOmxCore * core)
963 GstOmxBaseVideoEnc *omx_base;
964 GstOmxBaseFilter *omx_base_filter;
970 omx_base_filter = core->object;
971 omx_base = GST_OMX_BASE_VIDEOENC (omx_base_filter);
972 self = GST_OMX_H264ENC (omx_base_filter);
974 GST_DEBUG_OBJECT (omx_base, "settings changed");
977 OMX_PARAM_PORTDEFINITIONTYPE param;
979 G_OMX_INIT_PARAM (param);
981 param.nPortIndex = omx_base_filter->out_port->port_index;
982 OMX_GetParameter (core->omx_handle, OMX_IndexParamPortDefinition, ¶m);
984 width = param.format.video.nFrameWidth;
985 height = param.format.video.nFrameHeight;
989 GstCaps *new_caps, *peer_caps;
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);
999 /* get peer pad caps */
1000 peer_caps = gst_pad_peer_get_caps(omx_base_filter->srcpad);
1002 GST_LOG_OBJECT (omx_base, "peer caps : %" GST_PTR_FORMAT, peer_caps);
1004 for (i = 0; i < peer_caps->structs->len; i++) {
1006 s = gst_caps_get_structure (peer_caps, i);
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...");
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;
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");
1025 GST_INFO_OBJECT (self, "Is in PACKETIZED");
1032 gst_caps_unref(peer_caps);
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);
1042 instance_private_value_init(GstElement * element)
1044 GstOmxBaseFilter *omx_base_filter;
1045 GstOmxBaseVideoEnc *omx_base;
1046 GstOmxH264Enc *self;
1048 omx_base_filter = GST_OMX_BASE_FILTER (element);
1049 omx_base = GST_OMX_BASE_VIDEOENC (element);
1050 self = GST_OMX_H264ENC (element);
1052 self->byte_stream = FALSE;
1053 self->append_dci = FALSE;
1054 self->first_frame = TRUE;
1056 self->slice_fmo.eSliceMode = OMX_VIDEO_SLICEMODE_AVCLevelMax;
1057 omx_base_filter->bPhysicalOutput = FALSE;
1059 omx_base->compression_format = OMX_VIDEO_CodingAVC;
1061 omx_base_filter->gomx->settings_changed_cb = settings_changed_cb;
1065 instance_init (GstElement * element)
1067 GST_OMX_BASE_FILTER_CLASS (parent_class)->instance_init(element);
1069 instance_private_value_init(element);
1073 type_instance_init (GTypeInstance * instance, gpointer g_class)
1075 instance_private_value_init(GST_ELEMENT(instance));