2 * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation
8 * version 2.1 of the License.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <gst/video/gstvideometa.h>
29 #include "gstomxvideo.h"
30 #include "gstomxvideoenc.h"
32 #ifdef USE_OMX_TARGET_RPI
33 #include <OMX_Broadcom.h>
34 #include <OMX_Index.h>
37 GST_DEBUG_CATEGORY_STATIC (gst_omx_video_enc_debug_category);
38 #define GST_CAT_DEFAULT gst_omx_video_enc_debug_category
40 #define GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE (gst_omx_video_enc_control_rate_get_type ())
42 gst_omx_video_enc_control_rate_get_type (void)
44 static GType qtype = 0;
47 static const GEnumValue values[] = {
48 {OMX_Video_ControlRateDisable, "Disable", "disable"},
49 {OMX_Video_ControlRateVariable, "Variable", "variable"},
50 {OMX_Video_ControlRateConstant, "Constant", "constant"},
51 {OMX_Video_ControlRateVariableSkipFrames, "Variable Skip Frames",
52 "variable-skip-frames"},
53 {OMX_Video_ControlRateConstantSkipFrames, "Constant Skip Frames",
54 "constant-skip-frames"},
55 {0xffffffff, "Component Default", "default"},
59 qtype = g_enum_register_static ("GstOMXVideoEncControlRate", values);
65 static void gst_omx_video_enc_finalize (GObject * object);
66 static void gst_omx_video_enc_set_property (GObject * object, guint prop_id,
67 const GValue * value, GParamSpec * pspec);
68 static void gst_omx_video_enc_get_property (GObject * object, guint prop_id,
69 GValue * value, GParamSpec * pspec);
72 static GstStateChangeReturn
73 gst_omx_video_enc_change_state (GstElement * element,
74 GstStateChange transition);
76 static gboolean gst_omx_video_enc_open (GstVideoEncoder * encoder);
77 static gboolean gst_omx_video_enc_close (GstVideoEncoder * encoder);
78 static gboolean gst_omx_video_enc_start (GstVideoEncoder * encoder);
79 static gboolean gst_omx_video_enc_stop (GstVideoEncoder * encoder);
80 static gboolean gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
81 GstVideoCodecState * state);
82 static gboolean gst_omx_video_enc_flush (GstVideoEncoder * encoder);
83 static GstFlowReturn gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
84 GstVideoCodecFrame * frame);
85 static gboolean gst_omx_video_enc_finish (GstVideoEncoder * encoder);
86 static gboolean gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
88 static GstCaps *gst_omx_video_enc_getcaps (GstVideoEncoder * encoder,
91 static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self);
93 static GstFlowReturn gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc *
94 self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame);
106 /* FIXME: Better defaults */
107 #define GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT (0xffffffff)
108 #define GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT (0xffffffff)
109 #define GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT (0xffffffff)
110 #define GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT (0xffffffff)
111 #define GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT (0xffffffff)
113 /* class initialization */
116 GST_DEBUG_CATEGORY_INIT (gst_omx_video_enc_debug_category, "omxvideoenc", 0, \
117 "debug category for gst-omx video encoder base class");
119 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoEnc, gst_omx_video_enc,
120 GST_TYPE_VIDEO_ENCODER, DEBUG_INIT);
123 gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass)
125 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
126 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
127 GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
130 gobject_class->finalize = gst_omx_video_enc_finalize;
131 gobject_class->set_property = gst_omx_video_enc_set_property;
132 gobject_class->get_property = gst_omx_video_enc_get_property;
134 g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
135 g_param_spec_enum ("control-rate", "Control Rate",
136 "Bitrate control method",
137 GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE,
138 GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT,
139 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
140 GST_PARAM_MUTABLE_READY));
142 g_object_class_install_property (gobject_class, PROP_TARGET_BITRATE,
143 g_param_spec_uint ("target-bitrate", "Target Bitrate",
144 "Target bitrate (0xffffffff=component default)",
145 0, G_MAXUINT, GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT,
146 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
147 GST_PARAM_MUTABLE_PLAYING));
149 g_object_class_install_property (gobject_class, PROP_QUANT_I_FRAMES,
150 g_param_spec_uint ("quant-i-frames", "I-Frame Quantization",
151 "Quantization parameter for I-frames (0xffffffff=component default)",
152 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT,
153 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
154 GST_PARAM_MUTABLE_READY));
156 g_object_class_install_property (gobject_class, PROP_QUANT_P_FRAMES,
157 g_param_spec_uint ("quant-p-frames", "P-Frame Quantization",
158 "Quantization parameter for P-frames (0xffffffff=component default)",
159 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT,
160 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
161 GST_PARAM_MUTABLE_READY));
163 g_object_class_install_property (gobject_class, PROP_QUANT_B_FRAMES,
164 g_param_spec_uint ("quant-b-frames", "B-Frame Quantization",
165 "Quantization parameter for B-frames (0xffffffff=component default)",
166 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT,
167 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
168 GST_PARAM_MUTABLE_READY));
170 element_class->change_state =
171 GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state);
173 video_encoder_class->open = GST_DEBUG_FUNCPTR (gst_omx_video_enc_open);
174 video_encoder_class->close = GST_DEBUG_FUNCPTR (gst_omx_video_enc_close);
175 video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_enc_start);
176 video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_enc_stop);
177 video_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_video_enc_flush);
178 video_encoder_class->set_format =
179 GST_DEBUG_FUNCPTR (gst_omx_video_enc_set_format);
180 video_encoder_class->handle_frame =
181 GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_frame);
182 video_encoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_enc_finish);
183 video_encoder_class->propose_allocation =
184 GST_DEBUG_FUNCPTR (gst_omx_video_enc_propose_allocation);
185 video_encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_omx_video_enc_getcaps);
187 klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER;
188 klass->cdata.default_sink_template_caps = "video/x-raw, "
189 "width = " GST_VIDEO_SIZE_RANGE ", "
190 "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE;
192 klass->handle_output_frame =
193 GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_output_frame);
197 gst_omx_video_enc_init (GstOMXVideoEnc * self)
199 self->control_rate = GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT;
200 self->target_bitrate = GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT;
201 self->quant_i_frames = GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT;
202 self->quant_p_frames = GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT;
203 self->quant_b_frames = GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT;
205 g_mutex_init (&self->drain_lock);
206 g_cond_init (&self->drain_cond);
207 #ifdef GST_TIZEN_MODIFICATION
208 self->hTBMBufMgr = NULL;
214 gst_omx_video_enc_open (GstVideoEncoder * encoder)
216 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
217 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
218 gint in_port_index, out_port_index;
221 gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
222 klass->cdata.component_name, klass->cdata.component_role,
224 self->started = FALSE;
229 if (gst_omx_component_get_state (self->enc,
230 GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
233 in_port_index = klass->cdata.in_port_index;
234 out_port_index = klass->cdata.out_port_index;
236 if (in_port_index == -1 || out_port_index == -1) {
237 OMX_PORT_PARAM_TYPE param;
240 GST_OMX_INIT_STRUCT (¶m);
243 gst_omx_component_get_parameter (self->enc, OMX_IndexParamVideoInit,
245 if (err != OMX_ErrorNone) {
246 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
247 gst_omx_error_to_string (err), err);
252 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
253 (guint) param.nPorts, (guint) param.nStartPortNumber);
254 in_port_index = param.nStartPortNumber + 0;
255 out_port_index = param.nStartPortNumber + 1;
259 self->enc_in_port = gst_omx_component_add_port (self->enc, in_port_index);
260 self->enc_out_port = gst_omx_component_add_port (self->enc, out_port_index);
262 if (!self->enc_in_port || !self->enc_out_port)
269 if (self->control_rate != 0xffffffff || self->target_bitrate != 0xffffffff) {
270 OMX_VIDEO_PARAM_BITRATETYPE bitrate_param;
272 GST_OMX_INIT_STRUCT (&bitrate_param);
273 bitrate_param.nPortIndex = self->enc_out_port->index;
275 err = gst_omx_component_get_parameter (self->enc,
276 OMX_IndexParamVideoBitrate, &bitrate_param);
278 if (err == OMX_ErrorNone) {
279 #ifdef USE_OMX_TARGET_RPI
280 /* FIXME: Workaround for RPi returning garbage for this parameter */
281 if (bitrate_param.nVersion.nVersion == 0) {
282 GST_OMX_INIT_STRUCT (&bitrate_param);
283 bitrate_param.nPortIndex = self->enc_out_port->index;
286 if (self->control_rate != 0xffffffff)
287 bitrate_param.eControlRate = self->control_rate;
288 if (self->target_bitrate != 0xffffffff)
289 bitrate_param.nTargetBitrate = self->target_bitrate;
292 gst_omx_component_set_parameter (self->enc,
293 OMX_IndexParamVideoBitrate, &bitrate_param);
294 if (err == OMX_ErrorUnsupportedIndex) {
295 GST_WARNING_OBJECT (self,
296 "Setting a bitrate not supported by the component");
297 } else if (err == OMX_ErrorUnsupportedSetting) {
298 GST_WARNING_OBJECT (self,
299 "Setting bitrate settings %u %u not supported by the component",
300 self->control_rate, self->target_bitrate);
301 } else if (err != OMX_ErrorNone) {
302 GST_ERROR_OBJECT (self,
303 "Failed to set bitrate parameters: %s (0x%08x)",
304 gst_omx_error_to_string (err), err);
308 GST_ERROR_OBJECT (self, "Failed to get bitrate parameters: %s (0x%08x)",
309 gst_omx_error_to_string (err), err);
313 if (self->quant_i_frames != 0xffffffff ||
314 self->quant_p_frames != 0xffffffff ||
315 self->quant_b_frames != 0xffffffff) {
316 OMX_VIDEO_PARAM_QUANTIZATIONTYPE quant_param;
318 GST_OMX_INIT_STRUCT (&quant_param);
319 quant_param.nPortIndex = self->enc_out_port->index;
321 err = gst_omx_component_get_parameter (self->enc,
322 OMX_IndexParamVideoQuantization, &quant_param);
324 if (err == OMX_ErrorNone) {
326 if (self->quant_i_frames != 0xffffffff)
327 quant_param.nQpI = self->quant_i_frames;
328 if (self->quant_p_frames != 0xffffffff)
329 quant_param.nQpP = self->quant_p_frames;
330 if (self->quant_b_frames != 0xffffffff)
331 quant_param.nQpB = self->quant_b_frames;
334 gst_omx_component_set_parameter (self->enc,
335 OMX_IndexParamVideoQuantization, &quant_param);
336 if (err == OMX_ErrorUnsupportedIndex) {
337 GST_WARNING_OBJECT (self,
338 "Setting quantization parameters not supported by the component");
339 } else if (err == OMX_ErrorUnsupportedSetting) {
340 GST_WARNING_OBJECT (self,
341 "Setting quantization parameters %u %u %u not supported by the component",
342 self->quant_i_frames, self->quant_p_frames, self->quant_b_frames);
343 } else if (err != OMX_ErrorNone) {
344 GST_ERROR_OBJECT (self,
345 "Failed to set quantization parameters: %s (0x%08x)",
346 gst_omx_error_to_string (err), err);
350 GST_ERROR_OBJECT (self,
351 "Failed to get quantization parameters: %s (0x%08x)",
352 gst_omx_error_to_string (err), err);
357 #ifdef GST_TIZEN_MODIFICATION
358 self->hTBMBufMgr = tbm_bufmgr_init(self->drm_fd);
359 if(self->hTBMBufMgr == NULL){
360 GST_ERROR_OBJECT (self, "TBM initialization failed.");
368 gst_omx_video_enc_shutdown (GstOMXVideoEnc * self)
372 GST_DEBUG_OBJECT (self, "Shutting down encoder");
374 state = gst_omx_component_get_state (self->enc, 0);
375 if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
376 if (state > OMX_StateIdle) {
377 gst_omx_component_set_state (self->enc, OMX_StateIdle);
378 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
380 gst_omx_component_set_state (self->enc, OMX_StateLoaded);
381 gst_omx_port_deallocate_buffers (self->enc_in_port);
382 gst_omx_port_deallocate_buffers (self->enc_out_port);
383 if (state > OMX_StateLoaded)
384 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
391 gst_omx_video_enc_close (GstVideoEncoder * encoder)
393 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
395 GST_DEBUG_OBJECT (self, "Closing encoder");
397 if (!gst_omx_video_enc_shutdown (self))
400 self->enc_in_port = NULL;
401 self->enc_out_port = NULL;
403 gst_omx_component_free (self->enc);
410 gst_omx_video_enc_finalize (GObject * object)
412 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
414 g_mutex_clear (&self->drain_lock);
415 g_cond_clear (&self->drain_cond);
417 G_OBJECT_CLASS (gst_omx_video_enc_parent_class)->finalize (object);
421 gst_omx_video_enc_set_property (GObject * object, guint prop_id,
422 const GValue * value, GParamSpec * pspec)
424 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
427 case PROP_CONTROL_RATE:
428 self->control_rate = g_value_get_enum (value);
430 case PROP_TARGET_BITRATE:
431 self->target_bitrate = g_value_get_uint (value);
433 OMX_VIDEO_CONFIG_BITRATETYPE config;
436 GST_OMX_INIT_STRUCT (&config);
437 config.nPortIndex = self->enc_out_port->index;
438 config.nEncodeBitrate = self->target_bitrate;
440 gst_omx_component_set_config (self->enc,
441 OMX_IndexConfigVideoBitrate, &config);
442 if (err != OMX_ErrorNone)
443 GST_ERROR_OBJECT (self,
444 "Failed to set bitrate parameter: %s (0x%08x)",
445 gst_omx_error_to_string (err), err);
448 case PROP_QUANT_I_FRAMES:
449 self->quant_i_frames = g_value_get_uint (value);
451 case PROP_QUANT_P_FRAMES:
452 self->quant_p_frames = g_value_get_uint (value);
454 case PROP_QUANT_B_FRAMES:
455 self->quant_b_frames = g_value_get_uint (value);
458 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
464 gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value,
467 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
470 case PROP_CONTROL_RATE:
471 g_value_set_enum (value, self->control_rate);
473 case PROP_TARGET_BITRATE:
474 g_value_set_uint (value, self->target_bitrate);
476 case PROP_QUANT_I_FRAMES:
477 g_value_set_uint (value, self->quant_i_frames);
479 case PROP_QUANT_P_FRAMES:
480 g_value_set_uint (value, self->quant_p_frames);
482 case PROP_QUANT_B_FRAMES:
483 g_value_set_uint (value, self->quant_b_frames);
486 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
491 static GstStateChangeReturn
492 gst_omx_video_enc_change_state (GstElement * element, GstStateChange transition)
494 GstOMXVideoEnc *self;
495 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
497 g_return_val_if_fail (GST_IS_OMX_VIDEO_ENC (element),
498 GST_STATE_CHANGE_FAILURE);
499 self = GST_OMX_VIDEO_ENC (element);
501 switch (transition) {
502 case GST_STATE_CHANGE_NULL_TO_READY:
504 case GST_STATE_CHANGE_READY_TO_PAUSED:
505 self->downstream_flow_ret = GST_FLOW_OK;
507 self->draining = FALSE;
508 self->started = FALSE;
510 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
512 case GST_STATE_CHANGE_PAUSED_TO_READY:
513 if (self->enc_in_port)
514 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
515 if (self->enc_out_port)
516 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
518 g_mutex_lock (&self->drain_lock);
519 self->draining = FALSE;
520 g_cond_broadcast (&self->drain_cond);
521 g_mutex_unlock (&self->drain_lock);
527 if (ret == GST_STATE_CHANGE_FAILURE)
531 GST_ELEMENT_CLASS (gst_omx_video_enc_parent_class)->change_state (element,
534 if (ret == GST_STATE_CHANGE_FAILURE)
537 switch (transition) {
538 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
540 case GST_STATE_CHANGE_PAUSED_TO_READY:
541 self->downstream_flow_ret = GST_FLOW_FLUSHING;
542 self->started = FALSE;
544 if (!gst_omx_video_enc_shutdown (self))
545 ret = GST_STATE_CHANGE_FAILURE;
547 case GST_STATE_CHANGE_READY_TO_NULL:
557 gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port,
558 GstOMXBuffer * buf, GstVideoCodecFrame * frame)
560 GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
561 GstFlowReturn flow_ret = GST_FLOW_OK;
563 if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
564 && buf->omx_buf->nFilledLen > 0) {
565 GstVideoCodecState *state;
566 GstBuffer *codec_data;
567 GstMapInfo map = GST_MAP_INFO_INIT;
570 GST_DEBUG_OBJECT (self, "Handling codec data");
572 caps = klass->get_caps (self, self->enc_out_port, self->input_state);
573 codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
575 gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
577 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
578 buf->omx_buf->nFilledLen);
579 gst_buffer_unmap (codec_data, &map);
581 gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
583 state->codec_data = codec_data;
584 gst_video_codec_state_unref (state);
585 if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
586 gst_video_codec_frame_unref (frame);
587 return GST_FLOW_NOT_NEGOTIATED;
589 flow_ret = GST_FLOW_OK;
590 } else if (buf->omx_buf->nFilledLen > 0) {
592 GstMapInfo map = GST_MAP_INFO_INIT;
594 GST_DEBUG_OBJECT (self, "Handling output data");
596 if (buf->omx_buf->nFilledLen > 0) {
597 outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
599 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
601 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
602 buf->omx_buf->nFilledLen);
603 gst_buffer_unmap (outbuf, &map);
605 outbuf = gst_buffer_new ();
608 GST_BUFFER_TIMESTAMP (outbuf) =
609 gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
610 OMX_TICKS_PER_SECOND);
611 if (buf->omx_buf->nTickCount != 0)
612 GST_BUFFER_DURATION (outbuf) =
613 gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
614 OMX_TICKS_PER_SECOND);
616 if ((klass->cdata.hacks & GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED)
617 || (buf->omx_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
619 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
621 GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
624 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
626 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
630 frame->output_buffer = outbuf;
632 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
634 GST_ERROR_OBJECT (self, "No corresponding frame found");
635 flow_ret = gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (self), outbuf);
637 } else if (frame != NULL) {
638 flow_ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
645 gst_omx_video_enc_loop (GstOMXVideoEnc * self)
647 GstOMXVideoEncClass *klass;
648 GstOMXPort *port = self->enc_out_port;
649 GstOMXBuffer *buf = NULL;
650 GstVideoCodecFrame *frame;
651 GstFlowReturn flow_ret = GST_FLOW_OK;
652 GstOMXAcquireBufferReturn acq_return;
655 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
657 acq_return = gst_omx_port_acquire_buffer (port, &buf);
658 if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
659 goto component_error;
660 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
662 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
666 if (!gst_pad_has_current_caps (GST_VIDEO_ENCODER_SRC_PAD (self))
667 || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
669 GstVideoCodecState *state;
671 GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
673 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
674 && gst_omx_port_is_enabled (port)) {
675 /* Reallocate all buffers */
676 err = gst_omx_port_set_enabled (port, FALSE);
677 if (err != OMX_ErrorNone)
678 goto reconfigure_error;
680 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
681 if (err != OMX_ErrorNone)
682 goto reconfigure_error;
684 err = gst_omx_port_deallocate_buffers (port);
685 if (err != OMX_ErrorNone)
686 goto reconfigure_error;
688 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
689 if (err != OMX_ErrorNone)
690 goto reconfigure_error;
693 GST_VIDEO_ENCODER_STREAM_LOCK (self);
695 caps = klass->get_caps (self, self->enc_out_port, self->input_state);
698 gst_omx_port_release_buffer (self->enc_out_port, buf);
699 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
703 GST_DEBUG_OBJECT (self, "Setting output state: %" GST_PTR_FORMAT, caps);
706 gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
708 gst_video_codec_state_unref (state);
710 if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
712 gst_omx_port_release_buffer (self->enc_out_port, buf);
713 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
717 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
719 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
720 err = gst_omx_port_set_enabled (port, TRUE);
721 if (err != OMX_ErrorNone)
722 goto reconfigure_error;
723 #ifdef GST_TIZEN_MODIFICATION
724 err = gst_omx_port_tbm_allocate_enc_buffers(port, self->hTBMBufMgr,
725 self->enc_in_port->port_def.format.video.eCompressionFormat);
727 err = gst_omx_port_allocate_buffers (port);
729 if (err != OMX_ErrorNone)
730 goto reconfigure_error;
732 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
733 if (err != OMX_ErrorNone)
734 goto reconfigure_error;
736 err = gst_omx_port_populate (port);
737 if (err != OMX_ErrorNone)
738 goto reconfigure_error;
740 err = gst_omx_port_mark_reconfigured (port);
741 if (err != OMX_ErrorNone)
742 goto reconfigure_error;
745 /* Now get a buffer */
746 if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
751 g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
753 /* This prevents a deadlock between the srcpad stream
754 * lock and the videocodec stream lock, if ::flush()
755 * is called at the wrong time
757 if (gst_omx_port_is_flushing (self->enc_out_port)) {
758 GST_DEBUG_OBJECT (self, "Flushing");
759 gst_omx_port_release_buffer (self->enc_out_port, buf);
763 GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %" G_GUINT64_FORMAT,
764 (guint) buf->omx_buf->nFlags, (guint64) buf->omx_buf->nTimeStamp);
766 GST_VIDEO_ENCODER_STREAM_LOCK (self);
767 frame = gst_omx_video_find_nearest_frame (buf,
768 gst_video_encoder_get_frames (GST_VIDEO_ENCODER (self)));
770 g_assert (klass->handle_output_frame);
771 flow_ret = klass->handle_output_frame (self, self->enc_out_port, buf, frame);
773 GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
775 err = gst_omx_port_release_buffer (port, buf);
776 if (err != OMX_ErrorNone)
779 self->downstream_flow_ret = flow_ret;
781 GST_DEBUG_OBJECT (self, "Read frame from component");
783 if (flow_ret != GST_FLOW_OK)
786 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
792 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
793 ("OpenMAX component in error state %s (0x%08x)",
794 gst_omx_component_get_last_error_string (self->enc),
795 gst_omx_component_get_last_error (self->enc)));
796 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
797 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
798 self->downstream_flow_ret = GST_FLOW_ERROR;
799 self->started = FALSE;
804 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
805 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
806 self->downstream_flow_ret = GST_FLOW_FLUSHING;
807 self->started = FALSE;
813 g_mutex_lock (&self->drain_lock);
814 if (self->draining) {
815 GST_DEBUG_OBJECT (self, "Drained");
816 self->draining = FALSE;
817 g_cond_broadcast (&self->drain_cond);
818 flow_ret = GST_FLOW_OK;
819 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
821 GST_DEBUG_OBJECT (self, "Component signalled EOS");
822 flow_ret = GST_FLOW_EOS;
824 g_mutex_unlock (&self->drain_lock);
826 GST_VIDEO_ENCODER_STREAM_LOCK (self);
827 self->downstream_flow_ret = flow_ret;
829 /* Here we fallback and pause the task for the EOS case */
830 if (flow_ret != GST_FLOW_OK)
833 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
839 if (flow_ret == GST_FLOW_EOS) {
840 GST_DEBUG_OBJECT (self, "EOS");
842 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
843 gst_event_new_eos ());
844 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
845 self->started = FALSE;
846 } else if (flow_ret < GST_FLOW_EOS) {
847 GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."),
848 ("stream stopped, reason %s", gst_flow_get_name (flow_ret)));
850 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
851 gst_event_new_eos ());
852 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
853 self->started = FALSE;
854 } else if (flow_ret == GST_FLOW_FLUSHING) {
855 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
856 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
857 self->started = FALSE;
859 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
864 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
865 ("Unable to reconfigure output port"));
866 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
867 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
868 self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
869 self->started = FALSE;
874 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
875 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
876 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
877 self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
878 self->started = FALSE;
883 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
884 ("Failed to relase output buffer to component: %s (0x%08x)",
885 gst_omx_error_to_string (err), err));
886 gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
887 gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
888 self->downstream_flow_ret = GST_FLOW_ERROR;
889 self->started = FALSE;
890 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
896 gst_omx_video_enc_start (GstVideoEncoder * encoder)
898 GstOMXVideoEnc *self;
900 self = GST_OMX_VIDEO_ENC (encoder);
902 self->last_upstream_ts = 0;
903 self->downstream_flow_ret = GST_FLOW_OK;
909 gst_omx_video_enc_stop (GstVideoEncoder * encoder)
911 GstOMXVideoEnc *self;
913 self = GST_OMX_VIDEO_ENC (encoder);
915 GST_DEBUG_OBJECT (self, "Stopping encoder");
917 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
918 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
920 gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
922 if (gst_omx_component_get_state (self->enc, 0) > OMX_StateIdle)
923 gst_omx_component_set_state (self->enc, OMX_StateIdle);
925 self->downstream_flow_ret = GST_FLOW_FLUSHING;
926 self->started = FALSE;
928 if (self->input_state)
929 gst_video_codec_state_unref (self->input_state);
930 self->input_state = NULL;
932 g_mutex_lock (&self->drain_lock);
933 self->draining = FALSE;
934 g_cond_broadcast (&self->drain_cond);
935 g_mutex_unlock (&self->drain_lock);
937 gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
943 gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
944 GstVideoCodecState * state)
946 GstOMXVideoEnc *self;
947 GstOMXVideoEncClass *klass;
948 gboolean needs_disable = FALSE;
949 OMX_PARAM_PORTDEFINITIONTYPE port_def;
950 GstVideoInfo *info = &state->info;
951 GList *negotiation_map = NULL, *l;
953 self = GST_OMX_VIDEO_ENC (encoder);
954 klass = GST_OMX_VIDEO_ENC_GET_CLASS (encoder);
956 GST_DEBUG_OBJECT (self, "Setting new format %s",
957 gst_video_format_to_string (info->finfo->format));
959 gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
962 gst_omx_component_get_state (self->enc,
963 GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
964 /* If the component is not in Loaded state and a real format change happens
965 * we have to disable the port and re-allocate all buffers. If no real
966 * format change happened we can just exit here.
969 GST_DEBUG_OBJECT (self, "Need to disable and drain encoder");
970 gst_omx_video_enc_drain (self);
971 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
973 /* Wait until the srcpad loop is finished,
974 * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
975 * caused by using this lock from inside the loop function */
976 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
977 gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
978 GST_VIDEO_ENCODER_STREAM_LOCK (self);
980 if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
981 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
982 gst_omx_video_enc_stop (GST_VIDEO_ENCODER (self));
983 gst_omx_video_enc_close (GST_VIDEO_ENCODER (self));
984 GST_VIDEO_ENCODER_STREAM_LOCK (self);
986 if (!gst_omx_video_enc_open (GST_VIDEO_ENCODER (self)))
988 needs_disable = FALSE;
990 if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
992 if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
994 if (gst_omx_port_wait_buffers_released (self->enc_in_port,
995 5 * GST_SECOND) != OMX_ErrorNone)
997 if (gst_omx_port_wait_buffers_released (self->enc_out_port,
998 1 * GST_SECOND) != OMX_ErrorNone)
1000 if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1002 if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1004 if (gst_omx_port_wait_enabled (self->enc_in_port,
1005 1 * GST_SECOND) != OMX_ErrorNone)
1007 if (gst_omx_port_wait_enabled (self->enc_out_port,
1008 1 * GST_SECOND) != OMX_ErrorNone)
1012 GST_DEBUG_OBJECT (self, "Encoder drained and disabled");
1016 gst_omx_video_get_supported_colorformats (self->enc_in_port,
1018 if (!negotiation_map) {
1020 switch (info->finfo->format) {
1021 case GST_VIDEO_FORMAT_I420:
1022 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
1024 case GST_VIDEO_FORMAT_NV12:
1025 port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
1028 GST_ERROR_OBJECT (self, "Unsupported format %s",
1029 gst_video_format_to_string (info->finfo->format));
1034 for (l = negotiation_map; l; l = l->next) {
1035 GstOMXVideoNegotiationMap *m = l->data;
1037 if (m->format == info->finfo->format) {
1038 port_def.format.video.eColorFormat = m->type;
1042 g_list_free_full (negotiation_map,
1043 (GDestroyNotify) gst_omx_video_negotiation_map_free);
1046 port_def.format.video.nFrameWidth = info->width;
1047 if (port_def.nBufferAlignment)
1048 port_def.format.video.nStride =
1049 (info->width + port_def.nBufferAlignment - 1) &
1050 (~(port_def.nBufferAlignment - 1));
1052 port_def.format.video.nStride = GST_ROUND_UP_4 (info->width); /* safe (?) default */
1054 port_def.format.video.nFrameHeight = info->height;
1055 port_def.format.video.nSliceHeight = info->height;
1057 switch (port_def.format.video.eColorFormat) {
1058 case OMX_COLOR_FormatYUV420Planar:
1059 case OMX_COLOR_FormatYUV420PackedPlanar:
1060 port_def.nBufferSize =
1061 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1062 2 * ((port_def.format.video.nStride / 2) *
1063 ((port_def.format.video.nFrameHeight + 1) / 2));
1066 case OMX_COLOR_FormatYUV420SemiPlanar:
1067 port_def.nBufferSize =
1068 (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1069 (port_def.format.video.nStride *
1070 ((port_def.format.video.nFrameHeight + 1) / 2));
1073 case OMX_EXT_COLOR_FormatNV12LPhysicalAddress: /* FALL THROUGH */
1074 case OMX_EXT_COLOR_FormatNV12TPhysicalAddress:
1075 #ifdef GST_TIZEN_MODIFICATION
1076 port_def.nBufferSize = sizeof(MMVideoBuffer);
1081 g_assert_not_reached ();
1084 if (info->fps_n == 0) {
1085 port_def.format.video.xFramerate = 0;
1087 if (!(klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER))
1088 port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d);
1090 port_def.format.video.xFramerate = (info->fps_n) / (info->fps_d);
1093 GST_DEBUG_OBJECT (self, "Setting inport port definition");
1094 if (gst_omx_port_update_port_definition (self->enc_in_port,
1095 &port_def) != OMX_ErrorNone)
1098 #ifdef USE_OMX_TARGET_RPI
1102 OMX_CONFIG_POINTTYPE aspect_ratio_param;
1104 GST_OMX_INIT_STRUCT (&aspect_ratio_param);
1105 aspect_ratio_param.nPortIndex = self->enc_out_port->index;
1107 err = gst_omx_component_get_parameter (self->enc,
1108 OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
1110 if (err == OMX_ErrorNone) {
1112 aspect_ratio_param.nX = info->par_n;
1113 aspect_ratio_param.nY = info->par_d;
1116 gst_omx_component_set_parameter (self->enc,
1117 OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
1119 if (err == OMX_ErrorUnsupportedIndex) {
1120 GST_WARNING_OBJECT (self,
1121 "Setting aspect ratio parameters not supported by the component");
1122 } else if (err == OMX_ErrorUnsupportedSetting) {
1123 GST_WARNING_OBJECT (self,
1124 "Setting aspect ratio %u %u not supported by the component",
1125 aspect_ratio_param.nX, aspect_ratio_param.nY);
1126 } else if (err != OMX_ErrorNone) {
1127 GST_ERROR_OBJECT (self,
1128 "Failed to set aspect ratio: %s (0x%08x)",
1129 gst_omx_error_to_string (err), err);
1134 #endif // USE_OMX_TARGET_RPI
1136 if (klass->set_format) {
1137 if (!klass->set_format (self, self->enc_in_port, state)) {
1138 GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
1143 GST_DEBUG_OBJECT (self, "Updating outport port definition");
1144 if (gst_omx_port_update_port_definition (self->enc_out_port,
1145 NULL) != OMX_ErrorNone)
1148 if (self->target_bitrate != 0xffffffff) {
1149 OMX_VIDEO_PARAM_BITRATETYPE config;
1152 GST_OMX_INIT_STRUCT (&config);
1153 config.nPortIndex = self->enc_out_port->index;
1154 config.nTargetBitrate = self->target_bitrate;
1155 config.eControlRate = self->control_rate;
1156 err = gst_omx_component_set_parameter (self->enc,
1157 OMX_IndexParamVideoBitrate, &config);
1158 if (err != OMX_ErrorNone)
1159 GST_ERROR_OBJECT (self, "Failed to set bitrate parameter: %s (0x%08x)",
1160 gst_omx_error_to_string (err), err);
1163 GST_DEBUG_OBJECT (self, "Enabling component");
1164 if (needs_disable) {
1165 if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone)
1167 #ifdef GST_TIZEN_MODIFICATION
1168 if(gst_omx_port_tbm_allocate_enc_buffers(self->enc_in_port, self->hTBMBufMgr,
1169 self->enc_in_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone)
1172 if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1175 if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
1176 if (gst_omx_port_set_enabled (self->enc_out_port, TRUE) != OMX_ErrorNone)
1178 if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1181 if (gst_omx_port_wait_enabled (self->enc_out_port,
1182 5 * GST_SECOND) != OMX_ErrorNone)
1186 if (gst_omx_port_wait_enabled (self->enc_in_port,
1187 5 * GST_SECOND) != OMX_ErrorNone)
1189 if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone)
1192 if (!(klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
1193 /* Disable output port */
1194 if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
1197 if (gst_omx_port_wait_enabled (self->enc_out_port,
1198 1 * GST_SECOND) != OMX_ErrorNone)
1201 if (gst_omx_component_set_state (self->enc,
1202 OMX_StateIdle) != OMX_ErrorNone)
1205 /* Need to allocate buffers to reach Idle state */
1207 if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1210 if (gst_omx_component_set_state (self->enc,
1211 OMX_StateIdle) != OMX_ErrorNone)
1214 /* Need to allocate buffers to reach Idle state */
1215 #ifdef GST_TIZEN_MODIFICATION
1216 if(gst_omx_port_tbm_allocate_enc_buffers(self->enc_in_port, self->hTBMBufMgr,
1217 self->enc_in_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone)
1220 if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1224 #ifdef GST_TIZEN_MODIFICATION
1225 if(gst_omx_port_tbm_allocate_enc_buffers(self->enc_out_port, self->hTBMBufMgr,
1226 self->enc_out_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone)
1228 if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1233 if (gst_omx_component_get_state (self->enc,
1234 GST_CLOCK_TIME_NONE) != OMX_StateIdle)
1237 if (gst_omx_component_set_state (self->enc,
1238 OMX_StateExecuting) != OMX_ErrorNone)
1241 if (gst_omx_component_get_state (self->enc,
1242 GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
1246 /* Unset flushing to allow ports to accept data again */
1247 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
1248 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
1250 if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone) {
1251 GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
1252 gst_omx_component_get_last_error_string (self->enc),
1253 gst_omx_component_get_last_error (self->enc));
1257 if (self->input_state)
1258 gst_video_codec_state_unref (self->input_state);
1259 self->input_state = gst_video_codec_state_ref (state);
1261 /* Start the srcpad loop again */
1262 GST_DEBUG_OBJECT (self, "Starting task again");
1263 self->downstream_flow_ret = GST_FLOW_OK;
1264 gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
1265 (GstTaskFunction) gst_omx_video_enc_loop, encoder, NULL);
1271 gst_omx_video_enc_flush (GstVideoEncoder * encoder)
1273 GstOMXVideoEnc *self;
1275 self = GST_OMX_VIDEO_ENC (encoder);
1277 GST_DEBUG_OBJECT (self, "Flushing encoder");
1279 if (gst_omx_component_get_state (self->enc, 0) == OMX_StateLoaded)
1282 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
1283 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1285 /* Wait until the srcpad loop is finished,
1286 * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
1287 * caused by using this lock from inside the loop function */
1288 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1289 GST_PAD_STREAM_LOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
1290 GST_PAD_STREAM_UNLOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
1291 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1293 gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
1294 gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
1295 gst_omx_port_populate (self->enc_out_port);
1297 /* Start the srcpad loop again */
1298 self->last_upstream_ts = 0;
1299 self->downstream_flow_ret = GST_FLOW_OK;
1300 gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
1301 (GstTaskFunction) gst_omx_video_enc_loop, encoder, NULL);
1307 gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf,
1308 GstOMXBuffer * outbuf)
1310 GstVideoCodecState *state = gst_video_codec_state_ref (self->input_state);
1311 GstVideoInfo *info = &state->info;
1312 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
1313 gboolean ret = FALSE;
1314 GstVideoFrame frame;
1316 if (info->width != port_def->format.video.nFrameWidth ||
1317 info->height != port_def->format.video.nFrameHeight) {
1318 GST_ERROR_OBJECT (self, "Width or height do not match");
1322 /* Same strides and everything */
1323 if (gst_buffer_get_size (inbuf) ==
1324 outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) {
1325 outbuf->omx_buf->nFilledLen = gst_buffer_get_size (inbuf);
1327 gst_buffer_extract (inbuf, 0,
1328 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset,
1329 outbuf->omx_buf->nFilledLen);
1334 /* Different strides */
1336 switch (info->finfo->format) {
1337 case GST_VIDEO_FORMAT_I420:{
1338 gint i, j, height, width;
1340 gint src_stride, dest_stride;
1342 outbuf->omx_buf->nFilledLen = 0;
1344 if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
1345 GST_ERROR_OBJECT (self, "Invalid input buffer size");
1350 for (i = 0; i < 3; i++) {
1352 dest_stride = port_def->format.video.nStride;
1353 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
1355 /* XXX: Try this if no stride was set */
1356 if (dest_stride == 0)
1357 dest_stride = src_stride;
1359 dest_stride = port_def->format.video.nStride / 2;
1360 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
1362 /* XXX: Try this if no stride was set */
1363 if (dest_stride == 0)
1364 dest_stride = src_stride;
1367 dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
1370 port_def->format.video.nSliceHeight *
1371 port_def->format.video.nStride;
1374 (port_def->format.video.nSliceHeight / 2) *
1375 (port_def->format.video.nStride / 2);
1377 src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
1378 height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
1379 width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i);
1381 if (dest + dest_stride * height >
1382 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
1383 gst_video_frame_unmap (&frame);
1384 GST_ERROR_OBJECT (self, "Invalid output buffer size");
1389 for (j = 0; j < height; j++) {
1390 memcpy (dest, src, width);
1391 outbuf->omx_buf->nFilledLen += dest_stride;
1393 dest += dest_stride;
1396 gst_video_frame_unmap (&frame);
1400 case GST_VIDEO_FORMAT_NV12:{
1401 gint i, j, height, width;
1403 gint src_stride, dest_stride;
1405 outbuf->omx_buf->nFilledLen = 0;
1407 if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
1408 GST_ERROR_OBJECT (self, "Invalid input buffer size");
1413 for (i = 0; i < 2; i++) {
1415 dest_stride = port_def->format.video.nStride;
1416 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
1417 /* XXX: Try this if no stride was set */
1418 if (dest_stride == 0)
1419 dest_stride = src_stride;
1421 dest_stride = port_def->format.video.nStride;
1422 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
1424 /* XXX: Try this if no stride was set */
1425 if (dest_stride == 0)
1426 dest_stride = src_stride;
1429 dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
1432 port_def->format.video.nSliceHeight *
1433 port_def->format.video.nStride;
1435 src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
1436 height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
1437 width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i) * (i == 0 ? 1 : 2);
1439 if (dest + dest_stride * height >
1440 outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
1441 gst_video_frame_unmap (&frame);
1442 GST_ERROR_OBJECT (self, "Invalid output buffer size");
1447 for (j = 0; j < height; j++) {
1448 memcpy (dest, src, width);
1449 outbuf->omx_buf->nFilledLen += dest_stride;
1451 dest += dest_stride;
1455 gst_video_frame_unmap (&frame);
1459 case GST_VIDEO_FORMAT_ST12:
1460 case GST_VIDEO_FORMAT_SN12:{
1461 GstMemory* ext_memory = gst_buffer_peek_memory(inbuf, 1);
1462 GstMapInfo ext_info = GST_MAP_INFO_INIT;
1463 MMVideoBuffer *ext_buf = NULL;
1466 GST_WARNING_OBJECT (self, "null MMVideoBuffer pointer in hw color format. skip this.");
1470 gst_memory_map(ext_memory, &ext_info, GST_MAP_READ);
1471 ext_buf = (MMVideoBuffer*)ext_info.data;
1472 gst_memory_unmap(ext_memory, &ext_info);
1474 if (ext_buf != NULL && ext_buf->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
1476 if (ext_buf->handle.dmabuf_fd[0] == NULL)
1477 gst_omx_tbm_get_bo_fd(ext_buf->handle.bo[0]);
1479 if (ext_buf->handle.dmabuf_fd[1] == NULL)
1480 gst_omx_tbm_get_bo_fd(ext_buf->handle.bo[1]);
1482 GST_LOG_OBJECT (self, "enc. fd[0]:%d fd[1]:%d fd[2]:%d w[0]:%d h[0]:%d buf_share_method:%d",
1483 ext_buf->handle.dmabuf_fd[0], ext_buf->handle.dmabuf_fd[1], ext_buf->handle.dmabuf_fd[2], ext_buf->width[0], ext_buf->height[0], ext_buf->type);
1485 GST_WARNING_OBJECT (self, "enc input buf has wrong buf_share_method[%d]", ext_buf->type);
1488 outbuf->omx_buf->nAllocLen = sizeof(MMVideoBuffer);
1489 outbuf->omx_buf->nFilledLen = sizeof(MMVideoBuffer);
1490 memcpy (outbuf->omx_buf->pBuffer, ext_buf, sizeof(MMVideoBuffer));
1492 #ifdef CODEC_ENC_INPUT_DUMP
1493 gst_omx_video_enc_input_dump(ext_buf);
1500 GST_ERROR_OBJECT (self, "Unsupported format");
1507 gst_video_codec_state_unref (state);
1512 static GstFlowReturn
1513 gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
1514 GstVideoCodecFrame * frame)
1516 GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
1517 GstOMXVideoEnc *self;
1522 self = GST_OMX_VIDEO_ENC (encoder);
1524 GST_DEBUG_OBJECT (self, "Handling frame");
1526 if (self->downstream_flow_ret != GST_FLOW_OK) {
1527 gst_video_codec_frame_unref (frame);
1528 return self->downstream_flow_ret;
1531 port = self->enc_in_port;
1533 while (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
1534 GstClockTime timestamp, duration;
1536 /* Make sure to release the base class stream lock, otherwise
1537 * _loop() can't call _finish_frame() and we might block forever
1538 * because no input buffers are released */
1539 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1540 acq_ret = gst_omx_port_acquire_buffer (port, &buf);
1542 if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
1543 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1544 goto component_error;
1545 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
1546 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1548 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1549 /* Reallocate all buffers */
1550 err = gst_omx_port_set_enabled (port, FALSE);
1551 if (err != OMX_ErrorNone) {
1552 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1553 goto reconfigure_error;
1556 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
1557 if (err != OMX_ErrorNone) {
1558 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1559 goto reconfigure_error;
1562 err = gst_omx_port_deallocate_buffers (port);
1563 if (err != OMX_ErrorNone) {
1564 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1565 goto reconfigure_error;
1568 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
1569 if (err != OMX_ErrorNone) {
1570 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1571 goto reconfigure_error;
1574 err = gst_omx_port_set_enabled (port, TRUE);
1575 if (err != OMX_ErrorNone) {
1576 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1577 goto reconfigure_error;
1579 #ifdef GST_TIZEN_MODIFICATION
1580 err = gst_omx_port_tbm_allocate_enc_buffers(port, self->hTBMBufMgr,
1581 self->enc_in_port->port_def.format.video.eCompressionFormat);
1583 err = gst_omx_port_allocate_buffers (port);
1585 if (err != OMX_ErrorNone) {
1586 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1587 goto reconfigure_error;
1590 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
1591 if (err != OMX_ErrorNone) {
1592 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1593 goto reconfigure_error;
1596 err = gst_omx_port_mark_reconfigured (port);
1597 if (err != OMX_ErrorNone) {
1598 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1599 goto reconfigure_error;
1602 /* Now get a new buffer and fill it */
1603 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1606 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1608 g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
1610 if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
1611 gst_omx_port_release_buffer (port, buf);
1615 if (self->downstream_flow_ret != GST_FLOW_OK) {
1616 gst_omx_port_release_buffer (port, buf);
1620 /* Now handle the frame */
1621 GST_DEBUG_OBJECT (self, "Handling frame");
1623 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
1624 #ifdef USE_OMX_TARGET_RPI
1625 OMX_CONFIG_BOOLEANTYPE config;
1627 GST_OMX_INIT_STRUCT (&config);
1628 config.bEnabled = OMX_TRUE;
1630 GST_DEBUG_OBJECT (self, "Forcing a keyframe (iframe on the RPi)");
1633 gst_omx_component_set_config (self->enc,
1634 OMX_IndexConfigBrcmVideoRequestIFrame, &config);
1636 OMX_CONFIG_INTRAREFRESHVOPTYPE config;
1638 GST_OMX_INIT_STRUCT (&config);
1639 config.nPortIndex = port->index;
1640 config.IntraRefreshVOP = OMX_TRUE;
1642 GST_DEBUG_OBJECT (self, "Forcing a keyframe");
1644 gst_omx_component_set_config (self->enc,
1645 OMX_IndexConfigVideoIntraVOPRefresh, &config);
1647 if (err != OMX_ErrorNone)
1648 GST_ERROR_OBJECT (self, "Failed to force a keyframe: %s (0x%08x)",
1649 gst_omx_error_to_string (err), err);
1652 /* Copy the buffer content in chunks of size as requested
1654 if (!gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) {
1655 gst_omx_port_release_buffer (port, buf);
1656 goto buffer_fill_error;
1659 timestamp = frame->pts;
1660 if (timestamp != GST_CLOCK_TIME_NONE) {
1661 buf->omx_buf->nTimeStamp =
1662 gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND);
1663 self->last_upstream_ts = timestamp;
1666 duration = frame->duration;
1667 if (duration != GST_CLOCK_TIME_NONE) {
1668 buf->omx_buf->nTickCount =
1669 gst_util_uint64_scale (duration, OMX_TICKS_PER_SECOND, GST_SECOND);
1670 self->last_upstream_ts += duration;
1672 buf->omx_buf->nTickCount = 0;
1675 self->started = TRUE;
1676 err = gst_omx_port_release_buffer (port, buf);
1677 if (err != OMX_ErrorNone)
1680 GST_DEBUG_OBJECT (self, "Passed frame to component");
1683 gst_video_codec_frame_unref (frame);
1685 return self->downstream_flow_ret;
1689 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1690 ("Got OpenMAX buffer with no free space (%p, %u/%u)", buf,
1691 (guint) buf->omx_buf->nOffset, (guint) buf->omx_buf->nAllocLen));
1692 gst_video_codec_frame_unref (frame);
1693 return GST_FLOW_ERROR;
1698 gst_video_codec_frame_unref (frame);
1699 return self->downstream_flow_ret;
1704 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1705 ("OpenMAX component in error state %s (0x%08x)",
1706 gst_omx_component_get_last_error_string (self->enc),
1707 gst_omx_component_get_last_error (self->enc)));
1708 gst_video_codec_frame_unref (frame);
1709 return GST_FLOW_ERROR;
1714 GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
1715 gst_video_codec_frame_unref (frame);
1716 return GST_FLOW_FLUSHING;
1720 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1721 ("Unable to reconfigure input port"));
1722 gst_video_codec_frame_unref (frame);
1723 return GST_FLOW_ERROR;
1727 GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL),
1728 ("Failed to write input into the OpenMAX buffer"));
1729 gst_video_codec_frame_unref (frame);
1730 return GST_FLOW_ERROR;
1734 gst_video_codec_frame_unref (frame);
1735 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1736 ("Failed to relase input buffer to component: %s (0x%08x)",
1737 gst_omx_error_to_string (err), err));
1738 return GST_FLOW_ERROR;
1742 static GstFlowReturn
1743 gst_omx_video_enc_finish (GstVideoEncoder * encoder)
1745 GstOMXVideoEnc *self;
1747 self = GST_OMX_VIDEO_ENC (encoder);
1749 return gst_omx_video_enc_drain (self);
1752 static GstFlowReturn
1753 gst_omx_video_enc_drain (GstOMXVideoEnc * self)
1755 GstOMXVideoEncClass *klass;
1757 GstOMXAcquireBufferReturn acq_ret;
1760 GST_DEBUG_OBJECT (self, "Draining component");
1762 klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1764 if (!self->started) {
1765 GST_DEBUG_OBJECT (self, "Component not started yet");
1768 self->started = FALSE;
1770 if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
1771 GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
1775 /* Make sure to release the base class stream lock, otherwise
1776 * _loop() can't call _finish_frame() and we might block forever
1777 * because no input buffers are released */
1778 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1780 /* Send an EOS buffer to the component and let the base
1781 * class drop the EOS event. We will send it later when
1782 * the EOS buffer arrives on the output port. */
1783 acq_ret = gst_omx_port_acquire_buffer (self->enc_in_port, &buf);
1784 if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
1785 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1786 GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
1788 return GST_FLOW_ERROR;
1791 g_mutex_lock (&self->drain_lock);
1792 self->draining = TRUE;
1793 buf->omx_buf->nFilledLen = 0;
1794 buf->omx_buf->nTimeStamp =
1795 gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
1797 buf->omx_buf->nTickCount = 0;
1798 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
1799 err = gst_omx_port_release_buffer (self->enc_in_port, buf);
1800 if (err != OMX_ErrorNone) {
1801 GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
1802 gst_omx_error_to_string (err), err);
1803 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1804 return GST_FLOW_ERROR;
1806 GST_DEBUG_OBJECT (self, "Waiting until component is drained");
1807 g_cond_wait (&self->drain_cond, &self->drain_lock);
1808 GST_DEBUG_OBJECT (self, "Drained component");
1809 g_mutex_unlock (&self->drain_lock);
1810 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1812 self->started = FALSE;
1818 gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
1821 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1824 GST_VIDEO_ENCODER_CLASS
1825 (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query);
1829 gst_omx_video_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
1831 GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
1832 GList *negotiation_map = NULL;
1833 GstCaps *comp_supported_caps;
1836 return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
1839 gst_omx_video_get_supported_colorformats (self->enc_in_port,
1841 comp_supported_caps = gst_omx_video_get_caps_for_map (negotiation_map);
1842 g_list_free_full (negotiation_map,
1843 (GDestroyNotify) gst_omx_video_negotiation_map_free);
1845 if (!gst_caps_is_empty (comp_supported_caps)) {
1847 gst_video_encoder_proxy_getcaps (encoder, comp_supported_caps, filter);
1849 gst_caps_unref (comp_supported_caps);
1852 gst_caps_unref (comp_supported_caps);
1853 return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);