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"
34 GSTOMX_BOILERPLATE (GstOmxH264Enc, gst_omx_h264enc, GstOmxBaseVideoEnc,
35 GST_OMX_BASE_VIDEOENC_TYPE);
38 * description : convert byte-stream format to packetized frame
39 * params : @self : GstOmxH264Enc, @buf: byte-stream buf, @sync: notify this buf is sync frame
44 convert_to_packetized_frame (GstOmxH264Enc *self, GstBuffer **buf)
46 unsigned char *data = GST_BUFFER_DATA (*buf);
47 unsigned int size = GST_BUFFER_SIZE(*buf);
50 unsigned char *nalu_start = NULL;
51 GstOmxBaseFilter *omx_base = GST_OMX_BASE_FILTER(self);
53 GST_LOG_OBJECT (self, "convert_to_packtized format. size=%d sliceMode=%d",
54 GST_BUFFER_SIZE(*buf), self->slice_fmo.eSliceMode);
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 !!");
65 GSTOMX_H264_WB32(data + idx, size - idx - GSTOMX_H264_NAL_START_LEN);
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 !!");
80 if (idx <= start_idx) {
81 GST_ERROR_OBJECT (self, "ERROR : idx <= start_idx !!");
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);
88 nalu_start = data + idx;
94 idx += GSTOMX_H264_NAL_START_LEN;
96 /* converting last nal unit */
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);
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
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)
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;
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, */
134 sps_queue = g_queue_new ();
135 pps_queue = g_queue_new ();
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;
145 sps_size = idx - prev_nalu_start;
147 sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
149 GST_ERROR_OBJECT (self, "failed to allocate memory..");
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;
160 pps_size = idx - prev_nalu_start;
162 pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
164 GST_ERROR_OBJECT (self, "failed to allocate memory..");
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);
172 /* present nalu type */
173 nal_type = nalu_dci[idx+3] & 0x1f;
175 if (nal_type == GSTOMX_H264_NUT_SPS) {
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) {
186 prev_nalu_start = idx + 3;
187 prev_nalu_type = GSTOMX_H264_NUT_PPS;
193 /* copy previous nal unit */
194 if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_SPS) {
195 sps_size = idx - prev_nalu_start;
197 sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
199 GST_ERROR_OBJECT (self, "failed to allocate memory..");
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);
208 } else if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_PPS) {
209 pps_size = idx - prev_nalu_start;
211 pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
213 GST_ERROR_OBJECT (self, "failed to allocate memory..");
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);
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));
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");
233 if (*packetized_dci == NULL) {
234 GST_ERROR_OBJECT (self, "Failed to allocate memory..");
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) */
248 while (!g_queue_is_empty (sps_queue)) {
249 sps_data = g_queue_pop_head (sps_queue);
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);
256 *packetized_dci = gst_buffer_join(*packetized_dci, sps_data);
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;
264 GstBuffer *next_data = gst_buffer_new_and_alloc(GSTOMX_H264_CNT_LEN);
266 GST_ERROR_OBJECT (self, "Failed to allocate memory..");
270 GST_BUFFER_DATA(next_data)[0] = pps_cnt;
271 *packetized_dci = gst_buffer_join(*packetized_dci, next_data);
275 while (!g_queue_is_empty (pps_queue)) {
276 pps_data = g_queue_pop_head (pps_queue);
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);
284 *packetized_dci = gst_buffer_join(*packetized_dci, pps_data);
289 while (!g_queue_is_empty (sps_queue)) {
290 queue_data = g_queue_pop_head (sps_queue);
291 gst_buffer_unref (queue_data);
294 g_queue_free (sps_queue);
296 while (!g_queue_is_empty (pps_queue)) {
297 queue_data = g_queue_pop_head (pps_queue);
298 gst_buffer_unref (queue_data);
301 g_queue_free (pps_queue);
303 *out_sps_cnt = sps_cnt;
304 *out_pps_cnt = sps_cnt;
310 * description : resotre packtized dci (codec_data)
311 * params : @self : GstOmxH264Enc, @inbuf: codec data, @outbuf: h264enc->dci
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
319 restore_packetized_dci (GstOmxH264Enc *self, GstBuffer *inbuf, GstBuffer **outbuf, gint sps_cnt, gint pps_cnt)
321 unsigned char *indata = GST_BUFFER_DATA(inbuf);
325 GstBuffer *next_data = NULL;
327 GST_INFO_OBJECT (self, "restore_packetized_dci. sps_cnt=%d, pps_cnt=%d", sps_cnt, pps_cnt);
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);
333 *outbuf = gst_buffer_new_and_alloc (GSTOMX_H264_A_DCI_LEN + sps_size + GSTOMX_H264_A_DCI_LEN + pps_size);
335 GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
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);
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);
349 /* in this case, dci has multi nalu. ex) sps + sps + sps + pps + pps */
350 indata += GSTOMX_H264_MDATA;
351 *outbuf = gst_buffer_new ();
353 for (i = 0; i < sps_cnt; i++) {
354 sps_size = GSTOMX_H264_RB16(indata); /* metadata(6) */
356 next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + sps_size);
358 GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
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);
365 *outbuf = gst_buffer_join(*outbuf, next_data);
368 indata += GSTOMX_H264_CNT_LEN; /* pps cnt field (1 byte) */
370 for (i = 0; i < pps_cnt; i++) {
371 pps_size = GSTOMX_H264_RB16(indata);
373 next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + pps_size);
375 GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
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);
382 *outbuf = gst_buffer_join(*outbuf, next_data);
391 gst_buffer_unref(*outbuf);
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
404 process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
407 self = GST_OMX_H264ENC (omx_base);
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.");
413 GST_LOG_OBJECT (self, "output buffer is Byte-stream format.");
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");
420 if (self->dci == NULL) {
421 GST_ERROR_OBJECT (self, "dci is null. can not append dci.");
422 self->append_dci = FALSE;
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;
429 gst_buffer_copy_metadata(newbuf, *buf, GST_BUFFER_COPY_ALL);
430 gst_buffer_unref(*buf);
435 if (self->first_frame == TRUE)
436 self->first_frame = FALSE;
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);
442 GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
445 return GSTOMX_RETURN_OK;
449 * description : if needed, convert byte-stream codec_data to packetized format, save dci.
450 * params : @self : GstOmxBaseFilter, @omx_buffer: omx_buffer
455 process_output_caps(GstOmxBaseFilter * base, OMX_BUFFERHEADERTYPE *omx_buffer)
457 GstOmxH264Enc *h264enc;
458 gboolean ret = FALSE;
460 h264enc = GST_OMX_H264ENC (base);
462 if (!h264enc->byte_stream) { /* Packtized Format */
463 GstCaps *caps = NULL;
464 GstStructure *structure;
465 GstBuffer *codec_data = NULL;
468 GValue value = { 0, {{0}
471 g_value_init (&value, GST_TYPE_BUFFER);
473 GST_INFO_OBJECT (h264enc, "Packtized Format: set src caps with codec-data");
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);
480 GST_ERROR_OBJECT (h264enc, "ERROR: convert to packetized dci");
482 gst_buffer_unref(codec_data);
488 /* restore packtized format sps, pps */
489 ret = restore_packetized_dci (h264enc, codec_data, &h264enc->dci, sps_cnt, pps_cnt);
491 GST_ERROR_OBJECT (h264enc, "ERROR: restore packetized dci");
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);
500 /* packetized format, set codec_data field in caps */
501 gst_value_set_buffer (&value,codec_data);
502 gst_buffer_unref (codec_data);
504 gst_structure_set_value (structure, "codec_data", &value);
505 g_value_unset (&value);
507 gst_pad_set_caps (base->srcpad, caps);
508 gst_caps_unref (caps);
510 /* byte-stream format */
511 GST_INFO_OBJECT (h264enc, "Byte-stream Format");
512 h264enc->dci = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
514 GST_ERROR_OBJECT (h264enc, "failed to allocate memory...");
517 memcpy (GST_BUFFER_DATA (h264enc->dci),
518 omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
523 finalize (GObject * obj)
525 GstOmxH264Enc *h264enc;
526 h264enc = GST_OMX_H264ENC (obj);
528 GST_LOG_OBJECT (h264enc, "h264enc finalize enter");
531 gst_buffer_unref(h264enc->dci);
534 G_OBJECT_CLASS (parent_class)->finalize (obj);
538 type_base_init (gpointer g_class)
540 GstElementClass *element_class;
542 element_class = GST_ELEMENT_CLASS (g_class);
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");
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")));
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")));
559 set_property (GObject * obj,
560 guint prop_id, const GValue * value, GParamSpec * pspec)
563 GstOmxBaseFilter *omx_base;
565 self = GST_OMX_H264ENC (obj);
566 omx_base = GST_OMX_BASE_FILTER (obj);
570 self->append_dci = g_value_get_boolean (value);
571 GST_INFO_OBJECT (self, "set Appending dci = %d", self->append_dci);
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);
581 OMX_VIDEO_PARAM_AVCSLICEFMO param;
584 self->slice_fmo.eSliceMode = g_value_get_uint (value);
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, ¶m);
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, ¶m);
594 if (ret != OMX_ErrorNone)
595 GST_ERROR_OBJECT (self, "failed to set eSliceMode = %d", self->slice_fmo.eSliceMode);
597 GST_INFO_OBJECT (self, "set eSliceMode = %d", self->slice_fmo.eSliceMode);
603 OMX_VIDEO_PARAM_AVCTYPE param;
606 self->h264type.nSliceHeaderSpacing = g_value_get_uint (value);
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, ¶m);
612 param.nSliceHeaderSpacing = self->h264type.nSliceHeaderSpacing;
613 ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, ¶m);
614 if (ret != OMX_ErrorNone)
615 GST_ERROR_OBJECT (self, "failed to set nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
617 GST_INFO_OBJECT (self, "nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
622 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
628 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
632 self = GST_OMX_H264ENC (obj);
636 g_value_set_boolean (value, self->append_dci);
638 case ARG_BYTE_STREAM:
639 g_value_set_boolean (value, self->byte_stream);
642 g_value_set_int (value, self->slice_fmo.eSliceMode);
645 g_value_set_uint (value, self->h264type.nSliceHeaderSpacing);
649 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
655 type_class_init (gpointer g_class, gpointer class_data)
657 GObjectClass *gobject_class;
658 GstOmxBaseFilterClass *basefilter_class;
660 gobject_class = G_OBJECT_CLASS (g_class);
661 basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
664 gobject_class->set_property = set_property;
665 gobject_class->get_property = get_property;
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",
671 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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)",
677 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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",
683 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
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) ~",
689 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
692 basefilter_class->process_output_buf = process_output_buf;
693 basefilter_class->process_output_caps = process_output_caps;
695 gobject_class->finalize = finalize;
700 settings_changed_cb (GOmxCore * core)
702 GstOmxBaseVideoEnc *omx_base;
703 GstOmxBaseFilter *omx_base_filter;
709 omx_base_filter = core->object;
710 omx_base = GST_OMX_BASE_VIDEOENC (omx_base_filter);
711 self = GST_OMX_H264ENC (omx_base_filter);
713 GST_DEBUG_OBJECT (omx_base, "settings changed");
716 OMX_PARAM_PORTDEFINITIONTYPE param;
718 G_OMX_INIT_PARAM (param);
720 param.nPortIndex = omx_base_filter->out_port->port_index;
721 OMX_GetParameter (core->omx_handle, OMX_IndexParamPortDefinition, ¶m);
723 width = param.format.video.nFrameWidth;
724 height = param.format.video.nFrameHeight;
728 GstCaps *new_caps, *peer_caps;
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);
738 /* get peer pad caps */
739 peer_caps = gst_pad_peer_get_caps(omx_base_filter->srcpad);
741 GST_LOG_OBJECT (omx_base, "peer caps : %s\n", gst_caps_to_string(peer_caps));
743 for (i = 0; i < peer_caps->structs->len; i++) {
745 s = gst_caps_get_structure (peer_caps, i);
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...");
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;
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");
764 GST_INFO_OBJECT (self, "Is in PACKETIZED");
772 GST_INFO_OBJECT (omx_base, "caps are: %" GST_PTR_FORMAT, new_caps);
773 gst_pad_set_caps (omx_base_filter->srcpad, new_caps);
778 type_instance_init (GTypeInstance * instance, gpointer g_class)
780 GstOmxBaseFilter *omx_base_filter;
781 GstOmxBaseVideoEnc *omx_base;
784 omx_base_filter = GST_OMX_BASE_FILTER (instance);
785 omx_base = GST_OMX_BASE_VIDEOENC (instance);
786 self = GST_OMX_H264ENC (instance);
788 self->byte_stream = FALSE;
789 self->append_dci = FALSE;
790 self->first_frame = TRUE;
792 self->slice_fmo.eSliceMode = OMX_VIDEO_SLICEMODE_AVCLevelMax;
794 omx_base->compression_format = OMX_VIDEO_CodingAVC;
796 omx_base_filter->gomx->settings_changed_cb = settings_changed_cb;