Merge tizen patch based on 1.12.2
[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 //#define CODEC_ENC_INPUT_DUMP
38 GST_DEBUG_CATEGORY_STATIC (gst_omx_video_enc_debug_category);
39 #define GST_CAT_DEFAULT gst_omx_video_enc_debug_category
40
41 #define GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE (gst_omx_video_enc_control_rate_get_type ())
42
43 #ifdef CODEC_ENC_INPUT_DUMP
44 #include <stdio.h>
45 #endif
46
47 static GType
48 gst_omx_video_enc_control_rate_get_type (void)
49 {
50   static GType qtype = 0;
51
52   if (qtype == 0) {
53     static const GEnumValue values[] = {
54       {OMX_Video_ControlRateDisable, "Disable", "disable"},
55       {OMX_Video_ControlRateVariable, "Variable", "variable"},
56       {OMX_Video_ControlRateConstant, "Constant", "constant"},
57       {OMX_Video_ControlRateVariableSkipFrames, "Variable Skip Frames",
58           "variable-skip-frames"},
59       {OMX_Video_ControlRateConstantSkipFrames, "Constant Skip Frames",
60           "constant-skip-frames"},
61       {0xffffffff, "Component Default", "default"},
62       {0, NULL, NULL}
63     };
64
65     qtype = g_enum_register_static ("GstOMXVideoEncControlRate", values);
66   }
67   return qtype;
68 }
69
70 /* prototypes */
71 static void gst_omx_video_enc_finalize (GObject * object);
72 static void gst_omx_video_enc_set_property (GObject * object, guint prop_id,
73     const GValue * value, GParamSpec * pspec);
74 static void gst_omx_video_enc_get_property (GObject * object, guint prop_id,
75     GValue * value, GParamSpec * pspec);
76
77
78 static GstStateChangeReturn
79 gst_omx_video_enc_change_state (GstElement * element,
80     GstStateChange transition);
81
82 static gboolean gst_omx_video_enc_open (GstVideoEncoder * encoder);
83 static gboolean gst_omx_video_enc_close (GstVideoEncoder * encoder);
84 static gboolean gst_omx_video_enc_start (GstVideoEncoder * encoder);
85 static gboolean gst_omx_video_enc_stop (GstVideoEncoder * encoder);
86 static gboolean gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
87     GstVideoCodecState * state);
88 static gboolean gst_omx_video_enc_flush (GstVideoEncoder * encoder);
89 static GstFlowReturn gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
90     GstVideoCodecFrame * frame);
91 static gboolean gst_omx_video_enc_finish (GstVideoEncoder * encoder);
92 static gboolean gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
93     GstQuery * query);
94 static GstCaps *gst_omx_video_enc_getcaps (GstVideoEncoder * encoder,
95     GstCaps * filter);
96
97 static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self);
98
99 static GstFlowReturn gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc *
100     self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame);
101
102 enum
103 {
104   PROP_0,
105   PROP_CONTROL_RATE,
106   PROP_TARGET_BITRATE,
107   PROP_QUANT_I_FRAMES,
108   PROP_QUANT_P_FRAMES,
109   PROP_QUANT_B_FRAMES
110 };
111
112 /* FIXME: Better defaults */
113 #define GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT (0xffffffff)
114 #define GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT (0xffffffff)
115 #define GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT (0xffffffff)
116 #define GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT (0xffffffff)
117 #define GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT (0xffffffff)
118
119
120 /* class initialization */
121
122 #define DEBUG_INIT \
123   GST_DEBUG_CATEGORY_INIT (gst_omx_video_enc_debug_category, "omxvideoenc", 0, \
124       "debug category for gst-omx video encoder base class");
125
126 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoEnc, gst_omx_video_enc,
127     GST_TYPE_VIDEO_ENCODER, DEBUG_INIT);
128
129 static void
130 gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass)
131 {
132   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
133   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
134   GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
135
136
137   gobject_class->finalize = gst_omx_video_enc_finalize;
138   gobject_class->set_property = gst_omx_video_enc_set_property;
139   gobject_class->get_property = gst_omx_video_enc_get_property;
140
141   g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
142       g_param_spec_enum ("control-rate", "Control Rate",
143           "Bitrate control method",
144           GST_TYPE_OMX_VIDEO_ENC_CONTROL_RATE,
145           GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT,
146           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
147           GST_PARAM_MUTABLE_READY));
148
149   g_object_class_install_property (gobject_class, PROP_TARGET_BITRATE,
150       g_param_spec_uint ("target-bitrate", "Target Bitrate",
151           "Target bitrate (0xffffffff=component default)",
152           0, G_MAXUINT, GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT,
153           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
154           GST_PARAM_MUTABLE_PLAYING));
155
156   g_object_class_install_property (gobject_class, PROP_QUANT_I_FRAMES,
157       g_param_spec_uint ("quant-i-frames", "I-Frame Quantization",
158           "Quantization parameter for I-frames (0xffffffff=component default)",
159           0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_I_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_P_FRAMES,
164       g_param_spec_uint ("quant-p-frames", "P-Frame Quantization",
165           "Quantization parameter for P-frames (0xffffffff=component default)",
166           0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT,
167           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
168           GST_PARAM_MUTABLE_READY));
169
170   g_object_class_install_property (gobject_class, PROP_QUANT_B_FRAMES,
171       g_param_spec_uint ("quant-b-frames", "B-Frame Quantization",
172           "Quantization parameter for B-frames (0xffffffff=component default)",
173           0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT,
174           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
175           GST_PARAM_MUTABLE_READY));
176
177   element_class->change_state =
178       GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state);
179
180   video_encoder_class->open = GST_DEBUG_FUNCPTR (gst_omx_video_enc_open);
181   video_encoder_class->close = GST_DEBUG_FUNCPTR (gst_omx_video_enc_close);
182   video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_enc_start);
183   video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_enc_stop);
184   video_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_video_enc_flush);
185   video_encoder_class->set_format =
186       GST_DEBUG_FUNCPTR (gst_omx_video_enc_set_format);
187   video_encoder_class->handle_frame =
188       GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_frame);
189   video_encoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_enc_finish);
190   video_encoder_class->propose_allocation =
191       GST_DEBUG_FUNCPTR (gst_omx_video_enc_propose_allocation);
192   video_encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_omx_video_enc_getcaps);
193
194   klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER;
195   klass->cdata.default_sink_template_caps = "video/x-raw, "
196       "width = " GST_VIDEO_SIZE_RANGE ", "
197       "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE;
198
199   klass->handle_output_frame =
200       GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_output_frame);
201 }
202
203 static void
204 gst_omx_video_enc_init (GstOMXVideoEnc * self)
205 {
206   self->control_rate = GST_OMX_VIDEO_ENC_CONTROL_RATE_DEFAULT;
207   self->target_bitrate = GST_OMX_VIDEO_ENC_TARGET_BITRATE_DEFAULT;
208   self->quant_i_frames = GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT;
209   self->quant_p_frames = GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT;
210   self->quant_b_frames = GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT;
211
212   g_mutex_init (&self->drain_lock);
213   g_cond_init (&self->drain_cond);
214 #ifdef TIZEN_FEATURE_OMX
215   self->bufmgr = NULL;
216   self->drm_fd = -1;
217 #endif
218 }
219
220 #ifdef CODEC_ENC_INPUT_DUMP
221 static inline void
222 gst_omx_video_enc_input_dump (MMVideoBuffer *inbuf)
223 {
224   char *temp = (char *)inbuf->data[0];
225   int i = 0;
226   char filename[100]={0};
227   FILE *fp = NULL;
228
229   GST_WARNING ("codec enc input dump start. w = %d, h = %d", inbuf->width[0], inbuf->height[0]);
230
231   sprintf(filename, "/tmp/enc_input_dump_%d_%d.yuv", inbuf->width[0], inbuf->height[0]);
232   fp = fopen(filename, "ab");
233
234   for (i = 0; i < inbuf->height[0]; i++) {
235       fwrite(temp, inbuf->width[0], 1, fp);
236       temp += inbuf->stride_width[0];
237   }
238
239   temp = (char*)inbuf->data[1];
240
241   for(i = 0; i < inbuf->height[1] ; i++) {
242       fwrite(temp, inbuf->width[1], 1, fp);
243       temp += inbuf->stride_width[1];
244   }
245   GST_WARNING ("codec encoder input dumped!!");
246   fclose(fp);
247 }
248 #endif
249
250 static gboolean
251 gst_omx_video_enc_open (GstVideoEncoder * encoder)
252 {
253   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
254   GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
255   gint in_port_index, out_port_index;
256
257   self->enc =
258       gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
259       klass->cdata.component_name, klass->cdata.component_role,
260       klass->cdata.hacks);
261   self->started = FALSE;
262
263   if (!self->enc)
264     return FALSE;
265
266   if (gst_omx_component_get_state (self->enc,
267           GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
268     return FALSE;
269
270   in_port_index = klass->cdata.in_port_index;
271   out_port_index = klass->cdata.out_port_index;
272
273   if (in_port_index == -1 || out_port_index == -1) {
274     OMX_PORT_PARAM_TYPE param;
275     OMX_ERRORTYPE err;
276
277     GST_OMX_INIT_STRUCT (&param);
278
279     err =
280         gst_omx_component_get_parameter (self->enc, OMX_IndexParamVideoInit,
281         &param);
282     if (err != OMX_ErrorNone) {
283       GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
284           gst_omx_error_to_string (err), err);
285       /* Fallback */
286       in_port_index = 0;
287       out_port_index = 1;
288     } else {
289       GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
290           (guint) param.nPorts, (guint) param.nStartPortNumber);
291       in_port_index = param.nStartPortNumber + 0;
292       out_port_index = param.nStartPortNumber + 1;
293     }
294   }
295
296   self->enc_in_port = gst_omx_component_add_port (self->enc, in_port_index);
297   self->enc_out_port = gst_omx_component_add_port (self->enc, out_port_index);
298
299
300   if (!self->enc_in_port || !self->enc_out_port)
301     return FALSE;
302
303   /* Set properties */
304   {
305     OMX_ERRORTYPE err;
306
307     if (self->control_rate != 0xffffffff || self->target_bitrate != 0xffffffff) {
308       OMX_VIDEO_PARAM_BITRATETYPE bitrate_param;
309
310       GST_OMX_INIT_STRUCT (&bitrate_param);
311       bitrate_param.nPortIndex = self->enc_out_port->index;
312
313       err = gst_omx_component_get_parameter (self->enc,
314           OMX_IndexParamVideoBitrate, &bitrate_param);
315
316       if (err == OMX_ErrorNone) {
317 #ifdef USE_OMX_TARGET_RPI
318         /* FIXME: Workaround for RPi returning garbage for this parameter */
319         if (bitrate_param.nVersion.nVersion == 0) {
320           GST_OMX_INIT_STRUCT (&bitrate_param);
321           bitrate_param.nPortIndex = self->enc_out_port->index;
322         }
323 #endif
324         if (self->control_rate != 0xffffffff)
325           bitrate_param.eControlRate = self->control_rate;
326         if (self->target_bitrate != 0xffffffff)
327           bitrate_param.nTargetBitrate = self->target_bitrate;
328
329         err =
330             gst_omx_component_set_parameter (self->enc,
331             OMX_IndexParamVideoBitrate, &bitrate_param);
332         if (err == OMX_ErrorUnsupportedIndex) {
333           GST_WARNING_OBJECT (self,
334               "Setting a bitrate not supported by the component");
335         } else if (err == OMX_ErrorUnsupportedSetting) {
336           GST_WARNING_OBJECT (self,
337               "Setting bitrate settings %u %u not supported by the component",
338               self->control_rate, self->target_bitrate);
339         } else if (err != OMX_ErrorNone) {
340           GST_ERROR_OBJECT (self,
341               "Failed to set bitrate parameters: %s (0x%08x)",
342               gst_omx_error_to_string (err), err);
343           return FALSE;
344         }
345       } else {
346         GST_ERROR_OBJECT (self, "Failed to get bitrate parameters: %s (0x%08x)",
347             gst_omx_error_to_string (err), err);
348       }
349     }
350
351     if (self->quant_i_frames != 0xffffffff ||
352         self->quant_p_frames != 0xffffffff ||
353         self->quant_b_frames != 0xffffffff) {
354       OMX_VIDEO_PARAM_QUANTIZATIONTYPE quant_param;
355
356       GST_OMX_INIT_STRUCT (&quant_param);
357       quant_param.nPortIndex = self->enc_out_port->index;
358
359       err = gst_omx_component_get_parameter (self->enc,
360           OMX_IndexParamVideoQuantization, &quant_param);
361
362       if (err == OMX_ErrorNone) {
363
364         if (self->quant_i_frames != 0xffffffff)
365           quant_param.nQpI = self->quant_i_frames;
366         if (self->quant_p_frames != 0xffffffff)
367           quant_param.nQpP = self->quant_p_frames;
368         if (self->quant_b_frames != 0xffffffff)
369           quant_param.nQpB = self->quant_b_frames;
370
371         err =
372             gst_omx_component_set_parameter (self->enc,
373             OMX_IndexParamVideoQuantization, &quant_param);
374         if (err == OMX_ErrorUnsupportedIndex) {
375           GST_WARNING_OBJECT (self,
376               "Setting quantization parameters not supported by the component");
377         } else if (err == OMX_ErrorUnsupportedSetting) {
378           GST_WARNING_OBJECT (self,
379               "Setting quantization parameters %u %u %u not supported by the component",
380               self->quant_i_frames, self->quant_p_frames, self->quant_b_frames);
381         } else if (err != OMX_ErrorNone) {
382           GST_ERROR_OBJECT (self,
383               "Failed to set quantization parameters: %s (0x%08x)",
384               gst_omx_error_to_string (err), err);
385           return FALSE;
386         }
387       } else {
388         GST_ERROR_OBJECT (self,
389             "Failed to get quantization parameters: %s (0x%08x)",
390             gst_omx_error_to_string (err), err);
391
392       }
393     }
394   }
395 #ifdef TIZEN_FEATURE_OMX
396    self->bufmgr = tbm_bufmgr_init (self->drm_fd);
397    if (self->bufmgr == NULL){
398     GST_ERROR_OBJECT (self, "TBM initialization failed.");
399     return FALSE;
400    }
401
402   self->enc_in_port->use_buffer = klass->cdata.in_port_usebuffer;
403   self->enc_out_port->use_buffer = klass->cdata.out_port_usebuffer;
404
405   /* get extension index and set platform specific buffer enable */
406 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
407   {
408     OMX_ERRORTYPE err;
409     OMX_INDEXTYPE index = OMX_IndexComponentStartUnused;
410     EnableGemBuffersParams gem_param;
411
412     err = gst_omx_component_get_extension_index (self->enc, (OMX_STRING) EXYNOS_INDEX_PARAM_STORE_METADATA_BUFFER, &index);
413     if (err != OMX_ErrorNone) {
414       GST_WARNING_OBJECT (self, "Failed to get extension index : %s (0x%08x)",
415           gst_omx_error_to_string (err), err);
416     }
417
418     OMX_INIT_PARAM (gem_param);
419     gem_param.enable = OMX_TRUE;
420     gem_param.nPortIndex = 0;
421
422
423     err = gst_omx_component_set_parameter (self->enc, index, &gem_param);
424     if (err != OMX_ErrorNone) {
425       GST_ERROR_OBJECT (self, "Failed to set platform specific buffer: %s (0x%08x)",
426           gst_omx_error_to_string (err), err);
427     }
428
429   }
430 #endif
431 #endif
432   return TRUE;
433 }
434
435 static gboolean
436 gst_omx_video_enc_shutdown (GstOMXVideoEnc * self)
437 {
438   OMX_STATETYPE state;
439
440   GST_DEBUG_OBJECT (self, "Shutting down encoder");
441
442   state = gst_omx_component_get_state (self->enc, 0);
443   if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
444     if (state > OMX_StateIdle) {
445       gst_omx_component_set_state (self->enc, OMX_StateIdle);
446       gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
447     }
448     gst_omx_component_set_state (self->enc, OMX_StateLoaded);
449     gst_omx_port_deallocate_buffers (self->enc_in_port);
450     gst_omx_port_deallocate_buffers (self->enc_out_port);
451     if (state > OMX_StateLoaded)
452       gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
453   }
454
455   return TRUE;
456 }
457
458 static gboolean
459 gst_omx_video_enc_close (GstVideoEncoder * encoder)
460 {
461   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
462
463   GST_DEBUG_OBJECT (self, "Closing encoder");
464
465   if (!gst_omx_video_enc_shutdown (self))
466     return FALSE;
467
468   self->enc_in_port = NULL;
469   self->enc_out_port = NULL;
470   if (self->enc)
471     gst_omx_component_free (self->enc);
472   self->enc = NULL;
473
474   return TRUE;
475 }
476
477 static void
478 gst_omx_video_enc_finalize (GObject * object)
479 {
480   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
481
482   g_mutex_clear (&self->drain_lock);
483   g_cond_clear (&self->drain_cond);
484
485   G_OBJECT_CLASS (gst_omx_video_enc_parent_class)->finalize (object);
486 }
487
488 static void
489 gst_omx_video_enc_set_property (GObject * object, guint prop_id,
490     const GValue * value, GParamSpec * pspec)
491 {
492   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
493
494   switch (prop_id) {
495     case PROP_CONTROL_RATE:
496       self->control_rate = g_value_get_enum (value);
497       break;
498     case PROP_TARGET_BITRATE:
499       self->target_bitrate = g_value_get_uint (value);
500       if (self->enc) {
501         OMX_VIDEO_CONFIG_BITRATETYPE config;
502         OMX_ERRORTYPE err;
503
504         GST_OMX_INIT_STRUCT (&config);
505         config.nPortIndex = self->enc_out_port->index;
506         config.nEncodeBitrate = self->target_bitrate;
507         err =
508             gst_omx_component_set_config (self->enc,
509             OMX_IndexConfigVideoBitrate, &config);
510         if (err != OMX_ErrorNone)
511           GST_ERROR_OBJECT (self,
512               "Failed to set bitrate parameter: %s (0x%08x)",
513               gst_omx_error_to_string (err), err);
514       }
515       break;
516     case PROP_QUANT_I_FRAMES:
517       self->quant_i_frames = g_value_get_uint (value);
518       break;
519     case PROP_QUANT_P_FRAMES:
520       self->quant_p_frames = g_value_get_uint (value);
521       break;
522     case PROP_QUANT_B_FRAMES:
523       self->quant_b_frames = g_value_get_uint (value);
524       break;
525     default:
526       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
527       break;
528   }
529 }
530
531 static void
532 gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value,
533     GParamSpec * pspec)
534 {
535   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (object);
536
537   switch (prop_id) {
538     case PROP_CONTROL_RATE:
539       g_value_set_enum (value, self->control_rate);
540       break;
541     case PROP_TARGET_BITRATE:
542       g_value_set_uint (value, self->target_bitrate);
543       break;
544     case PROP_QUANT_I_FRAMES:
545       g_value_set_uint (value, self->quant_i_frames);
546       break;
547     case PROP_QUANT_P_FRAMES:
548       g_value_set_uint (value, self->quant_p_frames);
549       break;
550     case PROP_QUANT_B_FRAMES:
551       g_value_set_uint (value, self->quant_b_frames);
552       break;
553     default:
554       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
555       break;
556   }
557 }
558
559 static GstStateChangeReturn
560 gst_omx_video_enc_change_state (GstElement * element, GstStateChange transition)
561 {
562   GstOMXVideoEnc *self;
563   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
564
565   g_return_val_if_fail (GST_IS_OMX_VIDEO_ENC (element),
566       GST_STATE_CHANGE_FAILURE);
567   self = GST_OMX_VIDEO_ENC (element);
568
569   switch (transition) {
570     case GST_STATE_CHANGE_NULL_TO_READY:
571       break;
572     case GST_STATE_CHANGE_READY_TO_PAUSED:
573       self->downstream_flow_ret = GST_FLOW_OK;
574
575       self->draining = FALSE;
576       self->started = FALSE;
577       break;
578     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
579       break;
580     case GST_STATE_CHANGE_PAUSED_TO_READY:
581       if (self->enc_in_port)
582         gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
583       if (self->enc_out_port)
584         gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
585
586       g_mutex_lock (&self->drain_lock);
587       self->draining = FALSE;
588       g_cond_broadcast (&self->drain_cond);
589       g_mutex_unlock (&self->drain_lock);
590       break;
591     default:
592       break;
593   }
594
595   ret =
596       GST_ELEMENT_CLASS (gst_omx_video_enc_parent_class)->change_state (element,
597       transition);
598
599   if (ret == GST_STATE_CHANGE_FAILURE)
600     return ret;
601
602   switch (transition) {
603     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
604       break;
605     case GST_STATE_CHANGE_PAUSED_TO_READY:
606       self->downstream_flow_ret = GST_FLOW_FLUSHING;
607       self->started = FALSE;
608
609       if (!gst_omx_video_enc_shutdown (self))
610         ret = GST_STATE_CHANGE_FAILURE;
611       break;
612     case GST_STATE_CHANGE_READY_TO_NULL:
613       break;
614     default:
615       break;
616   }
617
618   return ret;
619 }
620
621 static GstFlowReturn
622 gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port,
623     GstOMXBuffer * buf, GstVideoCodecFrame * frame)
624 {
625   GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
626   GstFlowReturn flow_ret = GST_FLOW_OK;
627
628   if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
629       && buf->omx_buf->nFilledLen > 0) {
630     GstVideoCodecState *state;
631     GstBuffer *codec_data;
632     GstMapInfo map = GST_MAP_INFO_INIT;
633     GstCaps *caps;
634
635     GST_DEBUG_OBJECT (self, "Handling codec data");
636
637     caps = klass->get_caps (self, self->enc_out_port, self->input_state);
638     codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
639
640     gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
641     memcpy (map.data,
642         buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
643         buf->omx_buf->nFilledLen);
644     gst_buffer_unmap (codec_data, &map);
645     state =
646         gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
647         self->input_state);
648     state->codec_data = codec_data;
649     gst_video_codec_state_unref (state);
650 #ifdef TIZEN_FEATURE_OMX
651     /*Modification : codec data already set_caps, so unref frame whenever negotiate ok or not*/
652     if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self)))
653       flow_ret = GST_FLOW_NOT_NEGOTIATED;
654     else
655       flow_ret = GST_FLOW_OK;
656     gst_video_codec_frame_unref (frame);
657 #else
658     if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
659       gst_video_codec_frame_unref (frame);
660       return GST_FLOW_NOT_NEGOTIATED;
661     }
662     flow_ret = GST_FLOW_OK;
663 #endif
664   } else if (buf->omx_buf->nFilledLen > 0) {
665     GstBuffer *outbuf;
666     GstMapInfo map = GST_MAP_INFO_INIT;
667
668     GST_DEBUG_OBJECT (self, "Handling output data");
669
670     if (buf->omx_buf->nFilledLen > 0) {
671       outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
672
673       gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
674       memcpy (map.data,
675           buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
676           buf->omx_buf->nFilledLen);
677       gst_buffer_unmap (outbuf, &map);
678     } else {
679       outbuf = gst_buffer_new ();
680     }
681
682     GST_BUFFER_TIMESTAMP (outbuf) =
683         gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
684         OMX_TICKS_PER_SECOND);
685     if (buf->omx_buf->nTickCount != 0)
686       GST_BUFFER_DURATION (outbuf) =
687           gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
688           OMX_TICKS_PER_SECOND);
689
690     if ((klass->cdata.hacks & GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED)
691         || (buf->omx_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
692       if (frame)
693         GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
694       else
695         GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
696     } else {
697       if (frame)
698         GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
699       else
700         GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
701     }
702
703     if (frame) {
704       frame->output_buffer = outbuf;
705       flow_ret =
706           gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
707     } else {
708       GST_ERROR_OBJECT (self, "No corresponding frame found");
709       flow_ret = gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (self), outbuf);
710     }
711   } else if (frame != NULL) {
712     flow_ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
713   }
714
715   return flow_ret;
716 }
717
718 static void
719 gst_omx_video_enc_loop (GstOMXVideoEnc * self)
720 {
721   GstOMXVideoEncClass *klass;
722   GstOMXPort *port = self->enc_out_port;
723   GstOMXBuffer *buf = NULL;
724   GstVideoCodecFrame *frame;
725   GstFlowReturn flow_ret = GST_FLOW_OK;
726   GstOMXAcquireBufferReturn acq_return;
727   OMX_ERRORTYPE err;
728
729   klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
730
731   acq_return = gst_omx_port_acquire_buffer (port, &buf);
732   if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
733     goto component_error;
734   } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
735     goto flushing;
736   } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
737     goto eos;
738   }
739
740   if (!gst_pad_has_current_caps (GST_VIDEO_ENCODER_SRC_PAD (self))
741       || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
742     GstCaps *caps;
743     GstVideoCodecState *state;
744
745     GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
746
747     if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
748         && gst_omx_port_is_enabled (port)) {
749       /* Reallocate all buffers */
750       err = gst_omx_port_set_enabled (port, FALSE);
751       if (err != OMX_ErrorNone)
752         goto reconfigure_error;
753
754       err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
755       if (err != OMX_ErrorNone)
756         goto reconfigure_error;
757
758       err = gst_omx_port_deallocate_buffers (port);
759       if (err != OMX_ErrorNone)
760         goto reconfigure_error;
761
762       err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
763       if (err != OMX_ErrorNone)
764         goto reconfigure_error;
765     }
766
767     GST_VIDEO_ENCODER_STREAM_LOCK (self);
768
769     caps = klass->get_caps (self, self->enc_out_port, self->input_state);
770     if (!caps) {
771       if (buf)
772         gst_omx_port_release_buffer (self->enc_out_port, buf);
773       GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
774       goto caps_failed;
775     }
776
777     GST_DEBUG_OBJECT (self, "Setting output state: %" GST_PTR_FORMAT, caps);
778
779     state =
780         gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
781         self->input_state);
782     gst_video_codec_state_unref (state);
783
784     if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) {
785       if (buf)
786         gst_omx_port_release_buffer (self->enc_out_port, buf);
787       GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
788       goto caps_failed;
789     }
790
791     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
792
793     if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
794       err = gst_omx_port_set_enabled (port, TRUE);
795       if (err != OMX_ErrorNone)
796         goto reconfigure_error;
797 #ifdef TIZEN_FEATURE_OMX
798     err = gst_omx_port_tbm_allocate_enc_buffers(port, self->bufmgr, port->use_buffer);
799 #else
800       err = gst_omx_port_allocate_buffers (port);
801 #endif
802       if (err != OMX_ErrorNone)
803         goto reconfigure_error;
804
805       err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
806       if (err != OMX_ErrorNone)
807         goto reconfigure_error;
808
809       err = gst_omx_port_populate (port);
810       if (err != OMX_ErrorNone)
811         goto reconfigure_error;
812
813       err = gst_omx_port_mark_reconfigured (port);
814       if (err != OMX_ErrorNone)
815         goto reconfigure_error;
816     }
817
818     /* Now get a buffer */
819     if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
820       return;
821     }
822   }
823
824   g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
825
826   /* This prevents a deadlock between the srcpad stream
827    * lock and the videocodec stream lock, if ::flush()
828    * is called at the wrong time
829    */
830   if (gst_omx_port_is_flushing (self->enc_out_port)) {
831     GST_DEBUG_OBJECT (self, "Flushing");
832     gst_omx_port_release_buffer (self->enc_out_port, buf);
833     goto flushing;
834   }
835
836   GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %" G_GUINT64_FORMAT,
837       (guint) buf->omx_buf->nFlags, (guint64) buf->omx_buf->nTimeStamp);
838
839   GST_VIDEO_ENCODER_STREAM_LOCK (self);
840   frame = gst_omx_video_find_nearest_frame (buf,
841       gst_video_encoder_get_frames (GST_VIDEO_ENCODER (self)));
842
843   g_assert (klass->handle_output_frame);
844   flow_ret = klass->handle_output_frame (self, self->enc_out_port, buf, frame);
845
846   GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
847
848   err = gst_omx_port_release_buffer (port, buf);
849   if (err != OMX_ErrorNone)
850     goto release_error;
851
852   self->downstream_flow_ret = flow_ret;
853
854   GST_DEBUG_OBJECT (self, "Read frame from component");
855
856   if (flow_ret != GST_FLOW_OK)
857     goto flow_error;
858
859   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
860
861   return;
862
863 component_error:
864   {
865     GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
866         ("OpenMAX component in error state %s (0x%08x)",
867             gst_omx_component_get_last_error_string (self->enc),
868             gst_omx_component_get_last_error (self->enc)));
869     gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
870     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
871     self->downstream_flow_ret = GST_FLOW_ERROR;
872     self->started = FALSE;
873     return;
874   }
875 flushing:
876   {
877     GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
878     g_mutex_lock (&self->drain_lock);
879     if (self->draining) {
880       self->draining = FALSE;
881       g_cond_broadcast (&self->drain_cond);
882     }
883     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
884     self->downstream_flow_ret = GST_FLOW_FLUSHING;
885     self->started = FALSE;
886     g_mutex_unlock (&self->drain_lock);
887     return;
888   }
889
890 eos:
891   {
892     g_mutex_lock (&self->drain_lock);
893     if (self->draining) {
894       GST_DEBUG_OBJECT (self, "Drained");
895       self->draining = FALSE;
896       g_cond_broadcast (&self->drain_cond);
897       flow_ret = GST_FLOW_OK;
898       gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
899     } else {
900       GST_DEBUG_OBJECT (self, "Component signalled EOS");
901       flow_ret = GST_FLOW_EOS;
902     }
903     g_mutex_unlock (&self->drain_lock);
904
905     GST_VIDEO_ENCODER_STREAM_LOCK (self);
906     self->downstream_flow_ret = flow_ret;
907
908     /* Here we fallback and pause the task for the EOS case */
909     if (flow_ret != GST_FLOW_OK)
910       goto flow_error;
911
912     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
913
914     return;
915   }
916 flow_error:
917   {
918     if (flow_ret == GST_FLOW_EOS) {
919       GST_DEBUG_OBJECT (self, "EOS");
920
921       gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
922           gst_event_new_eos ());
923       gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
924       self->started = FALSE;
925     } else if (flow_ret < GST_FLOW_EOS) {
926       GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."),
927           ("stream stopped, reason %s", gst_flow_get_name (flow_ret)));
928
929       gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self),
930           gst_event_new_eos ());
931       gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
932       self->started = FALSE;
933     } else if (flow_ret == GST_FLOW_FLUSHING) {
934       GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
935       g_mutex_lock (&self->drain_lock);
936       if (self->draining) {
937         self->draining = FALSE;
938         g_cond_broadcast (&self->drain_cond);
939       }
940       gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
941       self->started = FALSE;
942       g_mutex_unlock (&self->drain_lock);
943     }
944     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
945     return;
946   }
947 reconfigure_error:
948   {
949     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
950         ("Unable to reconfigure output port"));
951     gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
952     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
953     self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
954     self->started = FALSE;
955     return;
956   }
957 caps_failed:
958   {
959     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
960     gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
961     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
962     self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
963     self->started = FALSE;
964     return;
965   }
966 release_error:
967   {
968     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
969         ("Failed to relase output buffer to component: %s (0x%08x)",
970             gst_omx_error_to_string (err), err));
971     gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
972     gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self));
973     self->downstream_flow_ret = GST_FLOW_ERROR;
974     self->started = FALSE;
975     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
976     return;
977   }
978 }
979
980 static gboolean
981 gst_omx_video_enc_start (GstVideoEncoder * encoder)
982 {
983   GstOMXVideoEnc *self;
984
985   self = GST_OMX_VIDEO_ENC (encoder);
986
987   self->last_upstream_ts = 0;
988   self->downstream_flow_ret = GST_FLOW_OK;
989
990   return TRUE;
991 }
992
993 static gboolean
994 gst_omx_video_enc_stop (GstVideoEncoder * encoder)
995 {
996   GstOMXVideoEnc *self;
997
998   self = GST_OMX_VIDEO_ENC (encoder);
999
1000   GST_DEBUG_OBJECT (self, "Stopping encoder");
1001
1002   gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
1003   gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1004
1005   gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1006
1007   if (gst_omx_component_get_state (self->enc, 0) > OMX_StateIdle)
1008     gst_omx_component_set_state (self->enc, OMX_StateIdle);
1009
1010   self->downstream_flow_ret = GST_FLOW_FLUSHING;
1011   self->started = FALSE;
1012
1013   if (self->input_state)
1014     gst_video_codec_state_unref (self->input_state);
1015   self->input_state = NULL;
1016
1017   g_mutex_lock (&self->drain_lock);
1018   self->draining = FALSE;
1019   g_cond_broadcast (&self->drain_cond);
1020   g_mutex_unlock (&self->drain_lock);
1021
1022   gst_omx_component_get_state (self->enc, 5 * GST_SECOND);
1023
1024   return TRUE;
1025 }
1026
1027 static gboolean
1028 gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
1029     GstVideoCodecState * state)
1030 {
1031   GstOMXVideoEnc *self;
1032   GstOMXVideoEncClass *klass;
1033   gboolean needs_disable = FALSE;
1034   OMX_PARAM_PORTDEFINITIONTYPE port_def;
1035   GstVideoInfo *info = &state->info;
1036   GList *negotiation_map = NULL, *l;
1037
1038   self = GST_OMX_VIDEO_ENC (encoder);
1039   klass = GST_OMX_VIDEO_ENC_GET_CLASS (encoder);
1040
1041   GST_DEBUG_OBJECT (self, "Setting new format %s",
1042       gst_video_format_to_string (info->finfo->format));
1043
1044   gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
1045
1046   needs_disable =
1047       gst_omx_component_get_state (self->enc,
1048       GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
1049   /* If the component is not in Loaded state and a real format change happens
1050    * we have to disable the port and re-allocate all buffers. If no real
1051    * format change happened we can just exit here.
1052    */
1053   if (needs_disable) {
1054     GST_DEBUG_OBJECT (self, "Need to disable and drain encoder");
1055     gst_omx_video_enc_drain (self);
1056     gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1057
1058     /* Wait until the srcpad loop is finished,
1059      * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
1060      * caused by using this lock from inside the loop function */
1061     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1062     gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1063     GST_VIDEO_ENCODER_STREAM_LOCK (self);
1064
1065     if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
1066       GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1067       gst_omx_video_enc_stop (GST_VIDEO_ENCODER (self));
1068       gst_omx_video_enc_close (GST_VIDEO_ENCODER (self));
1069       GST_VIDEO_ENCODER_STREAM_LOCK (self);
1070
1071       if (!gst_omx_video_enc_open (GST_VIDEO_ENCODER (self)))
1072         return FALSE;
1073       needs_disable = FALSE;
1074     } else {
1075       if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
1076         return FALSE;
1077       if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
1078         return FALSE;
1079       if (gst_omx_port_wait_buffers_released (self->enc_in_port,
1080               5 * GST_SECOND) != OMX_ErrorNone)
1081         return FALSE;
1082       if (gst_omx_port_wait_buffers_released (self->enc_out_port,
1083               1 * GST_SECOND) != OMX_ErrorNone)
1084         return FALSE;
1085       if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1086         return FALSE;
1087       if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1088         return FALSE;
1089       if (gst_omx_port_wait_enabled (self->enc_in_port,
1090               1 * GST_SECOND) != OMX_ErrorNone)
1091         return FALSE;
1092       if (gst_omx_port_wait_enabled (self->enc_out_port,
1093               1 * GST_SECOND) != OMX_ErrorNone)
1094         return FALSE;
1095     }
1096
1097     GST_DEBUG_OBJECT (self, "Encoder drained and disabled");
1098   }
1099
1100   negotiation_map =
1101       gst_omx_video_get_supported_colorformats (self->enc_in_port,
1102       self->input_state);
1103   if (!negotiation_map) {
1104     /* Fallback */
1105     switch (info->finfo->format) {
1106       case GST_VIDEO_FORMAT_I420:
1107         port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
1108         break;
1109       case GST_VIDEO_FORMAT_NV12:
1110         port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
1111         break;
1112       case GST_VIDEO_FORMAT_SN12:
1113         port_def.format.video.eColorFormat = OMX_EXT_COLOR_FormatNV12LPhysicalAddress;
1114         break;
1115       default:
1116         GST_ERROR_OBJECT (self, "Unsupported format %s",
1117             gst_video_format_to_string (info->finfo->format));
1118         return FALSE;
1119         break;
1120     }
1121   } else {
1122     for (l = negotiation_map; l; l = l->next) {
1123       GstOMXVideoNegotiationMap *m = l->data;
1124
1125       if (m->format == info->finfo->format) {
1126         port_def.format.video.eColorFormat = m->type;
1127         break;
1128       }
1129     }
1130     g_list_free_full (negotiation_map,
1131         (GDestroyNotify) gst_omx_video_negotiation_map_free);
1132   }
1133
1134   port_def.format.video.nFrameWidth = info->width;
1135 #ifdef TIZEN_FEATURE_OMX
1136   port_def.format.video.nStride = ALIGN(info->width, 16);
1137 #else
1138   if (port_def.nBufferAlignment)
1139     port_def.format.video.nStride =
1140         (info->width + port_def.nBufferAlignment - 1) &
1141         (~(port_def.nBufferAlignment - 1));
1142   else
1143     port_def.format.video.nStride = GST_ROUND_UP_4 (info->width);       /* safe (?) default */
1144 #endif
1145
1146   port_def.format.video.nFrameHeight = info->height;
1147 #ifdef TIZEN_FEATURE_OMX
1148   port_def.format.video.nSliceHeight = ALIGN(info->width, 16);
1149 #else
1150   port_def.format.video.nSliceHeight = info->height;
1151 #endif
1152
1153   switch (port_def.format.video.eColorFormat) {
1154     case OMX_COLOR_FormatYUV420Planar:
1155     case OMX_COLOR_FormatYUV420PackedPlanar:
1156       port_def.nBufferSize =
1157           (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1158           2 * ((port_def.format.video.nStride / 2) *
1159           ((port_def.format.video.nFrameHeight + 1) / 2));
1160       break;
1161
1162     case OMX_COLOR_FormatYUV420SemiPlanar:
1163       port_def.nBufferSize =
1164           (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
1165           (port_def.format.video.nStride *
1166           ((port_def.format.video.nFrameHeight + 1) / 2));
1167       break;
1168
1169     case OMX_EXT_COLOR_FormatNV12LPhysicalAddress: /* FALL THROUGH */
1170     case OMX_EXT_COLOR_FormatNV12TPhysicalAddress:
1171 #ifdef TIZEN_FEATURE_OMX
1172         port_def.nBufferSize = sizeof(MMVideoBuffer);
1173 #endif
1174         break;
1175
1176     default:
1177       g_assert_not_reached ();
1178   }
1179
1180   if (info->fps_n == 0) {
1181     port_def.format.video.xFramerate = 0;
1182   } else {
1183     if (!(klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER))
1184       port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d);
1185     else
1186       port_def.format.video.xFramerate = (info->fps_n) / (info->fps_d);
1187   }
1188
1189   GST_DEBUG_OBJECT (self, "Setting inport port definition");
1190   if (gst_omx_port_update_port_definition (self->enc_in_port,
1191           &port_def) != OMX_ErrorNone)
1192     return FALSE;
1193
1194 #ifdef TIZEN_FEATURE_OMX
1195   GST_DEBUG_OBJECT (self, "Updating outport port definition");
1196   gst_omx_port_get_port_definition (self->enc_out_port, &port_def);
1197
1198   port_def.format.video.nFrameWidth = info->width;
1199   port_def.format.video.nFrameHeight = info->height;
1200
1201   if (gst_omx_port_update_port_definition (self->enc_out_port, &port_def) != OMX_ErrorNone)
1202     return FALSE;
1203 #endif
1204
1205 #ifdef USE_OMX_TARGET_RPI
1206   /* aspect ratio */
1207   {
1208     OMX_ERRORTYPE err;
1209     OMX_CONFIG_POINTTYPE aspect_ratio_param;
1210
1211     GST_OMX_INIT_STRUCT (&aspect_ratio_param);
1212     aspect_ratio_param.nPortIndex = self->enc_out_port->index;
1213
1214     err = gst_omx_component_get_parameter (self->enc,
1215         OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
1216
1217     if (err == OMX_ErrorNone) {
1218
1219       aspect_ratio_param.nX = info->par_n;
1220       aspect_ratio_param.nY = info->par_d;
1221
1222       err =
1223           gst_omx_component_set_parameter (self->enc,
1224           OMX_IndexParamBrcmPixelAspectRatio, &aspect_ratio_param);
1225
1226       if (err == OMX_ErrorUnsupportedIndex) {
1227         GST_WARNING_OBJECT (self,
1228             "Setting aspect ratio parameters not supported by the component");
1229       } else if (err == OMX_ErrorUnsupportedSetting) {
1230         GST_WARNING_OBJECT (self,
1231             "Setting aspect ratio %u %u not supported by the component",
1232             aspect_ratio_param.nX, aspect_ratio_param.nY);
1233       } else if (err != OMX_ErrorNone) {
1234         GST_ERROR_OBJECT (self,
1235             "Failed to set aspect ratio: %s (0x%08x)",
1236             gst_omx_error_to_string (err), err);
1237         return FALSE;
1238       }
1239     }
1240   }
1241 #endif // USE_OMX_TARGET_RPI
1242
1243   if (klass->set_format) {
1244     if (!klass->set_format (self, self->enc_in_port, state)) {
1245       GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
1246       return FALSE;
1247     }
1248   }
1249
1250   GST_DEBUG_OBJECT (self, "Updating outport port definition");
1251   if (gst_omx_port_update_port_definition (self->enc_out_port,
1252           NULL) != OMX_ErrorNone)
1253     return FALSE;
1254
1255   if (self->target_bitrate != 0xffffffff) {
1256     OMX_VIDEO_PARAM_BITRATETYPE config;
1257     OMX_ERRORTYPE err;
1258
1259     GST_OMX_INIT_STRUCT (&config);
1260     config.nPortIndex = self->enc_out_port->index;
1261     config.nTargetBitrate = self->target_bitrate;
1262     config.eControlRate = self->control_rate;
1263     err = gst_omx_component_set_parameter (self->enc,
1264         OMX_IndexParamVideoBitrate, &config);
1265     if (err != OMX_ErrorNone)
1266       GST_ERROR_OBJECT (self, "Failed to set bitrate parameter: %s (0x%08x)",
1267           gst_omx_error_to_string (err), err);
1268   }
1269
1270   GST_DEBUG_OBJECT (self, "Enabling component");
1271   if (needs_disable) {
1272     if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone)
1273       return FALSE;
1274 #ifdef TIZEN_FEATURE_OMX
1275     if (gst_omx_port_tbm_allocate_enc_buffers (self->enc_in_port, self->bufmgr,
1276         self->enc_in_port->use_buffer) != OMX_ErrorNone)
1277         return FALSE;
1278 #else
1279     if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1280       return FALSE;
1281 #endif
1282     if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
1283       if (gst_omx_port_set_enabled (self->enc_out_port, TRUE) != OMX_ErrorNone)
1284         return FALSE;
1285       if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1286         return FALSE;
1287
1288       if (gst_omx_port_wait_enabled (self->enc_out_port,
1289               5 * GST_SECOND) != OMX_ErrorNone)
1290         return FALSE;
1291     }
1292
1293     if (gst_omx_port_wait_enabled (self->enc_in_port,
1294             5 * GST_SECOND) != OMX_ErrorNone)
1295       return FALSE;
1296     if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone)
1297       return FALSE;
1298   } else {
1299     if (!(klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
1300       /* Disable output port */
1301       if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
1302         return FALSE;
1303
1304       if (gst_omx_port_wait_enabled (self->enc_out_port,
1305               1 * GST_SECOND) != OMX_ErrorNone)
1306         return FALSE;
1307
1308       if (gst_omx_component_set_state (self->enc,
1309               OMX_StateIdle) != OMX_ErrorNone)
1310         return FALSE;
1311
1312       /* Need to allocate buffers to reach Idle state */
1313
1314       if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1315         return FALSE;
1316     } else {
1317       if (gst_omx_component_set_state (self->enc,
1318               OMX_StateIdle) != OMX_ErrorNone)
1319         return FALSE;
1320
1321       /* Need to allocate buffers to reach Idle state */
1322 #ifdef TIZEN_FEATURE_OMX
1323     if (gst_omx_port_tbm_allocate_enc_buffers(self->enc_in_port, self->bufmgr,
1324         self->enc_in_port->use_buffer) != OMX_ErrorNone)
1325         return FALSE;
1326 #else
1327       if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
1328         return FALSE;
1329 #endif
1330
1331 #ifdef TIZEN_FEATURE_OMX
1332     if (gst_omx_port_tbm_allocate_enc_buffers(self->enc_out_port, self->bufmgr,
1333         self->enc_out_port->use_buffer) != OMX_ErrorNone)
1334 #else
1335       if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
1336 #endif
1337         return FALSE;
1338     }
1339
1340     if (gst_omx_component_get_state (self->enc,
1341             GST_CLOCK_TIME_NONE) != OMX_StateIdle)
1342       return FALSE;
1343
1344     if (gst_omx_component_set_state (self->enc,
1345             OMX_StateExecuting) != OMX_ErrorNone)
1346       return FALSE;
1347
1348     if (gst_omx_component_get_state (self->enc,
1349             GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
1350       return FALSE;
1351   }
1352
1353   /* Unset flushing to allow ports to accept data again */
1354   gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
1355   gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
1356
1357   if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone) {
1358     GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
1359         gst_omx_component_get_last_error_string (self->enc),
1360         gst_omx_component_get_last_error (self->enc));
1361     return FALSE;
1362   }
1363
1364   if (self->input_state)
1365     gst_video_codec_state_unref (self->input_state);
1366   self->input_state = gst_video_codec_state_ref (state);
1367
1368   /* Start the srcpad loop again */
1369   GST_DEBUG_OBJECT (self, "Starting task again");
1370   self->downstream_flow_ret = GST_FLOW_OK;
1371   gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
1372       (GstTaskFunction) gst_omx_video_enc_loop, encoder, NULL);
1373
1374   return TRUE;
1375 }
1376
1377 static gboolean
1378 gst_omx_video_enc_flush (GstVideoEncoder * encoder)
1379 {
1380   GstOMXVideoEnc *self;
1381
1382   self = GST_OMX_VIDEO_ENC (encoder);
1383
1384   GST_DEBUG_OBJECT (self, "Flushing encoder");
1385
1386   if (gst_omx_component_get_state (self->enc, 0) == OMX_StateLoaded)
1387     return TRUE;
1388
1389   gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
1390   gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
1391
1392   /* Wait until the srcpad loop is finished,
1393    * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
1394    * caused by using this lock from inside the loop function */
1395   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1396   GST_PAD_STREAM_LOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
1397   GST_PAD_STREAM_UNLOCK (GST_VIDEO_ENCODER_SRC_PAD (self));
1398   GST_VIDEO_ENCODER_STREAM_LOCK (self);
1399
1400   gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
1401   gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);
1402   gst_omx_port_populate (self->enc_out_port);
1403
1404   /* Start the srcpad loop again */
1405   self->last_upstream_ts = 0;
1406   self->downstream_flow_ret = GST_FLOW_OK;
1407   gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
1408       (GstTaskFunction) gst_omx_video_enc_loop, encoder, NULL);
1409
1410   return TRUE;
1411 }
1412
1413 static gboolean
1414 gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf,
1415     GstOMXBuffer * outbuf)
1416 {
1417   GstVideoCodecState *state = gst_video_codec_state_ref (self->input_state);
1418   GstVideoInfo *info = &state->info;
1419   OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
1420   gboolean ret = FALSE;
1421   GstVideoFrame frame;
1422
1423   if (info->width != port_def->format.video.nFrameWidth ||
1424       info->height != port_def->format.video.nFrameHeight) {
1425     GST_ERROR_OBJECT (self, "Width or height do not match");
1426     goto done;
1427   }
1428 #ifndef TIZEN_FEATURE_OMX
1429   /* Same strides and everything */
1430   if (gst_buffer_get_size (inbuf) ==
1431       outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) {
1432     outbuf->omx_buf->nFilledLen = gst_buffer_get_size (inbuf);
1433
1434     gst_buffer_extract (inbuf, 0,
1435         outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset,
1436         outbuf->omx_buf->nFilledLen);
1437     ret = TRUE;
1438     goto done;
1439   }
1440 #endif
1441   /* Different strides */
1442
1443   switch (info->finfo->format) {
1444     case GST_VIDEO_FORMAT_I420:{
1445       gint i, j, height, width;
1446       guint8 *src, *dest;
1447       gint src_stride, dest_stride;
1448
1449       outbuf->omx_buf->nFilledLen = 0;
1450
1451       if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
1452         GST_ERROR_OBJECT (self, "Invalid input buffer size");
1453         ret = FALSE;
1454         break;
1455       }
1456
1457       for (i = 0; i < 3; i++) {
1458         if (i == 0) {
1459           dest_stride = port_def->format.video.nStride;
1460           src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
1461
1462           /* XXX: Try this if no stride was set */
1463           if (dest_stride == 0)
1464             dest_stride = src_stride;
1465         } else {
1466           dest_stride = port_def->format.video.nStride / 2;
1467           src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
1468
1469           /* XXX: Try this if no stride was set */
1470           if (dest_stride == 0)
1471             dest_stride = src_stride;
1472         }
1473
1474         dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
1475         if (i > 0)
1476           dest +=
1477               port_def->format.video.nSliceHeight *
1478               port_def->format.video.nStride;
1479         if (i == 2)
1480           dest +=
1481               (port_def->format.video.nSliceHeight / 2) *
1482               (port_def->format.video.nStride / 2);
1483
1484         src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
1485         height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
1486         width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i);
1487
1488         if (dest + dest_stride * height >
1489             outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
1490           gst_video_frame_unmap (&frame);
1491           GST_ERROR_OBJECT (self, "Invalid output buffer size");
1492           ret = FALSE;
1493           break;
1494         }
1495
1496         for (j = 0; j < height; j++) {
1497           memcpy (dest, src, width);
1498           outbuf->omx_buf->nFilledLen += dest_stride;
1499           src += src_stride;
1500           dest += dest_stride;
1501         }
1502       }
1503       gst_video_frame_unmap (&frame);
1504       ret = TRUE;
1505       break;
1506     }
1507     case GST_VIDEO_FORMAT_NV12:{
1508       gint i, j, height, width;
1509       guint8 *src, *dest;
1510       gint src_stride, dest_stride;
1511
1512       outbuf->omx_buf->nFilledLen = 0;
1513
1514       if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
1515         GST_ERROR_OBJECT (self, "Invalid input buffer size");
1516         ret = FALSE;
1517         break;
1518       }
1519
1520       for (i = 0; i < 2; i++) {
1521         if (i == 0) {
1522           dest_stride = port_def->format.video.nStride;
1523           src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
1524           /* XXX: Try this if no stride was set */
1525           if (dest_stride == 0)
1526             dest_stride = src_stride;
1527         } else {
1528           dest_stride = port_def->format.video.nStride;
1529           src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
1530
1531           /* XXX: Try this if no stride was set */
1532           if (dest_stride == 0)
1533             dest_stride = src_stride;
1534         }
1535
1536         dest = outbuf->omx_buf->pBuffer + outbuf->omx_buf->nOffset;
1537         if (i == 1)
1538           dest +=
1539               port_def->format.video.nSliceHeight *
1540               port_def->format.video.nStride;
1541
1542         src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
1543         height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
1544         width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i) * (i == 0 ? 1 : 2);
1545
1546         if (dest + dest_stride * height >
1547             outbuf->omx_buf->pBuffer + outbuf->omx_buf->nAllocLen) {
1548           gst_video_frame_unmap (&frame);
1549           GST_ERROR_OBJECT (self, "Invalid output buffer size");
1550           ret = FALSE;
1551           break;
1552         }
1553
1554         for (j = 0; j < height; j++) {
1555           memcpy (dest, src, width);
1556           outbuf->omx_buf->nFilledLen += dest_stride;
1557           src += src_stride;
1558           dest += dest_stride;
1559         }
1560
1561       }
1562       gst_video_frame_unmap (&frame);
1563       ret = TRUE;
1564       break;
1565     }
1566     case GST_VIDEO_FORMAT_ST12:
1567     case GST_VIDEO_FORMAT_SN12:
1568     {
1569       GstMemory* ext_memory = gst_buffer_peek_memory(inbuf, 1);
1570       GstMapInfo ext_info =  GST_MAP_INFO_INIT;
1571       MMVideoBuffer *mm_vbuffer = NULL;
1572
1573       if (!ext_memory) {
1574         GST_WARNING_OBJECT (self, "null MMVideoBuffer pointer  in hw color format. skip this.");
1575         goto done;
1576       }
1577
1578       gst_memory_map(ext_memory, &ext_info, GST_MAP_READ);
1579       mm_vbuffer = (MMVideoBuffer*)ext_info.data;
1580       gst_memory_unmap(ext_memory, &ext_info);
1581
1582       if (mm_vbuffer != NULL && mm_vbuffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
1583         mm_vbuffer->handle.dmabuf_fd[0] = tbm_bo_get_handle (mm_vbuffer->handle.bo[0], TBM_DEVICE_MM).u32;
1584         mm_vbuffer->handle.dmabuf_fd[1] = tbm_bo_get_handle (mm_vbuffer->handle.bo[1], TBM_DEVICE_MM).u32;
1585         mm_vbuffer->data[0] = tbm_bo_get_handle (mm_vbuffer->handle.bo[0], TBM_DEVICE_CPU).ptr;
1586         mm_vbuffer->data[1] = tbm_bo_get_handle (mm_vbuffer->handle.bo[1], TBM_DEVICE_CPU).ptr;
1587
1588         GST_LOG_OBJECT (self, "enc. fd[0]:%d  fd[1]:%d  a[0]:%p, a[1]:%p, w[0]:%d  h[0]:%d   %d, %d, buf_share_method:%d",
1589             mm_vbuffer->handle.dmabuf_fd[0], mm_vbuffer->handle.dmabuf_fd[1], mm_vbuffer->data[0], mm_vbuffer->data[1],
1590             mm_vbuffer->width[0], mm_vbuffer->height[0], mm_vbuffer->width[1], mm_vbuffer->height[1], mm_vbuffer->type);
1591
1592         outbuf->omx_buf->nAllocLen = sizeof (MMVideoBuffer);
1593         outbuf->omx_buf->nFilledLen = sizeof (MMVideoBuffer);
1594         memcpy (outbuf->omx_buf->pBuffer, mm_vbuffer, sizeof (MMVideoBuffer));
1595       } else {
1596         GST_WARNING_OBJECT (self, "enc input has wrong buf");
1597       }
1598
1599 #ifdef CODEC_ENC_INPUT_DUMP
1600       gst_omx_video_enc_input_dump(mm_vbuffer);
1601 #endif
1602
1603       ret = TRUE;
1604       break;
1605     }
1606     default:
1607       GST_ERROR_OBJECT (self, "Unsupported format");
1608       goto done;
1609       break;
1610   }
1611
1612 done:
1613
1614   gst_video_codec_state_unref (state);
1615
1616   return ret;
1617 }
1618
1619 static GstFlowReturn
1620 gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
1621     GstVideoCodecFrame * frame)
1622 {
1623   GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
1624   GstOMXVideoEnc *self;
1625   GstOMXPort *port;
1626   GstOMXBuffer *buf;
1627   OMX_ERRORTYPE err;
1628
1629   self = GST_OMX_VIDEO_ENC (encoder);
1630
1631   GST_DEBUG_OBJECT (self, "Handling frame");
1632
1633   if (self->downstream_flow_ret != GST_FLOW_OK) {
1634     gst_video_codec_frame_unref (frame);
1635     return self->downstream_flow_ret;
1636   }
1637
1638   port = self->enc_in_port;
1639
1640   while (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
1641     GstClockTime timestamp, duration;
1642
1643     /* Make sure to release the base class stream lock, otherwise
1644      * _loop() can't call _finish_frame() and we might block forever
1645      * because no input buffers are released */
1646     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1647     acq_ret = gst_omx_port_acquire_buffer (port, &buf);
1648
1649     if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
1650       GST_VIDEO_ENCODER_STREAM_LOCK (self);
1651       goto component_error;
1652     } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
1653       GST_VIDEO_ENCODER_STREAM_LOCK (self);
1654       goto flushing;
1655     } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1656       /* Reallocate all buffers */
1657       err = gst_omx_port_set_enabled (port, FALSE);
1658       if (err != OMX_ErrorNone) {
1659         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1660         goto reconfigure_error;
1661       }
1662
1663       err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
1664       if (err != OMX_ErrorNone) {
1665         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1666         goto reconfigure_error;
1667       }
1668
1669       err = gst_omx_port_deallocate_buffers (port);
1670       if (err != OMX_ErrorNone) {
1671         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1672         goto reconfigure_error;
1673       }
1674
1675       err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
1676       if (err != OMX_ErrorNone) {
1677         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1678         goto reconfigure_error;
1679       }
1680
1681       err = gst_omx_port_set_enabled (port, TRUE);
1682       if (err != OMX_ErrorNone) {
1683         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1684         goto reconfigure_error;
1685       }
1686 #ifdef TIZEN_FEATURE_OMX
1687     err = gst_omx_port_tbm_allocate_enc_buffers (port, self->bufmgr, port->use_buffer);
1688 #else
1689       err = gst_omx_port_allocate_buffers (port);
1690 #endif
1691       if (err != OMX_ErrorNone) {
1692         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1693         goto reconfigure_error;
1694       }
1695
1696       err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
1697       if (err != OMX_ErrorNone) {
1698         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1699         goto reconfigure_error;
1700       }
1701
1702       err = gst_omx_port_mark_reconfigured (port);
1703       if (err != OMX_ErrorNone) {
1704         GST_VIDEO_ENCODER_STREAM_LOCK (self);
1705         goto reconfigure_error;
1706       }
1707
1708       /* Now get a new buffer and fill it */
1709       GST_VIDEO_ENCODER_STREAM_LOCK (self);
1710       continue;
1711     }
1712     GST_VIDEO_ENCODER_STREAM_LOCK (self);
1713
1714     g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
1715
1716     if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
1717       gst_omx_port_release_buffer (port, buf);
1718       goto full_buffer;
1719     }
1720
1721     if (self->downstream_flow_ret != GST_FLOW_OK) {
1722       gst_omx_port_release_buffer (port, buf);
1723       goto flow_error;
1724     }
1725
1726     /* Now handle the frame */
1727     GST_DEBUG_OBJECT (self, "Handling frame");
1728
1729     if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
1730 #ifdef USE_OMX_TARGET_RPI
1731       OMX_CONFIG_BOOLEANTYPE config;
1732
1733       GST_OMX_INIT_STRUCT (&config);
1734       config.bEnabled = OMX_TRUE;
1735
1736       GST_DEBUG_OBJECT (self, "Forcing a keyframe (iframe on the RPi)");
1737
1738       err =
1739           gst_omx_component_set_config (self->enc,
1740           OMX_IndexConfigBrcmVideoRequestIFrame, &config);
1741 #else
1742       OMX_CONFIG_INTRAREFRESHVOPTYPE config;
1743
1744       GST_OMX_INIT_STRUCT (&config);
1745       config.nPortIndex = port->index;
1746       config.IntraRefreshVOP = OMX_TRUE;
1747
1748       GST_DEBUG_OBJECT (self, "Forcing a keyframe");
1749       err =
1750           gst_omx_component_set_config (self->enc,
1751           OMX_IndexConfigVideoIntraVOPRefresh, &config);
1752 #endif
1753       if (err != OMX_ErrorNone)
1754         GST_ERROR_OBJECT (self, "Failed to force a keyframe: %s (0x%08x)",
1755             gst_omx_error_to_string (err), err);
1756     }
1757
1758     /* Copy the buffer content in chunks of size as requested
1759      * by the port */
1760     if (!gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) {
1761       gst_omx_port_release_buffer (port, buf);
1762       goto buffer_fill_error;
1763     }
1764
1765     timestamp = frame->pts;
1766     if (timestamp != GST_CLOCK_TIME_NONE) {
1767       buf->omx_buf->nTimeStamp =
1768           gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND);
1769       self->last_upstream_ts = timestamp;
1770     }
1771
1772     duration = frame->duration;
1773     if (duration != GST_CLOCK_TIME_NONE) {
1774       buf->omx_buf->nTickCount =
1775           gst_util_uint64_scale (duration, OMX_TICKS_PER_SECOND, GST_SECOND);
1776       self->last_upstream_ts += duration;
1777     } else {
1778       buf->omx_buf->nTickCount = 0;
1779     }
1780
1781     self->started = TRUE;
1782     err = gst_omx_port_release_buffer (port, buf);
1783     if (err != OMX_ErrorNone)
1784       goto release_error;
1785
1786     GST_DEBUG_OBJECT (self, "Passed frame to component");
1787   }
1788
1789   gst_video_codec_frame_unref (frame);
1790
1791   return self->downstream_flow_ret;
1792
1793 full_buffer:
1794   {
1795     GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1796         ("Got OpenMAX buffer with no free space (%p, %u/%u)", buf,
1797             (guint) buf->omx_buf->nOffset, (guint) buf->omx_buf->nAllocLen));
1798     gst_video_codec_frame_unref (frame);
1799     return GST_FLOW_ERROR;
1800   }
1801
1802 flow_error:
1803   {
1804     gst_video_codec_frame_unref (frame);
1805     return self->downstream_flow_ret;
1806   }
1807
1808 component_error:
1809   {
1810     GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1811         ("OpenMAX component in error state %s (0x%08x)",
1812             gst_omx_component_get_last_error_string (self->enc),
1813             gst_omx_component_get_last_error (self->enc)));
1814     gst_video_codec_frame_unref (frame);
1815     return GST_FLOW_ERROR;
1816   }
1817
1818 flushing:
1819   {
1820     GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
1821     gst_video_codec_frame_unref (frame);
1822     return GST_FLOW_FLUSHING;
1823   }
1824 reconfigure_error:
1825   {
1826     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1827         ("Unable to reconfigure input port"));
1828     gst_video_codec_frame_unref (frame);
1829     return GST_FLOW_ERROR;
1830   }
1831 buffer_fill_error:
1832   {
1833     GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL),
1834         ("Failed to write input into the OpenMAX buffer"));
1835     gst_video_codec_frame_unref (frame);
1836     return GST_FLOW_ERROR;
1837   }
1838 release_error:
1839   {
1840     gst_video_codec_frame_unref (frame);
1841     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1842         ("Failed to relase input buffer to component: %s (0x%08x)",
1843             gst_omx_error_to_string (err), err));
1844     return GST_FLOW_ERROR;
1845   }
1846 }
1847
1848 static GstFlowReturn
1849 gst_omx_video_enc_finish (GstVideoEncoder * encoder)
1850 {
1851   GstOMXVideoEnc *self;
1852
1853   self = GST_OMX_VIDEO_ENC (encoder);
1854
1855   return gst_omx_video_enc_drain (self);
1856 }
1857
1858 static GstFlowReturn
1859 gst_omx_video_enc_drain (GstOMXVideoEnc * self)
1860 {
1861   GstOMXVideoEncClass *klass;
1862   GstOMXBuffer *buf;
1863   GstOMXAcquireBufferReturn acq_ret;
1864   OMX_ERRORTYPE err;
1865
1866   GST_DEBUG_OBJECT (self, "Draining component");
1867
1868   klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
1869
1870   if (!self->started) {
1871     GST_DEBUG_OBJECT (self, "Component not started yet");
1872     return GST_FLOW_OK;
1873   }
1874   self->started = FALSE;
1875
1876   if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
1877     GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
1878     return GST_FLOW_OK;
1879   }
1880
1881   /* Make sure to release the base class stream lock, otherwise
1882    * _loop() can't call _finish_frame() and we might block forever
1883    * because no input buffers are released */
1884   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1885
1886   /* Send an EOS buffer to the component and let the base
1887    * class drop the EOS event. We will send it later when
1888    * the EOS buffer arrives on the output port. */
1889   acq_ret = gst_omx_port_acquire_buffer (self->enc_in_port, &buf);
1890   if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
1891     GST_VIDEO_ENCODER_STREAM_LOCK (self);
1892     GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
1893         acq_ret);
1894     return GST_FLOW_ERROR;
1895   }
1896
1897   g_mutex_lock (&self->drain_lock);
1898   self->draining = TRUE;
1899   buf->omx_buf->nFilledLen = 0;
1900   buf->omx_buf->nTimeStamp =
1901       gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
1902       GST_SECOND);
1903   buf->omx_buf->nTickCount = 0;
1904   buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
1905   err = gst_omx_port_release_buffer (self->enc_in_port, buf);
1906   if (err != OMX_ErrorNone) {
1907     GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
1908         gst_omx_error_to_string (err), err);
1909     GST_VIDEO_ENCODER_STREAM_LOCK (self);
1910     return GST_FLOW_ERROR;
1911   }
1912   GST_DEBUG_OBJECT (self, "Waiting until component is drained");
1913   g_cond_wait (&self->drain_cond, &self->drain_lock);
1914   GST_DEBUG_OBJECT (self, "Drained component");
1915   g_mutex_unlock (&self->drain_lock);
1916   GST_VIDEO_ENCODER_STREAM_LOCK (self);
1917
1918   self->started = FALSE;
1919
1920   return GST_FLOW_OK;
1921 }
1922
1923 static gboolean
1924 gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
1925     GstQuery * query)
1926 {
1927   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1928
1929   return
1930       GST_VIDEO_ENCODER_CLASS
1931       (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query);
1932 }
1933
1934 static GstCaps *
1935 gst_omx_video_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
1936 {
1937   GstOMXVideoEnc *self = GST_OMX_VIDEO_ENC (encoder);
1938   GList *negotiation_map = NULL;
1939   GstCaps *comp_supported_caps;
1940
1941   if (!self->enc)
1942     return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
1943
1944   negotiation_map =
1945       gst_omx_video_get_supported_colorformats (self->enc_in_port,
1946       self->input_state);
1947   comp_supported_caps = gst_omx_video_get_caps_for_map (negotiation_map);
1948   g_list_free_full (negotiation_map,
1949       (GDestroyNotify) gst_omx_video_negotiation_map_free);
1950
1951   if (!gst_caps_is_empty (comp_supported_caps)) {
1952     GstCaps *ret =
1953         gst_video_encoder_proxy_getcaps (encoder, comp_supported_caps, filter);
1954
1955     gst_caps_unref (comp_supported_caps);
1956     return ret;
1957   } else {
1958     gst_caps_unref (comp_supported_caps);
1959     return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
1960   }
1961 }