Remove core_finish, use core_unload
[gstreamer-omap:gst-openmax.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 memset, memcpy */
26
27 enum
28 {
29     ARG_0,
30     ARG_COMPONENT_NAME,
31     ARG_LIBRARY_NAME,
32 };
33
34 static GstElementClass *parent_class;
35
36 static void
37 setup_ports (GstOmxBaseSrc *self)
38 {
39     GOmxCore *core;
40     OMX_PARAM_PORTDEFINITIONTYPE param;
41
42     core = self->gomx;
43
44     memset (&param, 0, sizeof (param));
45     param.nSize = sizeof (OMX_PARAM_PORTDEFINITIONTYPE);
46     param.nVersion.s.nVersionMajor = 1;
47     param.nVersion.s.nVersionMinor = 1;
48
49     /* Input port configuration. */
50
51     param.nPortIndex = 0;
52     OMX_GetParameter (core->omx_handle, OMX_IndexParamPortDefinition, &param);
53     self->out_port = g_omx_core_setup_port (core, &param);
54
55     if (self->setup_ports)
56     {
57         self->setup_ports (self);
58     }
59 }
60
61 static gboolean
62 start (GstBaseSrc *gst_base)
63 {
64     GstOmxBaseSrc *self;
65
66     self = GST_OMX_BASE_SRC (gst_base);
67
68     GST_LOG_OBJECT (self, "begin");
69
70     g_omx_core_init (self->gomx, self->omx_library, self->omx_component);
71     if (self->gomx->omx_error)
72         return GST_STATE_CHANGE_FAILURE;
73
74     GST_LOG_OBJECT (self, "end");
75
76     return TRUE;
77 }
78
79 static gboolean
80 stop (GstBaseSrc *gst_base)
81 {
82     GstOmxBaseSrc *self;
83
84     self = GST_OMX_BASE_SRC (gst_base);
85
86     GST_LOG_OBJECT (self, "begin");
87
88     g_omx_core_stop (self->gomx);
89     g_omx_core_unload (self->gomx);
90     g_omx_core_deinit (self->gomx);
91
92     if (self->gomx->omx_error)
93         return GST_STATE_CHANGE_FAILURE;
94
95     GST_LOG_OBJECT (self, "end");
96
97     return TRUE;
98 }
99
100 static void
101 finalize (GObject *obj)
102 {
103     GstOmxBaseSrc *self;
104
105     self = GST_OMX_BASE_SRC (obj);
106
107     g_omx_core_free (self->gomx);
108
109     g_free (self->omx_component);
110     g_free (self->omx_library);
111
112     G_OBJECT_CLASS (parent_class)->finalize (obj);
113 }
114
115 static GstFlowReturn
116 create (GstBaseSrc *gst_base,
117         guint64 offset,
118         guint length,
119         GstBuffer **ret_buf)
120 {
121     GOmxCore *gomx;
122     GOmxPort *out_port;
123     GstOmxBaseSrc *self;
124     GstFlowReturn ret = GST_FLOW_OK;
125
126     self = GST_OMX_BASE_SRC (gst_base);
127
128     gomx = self->gomx;
129
130     GST_LOG_OBJECT (self, "begin");
131
132     GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);
133
134     if (gomx->omx_state == OMX_StateLoaded)
135     {
136         GST_INFO_OBJECT (self, "omx: prepare");
137
138         setup_ports (self);
139         g_omx_core_prepare (self->gomx);
140     }
141
142     out_port = self->out_port;
143
144     while (out_port->enabled)
145     {
146         switch (gomx->omx_state)
147         {
148             case OMX_StateIdle:
149                 {
150                     GST_INFO_OBJECT (self, "omx: play");
151                     g_omx_core_start (gomx);
152                 }
153                 break;
154             default:
155                 break;
156         }
157
158         switch (gomx->omx_state)
159         {
160             case OMX_StateExecuting:
161                 /* OK */
162                 break;
163             default:
164                 GST_ERROR_OBJECT (self, "Whoa! very wrong");
165                 break;
166         }
167
168         {
169             OMX_BUFFERHEADERTYPE *omx_buffer;
170
171             GST_LOG_OBJECT (self, "request_buffer");
172             omx_buffer = g_omx_port_request_buffer (out_port);
173
174             if (omx_buffer)
175             {
176                 GST_DEBUG_OBJECT (self, "omx_buffer: size=%lu, len=%lu, offset=%lu",
177                                   omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nOffset);
178
179                 if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)
180                 {
181                     GST_INFO_OBJECT (self, "got eos");
182                     g_omx_core_set_done (gomx);
183                     break;
184                 }
185
186                 if (omx_buffer->nFilledLen > 0)
187                 {
188                     GstBuffer *buf;
189
190                     if (out_port->enabled)
191                     {
192                         GstCaps *caps = NULL;
193
194                         caps = gst_pad_get_negotiated_caps (gst_base->srcpad);
195
196                         if (!caps)
197                         {
198                             /** @todo We shouldn't be doing this. */
199                             GST_WARNING_OBJECT (self, "somebody didn't do his work");
200                             gomx->settings_changed_cb (gomx);
201                         }
202                         else
203                         {
204                             GST_LOG_OBJECT (self, "caps already fixed");
205                             gst_caps_unref (caps);
206                         }
207                     }
208
209                     buf = omx_buffer->pAppPrivate;
210
211                     if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS))
212                     {
213                         GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
214 #if 0
215                         if (self->use_timestamps)
216                         {
217                             GST_BUFFER_TIMESTAMP (buf) = omx_buffer->nTimeStamp * (GST_SECOND / OMX_TICKS_PER_SECOND);
218                         }
219 #endif
220
221                         omx_buffer->pAppPrivate = NULL;
222                         omx_buffer->pBuffer = NULL;
223                         omx_buffer->nFilledLen = 0;
224
225                         *ret_buf = buf;
226
227                         gst_buffer_unref (buf);
228                     }
229                     else
230                     {
231                         /* This is only meant for the first OpenMAX buffers,
232                          * which need to be pre-allocated. */
233                         /* Also for the very last one. */
234                         gst_pad_alloc_buffer_and_set_caps (gst_base->srcpad,
235                                                            GST_BUFFER_OFFSET_NONE,
236                                                            omx_buffer->nFilledLen,
237                                                            GST_PAD_CAPS (gst_base->srcpad),
238                                                            &buf);
239
240                         if (buf)
241                         {
242                             GST_WARNING_OBJECT (self, "couldn't zero-copy");
243                             memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
244 #if 0
245                             if (self->use_timestamps)
246                             {
247                                 GST_BUFFER_TIMESTAMP (buf) = omx_buffer->nTimeStamp * (GST_SECOND / OMX_TICKS_PER_SECOND);
248                             }
249 #endif
250
251                             omx_buffer->nFilledLen = 0;
252                             g_free (omx_buffer->pBuffer);
253                             omx_buffer->pBuffer = NULL;
254
255                             *ret_buf = buf;
256                         }
257                         else
258                         {
259                             GST_ERROR_OBJECT (self, "whoa!");
260                         }
261                     }
262
263                     if (!omx_buffer->pBuffer)
264                     {
265                         GstBuffer *new_buf;
266                         GstFlowReturn result;
267
268                         GST_LOG_OBJECT (self, "allocate buffer");
269                         result = gst_pad_alloc_buffer_and_set_caps (gst_base->srcpad,
270                                                                     GST_BUFFER_OFFSET_NONE,
271                                                                     omx_buffer->nAllocLen,
272                                                                     GST_PAD_CAPS (gst_base->srcpad),
273                                                                     &new_buf);
274
275                         if (result == GST_FLOW_OK)
276                         {
277                             gst_buffer_ref (new_buf);
278                             omx_buffer->pAppPrivate = new_buf;
279
280                             omx_buffer->pBuffer = GST_BUFFER_DATA (new_buf);
281                             omx_buffer->nAllocLen = GST_BUFFER_SIZE (new_buf);
282                         }
283                         else
284                         {
285                             GST_WARNING_OBJECT (self, "could not allocate buffer");
286                             omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen);
287                         }
288                     }
289
290                     GST_LOG_OBJECT (self, "release_buffer");
291                     g_omx_port_release_buffer (out_port, omx_buffer);
292                     break;
293                 }
294                 else
295                 {
296                     GST_WARNING_OBJECT (self, "empty buffer");
297                     GST_LOG_OBJECT (self, "release_buffer");
298                     g_omx_port_release_buffer (out_port, omx_buffer);
299                     continue;
300                 }
301             }
302             else
303             {
304                 GST_WARNING_OBJECT (self, "null buffer");
305                 /* ret = GST_FLOW_ERROR; */
306                 break;
307             }
308         }
309     }
310
311     if (!out_port->enabled)
312     {
313         GST_WARNING_OBJECT (self, "done");
314         ret = GST_FLOW_UNEXPECTED;
315     }
316
317     GST_LOG_OBJECT (self, "end");
318
319     return ret;
320 }
321
322 static gboolean
323 handle_event (GstBaseSrc *gst_base,
324               GstEvent *event)
325 {
326     GstOmxBaseSrc *self;
327
328     self = GST_OMX_BASE_SRC (gst_base);
329
330     GST_LOG_OBJECT (self, "begin");
331
332     GST_DEBUG_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
333
334     switch (GST_EVENT_TYPE (event))
335     {
336         case GST_EVENT_EOS:
337             /* Close the output port. */
338             g_omx_core_set_done (self->gomx);
339             break;
340
341         case GST_EVENT_NEWSEGMENT:
342             break;
343
344         default:
345             break;
346     }
347
348     GST_LOG_OBJECT (self, "end");
349
350     return TRUE;
351 }
352
353 static void
354 set_property (GObject *obj,
355               guint prop_id,
356               const GValue *value,
357               GParamSpec *pspec)
358 {
359     GstOmxBaseSrc *self;
360
361     self = GST_OMX_BASE_SRC (obj);
362
363     switch (prop_id)
364     {
365         case ARG_COMPONENT_NAME:
366             if (self->omx_component)
367             {
368                 g_free (self->omx_component);
369             }
370             self->omx_component = g_value_dup_string (value);
371             break;
372         case ARG_LIBRARY_NAME:
373             if (self->omx_library)
374             {
375                 g_free (self->omx_library);
376             }
377             self->omx_library = g_value_dup_string (value);
378             break;
379         default:
380             G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
381             break;
382     }
383 }
384
385 static void
386 get_property (GObject *obj,
387               guint prop_id,
388               GValue *value,
389               GParamSpec *pspec)
390 {
391     GstOmxBaseSrc *self;
392
393     self = GST_OMX_BASE_SRC (obj);
394
395     switch (prop_id)
396     {
397         case ARG_COMPONENT_NAME:
398             g_value_set_string (value, self->omx_component);
399             break;
400         case ARG_LIBRARY_NAME:
401             g_value_set_string (value, self->omx_library);
402             break;
403         default:
404             G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
405             break;
406     }
407 }
408
409 static void
410 type_class_init (gpointer g_class,
411                  gpointer class_data)
412 {
413     GObjectClass *gobject_class;
414     GstBaseSrcClass *gst_base_src_class;
415
416     gobject_class = G_OBJECT_CLASS (g_class);
417     gst_base_src_class = GST_BASE_SRC_CLASS (g_class);
418
419     parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
420
421     gobject_class->finalize = finalize;
422
423     gst_base_src_class->start = start;
424     gst_base_src_class->stop = stop;
425     gst_base_src_class->event = handle_event;
426     gst_base_src_class->create = create;
427
428     /* Properties stuff */
429     {
430         gobject_class->set_property = set_property;
431         gobject_class->get_property = get_property;
432
433         g_object_class_install_property (gobject_class, ARG_COMPONENT_NAME,
434                                          g_param_spec_string ("component-name", "Component name",
435                                                               "Name of the OpenMAX IL component to use",
436                                                               NULL, G_PARAM_READWRITE));
437
438         g_object_class_install_property (gobject_class, ARG_LIBRARY_NAME,
439                                          g_param_spec_string ("library-name", "Library name",
440                                                               "Name of the OpenMAX IL implementation library to use",
441                                                               NULL, G_PARAM_READWRITE));
442     }
443 }
444
445 static void
446 type_instance_init (GTypeInstance *instance,
447                     gpointer g_class)
448 {
449     GstOmxBaseSrc *self;
450
451     self = GST_OMX_BASE_SRC (instance);
452
453     GST_LOG_OBJECT (self, "begin");
454
455     /* GOmx */
456     {
457         GOmxCore *gomx;
458         self->gomx = gomx = g_omx_core_new ();
459         gomx->object = self;
460     }
461
462     {
463         const char *tmp;
464         tmp = g_type_get_qdata (G_OBJECT_CLASS_TYPE (g_class),
465                                 g_quark_from_static_string ("library-name"));
466         self->omx_library = g_strdup (tmp);
467         tmp = g_type_get_qdata (G_OBJECT_CLASS_TYPE (g_class),
468                                 g_quark_from_static_string ("component-name"));
469         self->omx_component = g_strdup (tmp);
470     }
471
472
473     GST_LOG_OBJECT (self, "end");
474 }
475
476 GType
477 gst_omx_base_src_get_type (void)
478 {
479     static GType type = 0;
480
481     if (G_UNLIKELY (type == 0))
482     {
483         GTypeInfo *type_info;
484
485         type_info = g_new0 (GTypeInfo, 1);
486         type_info->class_size = sizeof (GstOmxBaseSrcClass);
487         type_info->class_init = type_class_init;
488         type_info->instance_size = sizeof (GstOmxBaseSrc);
489         type_info->instance_init = type_instance_init;
490
491         type = g_type_register_static (GST_TYPE_BASE_SRC, "GstOmxBaseSrc", type_info, 0);
492
493         g_free (type_info);
494     }
495
496     return type;
497 }