enabling omx decoder
[platform/upstream/gstreamer.git] / omx / gstomxvideoenc.c
1 /*
2  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
4  *
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.
9  *
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.
14  *
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
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/gst.h>
26 #include <gst/video/gstvideometa.h>
27 #include <string.h>
28
29 #include "gstomxvideo.h"
30 #include "gstomxvideoenc.h"
31
32 #ifdef USE_OMX_TARGET_RPI
33 #include <OMX_Broadcom.h>
34 #include <OMX_Index.h>
35 #endif
36
37 GST_DEBUG_CATEGORY_STATIC (gst_omx_video_enc_debug_category);
38 #define GST_CAT_DEFAULT gst_omx_video_enc_debug_category
39
40 #define GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE (gst_omx_video_enc_control_rate_get_type ())
41 static GType
42 gst_omx_video_enc_control_rate_get_type (void)
43 {
44   static GType qtype = 0;
45
46   if (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"},
56       {0, NULL, NULL}
57     };
58
59     qtype = g_enum_register_static ("GstOMXVideoEncControlRate", values);
60   }
61   return qtype;
62 }
63
64 /* prototypes */
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);
70
71
72 static GstStateChangeReturn
73 gst_omx_video_enc_change_state (GstElement * element,
74     GstStateChange transition);
75
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,
87     GstQuery * query);
88 static GstCaps *gst_omx_video_enc_getcaps (GstVideoEncoder * encoder,
89     GstCaps * filter);
90
91 static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self);
92
93 static GstFlowReturn gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc *
94     self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame);
95
96 enum
97 {
98   PROP_0,
99   PROP_CONTROL_RATE,
100   PROP_TARGET_BITRATE,
101   PROP_QUANT_I_FRAMES,
102   PROP_QUANT_P_FRAMES,
103   PROP_QUANT_B_FRAMES
104 };
105
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)
112
113 /* class initialization */
114
115 #define DEBUG_INIT \
116   GST_DEBUG_CATEGORY_INIT (gst_omx_video_enc_debug_category, "omxvideoenc", 0, \
117       "debug category for gst-omx video encoder base class");
118
119 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoEnc, gst_omx_video_enc,
120     GST_TYPE_VIDEO_ENCODER, DEBUG_INIT);
121
122 static void
123 gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass)
124 {
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);
128
129
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;
133
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));
141
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));
148
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));
155
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));
162
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));
169
170   element_class->change_state =
171       GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state);
172
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);
186
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;
191
192   klass->handle_output_frame =
193       GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_output_frame);
194 }
195
196 static void
197 gst_omx_video_enc_init (GstOMXVideoEnc * self)
198 {
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;
204
205   g_mutex_init (&self->drain_lock);
206   g_cond_init (&self->drain_cond);
207 #ifdef GST_TIZEN_MODIFICATION
208   self->hTBMBufMgr = NULL;
209   self->drm_fd = -1;
210 #endif
211 }
212
213 static gboolean
214 gst_omx_video_enc_open (GstVideoEncoder * encoder)
215 {
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;
219
220   self->enc =
221       gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
222       klass->cdata.component_name, klass->cdata.component_role,
223       klass->cdata.hacks);
224   self->started = FALSE;
225
226   if (!self->enc)
227     return FALSE;
228
229   if (gst_omx_component_get_state (self->enc,
230           GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
231     return FALSE;
232
233   in_port_index = klass->cdata.in_port_index;
234   out_port_index = klass->cdata.out_port_index;
235
236   if (in_port_index == -1 || out_port_index == -1) {
237     OMX_PORT_PARAM_TYPE param;
238     OMX_ERRORTYPE err;
239
240     GST_OMX_INIT_STRUCT (&param);
241
242     err =
243         gst_omx_component_get_parameter (self->enc, OMX_IndexParamVideoInit,
244         &param);
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);
248       /* Fallback */
249       in_port_index = 0;
250       out_port_index = 1;
251     } else {
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;
256     }
257   }
258
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);
261
262   if (!self->enc_in_port || !self->enc_out_port)
263     return FALSE;
264
265   /* Set properties */
266   {
267     OMX_ERRORTYPE err;
268
269     if (self->control_rate != 0xffffffff || self->target_bitrate != 0xffffffff) {
270       OMX_VIDEO_PARAM_BITRATETYPE bitrate_param;
271
272       GST_OMX_INIT_STRUCT (&bitrate_param);
273       bitrate_param.nPortIndex = self->enc_out_port->index;
274
275       err = gst_omx_component_get_parameter (self->enc,
276           OMX_IndexParamVideoBitrate, &bitrate_param);
277
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;
284         }
285 #endif
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;
290
291         err =
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);
305           return FALSE;
306         }
307       } else {
308         GST_ERROR_OBJECT (self, "Failed to get bitrate parameters: %s (0x%08x)",
309             gst_omx_error_to_string (err), err);
310       }
311     }
312
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;
317
318       GST_OMX_INIT_STRUCT (&quant_param);
319       quant_param.nPortIndex = self->enc_out_port->index;
320
321       err = gst_omx_component_get_parameter (self->enc,
322           OMX_IndexParamVideoQuantization, &quant_param);
323
324       if (err == OMX_ErrorNone) {
325
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;
332
333         err =
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);
347           return FALSE;
348         }
349       } else {
350         GST_ERROR_OBJECT (self,
351             "Failed to get quantization parameters: %s (0x%08x)",
352             gst_omx_error_to_string (err), err);
353
354       }
355     }
356   }
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.");
361     return FALSE;
362    }
363 #endif
364   return TRUE;
365 }
366
367 static gboolean
368 gst_omx_video_enc_shutdown (GstOMXVideoEnc * self)
369 {
370   OMX_STATETYPE state;
371
372   GST_DEBUG_OBJECT (self, "Shutting down encoder");
373
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);
379     }
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);
385   }
386
387   return TRUE;
388 }
389
390 static gboolean
391 gst_omx_video_enc_close (GstVideoEncoder * encoder)
392 {
393   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
394
395   GST_DEBUG_OBJECT (self, "Closing encoder");
396
397   if (!gst_omx_video_enc_shutdown (self))
398     return FALSE;
399
400   self->enc_in_port = NULL;
401   self->enc_out_port = NULL;
402   if (self->enc)
403     gst_omx_component_free (self->enc);
404   self->enc = NULL;
405
406   return TRUE;
407 }
408
409 static void
410 gst_omx_video_enc_finalize (GObject * object)
411 {
412   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
413
414   g_mutex_clear (&self->drain_lock);
415   g_cond_clear (&self->drain_cond);
416
417   G_OBJECT_CLASS (gst_omx_video_enc_parent_class)->finalize (object);
418 }
419
420 static void
421 gst_omx_video_enc_set_property (GObject * object, guint prop_id,
422     const GValue * value, GParamSpec * pspec)
423 {
424   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
425
426   switch (prop_id) {
427     case PROP_CONTROL_RATE:
428       self->control_rate = g_value_get_enum (value);
429       break;
430     case PROP_TARGET_BITRATE:
431       self->target_bitrate = g_value_get_uint (value);
432       if (self->enc) {
433         OMX_VIDEO_CONFIG_BITRATETYPE config;
434         OMX_ERRORTYPE err;
435
436         GST_OMX_INIT_STRUCT (&config);
437         config.nPortIndex = self->enc_out_port->index;
438         config.nEncodeBitrate = self->target_bitrate;
439         err =
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);
446       }
447       break;
448     case PROP_QUANT_I_FRAMES:
449       self->quant_i_frames = g_value_get_uint (value);
450       break;
451     case PROP_QUANT_P_FRAMES:
452       self->quant_p_frames = g_value_get_uint (value);
453       break;
454     case PROP_QUANT_B_FRAMES:
455       self->quant_b_frames = g_value_get_uint (value);
456       break;
457     default:
458       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
459       break;
460   }
461 }
462
463 static void
464 gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value,
465     GParamSpec * pspec)
466 {
467   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
468
469   switch (prop_id) {
470     case PROP_CONTROL_RATE:
471       g_value_set_enum (value, self->control_rate);
472       break;
473     case PROP_TARGET_BITRATE:
474       g_value_set_uint (value, self->target_bitrate);
475       break;
476     case PROP_QUANT_I_FRAMES:
477       g_value_set_uint (value, self->quant_i_frames);
478       break;
479     case PROP_QUANT_P_FRAMES:
480       g_value_set_uint (value, self->quant_p_frames);
481       break;
482     case PROP_QUANT_B_FRAMES:
483       g_value_set_uint (value, self->quant_b_frames);
484       break;
485     default:
486       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
487       break;
488   }
489 }
490
491 static GstStateChangeReturn
492 gst_omx_video_enc_change_state (GstElement * element, GstStateChange transition)
493 {
494   GstOMXVideoEnc *self;
495   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
496
497   g_return_val_if_fail (GST_IS_OMX_VIDEO_ENC (element),
498       GST_STATE_CHANGE_FAILURE);
499   self = GST_OMX_VIDEO_ENC (element);
500
501   switch (transition) {
502     case GST_STATE_CHANGE_NULL_TO_READY:
503       break;
504     case GST_STATE_CHANGE_READY_TO_PAUSED:
505       self->downstream_flow_ret = GST_FLOW_OK;
506
507       self->draining = FALSE;
508       self->started = FALSE;
509       break;
510     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
511       break;
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);
517
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);
522       break;
523     default:
524       break;
525   }
526
527   if (ret == GST_STATE_CHANGE_FAILURE)
528     return ret;
529
530   ret =
531       GST_ELEMENT_CLASS (gst_omx_video_enc_parent_class)->change_state (element,
532       transition);
533
534   if (ret == GST_STATE_CHANGE_FAILURE)
535     return ret;
536
537   switch (transition) {
538     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
539       break;
540     case GST_STATE_CHANGE_PAUSED_TO_READY:
541       self->downstream_flow_ret = GST_FLOW_FLUSHING;
542       self->started = FALSE;
543
544       if (!gst_omx_video_enc_shutdown (self))
545         ret = GST_STATE_CHANGE_FAILURE;
546       break;
547     case GST_STATE_CHANGE_READY_TO_NULL:
548       break;
549     default:
550       break;
551   }
552
553   return ret;
554 }
555
556 static GstFlowReturn
557 gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port,
558     GstOMXBuffer * buf, GstVideoCodecFrame * frame)
559 {
560   GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
561   GstFlowReturn flow_ret = GST_FLOW_OK;
562
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;
568     GstCaps *caps;
569
570     GST_DEBUG_OBJECT (self, "Handling codec data");
571
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);
574
575     gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
576     memcpy (map.data,
577         buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
578         buf->omx_buf->nFilledLen);
579     gst_buffer_unmap (codec_data, &map);
580     state =
581         gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
582         self->input_state);
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;
588     }
589     flow_ret = GST_FLOW_OK;
590   } else if (buf->omx_buf->nFilledLen > 0) {
591     GstBuffer *outbuf;
592     GstMapInfo map = GST_MAP_INFO_INIT;
593
594     GST_DEBUG_OBJECT (self, "Handling output data");
595
596     if (buf->omx_buf->nFilledLen > 0) {
597       outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
598
599       gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
600       memcpy (map.data,
601           buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
602           buf->omx_buf->nFilledLen);
603       gst_buffer_unmap (outbuf, &map);
604     } else {
605       outbuf = gst_buffer_new ();
606     }
607
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);
615
616     if ((klass->cdata.hacks & GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED)
617         || (buf->omx_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
618       if (frame)
619         GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
620       else
621         GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
622     } else {
623       if (frame)
624         GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
625       else
626         GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
627     }
628
629     if (frame) {
630       frame->output_buffer = outbuf;
631       flow_ret =
632           gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
633     } else {
634       GST_ERROR_OBJECT (self, "No corresponding frame found");
635       flow_ret = gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (self), outbuf);
636     }
637   } else if (frame != NULL) {
638     flow_ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
639   }
640
641   return flow_ret;
642 }
643
644 static void
645 gst_omx_video_enc_loop (GstOMXVideoEnc * self)
646 {
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;
653   OMX_ERRORTYPE err;
654
655   klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
656
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) {
661     goto flushing;
662   } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
663     goto eos;
664   }
665
666   if (!gst_pad_has_current_caps (GST_VIDEO_ENCODER_SRC_PAD (self))
667       || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
668     GstCaps *caps;
669     GstVideoCodecState *state;
670
671     GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
672
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;
679
680       err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
681       if (err != OMX_ErrorNone)
682         goto reconfigure_error;
683
684       err = gst_omx_port_deallocate_buffers (port);
685       if (err != OMX_ErrorNone)
686         goto reconfigure_error;
687
688       err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
689       if (err != OMX_ErrorNone)
690         goto reconfigure_error;
691     }
692
693     GST_VIDEO_ENCODER_STREAM_LOCK (self);
694
695     caps = klass->get_caps (self, self->enc_out_port, self->input_state);
696     if (!caps) {
697       if (buf)
698         gst_omx_port_release_buffer (self->enc_out_port, buf);
699       GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
700       goto caps_failed;
701     }
702
703     GST_DEBUG_OBJECT (self, "Setting output state: %" GST_PTR_FORMAT, caps);
704
705     state =
706         gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
707         self->input_state);
708     gst_video_codec_state_unref (state);
709
710     if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
711       if (buf)
712         gst_omx_port_release_buffer (self->enc_out_port, buf);
713       GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
714       goto caps_failed;
715     }
716
717     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
718
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);
726 #else
727       err = gst_omx_port_allocate_buffers (port);
728 #endif
729       if (err != OMX_ErrorNone)
730         goto reconfigure_error;
731
732       err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
733       if (err != OMX_ErrorNone)
734         goto reconfigure_error;
735
736       err = gst_omx_port_populate (port);
737       if (err != OMX_ErrorNone)
738         goto reconfigure_error;
739
740       err = gst_omx_port_mark_reconfigured (port);
741       if (err != OMX_ErrorNone)
742         goto reconfigure_error;
743     }
744
745     /* Now get a buffer */
746     if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
747       return;
748     }
749   }
750
751   g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
752
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
756    */
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);
760     goto flushing;
761   }
762
763   GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %" G_GUINT64_FORMAT,
764       (guint) buf->omx_buf->nFlags, (guint64) buf->omx_buf->nTimeStamp);
765
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)));
769
770   g_assert (klass->handle_output_frame);
771   flow_ret = klass->handle_output_frame (self, self->enc_out_port, buf, frame);
772
773   GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
774
775   err = gst_omx_port_release_buffer (port, buf);
776   if (err != OMX_ErrorNone)
777     goto release_error;
778
779   self->downstream_flow_ret = flow_ret;
780
781   GST_DEBUG_OBJECT (self, "Read frame from component");
782
783   if (flow_ret != GST_FLOW_OK)
784     goto flow_error;
785
786   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
787
788   return;
789
790 component_error:
791   {
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;
800     return;
801   }
802 flushing:
803   {
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;
808     return;
809   }
810
811 eos:
812   {
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));
820     } else {
821       GST_DEBUG_OBJECT (self, "Component signalled EOS");
822       flow_ret = GST_FLOW_EOS;
823     }
824     g_mutex_unlock (&self->drain_lock);
825
826     GST_VIDEO_ENCODER_STREAM_LOCK (self);
827     self->downstream_flow_ret = flow_ret;
828
829     /* Here we fallback and pause the task for the EOS case */
830     if (flow_ret != GST_FLOW_OK)
831       goto flow_error;
832
833     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
834
835     return;
836   }
837 flow_error:
838   {
839     if (flow_ret == GST_FLOW_EOS) {
840       GST_DEBUG_OBJECT (self, "EOS");
841
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)));
849
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;
858     }
859     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
860     return;
861   }
862 reconfigure_error:
863   {
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;
870     return;
871   }
872 caps_failed:
873   {
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;
879     return;
880   }
881 release_error:
882   {
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);
891     return;
892   }
893 }
894
895 static gboolean
896 gst_omx_video_enc_start (GstVideoEncoder * encoder)
897 {
898   GstOMXVideoEnc *self;
899
900   self = GST_OMX_VIDEO_ENC (encoder);
901
902   self->last_upstream_ts = 0;
903   self->downstream_flow_ret = GST_FLOW_OK;
904
905   return TRUE;
906 }
907
908 static gboolean
909 gst_omx_video_enc_stop (GstVideoEncoder * encoder)
910 {
911   GstOMXVideoEnc *self;
912
913   self = GST_OMX_VIDEO_ENC (encoder);
914
915   GST_DEBUG_OBJECT (self, "Stopping encoder");
916
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);
919
920   gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
921
922   if (gst_omx_component_get_state (self->enc, 0) > OMX_StateIdle)
923     gst_omx_component_set_state (self->enc, OMX_StateIdle);
924
925   self->downstream_flow_ret = GST_FLOW_FLUSHING;
926   self->started = FALSE;
927
928   if (self->input_state)
929     gst_video_codec_state_unref (self->input_state);
930   self->input_state = NULL;
931
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);
936
937   gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
938
939   return TRUE;
940 }
941
942 static gboolean
943 gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
944     GstVideoCodecState * state)
945 {
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;
952
953   self = GST_OMX_VIDEO_ENC (encoder);
954   klass = GST_OMX_VIDEO_ENC_GET_CLASS (encoder);
955
956   GST_DEBUG_OBJECT (self, "Setting new format %s",
957       gst_video_format_to_string (info->finfo->format));
958
959   gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
960
961   needs_disable =
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.
967    */
968   if (needs_disable) {
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);
972
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);
979
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);
985
986       if (!gst_omx_video_enc_open (GST_VIDEO_ENCODER (self)))
987         return FALSE;
988       needs_disable = FALSE;
989     } else {
990       if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
991         return FALSE;
992       if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
993         return FALSE;
994       if (gst_omx_port_wait_buffers_released (self->enc_in_port,
995               5 * GST_SECOND) != OMX_ErrorNone)
996         return FALSE;
997       if (gst_omx_port_wait_buffers_released (self->enc_out_port,
998               1 * GST_SECOND) != OMX_ErrorNone)
999         return FALSE;
1000       if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1001         return FALSE;
1002       if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1003         return FALSE;
1004       if (gst_omx_port_wait_enabled (self->enc_in_port,
1005               1 * GST_SECOND) != OMX_ErrorNone)
1006         return FALSE;
1007       if (gst_omx_port_wait_enabled (self->enc_out_port,
1008               1 * GST_SECOND) != OMX_ErrorNone)
1009         return FALSE;
1010     }
1011
1012     GST_DEBUG_OBJECT (self, "Encoder drained and disabled");
1013   }
1014
1015   negotiation_map =
1016       gst_omx_video_get_supported_colorformats (self->enc_in_port,
1017       self->input_state);
1018   if (!negotiation_map) {
1019     /* Fallback */
1020     switch (info->finfo->format) {
1021       case GST_VIDEO_FORMAT_I420:
1022         port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
1023         break;
1024       case GST_VIDEO_FORMAT_NV12:
1025         port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
1026         break;
1027       default:
1028         GST_ERROR_OBJECT (self, "Unsupported format %s",
1029             gst_video_format_to_string (info->finfo->format));
1030         return FALSE;
1031         break;
1032     }
1033   } else {
1034     for (l = negotiation_map; l; l = l->next) {
1035       GstOMXVideoNegotiationMap *m = l->data;
1036
1037       if (m->format == info->finfo->format) {
1038         port_def.format.video.eColorFormat = m->type;
1039         break;
1040       }
1041     }
1042     g_list_free_full (negotiation_map,
1043         (GDestroyNotify) gst_omx_video_negotiation_map_free);
1044   }
1045
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));
1051   else
1052     port_def.format.video.nStride = GST_ROUND_UP_4 (info->width);       /* safe (?) default */
1053
1054   port_def.format.video.nFrameHeight = info->height;
1055   port_def.format.video.nSliceHeight = info->height;
1056
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));
1064       break;
1065
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));
1071       break;
1072
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);
1077 #endif
1078         break;
1079
1080     default:
1081       g_assert_not_reached ();
1082   }
1083
1084   if (info->fps_n == 0) {
1085     port_def.format.video.xFramerate = 0;
1086   } else {
1087     if (!(klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER))
1088       port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d);
1089     else
1090       port_def.format.video.xFramerate = (info->fps_n) / (info->fps_d);
1091   }
1092
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)
1096     return FALSE;
1097
1098 #ifdef USE_OMX_TARGET_RPI
1099   /* aspect ratio */
1100   {
1101     OMX_ERRORTYPE err;
1102     OMX_CONFIG_POINTTYPE aspect_ratio_param;
1103
1104     GST_OMX_INIT_STRUCT (&aspect_ratio_param);
1105     aspect_ratio_param.nPortIndex = self->enc_out_port->index;
1106
1107     err = gst_omx_component_get_parameter (self->enc,
1108         OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
1109
1110     if (err == OMX_ErrorNone) {
1111
1112       aspect_ratio_param.nX = info->par_n;
1113       aspect_ratio_param.nY = info->par_d;
1114
1115       err =
1116           gst_omx_component_set_parameter (self->enc,
1117           OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
1118
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);
1130         return FALSE;
1131       }
1132     }
1133   }
1134 #endif // USE_OMX_TARGET_RPI
1135
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");
1139       return FALSE;
1140     }
1141   }
1142
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)
1146     return FALSE;
1147
1148   if (self->target_bitrate != 0xffffffff) {
1149     OMX_VIDEO_PARAM_BITRATETYPE config;
1150     OMX_ERRORTYPE err;
1151
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);
1161   }
1162
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)
1166       return FALSE;
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)
1170         return FALSE;
1171 #else
1172     if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1173       return FALSE;
1174 #endif
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)
1177         return FALSE;
1178       if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1179         return FALSE;
1180
1181       if (gst_omx_port_wait_enabled (self->enc_out_port,
1182               5 * GST_SECOND) != OMX_ErrorNone)
1183         return FALSE;
1184     }
1185
1186     if (gst_omx_port_wait_enabled (self->enc_in_port,
1187             5 * GST_SECOND) != OMX_ErrorNone)
1188       return FALSE;
1189     if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone)
1190       return FALSE;
1191   } else {
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)
1195         return FALSE;
1196
1197       if (gst_omx_port_wait_enabled (self->enc_out_port,
1198               1 * GST_SECOND) != OMX_ErrorNone)
1199         return FALSE;
1200
1201       if (gst_omx_component_set_state (self->enc,
1202               OMX_StateIdle) != OMX_ErrorNone)
1203         return FALSE;
1204
1205       /* Need to allocate buffers to reach Idle state */
1206
1207       if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1208         return FALSE;
1209     } else {
1210       if (gst_omx_component_set_state (self->enc,
1211               OMX_StateIdle) != OMX_ErrorNone)
1212         return FALSE;
1213
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)
1218         return FALSE;
1219 #else
1220       if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1221         return FALSE;
1222 #endif
1223
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)
1227 #else
1228       if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1229 #endif
1230         return FALSE;
1231     }
1232
1233     if (gst_omx_component_get_state (self->enc,
1234             GST_CLOCK_TIME_NONE) != OMX_StateIdle)
1235       return FALSE;
1236
1237     if (gst_omx_component_set_state (self->enc,
1238             OMX_StateExecuting) != OMX_ErrorNone)
1239       return FALSE;
1240
1241     if (gst_omx_component_get_state (self->enc,
1242             GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
1243       return FALSE;
1244   }
1245
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);
1249
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));
1254     return FALSE;
1255   }
1256
1257   if (self->input_state)
1258     gst_video_codec_state_unref (self->input_state);
1259   self->input_state = gst_video_codec_state_ref (state);
1260
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);
1266
1267   return TRUE;
1268 }
1269
1270 static gboolean
1271 gst_omx_video_enc_flush (GstVideoEncoder * encoder)
1272 {
1273   GstOMXVideoEnc *self;
1274
1275   self = GST_OMX_VIDEO_ENC (encoder);
1276
1277   GST_DEBUG_OBJECT (self, "Flushing encoder");
1278
1279   if (gst_omx_component_get_state (self->enc, 0) == OMX_StateLoaded)
1280     return TRUE;
1281
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);
1284
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);
1292
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);
1296
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);
1302
1303   return TRUE;
1304 }
1305
1306 static gboolean
1307 gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf,
1308     GstOMXBuffer * outbuf)
1309 {
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;
1315
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");
1319     goto done;
1320   }
1321
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);
1326
1327     gst_buffer_extract (inbuf, 0,
1328         outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset,
1329         outbuf->omx_buf->nFilledLen);
1330     ret = TRUE;
1331     goto done;
1332   }
1333
1334   /* Different strides */
1335
1336   switch (info->finfo->format) {
1337     case GST_VIDEO_FORMAT_I420:{
1338       gint i, j, height, width;
1339       guint8 *src, *dest;
1340       gint src_stride, dest_stride;
1341
1342       outbuf->omx_buf->nFilledLen = 0;
1343
1344       if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
1345         GST_ERROR_OBJECT (self, "Invalid input buffer size");
1346         ret = FALSE;
1347         break;
1348       }
1349
1350       for (i = 0; i < 3; i++) {
1351         if (i == 0) {
1352           dest_stride = port_def->format.video.nStride;
1353           src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
1354
1355           /* XXX: Try this if no stride was set */
1356           if (dest_stride == 0)
1357             dest_stride = src_stride;
1358         } else {
1359           dest_stride = port_def->format.video.nStride / 2;
1360           src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
1361
1362           /* XXX: Try this if no stride was set */
1363           if (dest_stride == 0)
1364             dest_stride = src_stride;
1365         }
1366
1367         dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
1368         if (i > 0)
1369           dest +=
1370               port_def->format.video.nSliceHeight *
1371               port_def->format.video.nStride;
1372         if (i == 2)
1373           dest +=
1374               (port_def->format.video.nSliceHeight / 2) *
1375               (port_def->format.video.nStride / 2);
1376
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);
1380
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");
1385           ret = FALSE;
1386           break;
1387         }
1388
1389         for (j = 0; j < height; j++) {
1390           memcpy (dest, src, width);
1391           outbuf->omx_buf->nFilledLen += dest_stride;
1392           src += src_stride;
1393           dest += dest_stride;
1394         }
1395       }
1396       gst_video_frame_unmap (&frame);
1397       ret = TRUE;
1398       break;
1399     }
1400     case GST_VIDEO_FORMAT_NV12:{
1401       gint i, j, height, width;
1402       guint8 *src, *dest;
1403       gint src_stride, dest_stride;
1404
1405       outbuf->omx_buf->nFilledLen = 0;
1406
1407       if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
1408         GST_ERROR_OBJECT (self, "Invalid input buffer size");
1409         ret = FALSE;
1410         break;
1411       }
1412
1413       for (i = 0; i < 2; i++) {
1414         if (i == 0) {
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;
1420         } else {
1421           dest_stride = port_def->format.video.nStride;
1422           src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
1423
1424           /* XXX: Try this if no stride was set */
1425           if (dest_stride == 0)
1426             dest_stride = src_stride;
1427         }
1428
1429         dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
1430         if (i == 1)
1431           dest +=
1432               port_def->format.video.nSliceHeight *
1433               port_def->format.video.nStride;
1434
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);
1438
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");
1443           ret = FALSE;
1444           break;
1445         }
1446
1447         for (j = 0; j < height; j++) {
1448           memcpy (dest, src, width);
1449           outbuf->omx_buf->nFilledLen += dest_stride;
1450           src += src_stride;
1451           dest += dest_stride;
1452         }
1453
1454       }
1455       gst_video_frame_unmap (&frame);
1456       ret = TRUE;
1457       break;
1458     }
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;
1464
1465         if (!ext_memory) {
1466           GST_WARNING_OBJECT (self, "null MMVideoBuffer pointer  in hw color format. skip this.");
1467           goto done;
1468         }
1469
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);
1473
1474         if (ext_buf != NULL && ext_buf->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
1475
1476           if (ext_buf->handle.dmabuf_fd[0] == NULL)
1477             gst_omx_tbm_get_bo_fd(ext_buf->handle.bo[0]);
1478
1479           if (ext_buf->handle.dmabuf_fd[1] == NULL)
1480             gst_omx_tbm_get_bo_fd(ext_buf->handle.bo[1]);
1481
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);
1484         } else {
1485           GST_WARNING_OBJECT (self, "enc input buf has wrong buf_share_method[%d]", ext_buf->type);
1486         }
1487
1488         outbuf->omx_buf->nAllocLen = sizeof(MMVideoBuffer);
1489         outbuf->omx_buf->nFilledLen = sizeof(MMVideoBuffer);
1490         memcpy (outbuf->omx_buf->pBuffer, ext_buf, sizeof(MMVideoBuffer));
1491
1492 #ifdef CODEC_ENC_INPUT_DUMP
1493         gst_omx_video_enc_input_dump(ext_buf);
1494 #endif
1495
1496         ret = TRUE;
1497         break;
1498     }
1499     default:
1500       GST_ERROR_OBJECT (self, "Unsupported format");
1501       goto done;
1502       break;
1503   }
1504
1505 done:
1506
1507   gst_video_codec_state_unref (state);
1508
1509   return ret;
1510 }
1511
1512 static GstFlowReturn
1513 gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
1514     GstVideoCodecFrame * frame)
1515 {
1516   GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
1517   GstOMXVideoEnc *self;
1518   GstOMXPort *port;
1519   GstOMXBuffer *buf;
1520   OMX_ERRORTYPE err;
1521
1522   self = GST_OMX_VIDEO_ENC (encoder);
1523
1524   GST_DEBUG_OBJECT (self, "Handling frame");
1525
1526   if (self->downstream_flow_ret != GST_FLOW_OK) {
1527     gst_video_codec_frame_unref (frame);
1528     return self->downstream_flow_ret;
1529   }
1530
1531   port = self->enc_in_port;
1532
1533   while (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
1534     GstClockTime timestamp, duration;
1535
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);
1541
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);
1547       goto flushing;
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;
1554       }
1555
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;
1560       }
1561
1562       err = gst_omx_port_deallocate_buffers (port);
1563       if (err != OMX_ErrorNone) {
1564         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1565         goto reconfigure_error;
1566       }
1567
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;
1572       }
1573
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;
1578       }
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);
1582 #else
1583       err = gst_omx_port_allocate_buffers (port);
1584 #endif
1585       if (err != OMX_ErrorNone) {
1586         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1587         goto reconfigure_error;
1588       }
1589
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;
1594       }
1595
1596       err = gst_omx_port_mark_reconfigured (port);
1597       if (err != OMX_ErrorNone) {
1598         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1599         goto reconfigure_error;
1600       }
1601
1602       /* Now get a new buffer and fill it */
1603       GST_VIDEO_ENCODER_STREAM_LOCK (self);
1604       continue;
1605     }
1606     GST_VIDEO_ENCODER_STREAM_LOCK (self);
1607
1608     g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
1609
1610     if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
1611       gst_omx_port_release_buffer (port, buf);
1612       goto full_buffer;
1613     }
1614
1615     if (self->downstream_flow_ret != GST_FLOW_OK) {
1616       gst_omx_port_release_buffer (port, buf);
1617       goto flow_error;
1618     }
1619
1620     /* Now handle the frame */
1621     GST_DEBUG_OBJECT (self, "Handling frame");
1622
1623     if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
1624 #ifdef USE_OMX_TARGET_RPI
1625       OMX_CONFIG_BOOLEANTYPE config;
1626
1627       GST_OMX_INIT_STRUCT (&config);
1628       config.bEnabled = OMX_TRUE;
1629
1630       GST_DEBUG_OBJECT (self, "Forcing a keyframe (iframe on the RPi)");
1631
1632       err =
1633           gst_omx_component_set_config (self->enc,
1634           OMX_IndexConfigBrcmVideoRequestIFrame, &config);
1635 #else
1636       OMX_CONFIG_INTRAREFRESHVOPTYPE config;
1637
1638       GST_OMX_INIT_STRUCT (&config);
1639       config.nPortIndex = port->index;
1640       config.IntraRefreshVOP = OMX_TRUE;
1641
1642       GST_DEBUG_OBJECT (self, "Forcing a keyframe");
1643       err =
1644           gst_omx_component_set_config (self->enc,
1645           OMX_IndexConfigVideoIntraVOPRefresh, &config);
1646 #endif
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);
1650     }
1651
1652     /* Copy the buffer content in chunks of size as requested
1653      * by the port */
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;
1657     }
1658
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;
1664     }
1665
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;
1671     } else {
1672       buf->omx_buf->nTickCount = 0;
1673     }
1674
1675     self->started = TRUE;
1676     err = gst_omx_port_release_buffer (port, buf);
1677     if (err != OMX_ErrorNone)
1678       goto release_error;
1679
1680     GST_DEBUG_OBJECT (self, "Passed frame to component");
1681   }
1682
1683   gst_video_codec_frame_unref (frame);
1684
1685   return self->downstream_flow_ret;
1686
1687 full_buffer:
1688   {
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;
1694   }
1695
1696 flow_error:
1697   {
1698     gst_video_codec_frame_unref (frame);
1699     return self->downstream_flow_ret;
1700   }
1701
1702 component_error:
1703   {
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;
1710   }
1711
1712 flushing:
1713   {
1714     GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
1715     gst_video_codec_frame_unref (frame);
1716     return GST_FLOW_FLUSHING;
1717   }
1718 reconfigure_error:
1719   {
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;
1724   }
1725 buffer_fill_error:
1726   {
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;
1731   }
1732 release_error:
1733   {
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;
1739   }
1740 }
1741
1742 static GstFlowReturn
1743 gst_omx_video_enc_finish (GstVideoEncoder * encoder)
1744 {
1745   GstOMXVideoEnc *self;
1746
1747   self = GST_OMX_VIDEO_ENC (encoder);
1748
1749   return gst_omx_video_enc_drain (self);
1750 }
1751
1752 static GstFlowReturn
1753 gst_omx_video_enc_drain (GstOMXVideoEnc * self)
1754 {
1755   GstOMXVideoEncClass *klass;
1756   GstOMXBuffer *buf;
1757   GstOMXAcquireBufferReturn acq_ret;
1758   OMX_ERRORTYPE err;
1759
1760   GST_DEBUG_OBJECT (self, "Draining component");
1761
1762   klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1763
1764   if (!self->started) {
1765     GST_DEBUG_OBJECT (self, "Component not started yet");
1766     return GST_FLOW_OK;
1767   }
1768   self->started = FALSE;
1769
1770   if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
1771     GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
1772     return GST_FLOW_OK;
1773   }
1774
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);
1779
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",
1787         acq_ret);
1788     return GST_FLOW_ERROR;
1789   }
1790
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,
1796       GST_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;
1805   }
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);
1811
1812   self->started = FALSE;
1813
1814   return GST_FLOW_OK;
1815 }
1816
1817 static gboolean
1818 gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
1819     GstQuery * query)
1820 {
1821   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1822
1823   return
1824       GST_VIDEO_ENCODER_CLASS
1825       (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query);
1826 }
1827
1828 static GstCaps *
1829 gst_omx_video_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
1830 {
1831   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
1832   GList *negotiation_map = NULL;
1833   GstCaps *comp_supported_caps;
1834
1835   if (!self->enc)
1836     return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
1837
1838   negotiation_map =
1839       gst_omx_video_get_supported_colorformats (self->enc_in_port,
1840       self->input_state);
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);
1844
1845   if (!gst_caps_is_empty (comp_supported_caps)) {
1846     GstCaps *ret =
1847         gst_video_encoder_proxy_getcaps (encoder, comp_supported_caps, filter);
1848
1849     gst_caps_unref (comp_supported_caps);
1850     return ret;
1851   } else {
1852     gst_caps_unref (comp_supported_caps);
1853     return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
1854   }
1855 }