438c41b1530e0d2fb3f10864e551dc2bf1084862
[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 }
279
280 void
281 g_omx_core_init (GOmxCore * core)
282 {
283   GST_DEBUG_OBJECT (core->object, "loading: %s %s (%s)",
284       core->component_name,
285       core->component_role ? core->component_role : "", core->library_name);
286
287   core->imp = request_imp (core->library_name);
288
289   if (!core->imp)
290     return;
291
292   core->omx_error = core->imp->sym_table.get_handle (&core->omx_handle,
293       (char *) core->component_name, core, &callbacks);
294
295   GST_DEBUG_OBJECT (core->object, "OMX_GetHandle(&%p) -> %d",
296       core->omx_handle, core->omx_error);
297
298   if (!core->omx_error) {
299     core->omx_state = OMX_StateLoaded;
300
301     if (core->component_role) {
302       OMX_PARAM_COMPONENTROLETYPE param;
303
304       GST_DEBUG_OBJECT (core->object, "setting component role: %s",
305           core->component_role);
306
307       G_OMX_INIT_PARAM (param);
308
309       strncpy ((char *) param.cRole, core->component_role,
310           OMX_MAX_STRINGNAME_SIZE);
311
312       OMX_SetParameter (core->omx_handle, OMX_IndexParamStandardComponentRole,
313           &param);
314     }
315
316     /* Add_component_vendor */
317     if (strncmp(core->component_name+4, "SEC", 3) == 0)
318     {
319       core->component_vendor = GOMX_VENDOR_SLSI;
320     }
321     else
322     {
323       core->component_vendor = GOMX_VENDOR_DEFAULT;
324     }
325   }
326 }
327
328 static void
329 core_deinit (GOmxCore * core)
330 {
331   if (!core->imp)
332     return;
333
334   if (core->omx_state == OMX_StateLoaded || core->omx_state == OMX_StateInvalid) {
335     if (core->omx_handle) {
336       core->omx_error = core->imp->sym_table.free_handle (core->omx_handle);
337       GST_DEBUG_OBJECT (core->object, "OMX_FreeHandle(%p) -> %d",
338           core->omx_handle, core->omx_error);
339     }
340   } else {
341     GST_WARNING_OBJECT (core->object, "Incorrect state: %s",
342         omx_state_to_str (core->omx_state));
343   }
344
345   g_free (core->library_name);
346   g_free (core->component_name);
347   g_free (core->component_role);
348
349   release_imp (core->imp);
350   core->imp = NULL;
351 }
352
353 void
354 g_omx_core_prepare (GOmxCore * core)
355 {
356   change_state (core, OMX_StateIdle);
357
358   /* Allocate buffers. */
359   core_for_each_port (core, port_allocate_buffers);
360
361   wait_for_state (core, OMX_StateIdle);
362 }
363
364 void
365 g_omx_core_start (GOmxCore * core)
366 {
367   change_state (core, OMX_StateExecuting);
368   wait_for_state (core, OMX_StateExecuting);
369
370   if (core->omx_state == OMX_StateExecuting)
371     core_for_each_port (core, port_start_buffers);
372 }
373
374 void
375 g_omx_core_stop (GOmxCore * core)
376 {
377   if (core->omx_state == OMX_StateExecuting ||
378       core->omx_state == OMX_StatePause) {
379     change_state (core, OMX_StateIdle);
380     wait_for_state (core, OMX_StateIdle);
381   }
382 }
383
384 void
385 g_omx_core_pause (GOmxCore * core)
386 {
387   change_state (core, OMX_StatePause);
388   wait_for_state (core, OMX_StatePause);
389 }
390
391 void
392 g_omx_core_unload (GOmxCore * core)
393 {
394   if (core->omx_state == OMX_StateIdle ||
395       core->omx_state == OMX_StateWaitForResources ||
396       core->omx_state == OMX_StateInvalid) {
397     if (core->omx_state != OMX_StateInvalid)
398       change_state (core, OMX_StateLoaded);
399
400     core_for_each_port (core, port_free_buffers);
401
402     if (core->omx_state != OMX_StateInvalid)
403       wait_for_state (core, OMX_StateLoaded);
404   }
405
406   core_for_each_port (core, g_omx_port_free);
407   g_ptr_array_clear (core->ports);
408 }
409
410 static inline GOmxPort *
411 get_port (GOmxCore * core, guint index)
412 {
413   if (G_LIKELY (index < core->ports->len)) {
414     return g_ptr_array_index (core->ports, index);
415   }
416
417   return NULL;
418 }
419
420 GOmxPort *
421 g_omx_core_new_port (GOmxCore * core, guint index)
422 {
423   GOmxPort *port = get_port (core, index);
424
425   if (port) {
426     GST_WARNING_OBJECT (core->object, "port %d already exists", index);
427     return port;
428   }
429
430   port = g_omx_port_new (core, index);
431   g_ptr_array_insert (core->ports, index, port);
432
433   return port;
434 }
435
436 void
437 g_omx_core_set_done (GOmxCore * core)
438 {
439   g_sem_up (core->done_sem);
440 }
441
442 void
443 g_omx_core_wait_for_done (GOmxCore * core)
444 {
445   g_sem_down (core->done_sem);
446 }
447
448 void
449 g_omx_core_flush_start (GOmxCore * core)
450 {
451   core_for_each_port (core, g_omx_port_pause);
452 }
453
454 void
455 g_omx_core_flush_stop (GOmxCore * core)
456 {
457   core_for_each_port (core, g_omx_port_flush);
458   core_for_each_port (core, g_omx_port_resume);
459 }
460
461 /*
462  * Port
463  */
464
465 /**
466  * note: this is not intended to be called directly by elements (which should
467  * instead use g_omx_core_new_port())
468  */
469 GOmxPort *
470 g_omx_port_new (GOmxCore * core, guint index)
471 {
472   GOmxPort *port;
473   port = g_new0 (GOmxPort, 1);
474
475   port->core = core;
476   port->port_index = index;
477   port->num_buffers = 0;
478   port->buffer_size = 0;
479   port->buffers = NULL;
480
481   port->enabled = TRUE;
482   port->queue = async_queue_new ();
483   port->mutex = g_mutex_new ();
484
485   return port;
486 }
487
488 void
489 g_omx_port_free (GOmxPort * port)
490 {
491   g_mutex_free (port->mutex);
492   async_queue_free (port->queue);
493
494   g_free (port->buffers);
495   g_free (port);
496 }
497
498 void
499 g_omx_port_setup (GOmxPort * port)
500 {
501   GOmxPortType type = -1;
502   OMX_PARAM_PORTDEFINITIONTYPE param;
503
504   G_OMX_INIT_PARAM (param);
505
506   param.nPortIndex = port->port_index;
507   OMX_GetParameter (port->core->omx_handle, OMX_IndexParamPortDefinition,
508       &param);
509
510   switch (param.eDir) {
511     case OMX_DirInput:
512       type = GOMX_PORT_INPUT;
513       break;
514     case OMX_DirOutput:
515       type = GOMX_PORT_OUTPUT;
516       break;
517     default:
518       break;
519   }
520
521   port->type = type;
522     /** @todo should it be nBufferCountMin? */
523   port->num_buffers = param.nBufferCountActual;
524   port->buffer_size = param.nBufferSize;
525
526   GST_DEBUG_OBJECT (port->core->object,
527       "type=%d, num_buffers=%d, buffer_size=%ld, port_index=%d",
528       port->type, port->num_buffers, port->buffer_size, port->port_index);
529
530   g_free (port->buffers);
531   port->buffers = g_new0 (OMX_BUFFERHEADERTYPE *, port->num_buffers);
532 }
533
534 static void
535 port_allocate_buffers (GOmxPort * port)
536 {
537   guint i;
538   gsize size;
539
540   size = port->buffer_size;
541
542   for (i = 0; i < port->num_buffers; i++) {
543     if (port->omx_allocate) {
544       GST_DEBUG_OBJECT (port->core->object,
545           "%d: OMX_AllocateBuffer(), size=%" G_GSIZE_FORMAT, i, size);
546       OMX_AllocateBuffer (port->core->omx_handle, &port->buffers[i],
547           port->port_index, NULL, size);
548     } else {
549       gpointer buffer_data;
550       buffer_data = g_malloc (size);
551       GST_DEBUG_OBJECT (port->core->object,
552           "%d: OMX_UseBuffer(), size=%" G_GSIZE_FORMAT, i, size);
553       OMX_UseBuffer (port->core->omx_handle, &port->buffers[i],
554           port->port_index, NULL, size, buffer_data);
555     }
556   }
557 }
558
559 static void
560 port_free_buffers (GOmxPort * port)
561 {
562   guint i;
563
564   for (i = 0; i < port->num_buffers; i++) {
565     OMX_BUFFERHEADERTYPE *omx_buffer;
566
567     omx_buffer = port->buffers[i];
568
569     if (omx_buffer) {
570 #if 0
571             /** @todo how shall we free that buffer? */
572       if (!port->omx_allocate) {
573         g_free (omx_buffer->pBuffer);
574         omx_buffer->pBuffer = NULL;
575       }
576 #endif
577
578       OMX_FreeBuffer (port->core->omx_handle, port->port_index, omx_buffer);
579       port->buffers[i] = NULL;
580     }
581   }
582 }
583
584 static void
585 port_start_buffers (GOmxPort * port)
586 {
587   guint i;
588
589   for (i = 0; i < port->num_buffers; i++) {
590     OMX_BUFFERHEADERTYPE *omx_buffer;
591
592     omx_buffer = port->buffers[i];
593
594     /* If it's an input port we will need to fill the buffer, so put it in
595      * the queue, otherwise send to omx for processing (fill it up). */
596     if (port->type == GOMX_PORT_INPUT)
597       got_buffer (port->core, port, omx_buffer);
598     else
599       g_omx_port_release_buffer (port, omx_buffer);
600   }
601 }
602
603 void
604 g_omx_port_push_buffer (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
605 {
606   async_queue_push (port->queue, omx_buffer);
607 }
608
609 OMX_BUFFERHEADERTYPE *
610 g_omx_port_request_buffer (GOmxPort * port)
611 {
612   return async_queue_pop (port->queue);
613 }
614
615 void
616 g_omx_port_release_buffer (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
617 {
618   switch (port->type) {
619     case GOMX_PORT_INPUT:
620       OMX_EmptyThisBuffer (port->core->omx_handle, omx_buffer);
621       break;
622     case GOMX_PORT_OUTPUT:
623       OMX_FillThisBuffer (port->core->omx_handle, omx_buffer);
624       break;
625     default:
626       break;
627   }
628 }
629
630 void
631 g_omx_port_resume (GOmxPort * port)
632 {
633   async_queue_enable (port->queue);
634 }
635
636 void
637 g_omx_port_pause (GOmxPort * port)
638 {
639   async_queue_disable (port->queue);
640 }
641
642 void
643 g_omx_port_flush (GOmxPort * port)
644 {
645   if (port->type == GOMX_PORT_OUTPUT) {
646     OMX_BUFFERHEADERTYPE *omx_buffer;
647     while ((omx_buffer = async_queue_pop_forced (port->queue))) {
648       omx_buffer->nFilledLen = 0;
649       g_omx_port_release_buffer (port, omx_buffer);
650     }
651   } else {
652     OMX_SendCommand (port->core->omx_handle, OMX_CommandFlush, port->port_index,
653         NULL);
654     g_sem_down (port->core->flush_sem);
655   }
656 }
657
658 void
659 g_omx_port_enable (GOmxPort * port)
660 {
661   GOmxCore *core;
662
663   core = port->core;
664
665   OMX_SendCommand (core->omx_handle, OMX_CommandPortEnable, port->port_index,
666       NULL);
667   port_allocate_buffers (port);
668   if (core->omx_state != OMX_StateLoaded)
669     port_start_buffers (port);
670   g_omx_port_resume (port);
671
672   g_sem_down (core->port_sem);
673 }
674
675 void
676 g_omx_port_disable (GOmxPort * port)
677 {
678   GOmxCore *core;
679
680   core = port->core;
681
682   OMX_SendCommand (core->omx_handle, OMX_CommandPortDisable, port->port_index,
683       NULL);
684   g_omx_port_pause (port);
685   g_omx_port_flush (port);
686   port_free_buffers (port);
687
688   g_sem_down (core->port_sem);
689 }
690
691 void
692 g_omx_port_finish (GOmxPort * port)
693 {
694   port->enabled = FALSE;
695   async_queue_disable (port->queue);
696 }
697
698 /*
699  * Helper functions.
700  */
701
702 static inline void
703 change_state (GOmxCore * core, OMX_STATETYPE state)
704 {
705   GST_DEBUG_OBJECT (core->object, "state=%d", state);
706   OMX_SendCommand (core->omx_handle, OMX_CommandStateSet, state, NULL);
707 }
708
709 static inline void
710 complete_change_state (GOmxCore * core, OMX_STATETYPE state)
711 {
712   g_mutex_lock (core->omx_state_mutex);
713
714   core->omx_state = state;
715   g_cond_signal (core->omx_state_condition);
716   GST_DEBUG_OBJECT (core->object, "state=%d", state);
717
718   g_mutex_unlock (core->omx_state_mutex);
719 }
720
721 static inline void
722 wait_for_state (GOmxCore * core, OMX_STATETYPE state)
723 {
724   GTimeVal tv;
725   gboolean signaled;
726
727   g_mutex_lock (core->omx_state_mutex);
728
729   if (core->omx_error != OMX_ErrorNone)
730     goto leave;
731
732   g_get_current_time (&tv);
733   g_time_val_add (&tv, 15 * G_USEC_PER_SEC);
734
735   /* try once */
736   if (core->omx_state != state) {
737     signaled =
738         g_cond_timed_wait (core->omx_state_condition, core->omx_state_mutex,
739         &tv);
740
741     if (!signaled) {
742       GST_ERROR_OBJECT (core->object, "timed out switching from '%s' to '%s'",
743           omx_state_to_str (core->omx_state), omx_state_to_str (state));
744     }
745   }
746
747   if (core->omx_error != OMX_ErrorNone)
748     goto leave;
749
750   if (core->omx_state != state) {
751     GST_ERROR_OBJECT (core->object,
752         "wrong state received: state=%d, expected=%d", core->omx_state, state);
753   }
754
755 leave:
756   g_mutex_unlock (core->omx_state_mutex);
757 }
758
759 /*
760  * Callbacks
761  */
762
763 static inline void
764 in_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
765 {
766     /** @todo remove this */
767
768   if (!port->enabled)
769     return;
770 }
771
772 static inline void
773 out_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
774 {
775     /** @todo remove this */
776
777   if (!port->enabled)
778     return;
779
780 #if 0
781   if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS) {
782     g_omx_port_set_done (port);
783     return;
784   }
785 #endif
786 }
787
788 static inline void
789 got_buffer (GOmxCore * core, GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
790 {
791   if (G_UNLIKELY (!omx_buffer)) {
792     return;
793   }
794
795   if (G_LIKELY (port)) {
796     g_omx_port_push_buffer (port, omx_buffer);
797
798     switch (port->type) {
799       case GOMX_PORT_INPUT:
800         in_port_cb (port, omx_buffer);
801         break;
802       case GOMX_PORT_OUTPUT:
803         out_port_cb (port, omx_buffer);
804         break;
805       default:
806         break;
807     }
808   }
809 }
810
811 /*
812  * OpenMAX IL callbacks.
813  */
814
815 static OMX_ERRORTYPE
816 EventHandler (OMX_HANDLETYPE omx_handle,
817     OMX_PTR app_data,
818     OMX_EVENTTYPE event, OMX_U32 data_1, OMX_U32 data_2, OMX_PTR event_data)
819 {
820   GOmxCore *core;
821
822   core = (GOmxCore *) app_data;
823
824   switch (event) {
825     case OMX_EventCmdComplete:
826     {
827       OMX_COMMANDTYPE cmd;
828
829       cmd = (OMX_COMMANDTYPE) data_1;
830
831       GST_DEBUG_OBJECT (core->object, "OMX_EventCmdComplete: %d", cmd);
832
833       switch (cmd) {
834         case OMX_CommandStateSet:
835           complete_change_state (core, data_2);
836           break;
837         case OMX_CommandFlush:
838           g_sem_up (core->flush_sem);
839           break;
840         case OMX_CommandPortDisable:
841         case OMX_CommandPortEnable:
842           g_sem_up (core->port_sem);
843         default:
844           break;
845       }
846       break;
847     }
848     case OMX_EventBufferFlag:
849     {
850       GST_DEBUG_OBJECT (core->object, "OMX_EventBufferFlag");
851       if (data_2 & OMX_BUFFERFLAG_EOS) {
852         g_omx_core_set_done (core);
853       }
854       break;
855     }
856     case OMX_EventPortSettingsChanged:
857     {
858       GST_DEBUG_OBJECT (core->object, "OMX_EventPortSettingsChanged");
859                 /** @todo only on the relevant port. */
860       if (core->settings_changed_cb) {
861         core->settings_changed_cb (core);
862       }
863       break;
864     }
865     case OMX_EventError:
866     {
867       core->omx_error = data_1;
868       GST_ERROR_OBJECT (core->object, "unrecoverable error: %s (0x%lx)",
869           omx_error_to_str (data_1), data_1);
870       /* component might leave us waiting for buffers, unblock */
871       g_omx_core_flush_start (core);
872       /* unlock wait_for_state */
873       g_mutex_lock (core->omx_state_mutex);
874       g_cond_signal (core->omx_state_condition);
875       g_mutex_unlock (core->omx_state_mutex);
876       break;
877     }
878     default:
879       break;
880   }
881
882   return OMX_ErrorNone;
883 }
884
885 static OMX_ERRORTYPE
886 EmptyBufferDone (OMX_HANDLETYPE omx_handle,
887     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer)
888 {
889   GOmxCore *core;
890   GOmxPort *port;
891
892   core = (GOmxCore *) app_data;
893   port = get_port (core, omx_buffer->nInputPortIndex);
894
895   GST_CAT_LOG_OBJECT (gstomx_util_debug, core->object, "omx_buffer=%p",
896       omx_buffer);
897   omx_buffer->nFlags = 0x00000000;
898   got_buffer (core, port, omx_buffer);
899
900   return OMX_ErrorNone;
901 }
902
903 static OMX_ERRORTYPE
904 FillBufferDone (OMX_HANDLETYPE omx_handle,
905     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer)
906 {
907   GOmxCore *core;
908   GOmxPort *port;
909
910   core = (GOmxCore *) app_data;
911   port = get_port (core, omx_buffer->nOutputPortIndex);
912
913   GST_CAT_LOG_OBJECT (gstomx_util_debug, core->object, "omx_buffer=%p",
914       omx_buffer);
915   got_buffer (core, port, omx_buffer);
916
917   return OMX_ErrorNone;
918 }
919
920 static inline const char *
921 omx_state_to_str (OMX_STATETYPE omx_state)
922 {
923   switch (omx_state) {
924     case OMX_StateInvalid:
925       return "invalid";
926     case OMX_StateLoaded:
927       return "loaded";
928     case OMX_StateIdle:
929       return "idle";
930     case OMX_StateExecuting:
931       return "executing";
932     case OMX_StatePause:
933       return "pause";
934     case OMX_StateWaitForResources:
935       return "wait for resources";
936     default:
937       return "unknown";
938   }
939 }
940
941 static inline const char *
942 omx_error_to_str (OMX_ERRORTYPE omx_error)
943 {
944   switch (omx_error) {
945     case OMX_ErrorNone:
946       return "None";
947
948     case OMX_ErrorInsufficientResources:
949       return
950           "There were insufficient resources to perform the requested operation";
951
952     case OMX_ErrorUndefined:
953       return "The cause of the error could not be determined";
954
955     case OMX_ErrorInvalidComponentName:
956       return "The component name string was not valid";
957
958     case OMX_ErrorComponentNotFound:
959       return "No component with the specified name string was found";
960
961     case OMX_ErrorInvalidComponent:
962       return "The component specified did not have an entry point";
963
964     case OMX_ErrorBadParameter:
965       return "One or more parameters were not valid";
966
967     case OMX_ErrorNotImplemented:
968       return "The requested function is not implemented";
969
970     case OMX_ErrorUnderflow:
971       return "The buffer was emptied before the next buffer was ready";
972
973     case OMX_ErrorOverflow:
974       return "The buffer was not available when it was needed";
975
976     case OMX_ErrorHardware:
977       return "The hardware failed to respond as expected";
978
979     case OMX_ErrorInvalidState:
980       return "The component is in invalid state";
981
982     case OMX_ErrorStreamCorrupt:
983       return "Stream is found to be corrupt";
984
985     case OMX_ErrorPortsNotCompatible:
986       return "Ports being connected are not compatible";
987
988     case OMX_ErrorResourcesLost:
989       return "Resources allocated to an idle component have been lost";
990
991     case OMX_ErrorNoMore:
992       return "No more indices can be enumerated";
993
994     case OMX_ErrorVersionMismatch:
995       return "The component detected a version mismatch";
996
997     case OMX_ErrorNotReady:
998       return "The component is not ready to return data at this time";
999
1000     case OMX_ErrorTimeout:
1001       return "There was a timeout that occurred";
1002
1003     case OMX_ErrorSameState:
1004       return
1005           "This error occurs when trying to transition into the state you are already in";
1006
1007     case OMX_ErrorResourcesPreempted:
1008       return
1009           "Resources allocated to an executing or paused component have been preempted";
1010
1011     case OMX_ErrorPortUnresponsiveDuringAllocation:
1012       return
1013           "Waited an unusually long time for the supplier to allocate buffers";
1014
1015     case OMX_ErrorPortUnresponsiveDuringDeallocation:
1016       return
1017           "Waited an unusually long time for the supplier to de-allocate buffers";
1018
1019     case OMX_ErrorPortUnresponsiveDuringStop:
1020       return
1021           "Waited an unusually long time for the non-supplier to return a buffer during stop";
1022
1023     case OMX_ErrorIncorrectStateTransition:
1024       return "Attempting a state transition that is not allowed";
1025
1026     case OMX_ErrorIncorrectStateOperation:
1027       return
1028           "Attempting a command that is not allowed during the present state";
1029
1030     case OMX_ErrorUnsupportedSetting:
1031       return
1032           "The values encapsulated in the parameter or config structure are not supported";
1033
1034     case OMX_ErrorUnsupportedIndex:
1035       return
1036           "The parameter or config indicated by the given index is not supported";
1037
1038     case OMX_ErrorBadPortIndex:
1039       return "The port index supplied is incorrect";
1040
1041     case OMX_ErrorPortUnpopulated:
1042       return
1043           "The port has lost one or more of its buffers and it thus unpopulated";
1044
1045     case OMX_ErrorComponentSuspended:
1046       return "Component suspended due to temporary loss of resources";
1047
1048     case OMX_ErrorDynamicResourcesUnavailable:
1049       return
1050           "Component suspended due to an inability to acquire dynamic resources";
1051
1052     case OMX_ErrorMbErrorsInFrame:
1053       return "Frame generated macroblock error";
1054
1055     case OMX_ErrorFormatNotDetected:
1056       return "Cannot parse or determine the format of an input stream";
1057
1058     case OMX_ErrorContentPipeOpenFailed:
1059       return "The content open operation failed";
1060
1061     case OMX_ErrorContentPipeCreationFailed:
1062       return "The content creation operation failed";
1063
1064     case OMX_ErrorSeperateTablesUsed:
1065       return "Separate table information is being used";
1066
1067     case OMX_ErrorTunnelingUnsupported:
1068       return "Tunneling is unsupported by the component";
1069
1070     default:
1071       return "Unknown error";
1072   }
1073 }