Tizen 2.1 base
[profile/ivi/gst-openmax0.10.git] / omx / gstomx_util.c
1 /*
2  * Copyright (C) 2006-2007 Texas Instruments, Incorporated
3  * Copyright (C) 2007-2009 Nokia Corporation.
4  *
5  * Author: Felipe Contreras <felipe.contreras@nokia.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation
10  * version 2.1 of the License.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #include "gstomx_util.h"
24 #include <dlfcn.h>
25
26 #include "gstomx.h"
27
28 GST_DEBUG_CATEGORY (gstomx_util_debug);
29
30 /*
31  * Forward declarations
32  */
33
34 static inline void change_state (GOmxCore * core, OMX_STATETYPE state);
35
36 static inline void wait_for_state (GOmxCore * core, OMX_STATETYPE state);
37
38 static inline void
39 in_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer);
40
41 static inline void
42 out_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer);
43
44 static inline void
45 got_buffer (GOmxCore * core,
46     GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer);
47
48 static OMX_ERRORTYPE
49 EventHandler (OMX_HANDLETYPE omx_handle,
50     OMX_PTR app_data,
51     OMX_EVENTTYPE event, OMX_U32 data_1, OMX_U32 data_2, OMX_PTR event_data);
52
53 static OMX_ERRORTYPE
54 EmptyBufferDone (OMX_HANDLETYPE omx_handle,
55     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer);
56
57 static OMX_ERRORTYPE
58 FillBufferDone (OMX_HANDLETYPE omx_handle,
59     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer);
60
61 static inline const char *omx_state_to_str (OMX_STATETYPE omx_state);
62
63 static inline const char *omx_error_to_str (OMX_ERRORTYPE omx_error);
64
65 static inline GOmxPort *get_port (GOmxCore * core, guint index);
66
67 static void core_deinit (GOmxCore * core);
68
69 static inline void port_free_buffers (GOmxPort * port);
70
71 static inline void port_allocate_buffers (GOmxPort * port);
72
73 static inline void port_start_buffers (GOmxPort * port);
74
75 static OMX_CALLBACKTYPE callbacks =
76     { EventHandler, EmptyBufferDone, FillBufferDone };
77
78 /* protect implementations hash_table */
79 static GMutex *imp_mutex;
80 static GHashTable *implementations;
81 static gboolean initialized;
82
83 /*
84  * Util
85  */
86
87 static void
88 g_ptr_array_clear (GPtrArray * array)
89 {
90   guint index;
91   for (index = 0; index < array->len; index++)
92     array->pdata[index] = NULL;
93 }
94
95 static void
96 g_ptr_array_insert (GPtrArray * array, guint index, gpointer data)
97 {
98   if (index + 1 > array->len) {
99     g_ptr_array_set_size (array, index + 1);
100   }
101
102   array->pdata[index] = data;
103 }
104
105 typedef void (*GOmxPortFunc) (GOmxPort * port);
106
107 static inline void
108 core_for_each_port (GOmxCore * core, GOmxPortFunc func)
109 {
110   guint index;
111
112   for (index = 0; index < core->ports->len; index++) {
113     GOmxPort *port;
114
115     port = get_port (core, index);
116
117     if (port)
118       func (port);
119   }
120 }
121
122 /*
123  * Main
124  */
125
126 static GOmxImp *imp_new (const gchar * name);
127 static void imp_free (GOmxImp * imp);
128
129 static GOmxImp *
130 imp_new (const gchar * name)
131 {
132   GOmxImp *imp;
133
134   imp = g_new0 (GOmxImp, 1);
135
136   /* Load the OpenMAX IL symbols */
137   {
138     void *handle;
139
140     GST_DEBUG ("loading: %s", name);
141
142     imp->dl_handle = handle = dlopen (name, RTLD_LAZY);
143
144     GST_DEBUG ("dlopen(%s) -> %p", name, handle);
145
146     if (!handle) {
147       g_warning ("%s\n", dlerror ());
148       g_free (imp);
149       return NULL;
150     }
151
152     imp->mutex = g_mutex_new ();
153     imp->sym_table.init = dlsym (handle, "OMX_Init");
154     imp->sym_table.deinit = dlsym (handle, "OMX_Deinit");
155     imp->sym_table.get_handle = dlsym (handle, "OMX_GetHandle");
156     imp->sym_table.free_handle = dlsym (handle, "OMX_FreeHandle");
157   }
158
159   return imp;
160 }
161
162 static void
163 imp_free (GOmxImp * imp)
164 {
165   if (imp->dl_handle) {
166     dlclose (imp->dl_handle);
167   }
168   g_mutex_free (imp->mutex);
169   g_free (imp);
170 }
171
172 static inline GOmxImp *
173 request_imp (const gchar * name)
174 {
175   GOmxImp *imp = NULL;
176
177   g_mutex_lock (imp_mutex);
178   imp = g_hash_table_lookup (implementations, name);
179   if (!imp) {
180     imp = imp_new (name);
181     if (imp)
182       g_hash_table_insert (implementations, g_strdup (name), imp);
183   }
184   g_mutex_unlock (imp_mutex);
185
186   if (!imp)
187     return NULL;
188
189   g_mutex_lock (imp->mutex);
190   if (imp->client_count == 0) {
191     OMX_ERRORTYPE omx_error;
192     omx_error = imp->sym_table.init ();
193     if (omx_error) {
194       g_mutex_unlock (imp->mutex);
195       return NULL;
196     }
197   }
198   imp->client_count++;
199   g_mutex_unlock (imp->mutex);
200
201   return imp;
202 }
203
204 static inline void
205 release_imp (GOmxImp * imp)
206 {
207   g_mutex_lock (imp->mutex);
208   imp->client_count--;
209   if (imp->client_count == 0) {
210     imp->sym_table.deinit ();
211   }
212   g_mutex_unlock (imp->mutex);
213 }
214
215 void
216 g_omx_init (void)
217 {
218   if (!initialized) {
219     /* safe as plugin_init is safe */
220     imp_mutex = g_mutex_new ();
221     implementations = g_hash_table_new_full (g_str_hash,
222         g_str_equal, g_free, (GDestroyNotify) imp_free);
223     initialized = TRUE;
224   }
225 }
226
227 void
228 g_omx_deinit (void)
229 {
230   if (initialized) {
231     g_hash_table_destroy (implementations);
232     g_mutex_free (imp_mutex);
233     initialized = FALSE;
234   }
235 }
236
237 /*
238  * Core
239  */
240
241 GOmxCore *
242 g_omx_core_new (void *object)
243 {
244   GOmxCore *core;
245
246   core = g_new0 (GOmxCore, 1);
247
248   core->object = object;
249   core->ports = g_ptr_array_new ();
250
251   core->omx_state_condition = g_cond_new ();
252   core->omx_state_mutex = g_mutex_new ();
253
254   core->done_sem = g_sem_new ();
255   core->flush_sem = g_sem_new ();
256   core->port_sem = g_sem_new ();
257
258   core->omx_state = OMX_StateInvalid;
259
260   return core;
261 }
262
263 void
264 g_omx_core_free (GOmxCore * core)
265 {
266   core_deinit (core);
267
268   g_sem_free (core->port_sem);
269   g_sem_free (core->flush_sem);
270   g_sem_free (core->done_sem);
271
272   g_mutex_free (core->omx_state_mutex);
273   g_cond_free (core->omx_state_condition);
274
275   g_ptr_array_free (core->ports, TRUE);
276
277   g_free (core);
278   core = NULL;
279 }
280
281 void
282 g_omx_core_init (GOmxCore * core)
283 {
284   GST_DEBUG_OBJECT (core->object, "loading: %s %s (%s)",
285       core->component_name,
286       core->component_role ? core->component_role : "", core->library_name);
287
288   core->imp = request_imp (core->library_name);
289
290   if (!core->imp)
291     return;
292
293   core->omx_error = core->imp->sym_table.get_handle (&core->omx_handle,
294       (char *) core->component_name, core, &callbacks);
295
296   GST_DEBUG_OBJECT (core->object, "OMX_GetHandle(&%p) -> %d",
297       core->omx_handle, core->omx_error);
298
299   if (!core->omx_error) {
300     core->omx_state = OMX_StateLoaded;
301
302     if (core->component_role) {
303       OMX_PARAM_COMPONENTROLETYPE param;
304
305       GST_DEBUG_OBJECT (core->object, "setting component role: %s",
306           core->component_role);
307
308       G_OMX_INIT_PARAM (param);
309
310       strncpy ((char *) param.cRole, core->component_role,
311           OMX_MAX_STRINGNAME_SIZE - 1);
312
313       OMX_SetParameter (core->omx_handle, OMX_IndexParamStandardComponentRole,
314           &param);
315     }
316
317     /* MODIFICATION: Add_component_vendor */
318     if (strncmp(core->component_name+4, "SEC", 3) == 0)
319     {
320       core->component_vendor = GOMX_VENDOR_SLSI;
321     }
322     else if (strncmp(core->component_name+4, "qcom", 4) == 0)
323     {
324       core->component_vendor = GOMX_VENDOR_QCT;
325     }
326     else
327     {
328       core->component_vendor = GOMX_VENDOR_DEFAULT;
329     }
330   }
331 }
332
333 static void
334 core_deinit (GOmxCore * core)
335 {
336   if (!core->imp)
337     return;
338
339   if (core->omx_state == OMX_StateLoaded || core->omx_state == OMX_StateInvalid) {
340     if (core->omx_handle) {
341       core->omx_error = core->imp->sym_table.free_handle (core->omx_handle);
342       GST_DEBUG_OBJECT (core->object, "OMX_FreeHandle(%p) -> %d",
343           core->omx_handle, core->omx_error);
344     }
345   } else {
346     GST_WARNING_OBJECT (core->object, "Incorrect state: %s",
347         omx_state_to_str (core->omx_state));
348   }
349
350   g_free (core->library_name);
351   g_free (core->component_name);
352   g_free (core->component_role);
353   core->library_name = NULL;
354   core->component_name = NULL;
355   core->component_role = NULL;
356
357   release_imp (core->imp);
358   core->imp = NULL;
359 }
360
361 void
362 g_omx_core_prepare (GOmxCore * core)
363 {
364   change_state (core, OMX_StateIdle);
365
366   /* Allocate buffers. */
367   core_for_each_port (core, port_allocate_buffers);
368
369   wait_for_state (core, OMX_StateIdle);
370 }
371
372 void
373 g_omx_core_start (GOmxCore * core)
374 {
375   change_state (core, OMX_StateExecuting);
376   wait_for_state (core, OMX_StateExecuting);
377
378   if (core->omx_state == OMX_StateExecuting)
379     core_for_each_port (core, port_start_buffers);
380 }
381
382 void
383 g_omx_core_stop (GOmxCore * core)
384 {
385   if (core->omx_state == OMX_StateExecuting ||
386       core->omx_state == OMX_StatePause) {
387     change_state (core, OMX_StateIdle);
388     wait_for_state (core, OMX_StateIdle);
389   }
390 }
391
392 void
393 g_omx_core_pause (GOmxCore * core)
394 {
395   change_state (core, OMX_StatePause);
396   wait_for_state (core, OMX_StatePause);
397 }
398
399 void
400 g_omx_core_unload (GOmxCore * core)
401 {
402   if (core->omx_state == OMX_StateIdle ||
403       core->omx_state == OMX_StateWaitForResources ||
404       core->omx_state == OMX_StateInvalid) {
405     if (core->omx_state != OMX_StateInvalid)
406       change_state (core, OMX_StateLoaded);
407
408     core_for_each_port (core, port_free_buffers);
409
410     if (core->omx_state != OMX_StateInvalid)
411       wait_for_state (core, OMX_StateLoaded);
412   }
413
414   core_for_each_port (core, g_omx_port_free);
415   g_ptr_array_clear (core->ports);
416 }
417
418 static inline GOmxPort *
419 get_port (GOmxCore * core, guint index)
420 {
421   if (G_LIKELY (index < core->ports->len)) {
422     return g_ptr_array_index (core->ports, index);
423   }
424
425   return NULL;
426 }
427
428 GOmxPort *
429 g_omx_core_new_port (GOmxCore * core, guint index)
430 {
431   GOmxPort *port = get_port (core, index);
432
433   if (port) {
434     GST_WARNING_OBJECT (core->object, "port %d already exists", index);
435     return port;
436   }
437
438   port = g_omx_port_new (core, index);
439   g_ptr_array_insert (core->ports, index, port);
440
441   return port;
442 }
443
444 void
445 g_omx_core_set_done (GOmxCore * core)
446 {
447   g_sem_up (core->done_sem);
448 }
449
450 void
451 g_omx_core_wait_for_done (GOmxCore * core)
452 {
453   g_sem_down (core->done_sem);
454 }
455
456 void
457 g_omx_core_flush_start (GOmxCore * core)
458 {
459   core_for_each_port (core, g_omx_port_pause);
460 }
461
462 void
463 g_omx_core_flush_stop (GOmxCore * core)
464 {
465   core_for_each_port (core, g_omx_port_flush);
466   core_for_each_port (core, g_omx_port_resume);
467 }
468
469 /*
470  * Port
471  */
472
473 /**
474  * note: this is not intended to be called directly by elements (which should
475  * instead use g_omx_core_new_port())
476  */
477 GOmxPort *
478 g_omx_port_new (GOmxCore * core, guint index)
479 {
480   GOmxPort *port;
481   port = g_new0 (GOmxPort, 1);
482
483   port->core = core;
484   port->port_index = index;
485   port->num_buffers = 0;
486   port->buffer_size = 0;
487   port->buffers = NULL;
488   port->shared_buffer = FALSE;
489
490   port->enabled = TRUE;
491   port->queue = async_queue_new ();
492   port->mutex = g_mutex_new ();
493
494   return port;
495 }
496
497 void
498 g_omx_port_free (GOmxPort * port)
499 {
500   g_mutex_free (port->mutex);
501   async_queue_free (port->queue);
502
503   g_free (port->buffers);
504   port->buffers = NULL;
505   g_free (port);
506   port = NULL;
507 }
508
509 void
510 g_omx_port_setup (GOmxPort * port)
511 {
512   GOmxPortType type = -1;
513   OMX_PARAM_PORTDEFINITIONTYPE param;
514
515   G_OMX_INIT_PARAM (param);
516
517   param.nPortIndex = port->port_index;
518   OMX_GetParameter (port->core->omx_handle, OMX_IndexParamPortDefinition,
519       &param);
520
521   switch (param.eDir) {
522     case OMX_DirInput:
523       type = GOMX_PORT_INPUT;
524       break;
525     case OMX_DirOutput:
526       type = GOMX_PORT_OUTPUT;
527       break;
528     default:
529       break;
530   }
531
532   port->type = type;
533     /** @todo should it be nBufferCountMin? */
534   port->num_buffers = param.nBufferCountActual;
535   port->buffer_size = param.nBufferSize;
536
537   GST_DEBUG_OBJECT (port->core->object,
538       "type=%d, num_buffers=%d, buffer_size=%ld, port_index=%d",
539       port->type, port->num_buffers, port->buffer_size, port->port_index);
540
541   g_free (port->buffers);
542   port->buffers = g_new0 (OMX_BUFFERHEADERTYPE *, port->num_buffers);
543 }
544
545 static void
546 port_allocate_buffers (GOmxPort * port)
547 {
548   guint i;
549   gsize size;
550
551   size = port->buffer_size;
552
553   for (i = 0; i < port->num_buffers; i++) {
554     if (port->omx_allocate) {
555       GST_DEBUG_OBJECT (port->core->object,
556           "%d: OMX_AllocateBuffer(), size=%" G_GSIZE_FORMAT, i, size);
557       OMX_AllocateBuffer (port->core->omx_handle, &port->buffers[i],
558           port->port_index, NULL, size);
559     } else {
560       gpointer buffer_data;
561       buffer_data = g_malloc (size);
562       GST_DEBUG_OBJECT (port->core->object,
563           "%d: OMX_UseBuffer(), size=%" G_GSIZE_FORMAT, i, size);
564       OMX_UseBuffer (port->core->omx_handle, &port->buffers[i],
565           port->port_index, NULL, size, buffer_data);
566     }
567   }
568 }
569
570 static void
571 port_free_buffers (GOmxPort * port)
572 {
573   guint i;
574
575   if (port->type == GOMX_PORT_INPUT) {
576     GST_INFO_OBJECT(port->core->object, "Input port free buffers.");
577   } else {
578     GST_INFO_OBJECT(port->core->object, "Output port free buffers.");
579   }
580
581   for (i = 0; i < port->num_buffers; i++) {
582     OMX_BUFFERHEADERTYPE *omx_buffer;
583
584     omx_buffer = port->buffers[i];
585
586     if (omx_buffer) {
587
588       if (port->shared_buffer) {
589         /* Modification: free pAppPrivate when input/output buffer is shared */
590
591         if (!omx_buffer->pAppPrivate && port->type == GOMX_PORT_OUTPUT && omx_buffer->pBuffer) {
592           GST_INFO_OBJECT(port->core->object,
593           " %d: g_free shared buffer (pBuffer) %p", i, omx_buffer->pBuffer);
594           g_free (omx_buffer->pBuffer);
595           omx_buffer->pBuffer = NULL;
596         }
597
598         if (omx_buffer->pAppPrivate) {
599           GST_INFO_OBJECT(port->core->object,
600               " %d: unref shared buffer (pAppPrivate) %p", i, omx_buffer->pAppPrivate);
601           gst_buffer_unref(omx_buffer->pAppPrivate);
602           omx_buffer->pAppPrivate = NULL;
603         }
604
605       } else { /* this is not shared buffer */
606         if (!port->omx_allocate) {
607       /* Modification: free pBuffer allocated in plugin when OMX_UseBuffer.
608        * the component shall free only buffer header if it allocated only buffer header.*/
609           GST_INFO_OBJECT(port->core->object,
610               " %d: free buffer (pBuffer) %p", i, omx_buffer->pBuffer);
611           if (omx_buffer->pBuffer) {
612             g_free (omx_buffer->pBuffer);
613             omx_buffer->pBuffer = NULL;
614           }
615         }
616       }
617
618       OMX_FreeBuffer (port->core->omx_handle, port->port_index, omx_buffer);
619       port->buffers[i] = NULL;
620     }
621   }
622 }
623
624 static void
625 port_start_buffers (GOmxPort * port)
626 {
627   guint i;
628
629   for (i = 0; i < port->num_buffers; i++) {
630     OMX_BUFFERHEADERTYPE *omx_buffer;
631
632     omx_buffer = port->buffers[i];
633
634     /* If it's an input port we will need to fill the buffer, so put it in
635      * the queue, otherwise send to omx for processing (fill it up). */
636     if (port->type == GOMX_PORT_INPUT)
637       got_buffer (port->core, port, omx_buffer);
638     else
639       g_omx_port_release_buffer (port, omx_buffer);
640   }
641 }
642
643 void
644 g_omx_port_push_buffer (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
645 {
646   async_queue_push (port->queue, omx_buffer);
647 }
648
649 OMX_BUFFERHEADERTYPE *
650 g_omx_port_request_buffer (GOmxPort * port)
651 {
652   return async_queue_pop (port->queue);
653 }
654
655 void
656 g_omx_port_release_buffer (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
657 {
658   switch (port->type) {
659     case GOMX_PORT_INPUT:
660       OMX_EmptyThisBuffer (port->core->omx_handle, omx_buffer);
661       break;
662     case GOMX_PORT_OUTPUT:
663       OMX_FillThisBuffer (port->core->omx_handle, omx_buffer);
664       break;
665     default:
666       break;
667   }
668 }
669
670 void
671 g_omx_port_resume (GOmxPort * port)
672 {
673   async_queue_enable (port->queue);
674 }
675
676 void
677 g_omx_port_pause (GOmxPort * port)
678 {
679   async_queue_disable (port->queue);
680 }
681
682 void
683 g_omx_port_flush (GOmxPort * port)
684 {
685   if (port->type == GOMX_PORT_OUTPUT) {
686     OMX_BUFFERHEADERTYPE *omx_buffer;
687     while ((omx_buffer = async_queue_pop_forced (port->queue))) {
688       omx_buffer->nFilledLen = 0;
689       g_omx_port_release_buffer (port, omx_buffer);
690     }
691   } else {
692     OMX_SendCommand (port->core->omx_handle, OMX_CommandFlush, port->port_index,
693         NULL);
694     g_sem_down (port->core->flush_sem);
695   }
696 }
697
698 void
699 g_omx_port_enable (GOmxPort * port)
700 {
701   GOmxCore *core;
702
703   core = port->core;
704
705   OMX_SendCommand (core->omx_handle, OMX_CommandPortEnable, port->port_index,
706       NULL);
707   port_allocate_buffers (port);
708   if (core->omx_state != OMX_StateLoaded)
709     port_start_buffers (port);
710   g_omx_port_resume (port);
711
712   g_sem_down (core->port_sem);
713 }
714
715 void
716 g_omx_port_disable (GOmxPort * port)
717 {
718   GOmxCore *core;
719
720   core = port->core;
721
722   OMX_SendCommand (core->omx_handle, OMX_CommandPortDisable, port->port_index,
723       NULL);
724   g_omx_port_pause (port);
725   g_omx_port_flush (port);
726   port_free_buffers (port);
727
728   g_sem_down (core->port_sem);
729 }
730
731 void
732 g_omx_port_finish (GOmxPort * port)
733 {
734   port->enabled = FALSE;
735   async_queue_disable (port->queue);
736 }
737
738 /*
739  * Helper functions.
740  */
741
742 static inline void
743 change_state (GOmxCore * core, OMX_STATETYPE state)
744 {
745   GST_DEBUG_OBJECT (core->object, "state=%d", state);
746   OMX_SendCommand (core->omx_handle, OMX_CommandStateSet, state, NULL);
747 }
748
749 static inline void
750 complete_change_state (GOmxCore * core, OMX_STATETYPE state)
751 {
752   g_mutex_lock (core->omx_state_mutex);
753
754   core->omx_state = state;
755   g_cond_signal (core->omx_state_condition);
756   GST_DEBUG_OBJECT (core->object, "state=%d", state);
757
758   g_mutex_unlock (core->omx_state_mutex);
759 }
760
761 static inline void
762 wait_for_state (GOmxCore * core, OMX_STATETYPE state)
763 {
764   GTimeVal tv;
765   gboolean signaled;
766
767   g_mutex_lock (core->omx_state_mutex);
768
769   if (core->omx_error != OMX_ErrorNone)
770     goto leave;
771
772   g_get_current_time (&tv);
773   g_time_val_add (&tv, 15 * G_USEC_PER_SEC);
774
775   /* try once */
776   if (core->omx_state != state) {
777     signaled =
778         g_cond_timed_wait (core->omx_state_condition, core->omx_state_mutex,
779         &tv);
780
781     if (!signaled) {
782       GST_ERROR_OBJECT (core->object, "timed out switching from '%s' to '%s'",
783           omx_state_to_str (core->omx_state), omx_state_to_str (state));
784     }
785   }
786
787   if (core->omx_error != OMX_ErrorNone)
788     goto leave;
789
790   if (core->omx_state != state) {
791     GST_ERROR_OBJECT (core->object,
792         "wrong state received: state=%d, expected=%d", core->omx_state, state);
793   }
794
795 leave:
796   g_mutex_unlock (core->omx_state_mutex);
797 }
798
799 /*
800  * Callbacks
801  */
802
803 static inline void
804 in_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
805 {
806     /** @todo remove this */
807
808   if (!port->enabled)
809     return;
810 }
811
812 static inline void
813 out_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
814 {
815     /** @todo remove this */
816
817   if (!port->enabled)
818     return;
819
820 #if 0
821   if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS) {
822     g_omx_port_set_done (port);
823     return;
824   }
825 #endif
826 }
827
828 static inline void
829 got_buffer (GOmxCore * core, GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
830 {
831   if (G_UNLIKELY (!omx_buffer)) {
832     return;
833   }
834
835   if (G_LIKELY (port)) {
836     g_omx_port_push_buffer (port, omx_buffer);
837
838     switch (port->type) {
839       case GOMX_PORT_INPUT:
840         in_port_cb (port, omx_buffer);
841         break;
842       case GOMX_PORT_OUTPUT:
843         out_port_cb (port, omx_buffer);
844         break;
845       default:
846         break;
847     }
848   }
849 }
850
851 /*
852  * OpenMAX IL callbacks.
853  */
854
855 static OMX_ERRORTYPE
856 EventHandler (OMX_HANDLETYPE omx_handle,
857     OMX_PTR app_data,
858     OMX_EVENTTYPE event, OMX_U32 data_1, OMX_U32 data_2, OMX_PTR event_data)
859 {
860   GOmxCore *core;
861
862   core = (GOmxCore *) app_data;
863
864   switch (event) {
865     case OMX_EventCmdComplete:
866     {
867       OMX_COMMANDTYPE cmd;
868
869       cmd = (OMX_COMMANDTYPE) data_1;
870
871       GST_DEBUG_OBJECT (core->object, "OMX_EventCmdComplete: %d", cmd);
872
873       switch (cmd) {
874         case OMX_CommandStateSet:
875           complete_change_state (core, data_2);
876           break;
877         case OMX_CommandFlush:
878           g_sem_up (core->flush_sem);
879           break;
880         case OMX_CommandPortDisable:
881         case OMX_CommandPortEnable:
882           g_sem_up (core->port_sem);
883         default:
884           break;
885       }
886       break;
887     }
888     case OMX_EventBufferFlag:
889     {
890       GST_DEBUG_OBJECT (core->object, "OMX_EventBufferFlag");
891       if (data_2 & OMX_BUFFERFLAG_EOS) {
892         g_omx_core_set_done (core);
893       }
894       break;
895     }
896     case OMX_EventPortSettingsChanged:
897     {
898       GST_DEBUG_OBJECT (core->object, "OMX_EventPortSettingsChanged");
899                 /** @todo only on the relevant port. */
900       if (core->settings_changed_cb) {
901         core->settings_changed_cb (core);
902       }
903       break;
904     }
905     case OMX_EventError:
906     {
907       core->omx_error = data_1;
908       GST_ERROR_OBJECT (core->object, "unrecoverable error: %s (0x%lx)",
909           omx_error_to_str (data_1), data_1);
910       /* component might leave us waiting for buffers, unblock */
911       g_omx_core_flush_start (core);
912       /* unlock wait_for_state */
913       g_mutex_lock (core->omx_state_mutex);
914       g_cond_signal (core->omx_state_condition);
915       g_mutex_unlock (core->omx_state_mutex);
916       break;
917     }
918     default:
919       break;
920   }
921
922   return OMX_ErrorNone;
923 }
924
925 static OMX_ERRORTYPE
926 EmptyBufferDone (OMX_HANDLETYPE omx_handle,
927     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer)
928 {
929   GOmxCore *core;
930   GOmxPort *port;
931
932   core = (GOmxCore *) app_data;
933   port = get_port (core, omx_buffer->nInputPortIndex);
934
935   GST_CAT_LOG_OBJECT (gstomx_util_debug, core->object, "omx_buffer=%p",
936       omx_buffer);
937   omx_buffer->nFlags = 0x00000000;
938   got_buffer (core, port, omx_buffer);
939
940   return OMX_ErrorNone;
941 }
942
943 static OMX_ERRORTYPE
944 FillBufferDone (OMX_HANDLETYPE omx_handle,
945     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer)
946 {
947   GOmxCore *core;
948   GOmxPort *port;
949
950   core = (GOmxCore *) app_data;
951   port = get_port (core, omx_buffer->nOutputPortIndex);
952
953   GST_CAT_LOG_OBJECT (gstomx_util_debug, core->object, "omx_buffer=%p",
954       omx_buffer);
955   got_buffer (core, port, omx_buffer);
956
957   return OMX_ErrorNone;
958 }
959
960 static inline const char *
961 omx_state_to_str (OMX_STATETYPE omx_state)
962 {
963   switch (omx_state) {
964     case OMX_StateInvalid:
965       return "invalid";
966     case OMX_StateLoaded:
967       return "loaded";
968     case OMX_StateIdle:
969       return "idle";
970     case OMX_StateExecuting:
971       return "executing";
972     case OMX_StatePause:
973       return "pause";
974     case OMX_StateWaitForResources:
975       return "wait for resources";
976     default:
977       return "unknown";
978   }
979 }
980
981 static inline const char *
982 omx_error_to_str (OMX_ERRORTYPE omx_error)
983 {
984   switch (omx_error) {
985     case OMX_ErrorNone:
986       return "None";
987
988     case OMX_ErrorInsufficientResources:
989       return
990           "There were insufficient resources to perform the requested operation";
991
992     case OMX_ErrorUndefined:
993       return "The cause of the error could not be determined";
994
995     case OMX_ErrorInvalidComponentName:
996       return "The component name string was not valid";
997
998     case OMX_ErrorComponentNotFound:
999       return "No component with the specified name string was found";
1000
1001     case OMX_ErrorInvalidComponent:
1002       return "The component specified did not have an entry point";
1003
1004     case OMX_ErrorBadParameter:
1005       return "One or more parameters were not valid";
1006
1007     case OMX_ErrorNotImplemented:
1008       return "The requested function is not implemented";
1009
1010     case OMX_ErrorUnderflow:
1011       return "The buffer was emptied before the next buffer was ready";
1012
1013     case OMX_ErrorOverflow:
1014       return "The buffer was not available when it was needed";
1015
1016     case OMX_ErrorHardware:
1017       return "The hardware failed to respond as expected";
1018
1019     case OMX_ErrorInvalidState:
1020       return "The component is in invalid state";
1021
1022     case OMX_ErrorStreamCorrupt:
1023       return "Stream is found to be corrupt";
1024
1025     case OMX_ErrorPortsNotCompatible:
1026       return "Ports being connected are not compatible";
1027
1028     case OMX_ErrorResourcesLost:
1029       return "Resources allocated to an idle component have been lost";
1030
1031     case OMX_ErrorNoMore:
1032       return "No more indices can be enumerated";
1033
1034     case OMX_ErrorVersionMismatch:
1035       return "The component detected a version mismatch";
1036
1037     case OMX_ErrorNotReady:
1038       return "The component is not ready to return data at this time";
1039
1040     case OMX_ErrorTimeout:
1041       return "There was a timeout that occurred";
1042
1043     case OMX_ErrorSameState:
1044       return
1045           "This error occurs when trying to transition into the state you are already in";
1046
1047     case OMX_ErrorResourcesPreempted:
1048       return
1049           "Resources allocated to an executing or paused component have been preempted";
1050
1051     case OMX_ErrorPortUnresponsiveDuringAllocation:
1052       return
1053           "Waited an unusually long time for the supplier to allocate buffers";
1054
1055     case OMX_ErrorPortUnresponsiveDuringDeallocation:
1056       return
1057           "Waited an unusually long time for the supplier to de-allocate buffers";
1058
1059     case OMX_ErrorPortUnresponsiveDuringStop:
1060       return
1061           "Waited an unusually long time for the non-supplier to return a buffer during stop";
1062
1063     case OMX_ErrorIncorrectStateTransition:
1064       return "Attempting a state transition that is not allowed";
1065
1066     case OMX_ErrorIncorrectStateOperation:
1067       return
1068           "Attempting a command that is not allowed during the present state";
1069
1070     case OMX_ErrorUnsupportedSetting:
1071       return
1072           "The values encapsulated in the parameter or config structure are not supported";
1073
1074     case OMX_ErrorUnsupportedIndex:
1075       return
1076           "The parameter or config indicated by the given index is not supported";
1077
1078     case OMX_ErrorBadPortIndex:
1079       return "The port index supplied is incorrect";
1080
1081     case OMX_ErrorPortUnpopulated:
1082       return
1083           "The port has lost one or more of its buffers and it thus unpopulated";
1084
1085     case OMX_ErrorComponentSuspended:
1086       return "Component suspended due to temporary loss of resources";
1087
1088     case OMX_ErrorDynamicResourcesUnavailable:
1089       return
1090           "Component suspended due to an inability to acquire dynamic resources";
1091
1092     case OMX_ErrorMbErrorsInFrame:
1093       return "Frame generated macroblock error";
1094
1095     case OMX_ErrorFormatNotDetected:
1096       return "Cannot parse or determine the format of an input stream";
1097
1098     case OMX_ErrorContentPipeOpenFailed:
1099       return "The content open operation failed";
1100
1101     case OMX_ErrorContentPipeCreationFailed:
1102       return "The content creation operation failed";
1103
1104     case OMX_ErrorSeperateTablesUsed:
1105       return "Separate table information is being used";
1106
1107     case OMX_ErrorTunnelingUnsupported:
1108       return "Tunneling is unsupported by the component";
1109
1110     default:
1111       return "Unknown error";
1112   }
1113 }