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_base_videoenc.h"
25 #include <string.h> /* for strcmp */
34 ARG_USE_STATETUNING, /* STATE_TUNING */
45 #define DEFAULT_BITRATE 0
46 #define DEFAULT_IDR_PERIOD 20
47 #define DEFAULT_SKIP_BY_FORCE_IFRAME 0
49 GSTOMX_BOILERPLATE (GstOmxBaseVideoEnc, gst_omx_base_videoenc, GstOmxBaseFilter,
50 GST_OMX_BASE_FILTER_TYPE);
52 static void instance_init (GstElement * element);
55 /* modification: user force I frame */
57 add_force_key_frame(GstOmxBaseVideoEnc *enc)
59 GstOmxBaseFilter *omx_base;
61 OMX_CONFIG_INTRAREFRESHVOPTYPE config;
62 OMX_ERRORTYPE ret = OMX_ErrorNone;
64 omx_base = GST_OMX_BASE_FILTER (enc);
65 gomx = (GOmxCore *) omx_base->gomx;
67 GST_LOG_OBJECT (enc, "request forced key frame now.");
69 if (!omx_base->out_port || !gomx->omx_handle) {
70 GST_ERROR_OBJECT (enc, "failed to set force-i-frame...");
74 G_OMX_INIT_PARAM (config);
75 config.nPortIndex = omx_base->out_port->port_index;
76 config.IntraRefreshVOP = OMX_TRUE;
78 ret = OMX_SetConfig (gomx->omx_handle, OMX_IndexConfigVideoIntraVOPRefresh, &config);
79 if (ret == OMX_ErrorNone)
80 GST_WARNING_OBJECT (enc, "forced key frame is done. (OMX_IndexConfigVideoIntraVOPRefresh) ret = %d", ret);
82 GST_ERROR_OBJECT (enc, "Failed to set forced key frame (OMX_IndexConfigVideoIntraVOPRefresh) ret = %d", ret);
87 process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
89 GstOmxBaseVideoEnc *self;
91 self = GST_OMX_BASE_VIDEOENC (omx_base_filter);
93 GST_LOG_OBJECT (self, "base videoenc process_input_buf enter");
95 if (self->use_force_key_frame) { /* skip frame by cnt and make force key frame */
96 if (self->skip_inbuf_cnt > 0) {
97 GST_WARNING_OBJECT (self, "skip inbuf before enc force key frame (%d)", self->skip_inbuf_cnt);
98 self->skip_inbuf_cnt--;
99 return GSTOMX_RETURN_SKIP;
101 } else if (self->skip_inbuf_cnt == 0) {
102 add_force_key_frame (self);
105 self->use_force_key_frame = FALSE;
108 return GSTOMX_RETURN_OK;
111 /* modification: postprocess for outputbuf. in this videoenc case, set sync frame */
113 process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
115 GstOmxBaseVideoEnc *self;
117 self = GST_OMX_BASE_VIDEOENC (omx_base);
119 GST_LOG_OBJECT (self, "base videoenc process_output_buf enter");
121 /* modification: set sync frame info while encoding */
122 if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
123 GST_BUFFER_FLAG_UNSET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
125 GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
128 return GSTOMX_RETURN_OK;
131 /* modification: get codec_data from omx component and set it caps */
133 process_output_caps(GstOmxBaseFilter * self, OMX_BUFFERHEADERTYPE *omx_buffer)
136 GstCaps *caps = NULL;
137 GstStructure *structure;
138 GValue value = { 0, {{0}
142 caps = gst_pad_get_negotiated_caps (self->srcpad);
143 caps = gst_caps_make_writable (caps);
144 structure = gst_caps_get_structure (caps, 0);
146 g_value_init (&value, GST_TYPE_BUFFER);
147 buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
148 memcpy (GST_BUFFER_DATA (buf),
149 omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
150 gst_value_set_buffer (&value, buf);
151 gst_buffer_unref (buf);
152 gst_structure_set_value (structure, "codec_data", &value);
153 g_value_unset (&value);
155 gst_pad_set_caps (self->srcpad, caps);
156 gst_caps_unref (caps);
160 type_base_init (gpointer g_class)
165 set_property (GObject * obj,
166 guint prop_id, const GValue * value, GParamSpec * pspec)
168 GstOmxBaseVideoEnc *self;
169 GstOmxBaseFilter *omx_base;
171 self = GST_OMX_BASE_VIDEOENC (obj);
172 omx_base = GST_OMX_BASE_FILTER (obj);
177 self->bitrate = g_value_get_uint (value);
178 /*Set the bitrate by using set config For Dynamic bitrate */
179 if(omx_base->gomx->omx_state == OMX_StateExecuting) {
180 OMX_VIDEO_CONFIG_BITRATETYPE config;
181 OMX_ERRORTYPE ret = OMX_ErrorNone;
182 G_OMX_INIT_PARAM (config);
184 config.nPortIndex = omx_base->out_port->port_index;
185 OMX_GetConfig (omx_base->gomx->omx_handle, OMX_IndexConfigVideoBitrate, &config);
187 GST_WARNING_OBJECT (self, "bitrate was changed from %d to %d", config.nEncodeBitrate, self->bitrate);
188 config.nEncodeBitrate = self->bitrate;
189 ret = OMX_SetConfig (omx_base->gomx->omx_handle, OMX_IndexConfigVideoBitrate, &config);
190 if (ret == OMX_ErrorNone)
191 GST_WARNING_OBJECT (self, "set OMX_IndexConfigVideoBitrate for nEncodeBitrate = %d", self->bitrate);
193 GST_ERROR_OBJECT (self, "Failed to set OMX_IndexConfigVideoBitrate. nEncodeBitrate = %d ret = %d", self->bitrate, ret);
199 /* modification: request to component to make key frame */
200 case ARG_FORCE_KEY_FRAME:
201 self->use_force_key_frame = g_value_get_boolean (value);
202 GST_WARNING_OBJECT (self, "set use_force_key_frame");
205 case ARG_SKIP_INBUF_COUNT:
206 self->skip_inbuf_cnt = g_value_get_int (value);
207 GST_INFO_OBJECT (self, "set use_force_key_frame after %d frame skip", self->skip_inbuf_cnt);
211 self->idr_period = g_value_get_int (value);
213 OMX_VIDEO_PARAM_AVCTYPE param;
214 OMX_ERRORTYPE ret = OMX_ErrorNone;
216 G_OMX_INIT_PARAM (param);
217 param.nPortIndex = omx_base->out_port->port_index;
218 OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, ¶m);
220 param.nPFrames = self->idr_period;
221 ret = OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, ¶m);
222 if (ret == OMX_ErrorNone)
223 GST_WARNING_OBJECT (self, "set OMX_IndexParamVideoAvc for IDR period = %d", self->idr_period);
225 GST_ERROR_OBJECT (self, "Failed to set OMX_IndexParamVideoAvc. IDR period = %d ret = %d", self->idr_period, ret);
229 case ARG_USE_STATETUNING:
230 self->omx_base.use_state_tuning = g_value_get_boolean(value);
233 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
239 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
241 GstOmxBaseVideoEnc *self;
243 self = GST_OMX_BASE_VIDEOENC (obj);
247 /** @todo propagate this to OpenMAX when processing. */
248 g_value_set_uint (value, self->bitrate);
251 g_value_set_int (value, self->idr_period);
253 case ARG_SKIP_INBUF_COUNT:
254 g_value_set_int (value, self->skip_inbuf_cnt);
256 case ARG_USE_STATETUNING:
257 g_value_set_boolean(value, self->omx_base.use_state_tuning);
260 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
266 type_class_init (gpointer g_class, gpointer class_data)
268 GObjectClass *gobject_class;
269 GstOmxBaseFilterClass *basefilter_class;
271 GST_WARNING("video enc type_class_init");
272 gobject_class = G_OBJECT_CLASS (g_class);
273 basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
275 /* Properties stuff */
277 gobject_class->set_property = set_property;
278 gobject_class->get_property = get_property;
280 g_object_class_install_property (gobject_class, ARG_BITRATE,
281 g_param_spec_uint ("bitrate", "Bit-rate",
283 0, G_MAXUINT, DEFAULT_BITRATE,
284 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286 g_object_class_install_property (gobject_class, ARG_FORCE_KEY_FRAME,
287 g_param_spec_boolean ("force-i-frame", "force the encoder to produce I frame",
288 "force the encoder to produce I frame",
290 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
292 g_object_class_install_property (gobject_class, ARG_IDR_PERIOD,
293 g_param_spec_int ("idr-period", "set interval of I-frame",
294 "set interval of I-frame",
295 0, G_MAXINT, DEFAULT_IDR_PERIOD,
296 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
298 g_object_class_install_property (gobject_class, ARG_SKIP_INBUF_COUNT,
299 g_param_spec_int ("skip-inbuf", "skip inbuf in case of force I frame",
300 "skip inbuf in case of force I frame",
301 0, G_MAXINT, DEFAULT_SKIP_BY_FORCE_IFRAME,
302 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
305 g_object_class_install_property (gobject_class, ARG_USE_STATETUNING,
306 g_param_spec_boolean ("state-tuning", "start omx component in gst paused state",
307 "Whether or not to use state-tuning feature",
308 FALSE, G_PARAM_READWRITE));
310 basefilter_class->process_input_buf = process_input_buf;
311 basefilter_class->process_output_buf = process_output_buf;
312 basefilter_class->process_output_caps = process_output_caps;
313 basefilter_class->instance_init = instance_init;
317 sink_setcaps (GstPad * pad, GstCaps * caps)
319 GstStructure *structure;
320 GstOmxBaseVideoEnc *self;
321 GstOmxBaseFilter *omx_base;
323 OMX_COLOR_FORMATTYPE color_format = OMX_COLOR_FormatUnused;
326 const GValue *framerate = NULL;
328 self = GST_OMX_BASE_VIDEOENC (GST_PAD_PARENT (pad));
329 omx_base = GST_OMX_BASE_FILTER (self);
330 gomx = (GOmxCore *) omx_base->gomx;
332 GST_WARNING_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
334 g_return_val_if_fail (gst_caps_get_size (caps) == 1, FALSE);
336 structure = gst_caps_get_structure (caps, 0);
338 gst_structure_get_int (structure, "width", &width);
339 gst_structure_get_int (structure, "height", &height);
341 if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0) {
344 framerate = gst_structure_get_value (structure, "framerate");
346 self->framerate_num = gst_value_get_fraction_numerator (framerate);
347 self->framerate_denom = gst_value_get_fraction_denominator (framerate);
350 if (gst_structure_get_fourcc (structure, "format", &fourcc)) {
352 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
353 case GST_MAKE_FOURCC ('S', '4', '2', '0'):
354 color_format = OMX_COLOR_FormatYUV420PackedPlanar;
356 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
357 color_format = OMX_COLOR_FormatYCbYCr;
359 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
360 color_format = OMX_COLOR_FormatCbYCrY;
362 /* MODIFICATION: Add extended_color_format */
363 case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
364 color_format = OMX_EXT_COLOR_FormatNV12T_Phyaddr_Fd;
366 case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
367 color_format = OMX_EXT_COLOR_FormatNV12L_Phyaddr_Fd;
376 GST_ERROR_OBJECT(self, "GOmxCore is NULL! this can make seg fault");
379 if (gomx->omx_handle == NULL)
381 GST_ERROR_OBJECT(self, "omx_handle is NULL! this can make seg fault");
384 /* Input port configuration. */
386 OMX_PARAM_PORTDEFINITIONTYPE param;
387 G_OMX_INIT_PARAM (param);
389 param.nPortIndex = omx_base->in_port->port_index;
390 OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
392 param.format.video.nFrameWidth = width;
393 param.format.video.nFrameHeight = height;
394 param.format.video.eColorFormat = color_format;
396 /* convert to Q.16 */
397 param.format.video.xFramerate =
398 (OMX_U32)(gst_value_get_fraction_numerator (framerate) << 16) /
399 (OMX_U32)gst_value_get_fraction_denominator (framerate);
402 OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
405 /* Output port configuration. */
407 OMX_PARAM_PORTDEFINITIONTYPE param;
408 G_OMX_INIT_PARAM (param);
410 param.nPortIndex = omx_base->out_port->port_index;
411 OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
413 param.nBufferSize = width * height * 3 / 2;
415 OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
418 return gst_pad_set_caps (pad, caps);
422 omx_setup (GstOmxBaseFilter * omx_base)
424 GstOmxBaseVideoEnc *self;
427 self = GST_OMX_BASE_VIDEOENC (omx_base);
428 gomx = (GOmxCore *) omx_base->gomx;
430 GST_INFO_OBJECT (omx_base, "begin");
433 OMX_PARAM_PORTDEFINITIONTYPE param;
435 G_OMX_INIT_PARAM (param);
437 /* Output port configuration. */
439 param.nPortIndex = omx_base->out_port->port_index;
440 OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
442 param.format.video.eCompressionFormat = self->compression_format;
444 if (self->bitrate > 0)
445 param.format.video.nBitrate = self->bitrate;
447 OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
451 /* modification: set bitrate by using OMX_IndexParamVideoBitrate macro*/
452 if (self->bitrate > 0) {
453 if (gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS) {
455 /* set Bitrate and control rate*/
457 OMX_VIDEO_PARAM_BITRATETYPE param_bitrate;
458 G_OMX_INIT_PARAM (param_bitrate);
459 param_bitrate.nPortIndex = omx_base->out_port->port_index;
460 OMX_GetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, ¶m_bitrate);
462 param_bitrate.nTargetBitrate = self->bitrate;
464 param_bitrate.eControlRate = OMX_Video_ControlRateVariable; /* VBR */
465 GST_WARNING_OBJECT (self, "set bitrate (OMX_Video_ControlRateVariable): %d", param_bitrate.nTargetBitrate);
466 OMX_SetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, ¶m_bitrate);
469 /* set Quantization parameter*/
471 OMX_VIDEO_PARAM_QUANTIZATIONTYPE param_qp;
472 G_OMX_INIT_PARAM (param_qp);
473 param_qp.nPortIndex = omx_base->out_port->port_index;
474 OMX_GetParameter (gomx->omx_handle, OMX_IndexParamVideoQuantization, ¶m_qp);
480 GST_WARNING_OBJECT (self, "set quantization parameter (nQpI: %d nQpP: %d nQpB: %d)", param_qp.nQpI, param_qp.nQpP, param_qp.nQpB);
481 OMX_SetParameter (gomx->omx_handle, OMX_IndexParamVideoQuantization, ¶m_qp);
485 OMX_VIDEO_PARAM_BITRATETYPE param;
486 G_OMX_INIT_PARAM (param);
487 param.nPortIndex = omx_base->out_port->port_index;
488 OMX_GetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, ¶m);
490 param.nTargetBitrate = self->bitrate;
492 param.eControlRate = OMX_Video_ControlRateVariable; /* VBR */
493 GST_WARNING_OBJECT (self, "set bitrate (OMX_Video_ControlRateVariable): %d", param.nTargetBitrate);
494 OMX_SetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, ¶m);
498 GST_INFO_OBJECT (omx_base, "end");
502 instance_private_value_init(GstElement * element)
504 GstOmxBaseFilter *omx_base;
505 GstOmxBaseVideoEnc *self;
507 omx_base = GST_OMX_BASE_FILTER (element);
508 self = GST_OMX_BASE_VIDEOENC (element);
510 self->bitrate = DEFAULT_BITRATE;
511 self->use_force_key_frame = FALSE;
512 self->skip_inbuf_cnt = DEFAULT_SKIP_BY_FORCE_IFRAME;
514 omx_base->gomx->codec_type = GSTOMX_CODECTYPE_VIDEO_ENC;
518 instance_init (GstElement * element)
520 GST_OMX_BASE_FILTER_CLASS(parent_class)->instance_init(element);
522 instance_private_value_init(element);
526 type_instance_init (GTypeInstance * instance, gpointer g_class)
528 GstOmxBaseFilter *omx_base;
530 GST_WARNING("begin");
531 omx_base = GST_OMX_BASE_FILTER (instance);
533 instance_private_value_init(GST_ELEMENT(instance));
535 omx_base->omx_setup = omx_setup;
537 gst_pad_set_setcaps_function (omx_base->sinkpad, sink_setcaps);