Initialize Tizen 2.3
[framework/multimedia/gst-openmax.git] / wearable / omx / gstomx_base_videoenc.c
1 /*
2  * Copyright (C) 2007-2009 Nokia Corporation.
3  *
4  * Author: Felipe Contreras <felipe.contreras@nokia.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation
9  * version 2.1 of the License.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #include "gstomx_base_videoenc.h"
23 #include "gstomx.h"
24
25 #include <string.h>             /* for strcmp */
26
27 enum
28 {
29   ARG_0,
30   ARG_BITRATE,
31   ARG_FORCE_KEY_FRAME,
32   ARG_IDR_PERIOD,
33   ARG_SKIP_INBUF_COUNT,
34   ARG_USE_STATETUNING, /* STATE_TUNING */
35 };
36
37 enum PortIndexType
38 {
39   PORT_INDEX_IN = 0,
40   PORT_INDEX_OUT = 1,
41   PORT_INDEX_BOTH = -1,
42   PORT_INDEX_NONE = -2
43 };
44
45 #define DEFAULT_BITRATE 0
46 #define DEFAULT_IDR_PERIOD 20
47 #define DEFAULT_SKIP_BY_FORCE_IFRAME 0
48
49 GSTOMX_BOILERPLATE (GstOmxBaseVideoEnc, gst_omx_base_videoenc, GstOmxBaseFilter,
50     GST_OMX_BASE_FILTER_TYPE);
51
52 static void instance_init (GstElement * element);
53
54
55 /* modification: user force I frame */
56 static void
57 add_force_key_frame(GstOmxBaseVideoEnc *enc)
58 {
59   GstOmxBaseFilter *omx_base;
60   GOmxCore *gomx;
61   OMX_CONFIG_INTRAREFRESHVOPTYPE config;
62   OMX_ERRORTYPE ret = OMX_ErrorNone;
63
64   omx_base = GST_OMX_BASE_FILTER (enc);
65   gomx = (GOmxCore *) omx_base->gomx;
66
67   GST_LOG_OBJECT (enc, "request forced key frame now.");
68
69   if (!omx_base->out_port || !gomx->omx_handle) {
70     GST_ERROR_OBJECT (enc, "failed to set force-i-frame...");
71     return;
72   }
73
74   G_OMX_INIT_PARAM (config);
75   config.nPortIndex = omx_base->out_port->port_index;
76   config.IntraRefreshVOP = OMX_TRUE;
77
78   ret = OMX_SetConfig (gomx->omx_handle, OMX_IndexConfigVideoIntraVOPRefresh, &config);
79   if (ret == OMX_ErrorNone)
80     GST_WARNING_OBJECT (enc, "forced key frame is done. (OMX_IndexConfigVideoIntraVOPRefresh) ret = %d", ret);
81   else
82     GST_ERROR_OBJECT (enc, "Failed to set forced key frame (OMX_IndexConfigVideoIntraVOPRefresh) ret = %d", ret);
83 }
84
85
86 static GstOmxReturn
87 process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
88 {
89   GstOmxBaseVideoEnc *self;
90
91   self = GST_OMX_BASE_VIDEOENC (omx_base_filter);
92
93   GST_LOG_OBJECT (self, "base videoenc process_input_buf enter");
94
95   if (self->use_force_key_frame) { /* skip frame by cnt and make force key frame */
96     if (self->skip_inbuf_cnt > 0) {
97       GST_WARNING_OBJECT (self, "skip inbuf before enc force key frame (%d)", self->skip_inbuf_cnt);
98       self->skip_inbuf_cnt--;
99       return GSTOMX_RETURN_SKIP;
100
101     } else if (self->skip_inbuf_cnt == 0) {
102         add_force_key_frame (self);
103     }
104
105     self->use_force_key_frame = FALSE;
106   }
107
108   return GSTOMX_RETURN_OK;
109 }
110
111 /* modification: postprocess for outputbuf. in this videoenc case, set sync frame */
112 static GstOmxReturn
113 process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
114 {
115   GstOmxBaseVideoEnc *self;
116
117   self = GST_OMX_BASE_VIDEOENC (omx_base);
118
119   GST_LOG_OBJECT (self, "base videoenc process_output_buf enter");
120
121   /* modification: set sync frame info while encoding */
122   if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
123     GST_BUFFER_FLAG_UNSET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
124   } else {
125     GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
126   }
127
128   return GSTOMX_RETURN_OK;
129 }
130
131 /* modification: get codec_data from omx component and set it caps */
132 static void
133 process_output_caps(GstOmxBaseFilter * self, OMX_BUFFERHEADERTYPE *omx_buffer)
134 {
135   GstBuffer *buf;
136   GstCaps *caps = NULL;
137   GstStructure *structure;
138   GValue value = { 0, {{0}
139       }
140   };
141
142   caps = gst_pad_get_negotiated_caps (self->srcpad);
143   caps = gst_caps_make_writable (caps);
144   structure = gst_caps_get_structure (caps, 0);
145
146   g_value_init (&value, GST_TYPE_BUFFER);
147   buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
148   memcpy (GST_BUFFER_DATA (buf),
149       omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
150   gst_value_set_buffer (&value, buf);
151   gst_buffer_unref (buf);
152   gst_structure_set_value (structure, "codec_data", &value);
153   g_value_unset (&value);
154
155   gst_pad_set_caps (self->srcpad, caps);
156   gst_caps_unref (caps);
157 }
158
159 static void
160 type_base_init (gpointer g_class)
161 {
162 }
163
164 static void
165 set_property (GObject * obj,
166     guint prop_id, const GValue * value, GParamSpec * pspec)
167 {
168   GstOmxBaseVideoEnc *self;
169   GstOmxBaseFilter *omx_base;
170
171   self = GST_OMX_BASE_VIDEOENC (obj);
172   omx_base = GST_OMX_BASE_FILTER (obj);
173
174   switch (prop_id) {
175     case ARG_BITRATE:
176     {
177       self->bitrate = g_value_get_uint (value);
178       /*Set the bitrate by using set config For Dynamic bitrate */
179       if(omx_base->gomx->omx_state == OMX_StateExecuting) {
180         OMX_VIDEO_CONFIG_BITRATETYPE config;
181         OMX_ERRORTYPE ret = OMX_ErrorNone;
182         G_OMX_INIT_PARAM (config);
183
184         config.nPortIndex = omx_base->out_port->port_index;
185         OMX_GetConfig (omx_base->gomx->omx_handle, OMX_IndexConfigVideoBitrate, &config);
186
187         GST_WARNING_OBJECT (self, "bitrate was changed from %d to %d", config.nEncodeBitrate, self->bitrate);
188         config.nEncodeBitrate = self->bitrate;
189         ret = OMX_SetConfig (omx_base->gomx->omx_handle, OMX_IndexConfigVideoBitrate, &config);
190         if (ret == OMX_ErrorNone)
191           GST_WARNING_OBJECT (self, "set OMX_IndexConfigVideoBitrate for nEncodeBitrate = %d", self->bitrate);
192         else
193           GST_ERROR_OBJECT (self, "Failed to set OMX_IndexConfigVideoBitrate. nEncodeBitrate = %d  ret = %d", self->bitrate, ret);
194
195       }
196     }
197       break;
198
199     /* modification: request to component to make key frame */
200     case ARG_FORCE_KEY_FRAME:
201       self->use_force_key_frame = g_value_get_boolean (value);
202       GST_WARNING_OBJECT (self, "set use_force_key_frame");
203       break;
204
205     case ARG_SKIP_INBUF_COUNT:
206       self->skip_inbuf_cnt = g_value_get_int (value);
207       GST_INFO_OBJECT (self, "set use_force_key_frame after %d frame skip", self->skip_inbuf_cnt);
208       break;
209
210     case ARG_IDR_PERIOD:
211       self->idr_period = g_value_get_int (value);
212       {
213         OMX_VIDEO_PARAM_AVCTYPE param;
214         OMX_ERRORTYPE ret = OMX_ErrorNone;
215
216         G_OMX_INIT_PARAM (param);
217         param.nPortIndex = omx_base->out_port->port_index;
218         OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, &param);
219
220         param.nPFrames = self->idr_period;
221         ret = OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, &param);
222         if (ret == OMX_ErrorNone)
223           GST_WARNING_OBJECT (self, "set OMX_IndexParamVideoAvc for IDR period = %d", self->idr_period);
224         else
225           GST_ERROR_OBJECT (self, "Failed to set OMX_IndexParamVideoAvc. IDR period = %d  ret = %d", self->idr_period, ret);
226       }
227       break;
228
229     case ARG_USE_STATETUNING:
230       self->omx_base.use_state_tuning = g_value_get_boolean(value);
231       break;
232     default:
233       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
234       break;
235   }
236 }
237
238 static void
239 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
240 {
241   GstOmxBaseVideoEnc *self;
242
243   self = GST_OMX_BASE_VIDEOENC (obj);
244
245   switch (prop_id) {
246     case ARG_BITRATE:
247             /** @todo propagate this to OpenMAX when processing. */
248       g_value_set_uint (value, self->bitrate);
249       break;
250     case ARG_IDR_PERIOD:
251       g_value_set_int (value, self->idr_period);
252       break;
253     case ARG_SKIP_INBUF_COUNT:
254       g_value_set_int (value, self->skip_inbuf_cnt);
255       break;
256     case ARG_USE_STATETUNING:
257       g_value_set_boolean(value, self->omx_base.use_state_tuning);
258       break;
259     default:
260       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
261       break;
262   }
263 }
264
265 static void
266 type_class_init (gpointer g_class, gpointer class_data)
267 {
268   GObjectClass *gobject_class;
269   GstOmxBaseFilterClass *basefilter_class;
270
271   GST_WARNING("video enc  type_class_init");
272   gobject_class = G_OBJECT_CLASS (g_class);
273   basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
274
275   /* Properties stuff */
276   {
277     gobject_class->set_property = set_property;
278     gobject_class->get_property = get_property;
279
280     g_object_class_install_property (gobject_class, ARG_BITRATE,
281         g_param_spec_uint ("bitrate", "Bit-rate",
282             "Encoding bit-rate",
283             0, G_MAXUINT, DEFAULT_BITRATE,
284             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
285
286     g_object_class_install_property (gobject_class, ARG_FORCE_KEY_FRAME,
287         g_param_spec_boolean ("force-i-frame", "force the encoder to produce I frame",
288             "force the encoder to produce I frame",
289             FALSE,
290             G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
291
292     g_object_class_install_property (gobject_class, ARG_IDR_PERIOD,
293         g_param_spec_int ("idr-period", "set interval of I-frame",
294             "set interval of I-frame",
295             0, G_MAXINT, DEFAULT_IDR_PERIOD,
296             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
297
298     g_object_class_install_property (gobject_class, ARG_SKIP_INBUF_COUNT,
299         g_param_spec_int ("skip-inbuf", "skip inbuf in case of force I frame",
300             "skip inbuf in case of force I frame",
301             0, G_MAXINT, DEFAULT_SKIP_BY_FORCE_IFRAME,
302             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
303
304     /* STATE_TUNING */
305     g_object_class_install_property (gobject_class, ARG_USE_STATETUNING,
306         g_param_spec_boolean ("state-tuning", "start omx component in gst paused state",
307         "Whether or not to use state-tuning feature",
308         FALSE, G_PARAM_READWRITE));
309   }
310   basefilter_class->process_input_buf = process_input_buf;
311   basefilter_class->process_output_buf = process_output_buf;
312   basefilter_class->process_output_caps = process_output_caps;
313   basefilter_class->instance_init = instance_init;
314 }
315
316 static gboolean
317 sink_setcaps (GstPad * pad, GstCaps * caps)
318 {
319   GstStructure *structure;
320   GstOmxBaseVideoEnc *self;
321   GstOmxBaseFilter *omx_base;
322   GOmxCore *gomx;
323   OMX_COLOR_FORMATTYPE color_format = OMX_COLOR_FormatUnused;
324   gint width = 0;
325   gint height = 0;
326   const GValue *framerate = NULL;
327
328   self = GST_OMX_BASE_VIDEOENC (GST_PAD_PARENT (pad));
329   omx_base = GST_OMX_BASE_FILTER (self);
330   gomx = (GOmxCore *) omx_base->gomx;
331
332   GST_WARNING_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
333
334   g_return_val_if_fail (gst_caps_get_size (caps) == 1, FALSE);
335
336   structure = gst_caps_get_structure (caps, 0);
337
338   gst_structure_get_int (structure, "width", &width);
339   gst_structure_get_int (structure, "height", &height);
340
341   if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0) {
342     guint32 fourcc;
343
344     framerate = gst_structure_get_value (structure, "framerate");
345     if (framerate) {
346       self->framerate_num = gst_value_get_fraction_numerator (framerate);
347       self->framerate_denom = gst_value_get_fraction_denominator (framerate);
348     }
349
350     if (gst_structure_get_fourcc (structure, "format", &fourcc)) {
351       switch (fourcc) {
352         case GST_MAKE_FOURCC ('I', '4', '2', '0'):
353         case GST_MAKE_FOURCC ('S', '4', '2', '0'):
354           color_format = OMX_COLOR_FormatYUV420PackedPlanar;
355           break;
356         case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
357           color_format = OMX_COLOR_FormatYCbYCr;
358           break;
359         case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
360           color_format = OMX_COLOR_FormatCbYCrY;
361           break;
362         /* MODIFICATION: Add extended_color_format */
363         case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
364           color_format = OMX_EXT_COLOR_FormatNV12T_Phyaddr_Fd;
365           break;
366         case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
367           color_format = OMX_EXT_COLOR_FormatNV12L_Phyaddr_Fd;
368           break;
369
370       }
371     }
372   }
373
374   if (gomx == NULL)
375   {
376     GST_ERROR_OBJECT(self, "GOmxCore is NULL! this can make seg fault");
377   }
378
379   if (gomx->omx_handle == NULL)
380   {
381     GST_ERROR_OBJECT(self, "omx_handle is NULL!  this can make seg fault");
382   }
383
384   /* Input port configuration. */
385   {
386     OMX_PARAM_PORTDEFINITIONTYPE param;
387     G_OMX_INIT_PARAM (param);
388
389     param.nPortIndex = omx_base->in_port->port_index;
390     OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
391
392     param.format.video.nFrameWidth = width;
393     param.format.video.nFrameHeight = height;
394     param.format.video.eColorFormat = color_format;
395     if (framerate) {
396       /* convert to Q.16 */
397       param.format.video.xFramerate =
398           (OMX_U32)(gst_value_get_fraction_numerator (framerate) << 16) /
399           (OMX_U32)gst_value_get_fraction_denominator (framerate);
400     }
401
402     OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
403   }
404
405   /* Output port configuration. */
406   {
407     OMX_PARAM_PORTDEFINITIONTYPE param;
408     G_OMX_INIT_PARAM (param);
409
410     param.nPortIndex = omx_base->out_port->port_index;
411     OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
412
413     param.nBufferSize = width * height * 3 / 2;
414
415     OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
416   }
417
418   return gst_pad_set_caps (pad, caps);
419 }
420
421 static void
422 omx_setup (GstOmxBaseFilter * omx_base)
423 {
424   GstOmxBaseVideoEnc *self;
425   GOmxCore *gomx;
426
427   self = GST_OMX_BASE_VIDEOENC (omx_base);
428   gomx = (GOmxCore *) omx_base->gomx;
429
430   GST_INFO_OBJECT (omx_base, "begin");
431
432   {
433     OMX_PARAM_PORTDEFINITIONTYPE param;
434
435     G_OMX_INIT_PARAM (param);
436
437     /* Output port configuration. */
438     {
439       param.nPortIndex = omx_base->out_port->port_index;
440       OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
441
442       param.format.video.eCompressionFormat = self->compression_format;
443
444       if (self->bitrate > 0)
445         param.format.video.nBitrate = self->bitrate;
446
447       OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
448     }
449   }
450
451   /* modification: set bitrate by using OMX_IndexParamVideoBitrate macro*/
452   if (self->bitrate > 0) {
453     if (gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS) {
454
455       /* set Bitrate and control rate*/
456       {
457         OMX_VIDEO_PARAM_BITRATETYPE param_bitrate;
458         G_OMX_INIT_PARAM (param_bitrate);
459         param_bitrate.nPortIndex = omx_base->out_port->port_index;
460         OMX_GetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, &param_bitrate);
461
462         param_bitrate.nTargetBitrate = self->bitrate;
463
464         param_bitrate.eControlRate = OMX_Video_ControlRateVariable; /* VBR */
465         GST_WARNING_OBJECT (self, "set bitrate (OMX_Video_ControlRateVariable): %d", param_bitrate.nTargetBitrate);
466         OMX_SetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, &param_bitrate);
467       }
468
469       /* set Quantization parameter*/
470       {
471         OMX_VIDEO_PARAM_QUANTIZATIONTYPE param_qp;
472         G_OMX_INIT_PARAM (param_qp);
473         param_qp.nPortIndex = omx_base->out_port->port_index;
474         OMX_GetParameter (gomx->omx_handle, OMX_IndexParamVideoQuantization, &param_qp);
475
476         param_qp.nQpI = 20;
477         param_qp.nQpP = 20;
478         param_qp.nQpB = 20;
479
480         GST_WARNING_OBJECT (self, "set quantization parameter (nQpI: %d  nQpP: %d  nQpB: %d)", param_qp.nQpI, param_qp.nQpP, param_qp.nQpB);
481         OMX_SetParameter (gomx->omx_handle, OMX_IndexParamVideoQuantization, &param_qp);
482       }
483
484     } else {
485       OMX_VIDEO_PARAM_BITRATETYPE param;
486       G_OMX_INIT_PARAM (param);
487       param.nPortIndex = omx_base->out_port->port_index;
488       OMX_GetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, &param);
489
490       param.nTargetBitrate = self->bitrate;
491
492       param.eControlRate = OMX_Video_ControlRateVariable; /* VBR */
493       GST_WARNING_OBJECT (self, "set bitrate (OMX_Video_ControlRateVariable): %d", param.nTargetBitrate);
494       OMX_SetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, &param);
495     }
496   }
497
498   GST_INFO_OBJECT (omx_base, "end");
499 }
500
501 static void
502 instance_private_value_init(GstElement * element)
503 {
504   GstOmxBaseFilter *omx_base;
505   GstOmxBaseVideoEnc *self;
506
507   omx_base = GST_OMX_BASE_FILTER (element);
508   self = GST_OMX_BASE_VIDEOENC (element);
509
510   self->bitrate = DEFAULT_BITRATE;
511   self->use_force_key_frame = FALSE;
512   self->skip_inbuf_cnt = DEFAULT_SKIP_BY_FORCE_IFRAME;
513
514   omx_base->gomx->codec_type = GSTOMX_CODECTYPE_VIDEO_ENC;
515 }
516
517 static void
518 instance_init (GstElement * element)
519 {
520   GST_OMX_BASE_FILTER_CLASS(parent_class)->instance_init(element);
521
522   instance_private_value_init(element);
523 }
524
525 static void
526 type_instance_init (GTypeInstance * instance, gpointer g_class)
527 {
528   GstOmxBaseFilter *omx_base;
529
530   GST_WARNING("begin");
531   omx_base = GST_OMX_BASE_FILTER (instance);
532
533   instance_private_value_init(GST_ELEMENT(instance));
534
535   omx_base->omx_setup = omx_setup;
536
537   gst_pad_set_setcaps_function (omx_base->sinkpad, sink_setcaps);
538
539   GST_WARNING("end");
540 }