Tizen 2.1 base
[profile/ivi/gst-openmax0.10.git] / 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 };
33
34 #define DEFAULT_BITRATE 0
35
36 GSTOMX_BOILERPLATE (GstOmxBaseVideoEnc, gst_omx_base_videoenc, GstOmxBaseFilter,
37     GST_OMX_BASE_FILTER_TYPE);
38
39
40 /* modification: user force I frame */
41 static void
42 add_force_key_frame(GstOmxBaseVideoEnc *enc)
43 {
44   GstOmxBaseFilter *omx_base;
45   GOmxCore *gomx;
46   OMX_CONFIG_INTRAREFRESHVOPTYPE config;
47
48   omx_base = GST_OMX_BASE_FILTER (enc);
49   gomx = (GOmxCore *) omx_base->gomx;
50
51
52   GST_INFO_OBJECT (enc, "request forced key frame now.");
53
54   if (!omx_base->out_port || !gomx->omx_handle) {
55     GST_WARNING_OBJECT (enc, "failed to set force-i-frame...");
56     return;
57   }
58
59   G_OMX_INIT_PARAM (config);
60   config.nPortIndex = omx_base->out_port->port_index;
61
62   OMX_GetConfig (gomx->omx_handle, OMX_IndexConfigVideoIntraVOPRefresh, &config);
63   config.IntraRefreshVOP = OMX_TRUE;
64
65   OMX_SetConfig (gomx->omx_handle, OMX_IndexConfigVideoIntraVOPRefresh, &config);
66 }
67
68
69 static GstOmxReturn
70 process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
71 {
72   GstOmxBaseVideoEnc *self;
73
74   self = GST_OMX_BASE_VIDEOENC (omx_base_filter);
75
76   GST_LOG_OBJECT (self, "base videoenc process_input_buf enter");
77
78
79   return GSTOMX_RETURN_OK;
80 }
81
82 /* modification: postprocess for outputbuf. in this videoenc case, set sync frame */
83 static GstOmxReturn
84 process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
85 {
86   GstOmxBaseVideoEnc *self;
87
88   self = GST_OMX_BASE_VIDEOENC (omx_base);
89
90   GST_LOG_OBJECT (self, "base videoenc process_output_buf enter");
91
92   /* modification: set sync frame info while encoding */
93   if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
94     GST_BUFFER_FLAG_UNSET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
95   } else {
96     GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
97   }
98
99   return GSTOMX_RETURN_OK;
100 }
101
102 /* modification: get codec_data from omx component and set it caps */
103 static void
104 process_output_caps(GstOmxBaseFilter * self, OMX_BUFFERHEADERTYPE *omx_buffer)
105 {
106   GstBuffer *buf;
107   GstCaps *caps = NULL;
108   GstStructure *structure;
109   GValue value = { 0, {{0}
110       }
111   };
112
113   caps = gst_pad_get_negotiated_caps (self->srcpad);
114   caps = gst_caps_make_writable (caps);
115   structure = gst_caps_get_structure (caps, 0);
116
117   g_value_init (&value, GST_TYPE_BUFFER);
118   buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
119   memcpy (GST_BUFFER_DATA (buf),
120       omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
121   gst_value_set_buffer (&value, buf);
122   gst_buffer_unref (buf);
123   gst_structure_set_value (structure, "codec_data", &value);
124   g_value_unset (&value);
125
126   gst_pad_set_caps (self->srcpad, caps);
127   gst_caps_unref (caps);
128 }
129
130 static void
131 type_base_init (gpointer g_class)
132 {
133 }
134
135 static void
136 set_property (GObject * obj,
137     guint prop_id, const GValue * value, GParamSpec * pspec)
138 {
139   GstOmxBaseVideoEnc *self;
140
141   self = GST_OMX_BASE_VIDEOENC (obj);
142
143   switch (prop_id) {
144     case ARG_BITRATE:
145       self->bitrate = g_value_get_uint (value);
146       break;
147     /* modification: request to component to make key frame */
148     case ARG_FORCE_KEY_FRAME:
149       self->use_force_key_frame = g_value_get_boolean (value);
150       if (self->use_force_key_frame) {
151         add_force_key_frame (self);
152         self->use_force_key_frame = FALSE;
153       }
154       break;
155     default:
156       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
157       break;
158   }
159 }
160
161 static void
162 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
163 {
164   GstOmxBaseVideoEnc *self;
165
166   self = GST_OMX_BASE_VIDEOENC (obj);
167
168   switch (prop_id) {
169     case ARG_BITRATE:
170             /** @todo propagate this to OpenMAX when processing. */
171       g_value_set_uint (value, self->bitrate);
172       break;
173     default:
174       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
175       break;
176   }
177 }
178
179 static void
180 type_class_init (gpointer g_class, gpointer class_data)
181 {
182   GObjectClass *gobject_class;
183   GstOmxBaseFilterClass *basefilter_class;
184 //  GstOmxBaseVideoEncClass *videoenc_class;
185
186   gobject_class = G_OBJECT_CLASS (g_class);
187   basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
188 //  videoenc_class = GST_OMX_BASE_VIDEOENC_CLASS (g_class);
189
190   /* Properties stuff */
191   {
192     gobject_class->set_property = set_property;
193     gobject_class->get_property = get_property;
194
195     g_object_class_install_property (gobject_class, ARG_BITRATE,
196         g_param_spec_uint ("bitrate", "Bit-rate",
197             "Encoding bit-rate",
198             0, G_MAXUINT, DEFAULT_BITRATE,
199             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
200
201     g_object_class_install_property (gobject_class, ARG_FORCE_KEY_FRAME,
202         g_param_spec_boolean ("force-i-frame", "force the encoder to produce I frame",
203             "force the encoder to produce I frame",
204             FALSE,
205             G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
206   }
207   basefilter_class->process_input_buf = process_input_buf;
208   basefilter_class->process_output_buf = process_output_buf;
209   basefilter_class->process_output_caps = process_output_caps;
210 }
211
212 static gboolean
213 sink_setcaps (GstPad * pad, GstCaps * caps)
214 {
215   GstStructure *structure;
216   GstOmxBaseVideoEnc *self;
217   GstOmxBaseFilter *omx_base;
218   GOmxCore *gomx;
219   OMX_COLOR_FORMATTYPE color_format = OMX_COLOR_FormatUnused;
220   gint width = 0;
221   gint height = 0;
222   const GValue *framerate = NULL;
223
224   self = GST_OMX_BASE_VIDEOENC (GST_PAD_PARENT (pad));
225   omx_base = GST_OMX_BASE_FILTER (self);
226   gomx = (GOmxCore *) omx_base->gomx;
227
228   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
229
230   g_return_val_if_fail (gst_caps_get_size (caps) == 1, FALSE);
231
232   structure = gst_caps_get_structure (caps, 0);
233
234   gst_structure_get_int (structure, "width", &width);
235   gst_structure_get_int (structure, "height", &height);
236
237   if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0) {
238     guint32 fourcc;
239
240     framerate = gst_structure_get_value (structure, "framerate");
241     if (framerate) {
242       self->framerate_num = gst_value_get_fraction_numerator (framerate);
243       self->framerate_denom = gst_value_get_fraction_denominator (framerate);
244     }
245
246     if (gst_structure_get_fourcc (structure, "format", &fourcc)) {
247       switch (fourcc) {
248         case GST_MAKE_FOURCC ('I', '4', '2', '0'):
249         case GST_MAKE_FOURCC ('S', '4', '2', '0'):
250           color_format = OMX_COLOR_FormatYUV420PackedPlanar;
251           break;
252         case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
253           color_format = OMX_COLOR_FormatYCbYCr;
254           break;
255         case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
256           color_format = OMX_COLOR_FormatCbYCrY;
257           break;
258         /* MODIFICATION: Add extended_color_format */
259         case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
260           color_format = OMX_EXT_COLOR_FormatNV12TPhysicalAddress;
261           break;
262         case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
263           color_format = OMX_EXT_COLOR_FormatNV12LPhysicalAddress;
264           break;
265       }
266     }
267   }
268
269   {
270     OMX_PARAM_PORTDEFINITIONTYPE param;
271
272     G_OMX_INIT_PARAM (param);
273
274     /* Input port configuration. */
275     {
276       param.nPortIndex = omx_base->in_port->port_index;
277       OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
278
279       param.format.video.nFrameWidth = width;
280       param.format.video.nFrameHeight = height;
281       param.format.video.eColorFormat = color_format;
282       if (framerate) {
283         /* convert to Q.16 */
284         param.format.video.xFramerate =
285             (gst_value_get_fraction_numerator (framerate) << 16) /
286             gst_value_get_fraction_denominator (framerate);
287       }
288
289       OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
290     }
291
292     /* modification: set nBufferSize */
293     G_OMX_INIT_PARAM (param);
294
295     param.nPortIndex = omx_base->out_port->port_index;
296     OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
297
298     param.nBufferSize = width * height * 3 / 2;
299     OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
300   }
301
302   return gst_pad_set_caps (pad, caps);
303 }
304
305 static void
306 omx_setup (GstOmxBaseFilter * omx_base)
307 {
308   GstOmxBaseVideoEnc *self;
309   GOmxCore *gomx;
310
311   self = GST_OMX_BASE_VIDEOENC (omx_base);
312   gomx = (GOmxCore *) omx_base->gomx;
313
314   GST_INFO_OBJECT (omx_base, "begin");
315
316   {
317     OMX_PARAM_PORTDEFINITIONTYPE param;
318
319     G_OMX_INIT_PARAM (param);
320
321     /* Output port configuration. */
322     {
323       param.nPortIndex = omx_base->out_port->port_index;
324       OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
325
326       param.format.video.eCompressionFormat = self->compression_format;
327
328       if (self->bitrate > 0)
329         param.format.video.nBitrate = self->bitrate;
330
331       OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
332     }
333   }
334
335   /* modification: set bitrate by using OMX_IndexParamVideoBitrate macro*/
336   if (self->bitrate > 0) {
337     OMX_VIDEO_PARAM_BITRATETYPE param;
338     G_OMX_INIT_PARAM (param);
339
340     param.nPortIndex = omx_base->out_port->port_index;
341     OMX_GetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, &param);
342
343     param.nTargetBitrate = self->bitrate;
344     param.eControlRate = OMX_Video_ControlRateConstant;
345     GST_INFO_OBJECT (self, "set bitrate (OMX_Video_ControlRateConstant): %d", param.nTargetBitrate);
346
347     OMX_SetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, &param);
348   }
349
350   GST_INFO_OBJECT (omx_base, "end");
351 }
352
353 static void
354 type_instance_init (GTypeInstance * instance, gpointer g_class)
355 {
356   GstOmxBaseFilter *omx_base;
357   GstOmxBaseVideoEnc *self;
358
359   omx_base = GST_OMX_BASE_FILTER (instance);
360   self = GST_OMX_BASE_VIDEOENC (instance);
361
362   omx_base->omx_setup = omx_setup;
363
364   gst_pad_set_setcaps_function (omx_base->sinkpad, sink_setcaps);
365
366   self->bitrate = DEFAULT_BITRATE;
367   self->use_force_key_frame = FALSE;
368 }