tizen beta release
[profile/ivi/gst-openmax0.10.git] / omx / gstomx_base_src.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_src.h"
23 #include "gstomx.h"
24
25 #include <string.h>             /* for memcpy */
26
27 enum
28 {
29   ARG_NUM_OUTPUT_BUFFERS = GSTOMX_NUM_COMMON_PROP,
30 };
31
32 GSTOMX_BOILERPLATE (GstOmxBaseSrc, gst_omx_base_src, GstBaseSrc,
33     GST_TYPE_BASE_SRC);
34
35 static void
36 setup_ports (GstOmxBaseSrc * self)
37 {
38   /* Input port configuration. */
39   g_omx_port_setup (self->out_port);
40
41   if (self->setup_ports) {
42     self->setup_ports (self);
43   }
44 }
45
46 static gboolean
47 start (GstBaseSrc * gst_base)
48 {
49   GstOmxBaseSrc *self;
50
51   self = GST_OMX_BASE_SRC (gst_base);
52
53   GST_LOG_OBJECT (self, "begin");
54
55   if (self->gomx->omx_error)
56     return GST_STATE_CHANGE_FAILURE;
57
58   GST_LOG_OBJECT (self, "end");
59
60   return TRUE;
61 }
62
63 static gboolean
64 stop (GstBaseSrc * gst_base)
65 {
66   GstOmxBaseSrc *self;
67
68   self = GST_OMX_BASE_SRC (gst_base);
69
70   GST_LOG_OBJECT (self, "begin");
71
72   g_omx_core_stop (self->gomx);
73   g_omx_core_unload (self->gomx);
74
75   if (self->gomx->omx_error)
76     return GST_STATE_CHANGE_FAILURE;
77
78   GST_LOG_OBJECT (self, "end");
79
80   return TRUE;
81 }
82
83 static void
84 finalize (GObject * obj)
85 {
86   GstOmxBaseSrc *self;
87
88   self = GST_OMX_BASE_SRC (obj);
89
90   g_omx_core_free (self->gomx);
91
92   G_OBJECT_CLASS (parent_class)->finalize (obj);
93 }
94
95 static GstFlowReturn
96 create (GstBaseSrc * gst_base,
97     guint64 offset, guint length, GstBuffer ** ret_buf)
98 {
99   GOmxCore *gomx;
100   GOmxPort *out_port;
101   GstOmxBaseSrc *self;
102   GstFlowReturn ret = GST_FLOW_OK;
103
104   self = GST_OMX_BASE_SRC (gst_base);
105
106   gomx = self->gomx;
107
108   GST_LOG_OBJECT (self, "begin");
109
110   GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);
111
112   if (gomx->omx_state == OMX_StateLoaded) {
113     GST_INFO_OBJECT (self, "omx: prepare");
114
115     setup_ports (self);
116     g_omx_core_prepare (self->gomx);
117   }
118
119   out_port = self->out_port;
120
121   while (out_port->enabled) {
122     switch (gomx->omx_state) {
123       case OMX_StateIdle:
124       {
125         GST_INFO_OBJECT (self, "omx: play");
126         g_omx_core_start (gomx);
127       }
128         break;
129       default:
130         break;
131     }
132
133     switch (gomx->omx_state) {
134       case OMX_StateExecuting:
135         /* OK */
136         break;
137       default:
138         GST_ERROR_OBJECT (self, "Whoa! very wrong");
139         break;
140     }
141
142     {
143       OMX_BUFFERHEADERTYPE *omx_buffer;
144
145       GST_LOG_OBJECT (self, "request_buffer");
146       omx_buffer = g_omx_port_request_buffer (out_port);
147
148       if (omx_buffer) {
149         GST_DEBUG_OBJECT (self, "omx_buffer: size=%lu, len=%lu, offset=%lu",
150             omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nOffset);
151
152         if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS) {
153           GST_INFO_OBJECT (self, "got eos");
154           g_omx_core_set_done (gomx);
155           break;
156         }
157
158         if (omx_buffer->nFilledLen > 0) {
159           GstBuffer *buf;
160
161           if (out_port->enabled) {
162             GstCaps *caps = NULL;
163
164             caps = gst_pad_get_negotiated_caps (gst_base->srcpad);
165
166             if (!caps) {
167                             /** @todo We shouldn't be doing this. */
168               GST_WARNING_OBJECT (self, "somebody didn't do his work");
169               gomx->settings_changed_cb (gomx);
170             } else {
171               GST_LOG_OBJECT (self, "caps already fixed");
172               gst_caps_unref (caps);
173             }
174           }
175
176           buf = omx_buffer->pAppPrivate;
177
178           if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
179             GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
180 #if 0
181             if (self->use_timestamps) {
182               GST_BUFFER_TIMESTAMP (buf) =
183                   omx_buffer->nTimeStamp * (GST_SECOND / OMX_TICKS_PER_SECOND);
184             }
185 #endif
186
187             omx_buffer->pAppPrivate = NULL;
188             omx_buffer->pBuffer = NULL;
189             omx_buffer->nFilledLen = 0;
190
191             *ret_buf = buf;
192
193             gst_buffer_unref (buf);
194           } else {
195             /* This is only meant for the first OpenMAX buffers,
196              * which need to be pre-allocated. */
197             /* Also for the very last one. */
198             gst_pad_alloc_buffer_and_set_caps (gst_base->srcpad,
199                 GST_BUFFER_OFFSET_NONE,
200                 omx_buffer->nFilledLen, GST_PAD_CAPS (gst_base->srcpad), &buf);
201
202             if (buf) {
203               GST_WARNING_OBJECT (self, "couldn't zero-copy");
204               memcpy (GST_BUFFER_DATA (buf),
205                   omx_buffer->pBuffer + omx_buffer->nOffset,
206                   omx_buffer->nFilledLen);
207 #if 0
208               if (self->use_timestamps) {
209                 GST_BUFFER_TIMESTAMP (buf) =
210                     omx_buffer->nTimeStamp * (GST_SECOND /
211                     OMX_TICKS_PER_SECOND);
212               }
213 #endif
214
215               omx_buffer->nFilledLen = 0;
216               g_free (omx_buffer->pBuffer);
217               omx_buffer->pBuffer = NULL;
218
219               *ret_buf = buf;
220             } else {
221               GST_ERROR_OBJECT (self, "whoa!");
222             }
223           }
224
225           if (!omx_buffer->pBuffer) {
226             GstBuffer *new_buf;
227             GstFlowReturn result;
228
229             GST_LOG_OBJECT (self, "allocate buffer");
230             result = gst_pad_alloc_buffer_and_set_caps (gst_base->srcpad,
231                 GST_BUFFER_OFFSET_NONE,
232                 omx_buffer->nAllocLen,
233                 GST_PAD_CAPS (gst_base->srcpad), &new_buf);
234
235             if (result == GST_FLOW_OK) {
236               gst_buffer_ref (new_buf);
237               omx_buffer->pAppPrivate = new_buf;
238
239               omx_buffer->pBuffer = GST_BUFFER_DATA (new_buf);
240               omx_buffer->nAllocLen = GST_BUFFER_SIZE (new_buf);
241             } else {
242               GST_WARNING_OBJECT (self, "could not allocate buffer");
243               omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen);
244             }
245           }
246
247           GST_LOG_OBJECT (self, "release_buffer");
248           g_omx_port_release_buffer (out_port, omx_buffer);
249           break;
250         } else {
251           GST_WARNING_OBJECT (self, "empty buffer");
252           GST_LOG_OBJECT (self, "release_buffer");
253           g_omx_port_release_buffer (out_port, omx_buffer);
254           continue;
255         }
256       } else {
257         GST_WARNING_OBJECT (self, "null buffer");
258         /* ret = GST_FLOW_ERROR; */
259         break;
260       }
261     }
262   }
263
264   if (!out_port->enabled) {
265     GST_WARNING_OBJECT (self, "done");
266     ret = GST_FLOW_UNEXPECTED;
267   }
268
269   GST_LOG_OBJECT (self, "end");
270
271   return ret;
272 }
273
274 static gboolean
275 handle_event (GstBaseSrc * gst_base, GstEvent * event)
276 {
277   GstOmxBaseSrc *self;
278
279   self = GST_OMX_BASE_SRC (gst_base);
280
281   GST_LOG_OBJECT (self, "begin");
282
283   GST_DEBUG_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
284
285   switch (GST_EVENT_TYPE (event)) {
286     case GST_EVENT_EOS:
287       /* Close the output port. */
288       g_omx_core_set_done (self->gomx);
289       break;
290
291     case GST_EVENT_NEWSEGMENT:
292       break;
293
294     default:
295       break;
296   }
297
298   GST_LOG_OBJECT (self, "end");
299
300   return TRUE;
301 }
302
303 static void
304 set_property (GObject * obj,
305     guint prop_id, const GValue * value, GParamSpec * pspec)
306 {
307   GstOmxBaseSrc *self;
308
309   self = GST_OMX_BASE_SRC (obj);
310
311   switch (prop_id) {
312     case ARG_NUM_OUTPUT_BUFFERS:
313     {
314       OMX_PARAM_PORTDEFINITIONTYPE param;
315       OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
316       OMX_U32 nBufferCountActual;
317
318       if (G_UNLIKELY (omx_handle)) {
319         GST_WARNING_OBJECT (self, "no component");
320         break;
321       }
322
323       nBufferCountActual = g_value_get_uint (value);
324
325       G_OMX_INIT_PARAM (param);
326
327       param.nPortIndex = self->out_port->port_index;
328       OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, &param);
329
330       if (nBufferCountActual < param.nBufferCountMin) {
331         GST_ERROR_OBJECT (self, "buffer count %lu is less than minimum %lu",
332             nBufferCountActual, param.nBufferCountMin);
333         return;
334       }
335
336       param.nBufferCountActual = nBufferCountActual;
337
338       OMX_SetParameter (omx_handle, OMX_IndexParamPortDefinition, &param);
339     }
340       break;
341     default:
342       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
343       break;
344   }
345 }
346
347 static void
348 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
349 {
350   GstOmxBaseSrc *self;
351
352   self = GST_OMX_BASE_SRC (obj);
353
354   if (gstomx_get_property_helper (self->gomx, prop_id, value))
355     return;
356
357   switch (prop_id) {
358     case ARG_NUM_OUTPUT_BUFFERS:
359     {
360       OMX_PARAM_PORTDEFINITIONTYPE param;
361       OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
362
363       if (G_UNLIKELY (!omx_handle)) {
364         GST_WARNING_OBJECT (self, "no component");
365         g_value_set_uint (value, 0);
366         break;
367       }
368
369       G_OMX_INIT_PARAM (param);
370
371       param.nPortIndex = self->out_port->port_index;
372       OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, &param);
373
374       g_value_set_uint (value, param.nBufferCountActual);
375     }
376       break;
377     default:
378       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
379       break;
380   }
381 }
382
383 static void
384 type_base_init (gpointer g_class)
385 {
386 }
387
388 static void
389 type_class_init (gpointer g_class, gpointer class_data)
390 {
391   GObjectClass *gobject_class;
392   GstBaseSrcClass *gst_base_src_class;
393
394   gobject_class = G_OBJECT_CLASS (g_class);
395   gst_base_src_class = GST_BASE_SRC_CLASS (g_class);
396
397   gobject_class->finalize = finalize;
398
399   gst_base_src_class->start = start;
400   gst_base_src_class->stop = stop;
401   gst_base_src_class->event = handle_event;
402   gst_base_src_class->create = create;
403
404   /* Properties stuff */
405   {
406     gobject_class->set_property = set_property;
407     gobject_class->get_property = get_property;
408
409     gstomx_install_property_helper (gobject_class);
410
411     g_object_class_install_property (gobject_class, ARG_NUM_OUTPUT_BUFFERS,
412         g_param_spec_uint ("output-buffers", "Output buffers",
413             "The number of OMX output buffers",
414             1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
415   }
416 }
417
418 static void
419 type_instance_init (GTypeInstance * instance, gpointer g_class)
420 {
421   GstOmxBaseSrc *self;
422
423   self = GST_OMX_BASE_SRC (instance);
424
425   GST_LOG_OBJECT (self, "begin");
426
427   self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class));
428   self->out_port = g_omx_core_new_port (self->gomx, 1);
429
430   GST_LOG_OBJECT (self, "end");
431 }