omx: remove useless double negations
[platform/upstream/gstreamer.git] / omx / gstomx.c
1 /*
2  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
4  * Copyright (C) 2013, Collabora Ltd.
5  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gst/gst.h>
28 #include <gst/allocators/gstdmabuf.h>
29 #include <string.h>
30
31 #include "gstomx.h"
32 #include "gstomxmjpegdec.h"
33 #include "gstomxmpeg2videodec.h"
34 #include "gstomxmpeg4videodec.h"
35 #include "gstomxh264dec.h"
36 #include "gstomxh263dec.h"
37 #include "gstomxh265dec.h"
38 #include "gstomxvp8dec.h"
39 #include "gstomxtheoradec.h"
40 #include "gstomxwmvdec.h"
41 #include "gstomxmpeg4videoenc.h"
42 #include "gstomxh264enc.h"
43 #include "gstomxh263enc.h"
44 #include "gstomxh265enc.h"
45 #include "gstomxaacdec.h"
46 #include "gstomxmp3dec.h"
47 #include "gstomxmp3enc.h"
48 #include "gstomxaacenc.h"
49 #include "gstomxamrdec.h"
50 #include "gstomxanalogaudiosink.h"
51 #include "gstomxhdmiaudiosink.h"
52
53 GST_DEBUG_CATEGORY (gstomx_debug);
54 #define GST_CAT_DEFAULT gstomx_debug
55
56 GST_DEBUG_CATEGORY_STATIC (OMX_API_TRACE);
57
58 /* Macros used to log result of OMX calls. Use the requested debug level if the
59  * operation succeeded and GST_LEVEL_ERROR if not.
60  * Don't consider OMX_ErrorNoMore as an error as it means we're done iterating. */
61 #define DEBUG_IF_OK(obj,err,...) \
62   GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, (err == OMX_ErrorNone || err == OMX_ErrorNoMore) ? GST_LEVEL_DEBUG : GST_LEVEL_ERROR, obj, __VA_ARGS__)
63 #define INFO_IF_OK(obj,err,...) \
64   GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, (err == OMX_ErrorNone || err == OMX_ErrorNoMore) ? GST_LEVEL_INFO : GST_LEVEL_ERROR, obj, __VA_ARGS__)
65
66 G_LOCK_DEFINE_STATIC (core_handles);
67 static GHashTable *core_handles;
68
69 /* Cache used by gst_omx_buffer_flags_to_string() */
70 G_LOCK_DEFINE_STATIC (buffer_flags_str);
71 static GHashTable *buffer_flags_str;
72
73 GstOMXCore *
74 gst_omx_core_acquire (const gchar * filename)
75 {
76   GstOMXCore *core;
77
78   G_LOCK (core_handles);
79   if (!core_handles)
80     core_handles =
81         g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
82
83   core = g_hash_table_lookup (core_handles, filename);
84   if (!core) {
85     core = g_slice_new0 (GstOMXCore);
86     g_mutex_init (&core->lock);
87     core->user_count = 0;
88     g_hash_table_insert (core_handles, g_strdup (filename), core);
89
90     /* Hack for the Broadcom OpenMAX IL implementation */
91 #ifdef USE_OMX_TARGET_RPI
92     {
93 #else
94     if (g_str_has_suffix (filename, "vc/lib/libopenmaxil.so")) {
95 #endif
96       gchar *bcm_host_filename;
97       gchar *bcm_host_path;
98       GModule *bcm_host_module;
99       void (*bcm_host_init) (void);
100
101       bcm_host_path = g_path_get_dirname (filename);
102       bcm_host_filename =
103           g_build_filename (bcm_host_path, "libbcm_host.so", NULL);
104
105       bcm_host_module =
106           g_module_open (bcm_host_filename,
107           G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
108
109       g_free (bcm_host_filename);
110       g_free (bcm_host_path);
111
112       if (!bcm_host_module) {
113         /* Retry without an absolute path */
114         bcm_host_module =
115             g_module_open ("libbcm_host.so",
116             G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
117         if (!bcm_host_module) {
118           GST_ERROR ("Failed to load libbcm_host.so");
119           goto error;
120         }
121       }
122
123       if (!g_module_symbol (bcm_host_module, "bcm_host_init",
124               (gpointer *) & bcm_host_init)) {
125         GST_ERROR ("Failed to load symbol 'bcm_host_init' from libbcm_host.so");
126         goto error;
127       }
128
129       bcm_host_init ();
130     }
131
132     core->module =
133         g_module_open (filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
134     if (!core->module)
135       goto load_failed;
136
137     if (!g_module_symbol (core->module, "OMX_Init", (gpointer *) & core->init))
138       goto symbol_error;
139     if (!g_module_symbol (core->module, "OMX_Deinit",
140             (gpointer *) & core->deinit))
141       goto symbol_error;
142     if (!g_module_symbol (core->module, "OMX_GetHandle",
143             (gpointer *) & core->get_handle))
144       goto symbol_error;
145     if (!g_module_symbol (core->module, "OMX_FreeHandle",
146             (gpointer *) & core->free_handle))
147       goto symbol_error;
148     if (!g_module_symbol (core->module, "OMX_SetupTunnel",
149             (gpointer *) & core->setup_tunnel))
150       goto symbol_error;
151
152     GST_DEBUG ("Successfully loaded core '%s'", filename);
153   }
154
155   g_mutex_lock (&core->lock);
156   core->user_count++;
157   if (core->user_count == 1) {
158     OMX_ERRORTYPE err;
159
160     err = core->init ();
161     if (err != OMX_ErrorNone) {
162       GST_ERROR ("Failed to initialize core '%s': 0x%08x", filename, err);
163       g_mutex_unlock (&core->lock);
164       goto error;
165     }
166
167     GST_DEBUG ("Successfully initialized core '%s'", filename);
168   }
169
170   g_mutex_unlock (&core->lock);
171   G_UNLOCK (core_handles);
172
173   return core;
174
175 load_failed:
176   {
177     GST_ERROR ("Failed to load module '%s': %s", filename, g_module_error ());
178     goto error;
179   }
180 symbol_error:
181   {
182     GST_ERROR ("Failed to locate required OpenMAX symbol in '%s': %s", filename,
183         g_module_error ());
184     g_module_close (core->module);
185     core->module = NULL;
186     goto error;
187   }
188 error:
189   {
190     g_hash_table_remove (core_handles, filename);
191     g_mutex_clear (&core->lock);
192     g_slice_free (GstOMXCore, core);
193
194     G_UNLOCK (core_handles);
195
196     return NULL;
197   }
198 }
199
200 void
201 gst_omx_core_release (GstOMXCore * core)
202 {
203   g_return_if_fail (core != NULL);
204
205   G_LOCK (core_handles);
206
207   g_mutex_lock (&core->lock);
208
209   GST_DEBUG ("Releasing core %p", core);
210
211   core->user_count--;
212   if (core->user_count == 0) {
213     GST_DEBUG ("Deinit core %p", core);
214     core->deinit ();
215
216     G_LOCK (buffer_flags_str);
217     g_clear_pointer (&buffer_flags_str, g_hash_table_unref);
218     G_UNLOCK (buffer_flags_str);
219   }
220
221   g_mutex_unlock (&core->lock);
222
223   G_UNLOCK (core_handles);
224 }
225
226 /* NOTE: comp->messages_lock will be used */
227 static void
228 gst_omx_component_flush_messages (GstOMXComponent * comp)
229 {
230   GstOMXMessage *msg;
231
232   g_mutex_lock (&comp->messages_lock);
233   while ((msg = g_queue_pop_head (&comp->messages))) {
234     g_slice_free (GstOMXMessage, msg);
235   }
236   g_mutex_unlock (&comp->messages_lock);
237 }
238
239 static void
240 gst_omx_buffer_reset (GstOMXBuffer * buf)
241 {
242   buf->omx_buf->nFlags = 0;
243   buf->omx_buf->nOffset = 0;
244   buf->omx_buf->nFilledLen = 0;
245   GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp, G_GUINT64_CONSTANT (0));
246 }
247
248 static void gst_omx_buffer_unmap (GstOMXBuffer * buffer);
249
250 /* NOTE: Call with comp->lock, comp->messages_lock will be used */
251 static void
252 gst_omx_component_handle_messages (GstOMXComponent * comp)
253 {
254   GstOMXMessage *msg;
255
256   g_mutex_lock (&comp->messages_lock);
257   while ((msg = g_queue_pop_head (&comp->messages))) {
258     g_mutex_unlock (&comp->messages_lock);
259
260     switch (msg->type) {
261       case GST_OMX_MESSAGE_STATE_SET:{
262         GST_INFO_OBJECT (comp->parent, "%s state change to %s finished",
263             comp->name, gst_omx_state_to_string (msg->content.state_set.state));
264         comp->state = msg->content.state_set.state;
265         if (comp->state == comp->pending_state)
266           comp->pending_state = OMX_StateInvalid;
267         break;
268       }
269       case GST_OMX_MESSAGE_FLUSH:{
270         GstOMXPort *port = NULL;
271         OMX_U32 index = msg->content.flush.port;
272
273         port = gst_omx_component_get_port (comp, index);
274         if (!port)
275           break;
276
277         GST_DEBUG_OBJECT (comp->parent, "%s port %u flushed", comp->name,
278             port->index);
279
280         if (port->flushing) {
281           port->flushed = TRUE;
282         } else {
283           GST_ERROR_OBJECT (comp->parent, "%s port %u was not flushing",
284               comp->name, port->index);
285         }
286
287         break;
288       }
289       case GST_OMX_MESSAGE_ERROR:{
290         OMX_ERRORTYPE error = msg->content.error.error;
291
292         if (error == OMX_ErrorNone)
293           break;
294
295         GST_ERROR_OBJECT (comp->parent, "%s got error: %s (0x%08x)", comp->name,
296             gst_omx_error_to_string (error), error);
297
298         /* We only set the first error ever from which
299          * we can't recover anymore.
300          */
301         if (comp->last_error == OMX_ErrorNone)
302           comp->last_error = error;
303         g_cond_broadcast (&comp->messages_cond);
304
305         break;
306       }
307       case GST_OMX_MESSAGE_PORT_ENABLE:{
308         GstOMXPort *port = NULL;
309         OMX_U32 index = msg->content.port_enable.port;
310         OMX_BOOL enable = msg->content.port_enable.enable;
311
312         port = gst_omx_component_get_port (comp, index);
313         if (!port)
314           break;
315
316         GST_DEBUG_OBJECT (comp->parent, "%s port %u %s", comp->name,
317             port->index, (enable ? "enabled" : "disabled"));
318
319         if (enable)
320           port->enabled_pending = FALSE;
321         else
322           port->disabled_pending = FALSE;
323         break;
324       }
325       case GST_OMX_MESSAGE_PORT_SETTINGS_CHANGED:{
326         gint i, n;
327         OMX_U32 index = msg->content.port_settings_changed.port;
328         GList *outports = NULL, *l, *k;
329
330         GST_DEBUG_OBJECT (comp->parent, "%s settings changed (port %u)",
331             comp->name, (guint) index);
332
333         /* FIXME: This probably can be done better */
334
335         /* Now update the ports' states */
336         n = (comp->ports ? comp->ports->len : 0);
337         for (i = 0; i < n; i++) {
338           GstOMXPort *port = g_ptr_array_index (comp->ports, i);
339
340           if (index == OMX_ALL || index == port->index) {
341             port->settings_cookie++;
342             gst_omx_port_update_port_definition (port, NULL);
343             if (port->port_def.eDir == OMX_DirOutput && !port->tunneled)
344               outports = g_list_prepend (outports, port);
345           }
346         }
347
348         for (k = outports; k; k = k->next) {
349           gboolean found = FALSE;
350
351           for (l = comp->pending_reconfigure_outports; l; l = l->next) {
352             if (l->data == k->data) {
353               found = TRUE;
354               break;
355             }
356           }
357
358           if (!found)
359             comp->pending_reconfigure_outports =
360                 g_list_prepend (comp->pending_reconfigure_outports, k->data);
361         }
362
363         g_list_free (outports);
364
365         break;
366       }
367       case GST_OMX_MESSAGE_BUFFER_FLAG:{
368         GstOMXPort *port = NULL;
369         OMX_U32 index = msg->content.buffer_flag.port;
370         OMX_U32 flags = msg->content.buffer_flag.flags;
371
372         port = gst_omx_component_get_port (comp, index);
373         if (!port)
374           break;
375
376         GST_DEBUG_OBJECT (comp->parent,
377             "%s port %u got buffer flags 0x%08x (%s)", comp->name, port->index,
378             (guint) flags, gst_omx_buffer_flags_to_string (flags));
379         if ((flags & OMX_BUFFERFLAG_EOS)
380             && port->port_def.eDir == OMX_DirOutput && !port->eos) {
381           GST_DEBUG_OBJECT (comp->parent, "%s port %u is EOS", comp->name,
382               port->index);
383           port->eos = TRUE;
384         }
385
386         break;
387       }
388       case GST_OMX_MESSAGE_BUFFER_DONE:{
389         GstOMXBuffer *buf = msg->content.buffer_done.buffer->pAppPrivate;
390         GstOMXPort *port;
391
392         port = buf->port;
393
394         buf->used = FALSE;
395
396         if (msg->content.buffer_done.empty) {
397           /* Input buffer is empty again and can be used to contain new input */
398           GST_LOG_OBJECT (port->comp->parent,
399               "%s port %u emptied buffer %p (%p)", port->comp->name,
400               port->index, buf, buf->omx_buf->pBuffer);
401
402           /* Reset all flags, some implementations don't
403            * reset them themselves and the flags are not
404            * valid anymore after the buffer was consumed
405            */
406           gst_omx_buffer_reset (buf);
407
408           /* Release and unmap the parent buffer, if any */
409           gst_omx_buffer_unmap (buf);
410         } else {
411           /* Output buffer contains output now or
412            * the port was flushed */
413           GST_LOG_OBJECT (port->comp->parent,
414               "%s port %u filled buffer %p (%p)", port->comp->name, port->index,
415               buf, buf->omx_buf->pBuffer);
416
417           if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS)
418               && port->port_def.eDir == OMX_DirOutput && !port->eos) {
419             GST_DEBUG_OBJECT (comp->parent, "%s port %u is EOS", comp->name,
420                 port->index);
421             port->eos = TRUE;
422           }
423         }
424
425         /* If an input port is managed by a pool, the buffer will be ready to be
426          * filled again once it's been released to the pool. */
427         if (port->port_def.eDir == OMX_DirOutput || !port->using_pool) {
428           g_queue_push_tail (&port->pending_buffers, buf);
429         }
430
431         break;
432       }
433       default:{
434         g_assert_not_reached ();
435         break;
436       }
437     }
438
439     g_slice_free (GstOMXMessage, msg);
440
441     g_mutex_lock (&comp->messages_lock);
442   }
443
444   g_mutex_unlock (&comp->messages_lock);
445 }
446
447 /* NOTE: comp->messages_lock will be used */
448 static void
449 gst_omx_component_send_message (GstOMXComponent * comp, GstOMXMessage * msg)
450 {
451   g_mutex_lock (&comp->messages_lock);
452   if (msg)
453     g_queue_push_tail (&comp->messages, msg);
454   g_cond_broadcast (&comp->messages_cond);
455   g_mutex_unlock (&comp->messages_lock);
456 }
457
458 /* NOTE: Call with comp->lock, comp->messages_lock will be used */
459 static gboolean
460 gst_omx_component_wait_message (GstOMXComponent * comp, GstClockTime timeout)
461 {
462   gboolean signalled;
463   gint64 wait_until = -1;
464
465   if (timeout != GST_CLOCK_TIME_NONE) {
466     gint64 add = timeout / (GST_SECOND / G_TIME_SPAN_SECOND);
467
468     if (add == 0)
469       return FALSE;
470
471     wait_until = g_get_monotonic_time () + add;
472     GST_DEBUG_OBJECT (comp->parent, "%s waiting for %" G_GINT64_FORMAT "us",
473         comp->name, add);
474   } else {
475     GST_DEBUG_OBJECT (comp->parent, "%s waiting for signal", comp->name);
476   }
477
478   g_mutex_lock (&comp->messages_lock);
479   g_mutex_unlock (&comp->lock);
480
481   if (!g_queue_is_empty (&comp->messages)) {
482     signalled = TRUE;
483   } else if (timeout == GST_CLOCK_TIME_NONE) {
484     g_cond_wait (&comp->messages_cond, &comp->messages_lock);
485     signalled = TRUE;
486   } else {
487     signalled =
488         g_cond_wait_until (&comp->messages_cond, &comp->messages_lock,
489         wait_until);
490   }
491
492   g_mutex_unlock (&comp->messages_lock);
493   g_mutex_lock (&comp->lock);
494
495   return signalled;
496 }
497
498 static const gchar *
499 omx_event_type_to_str (OMX_EVENTTYPE event)
500 {
501   switch (event) {
502     case OMX_EventCmdComplete:
503       return "EventCmdComplete";
504     case OMX_EventError:
505       return "EventError";
506     case OMX_EventMark:
507       return "EventMark";
508     case OMX_EventPortSettingsChanged:
509       return "EventPortSettingsChanged";
510     case OMX_EventBufferFlag:
511       return "EventBufferFlag";
512     case OMX_EventResourcesAcquired:
513       return "EventResourcesAcquired";
514     case OMX_EventComponentResumed:
515       return "EventComponentResumed";
516     case OMX_EventDynamicResourcesAvailable:
517       return "EventDynamicResourcesAvailable";
518     case OMX_EventPortFormatDetected:
519       return "EventPortFormatDetected";
520 #ifdef OMX_EventIndexSettingChanged
521     case OMX_EventIndexSettingChanged:
522       return "EventIndexSettingChanged";
523 #endif
524 #ifdef OMX_EventPortNeedsDisable
525     case OMX_EventPortNeedsDisable:
526       return "EventPortNeedsDisable";
527 #endif
528 #ifdef OMX_EventPortNeedsFlush
529     case OMX_EventPortNeedsFlush:
530       return "EventPortNeedsFlush";
531 #endif
532     case OMX_EventKhronosExtensions:
533     case OMX_EventVendorStartUnused:
534     case OMX_EventMax:
535     default:
536       break;
537   }
538
539   return NULL;
540 }
541
542 /* See "Table 3-11: Event Parameter Usage" */
543 static GstStructure *
544 omx_event_to_debug_struct (OMX_EVENTTYPE event,
545     guint32 data1, guint32 data2, gpointer event_data)
546 {
547   const gchar *name;
548
549   name = omx_event_type_to_str (event);
550   switch (event) {
551     case OMX_EventCmdComplete:
552     {
553       const gchar *cmd = gst_omx_command_to_string (data1);
554
555       if (!cmd)
556         break;
557
558       switch (data1) {
559         case OMX_CommandStateSet:
560           return gst_structure_new (name,
561               "command", G_TYPE_STRING, cmd,
562               "state-reached", G_TYPE_STRING, gst_omx_state_to_string (data2),
563               NULL);
564         case OMX_CommandFlush:
565         case OMX_CommandPortDisable:
566         case OMX_CommandPortEnable:
567         case OMX_CommandMarkBuffer:
568           return gst_structure_new (name,
569               "command", G_TYPE_STRING, cmd, "port", G_TYPE_UINT, data2,
570               "error", G_TYPE_STRING,
571               gst_omx_error_to_string (GPOINTER_TO_UINT (event_data)), NULL);
572         case OMX_CommandKhronosExtensions:
573         case OMX_CommandVendorStartUnused:
574         case OMX_CommandMax:
575           break;
576       }
577     }
578       break;
579     case OMX_EventError:
580       return gst_structure_new (name, "error", G_TYPE_STRING,
581           gst_omx_error_to_string (data1), "extra-info", G_TYPE_STRING,
582           gst_omx_error_to_string (data2), NULL);
583     case OMX_EventMark:
584     case OMX_EventComponentResumed:
585     case OMX_EventResourcesAcquired:
586     case OMX_EventDynamicResourcesAvailable:
587     case OMX_EventPortFormatDetected:
588       return gst_structure_new_empty (name);
589     case OMX_EventPortSettingsChanged:
590 #ifdef OMX_EventIndexSettingChanged
591     case OMX_EventIndexSettingChanged:
592 #endif
593 #ifdef OMX_EventPortNeedsDisable
594     case OMX_EventPortNeedsDisable:
595 #endif
596 #ifdef OMX_EventPortNeedsFlush
597     case OMX_EventPortNeedsFlush:
598 #endif
599       return gst_structure_new (name, "port", G_TYPE_UINT,
600           data1, "param-config", G_TYPE_UINT, data2, NULL);
601     case OMX_EventBufferFlag:
602       return gst_structure_new (name, "port", G_TYPE_UINT,
603           data1, "flags", G_TYPE_STRING, gst_omx_buffer_flags_to_string (data2),
604           NULL);
605     case OMX_EventKhronosExtensions:
606     case OMX_EventVendorStartUnused:
607     case OMX_EventMax:
608     default:
609       break;
610   }
611
612   return NULL;
613 }
614
615 static void
616 log_omx_api_trace_event (GstOMXComponent * comp, OMX_EVENTTYPE event,
617     guint32 data1, guint32 data2, gpointer event_data)
618 {
619 #ifndef GST_DISABLE_GST_DEBUG
620   GstStructure *s;
621
622   /* Don't bother creating useless structs if not needed */
623   if (gst_debug_category_get_threshold (OMX_API_TRACE) < GST_LEVEL_DEBUG)
624     return;
625
626   s = omx_event_to_debug_struct (event, data1, data2, event_data);
627   if (!s) {
628     GST_CAT_WARNING_OBJECT (OMX_API_TRACE, comp->parent,
629         "invalid event 0x%08x Data1 %u Data2 %u EventData %p", event, data1,
630         data2, event_data);
631     return;
632   }
633
634   GST_CAT_DEBUG_OBJECT (OMX_API_TRACE, comp->parent, "%" GST_PTR_FORMAT, s);
635
636   gst_structure_free (s);
637 #endif /* GST_DISABLE_GST_DEBUG */
638 }
639
640 static OMX_ERRORTYPE
641 EventHandler (OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_EVENTTYPE eEvent,
642     OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData)
643 {
644   GstOMXComponent *comp = (GstOMXComponent *) pAppData;
645
646   log_omx_api_trace_event (comp, eEvent, nData1, nData2, pEventData);
647
648   switch (eEvent) {
649     case OMX_EventCmdComplete:
650     {
651       OMX_COMMANDTYPE cmd = (OMX_COMMANDTYPE) nData1;
652
653       GST_DEBUG_OBJECT (comp->parent, "%s %s command complete (%d)",
654           comp->name, gst_omx_command_to_string (cmd), cmd);
655
656       switch (cmd) {
657         case OMX_CommandStateSet:{
658           GstOMXMessage *msg = g_slice_new (GstOMXMessage);
659
660           msg->type = GST_OMX_MESSAGE_STATE_SET;
661           msg->content.state_set.state = nData2;
662
663           GST_DEBUG_OBJECT (comp->parent, "%s state change to %s finished",
664               comp->name,
665               gst_omx_state_to_string (msg->content.state_set.state));
666
667           gst_omx_component_send_message (comp, msg);
668           break;
669         }
670         case OMX_CommandFlush:{
671           GstOMXMessage *msg = g_slice_new (GstOMXMessage);
672
673           msg->type = GST_OMX_MESSAGE_FLUSH;
674           msg->content.flush.port = nData2;
675           GST_DEBUG_OBJECT (comp->parent, "%s port %u flushed", comp->name,
676               (guint) msg->content.flush.port);
677
678           gst_omx_component_send_message (comp, msg);
679           break;
680         }
681         case OMX_CommandPortEnable:
682         case OMX_CommandPortDisable:{
683           GstOMXMessage *msg = g_slice_new (GstOMXMessage);
684
685           msg->type = GST_OMX_MESSAGE_PORT_ENABLE;
686           msg->content.port_enable.port = nData2;
687           msg->content.port_enable.enable = (cmd == OMX_CommandPortEnable);
688           GST_DEBUG_OBJECT (comp->parent, "%s port %u %s", comp->name,
689               (guint) msg->content.port_enable.port,
690               (msg->content.port_enable.enable ? "enabled" : "disabled"));
691
692           gst_omx_component_send_message (comp, msg);
693           break;
694         }
695         default:
696           break;
697       }
698       break;
699     }
700     case OMX_EventError:
701     {
702       GstOMXMessage *msg;
703       OMX_ERRORTYPE error_type = nData1;
704
705       /* Yes, this really happens... */
706       if (error_type == OMX_ErrorNone)
707         break;
708
709       /* Always ignore PortUnpopulated error. This error is informational
710        * at best but it is useful for debugging some strange scenarios.
711        */
712       if (error_type == OMX_ErrorPortUnpopulated) {
713         GST_DEBUG_OBJECT (comp->parent, "%s got error: %s (0x%08x)",
714             comp->name, gst_omx_error_to_string (error_type), error_type);
715         break;
716       }
717
718       msg = g_slice_new (GstOMXMessage);
719
720       msg->type = GST_OMX_MESSAGE_ERROR;
721       msg->content.error.error = error_type;
722       GST_ERROR_OBJECT (comp->parent, "%s got error: %s (0x%08x)", comp->name,
723           gst_omx_error_to_string (msg->content.error.error),
724           msg->content.error.error);
725
726       gst_omx_component_send_message (comp, msg);
727       break;
728     }
729     case OMX_EventPortSettingsChanged:
730     {
731       GstOMXMessage *msg = g_slice_new (GstOMXMessage);
732       OMX_U32 index;
733
734       if (!(comp->hacks &
735               GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_NDATA_PARAMETER_SWAP)) {
736         index = nData1;
737       } else {
738         index = nData2;
739       }
740
741
742       if (index == 0
743           && (comp->hacks &
744               GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_PORT_0_TO_1))
745         index = 1;
746
747
748       msg->type = GST_OMX_MESSAGE_PORT_SETTINGS_CHANGED;
749       msg->content.port_settings_changed.port = index;
750       GST_DEBUG_OBJECT (comp->parent, "%s settings changed (port index: %u)",
751           comp->name, (guint) msg->content.port_settings_changed.port);
752
753       gst_omx_component_send_message (comp, msg);
754       break;
755     }
756     case OMX_EventBufferFlag:{
757       GstOMXMessage *msg;
758
759       msg = g_slice_new (GstOMXMessage);
760
761       msg->type = GST_OMX_MESSAGE_BUFFER_FLAG;
762       msg->content.buffer_flag.port = nData1;
763       msg->content.buffer_flag.flags = nData2;
764       GST_DEBUG_OBJECT (comp->parent, "%s port %u got buffer flags 0x%08x (%s)",
765           comp->name, (guint) msg->content.buffer_flag.port,
766           (guint) msg->content.buffer_flag.flags,
767           gst_omx_buffer_flags_to_string (msg->content.buffer_flag.flags));
768
769       gst_omx_component_send_message (comp, msg);
770       break;
771     }
772     case OMX_EventPortFormatDetected:
773     default:
774       GST_DEBUG_OBJECT (comp->parent, "%s unknown event 0x%08x", comp->name,
775           eEvent);
776       break;
777   }
778
779   return OMX_ErrorNone;
780 }
781
782 static void
783 gst_omx_buffer_unmap (GstOMXBuffer * buffer)
784 {
785   g_return_if_fail (buffer != NULL);
786
787   if (buffer->input_frame_mapped) {
788     g_assert (!buffer->input_mem);
789     g_assert (!buffer->input_buffer);
790     g_assert (!buffer->input_buffer_mapped);
791     gst_video_frame_unmap (&buffer->input_frame);
792     buffer->input_frame_mapped = FALSE;
793   } else if (buffer->input_mem) {
794     g_assert (!buffer->input_buffer);
795     g_assert (!buffer->input_buffer_mapped);
796     gst_memory_unmap (buffer->input_mem, &buffer->map);
797     g_clear_pointer (&buffer->input_mem, gst_memory_unref);
798   } else if (buffer->input_buffer) {
799     if (buffer->input_buffer_mapped)
800       gst_buffer_unmap (buffer->input_buffer, &buffer->map);
801     buffer->input_buffer_mapped = FALSE;
802     g_clear_pointer (&buffer->input_buffer, gst_buffer_unref);
803   }
804 }
805
806 static void
807 log_omx_api_trace_buffer (GstOMXComponent * comp, const gchar * event,
808     GstOMXBuffer * buf)
809 {
810 #ifndef GST_DISABLE_GST_DEBUG
811   GstStructure *s;
812
813   /* Don't bother creating useless structs if not needed */
814   if (gst_debug_category_get_threshold (OMX_API_TRACE) < GST_LEVEL_TRACE)
815     return;
816
817   if (buf) {
818     gchar *buf_str, *omx_buf_str, *pbuffer_str;
819
820     /* GST_PTR_FORMAT won't serialize G_TYPE_POINTER fields so stringify pointers */
821     buf_str = g_strdup_printf ("%p", buf);
822     omx_buf_str = g_strdup_printf ("%p", buf->omx_buf);
823     pbuffer_str = g_strdup_printf ("%p", buf->omx_buf->pBuffer);
824
825     /* *INDENT-OFF* */
826     s = gst_structure_new (event,
827         "GstOMXBuffer", G_TYPE_STRING, buf_str,
828         "OMX-buffer", G_TYPE_STRING, omx_buf_str,
829         "pBuffer", G_TYPE_STRING, pbuffer_str,
830         "TimeStamp", G_TYPE_UINT64, GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp),
831         "AllocLen", G_TYPE_UINT, buf->omx_buf->nAllocLen,
832         "FilledLen", G_TYPE_UINT, buf->omx_buf->nFilledLen,
833         "flags", G_TYPE_UINT, buf->omx_buf->nFlags,
834         "flags-str", G_TYPE_STRING, gst_omx_buffer_flags_to_string (buf->omx_buf->nFlags),
835         NULL);
836     /* *INDENT-ON* */
837
838     g_free (buf_str);
839     g_free (omx_buf_str);
840     g_free (pbuffer_str);
841   } else {
842     s = gst_structure_new_empty (event);
843   }
844
845   GST_CAT_TRACE_OBJECT (OMX_API_TRACE, comp->parent, "%" GST_PTR_FORMAT, s);
846
847   gst_structure_free (s);
848 #endif /* GST_DISABLE_GST_DEBUG */
849 }
850
851 static OMX_ERRORTYPE
852 EmptyBufferDone (OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
853     OMX_BUFFERHEADERTYPE * pBuffer)
854 {
855   GstOMXBuffer *buf;
856   GstOMXComponent *comp;
857   GstOMXMessage *msg;
858
859   buf = pBuffer->pAppPrivate;
860   if (!buf) {
861     GST_ERROR ("Have unknown or deallocated buffer %p", pBuffer);
862     return OMX_ErrorNone;
863   }
864
865   g_assert (buf->omx_buf == pBuffer);
866
867   if (buf->port->tunneled) {
868     GST_ERROR ("EmptyBufferDone on tunneled port");
869     return OMX_ErrorBadParameter;
870   }
871
872   comp = buf->port->comp;
873
874   msg = g_slice_new (GstOMXMessage);
875   msg->type = GST_OMX_MESSAGE_BUFFER_DONE;
876   msg->content.buffer_done.component = hComponent;
877   msg->content.buffer_done.app_data = pAppData;
878   msg->content.buffer_done.buffer = pBuffer;
879   msg->content.buffer_done.empty = OMX_TRUE;
880
881   log_omx_api_trace_buffer (comp, "EmptyBufferDone", buf);
882   GST_LOG_OBJECT (comp->parent, "%s port %u emptied buffer %p (%p)",
883       comp->name, buf->port->index, buf, buf->omx_buf->pBuffer);
884
885   gst_omx_component_send_message (comp, msg);
886
887   return OMX_ErrorNone;
888 }
889
890 static OMX_ERRORTYPE
891 FillBufferDone (OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
892     OMX_BUFFERHEADERTYPE * pBuffer)
893 {
894   GstOMXBuffer *buf;
895   GstOMXComponent *comp;
896   GstOMXMessage *msg;
897
898   buf = pBuffer->pAppPrivate;
899   if (!buf) {
900     GST_ERROR ("Have unknown or deallocated buffer %p", pBuffer);
901     return OMX_ErrorNone;
902   }
903
904   g_assert (buf->omx_buf == pBuffer);
905
906   if (buf->port->tunneled) {
907     GST_ERROR ("FillBufferDone on tunneled port");
908     return OMX_ErrorBadParameter;
909   }
910
911   comp = buf->port->comp;
912
913   msg = g_slice_new (GstOMXMessage);
914   msg->type = GST_OMX_MESSAGE_BUFFER_DONE;
915   msg->content.buffer_done.component = hComponent;
916   msg->content.buffer_done.app_data = pAppData;
917   msg->content.buffer_done.buffer = pBuffer;
918   msg->content.buffer_done.empty = OMX_FALSE;
919
920   log_omx_api_trace_buffer (comp, "FillBufferDone", buf);
921   GST_LOG_OBJECT (comp->parent, "%s port %u filled buffer %p (%p)", comp->name,
922       buf->port->index, buf, buf->omx_buf->pBuffer);
923
924   gst_omx_component_send_message (comp, msg);
925
926   return OMX_ErrorNone;
927 }
928
929 static OMX_CALLBACKTYPE callbacks =
930     { EventHandler, EmptyBufferDone, FillBufferDone };
931
932 GST_DEFINE_MINI_OBJECT_TYPE (GstOMXComponent, gst_omx_component);
933
934 static void gst_omx_component_free (GstOMXComponent * comp);
935
936 /* NOTE: Uses comp->lock and comp->messages_lock */
937 GstOMXComponent *
938 gst_omx_component_new (GstObject * parent, const gchar * core_name,
939     const gchar * component_name, const gchar * component_role, guint64 hacks)
940 {
941   OMX_ERRORTYPE err;
942   GstOMXCore *core;
943   GstOMXComponent *comp;
944   const gchar *dot;
945
946   core = gst_omx_core_acquire (core_name);
947   if (!core)
948     return NULL;
949
950   comp = g_slice_new0 (GstOMXComponent);
951   comp->core = core;
952
953   gst_mini_object_init (GST_MINI_OBJECT_CAST (comp), 0,
954       gst_omx_component_get_type (), NULL, NULL,
955       (GstMiniObjectFreeFunction) gst_omx_component_free);
956
957   if ((dot = g_strrstr (component_name, ".")))
958     comp->name = g_strdup (dot + 1);
959   else
960     comp->name = g_strdup (component_name);
961
962   err =
963       core->get_handle (&comp->handle, (OMX_STRING) component_name, comp,
964       &callbacks);
965   if (err != OMX_ErrorNone) {
966     GST_ERROR_OBJECT (parent,
967         "Failed to get component handle '%s' from core '%s': 0x%08x",
968         component_name, core_name, err);
969     gst_omx_core_release (core);
970     g_free (comp->name);
971     g_slice_free (GstOMXComponent, comp);
972     return NULL;
973   }
974   GST_DEBUG_OBJECT (parent,
975       "Successfully got component handle %p (%s) from core '%s'", comp->handle,
976       component_name, core_name);
977   comp->parent = gst_object_ref (parent);
978   comp->hacks = hacks;
979
980   comp->ports = g_ptr_array_new ();
981   comp->n_in_ports = 0;
982   comp->n_out_ports = 0;
983
984   g_mutex_init (&comp->lock);
985   g_mutex_init (&comp->messages_lock);
986   g_cond_init (&comp->messages_cond);
987
988   g_queue_init (&comp->messages);
989   comp->pending_state = OMX_StateInvalid;
990   comp->last_error = OMX_ErrorNone;
991
992   /* Set component role if any */
993   if (component_role && !(hacks & GST_OMX_HACK_NO_COMPONENT_ROLE)) {
994     OMX_PARAM_COMPONENTROLETYPE param;
995
996     GST_OMX_INIT_STRUCT (&param);
997
998     g_strlcpy ((gchar *) param.cRole, component_role, sizeof (param.cRole));
999     err =
1000         gst_omx_component_set_parameter (comp,
1001         OMX_IndexParamStandardComponentRole, &param);
1002
1003     DEBUG_IF_OK (comp->parent, err,
1004         "Setting component role to '%s': %s (0x%08x)", component_role,
1005         gst_omx_error_to_string (err), err);
1006
1007     /* If setting the role failed this component is unusable */
1008     if (err != OMX_ErrorNone) {
1009       gst_omx_component_free (comp);
1010       return NULL;
1011     }
1012   }
1013
1014   OMX_GetState (comp->handle, &comp->state);
1015
1016   g_mutex_lock (&comp->lock);
1017   gst_omx_component_handle_messages (comp);
1018   g_mutex_unlock (&comp->lock);
1019
1020   return comp;
1021 }
1022
1023 /* NOTE: Uses comp->messages_lock */
1024 static void
1025 gst_omx_component_free (GstOMXComponent * comp)
1026 {
1027   gint i, n;
1028
1029   g_return_if_fail (comp != NULL);
1030
1031   GST_INFO_OBJECT (comp->parent, "Unloading component %p %s", comp, comp->name);
1032
1033   if (comp->ports) {
1034     n = comp->ports->len;
1035     for (i = 0; i < n; i++) {
1036       GstOMXPort *port = g_ptr_array_index (comp->ports, i);
1037
1038       gst_omx_port_deallocate_buffers (port);
1039       g_assert (port->buffers == NULL);
1040       g_assert (g_queue_get_length (&port->pending_buffers) == 0);
1041
1042       g_slice_free (GstOMXPort, port);
1043     }
1044     g_ptr_array_unref (comp->ports);
1045     comp->ports = NULL;
1046   }
1047
1048   comp->core->free_handle (comp->handle);
1049   gst_omx_core_release (comp->core);
1050
1051   gst_omx_component_flush_messages (comp);
1052
1053   g_cond_clear (&comp->messages_cond);
1054   g_mutex_clear (&comp->messages_lock);
1055   g_mutex_clear (&comp->lock);
1056
1057   gst_object_unref (comp->parent);
1058
1059   g_free (comp->name);
1060   comp->name = NULL;
1061
1062   g_slice_free (GstOMXComponent, comp);
1063 }
1064
1065 GstOMXComponent *
1066 gst_omx_component_ref (GstOMXComponent * comp)
1067 {
1068   g_return_val_if_fail (comp, NULL);
1069
1070   gst_mini_object_ref (GST_MINI_OBJECT_CAST (comp));
1071   return comp;
1072 }
1073
1074 void
1075 gst_omx_component_unref (GstOMXComponent * comp)
1076 {
1077   g_return_if_fail (comp);
1078
1079   gst_mini_object_unref (GST_MINI_OBJECT_CAST (comp));
1080 }
1081
1082 static GstStructure *
1083 omx_command_to_debug_struct (OMX_COMMANDTYPE cmd,
1084     guint32 param, gpointer cmd_data)
1085 {
1086   const gchar *cmd_str;
1087
1088   cmd_str = gst_omx_command_to_string (cmd);
1089
1090   switch (cmd) {
1091     case OMX_CommandStateSet:
1092       return gst_structure_new ("SendCommand",
1093           "command", G_TYPE_STRING, cmd_str,
1094           "state", G_TYPE_STRING, gst_omx_state_to_string (param), NULL);
1095     case OMX_CommandFlush:
1096     case OMX_CommandPortDisable:
1097     case OMX_CommandPortEnable:
1098       return gst_structure_new ("SendCommand",
1099           "command", G_TYPE_STRING, cmd_str, "port", G_TYPE_UINT, param, NULL);
1100     case OMX_CommandMarkBuffer:
1101       return gst_structure_new ("SendCommand",
1102           "command", G_TYPE_STRING, cmd_str,
1103           "mark-type", G_TYPE_POINTER, cmd_data, NULL);
1104     case OMX_CommandKhronosExtensions:
1105     case OMX_CommandVendorStartUnused:
1106     case OMX_CommandMax:
1107     default:
1108       break;
1109   }
1110
1111   return NULL;
1112 }
1113
1114 static void
1115 log_omx_api_trace_send_command (GstOMXComponent * comp, OMX_COMMANDTYPE cmd,
1116     guint32 param, gpointer cmd_data)
1117 {
1118 #ifndef GST_DISABLE_GST_DEBUG
1119   GstStructure *s;
1120
1121   /* Don't bother creating useless structs if not needed */
1122   if (gst_debug_category_get_threshold (OMX_API_TRACE) < GST_LEVEL_DEBUG)
1123     return;
1124
1125   s = omx_command_to_debug_struct (cmd, param, cmd_data);
1126   if (!s) {
1127     GST_CAT_WARNING_OBJECT (OMX_API_TRACE, comp->parent,
1128         "invalid command 0x%08x Param %u CmdData %p", cmd, param, cmd_data);
1129     return;
1130   }
1131
1132   GST_CAT_DEBUG_OBJECT (OMX_API_TRACE, comp->parent, "%" GST_PTR_FORMAT, s);
1133
1134   gst_structure_free (s);
1135 #endif /* GST_DISABLE_GST_DEBUG */
1136 }
1137
1138 static OMX_ERRORTYPE
1139 gst_omx_component_send_command (GstOMXComponent * comp, OMX_COMMANDTYPE cmd,
1140     guint32 param, gpointer cmd_data)
1141 {
1142   OMX_ERRORTYPE err;
1143
1144   log_omx_api_trace_send_command (comp, cmd, param, cmd_data);
1145   err = OMX_SendCommand (comp->handle, cmd, param, cmd_data);
1146
1147   return err;
1148 }
1149
1150 /* NOTE: Uses comp->lock and comp->messages_lock */
1151 OMX_ERRORTYPE
1152 gst_omx_component_set_state (GstOMXComponent * comp, OMX_STATETYPE state)
1153 {
1154   OMX_STATETYPE old_state;
1155   OMX_ERRORTYPE err = OMX_ErrorNone;
1156
1157   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1158
1159   g_mutex_lock (&comp->lock);
1160
1161   gst_omx_component_handle_messages (comp);
1162
1163   old_state = comp->state;
1164   GST_INFO_OBJECT (comp->parent, "Setting %s state from %s to %s", comp->name,
1165       gst_omx_state_to_string (old_state), gst_omx_state_to_string (state));
1166
1167   if ((err = comp->last_error) != OMX_ErrorNone && state > old_state) {
1168     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
1169         comp->name, gst_omx_error_to_string (err), err);
1170     goto done;
1171   }
1172
1173   if (old_state == state || comp->pending_state == state) {
1174     GST_DEBUG_OBJECT (comp->parent, "Component %s already in state %s",
1175         comp->name, gst_omx_state_to_string (state));
1176     goto done;
1177   }
1178
1179   comp->pending_state = state;
1180
1181   /* Reset some things */
1182   if ((old_state == OMX_StateExecuting || old_state == OMX_StatePause)
1183       && state < old_state) {
1184     g_list_free (comp->pending_reconfigure_outports);
1185     comp->pending_reconfigure_outports = NULL;
1186     /* Notify all inports that are still waiting */
1187     gst_omx_component_send_message (comp, NULL);
1188   }
1189
1190   err = gst_omx_component_send_command (comp, OMX_CommandStateSet, state, NULL);
1191   /* No need to check if anything has changed here */
1192
1193 done:
1194
1195   gst_omx_component_handle_messages (comp);
1196
1197   if (err != OMX_ErrorNone && comp->last_error == OMX_ErrorNone) {
1198     GST_ERROR_OBJECT (comp->parent,
1199         "Last operation returned an error. Setting last_error manually.");
1200     comp->last_error = err;
1201   }
1202
1203   g_mutex_unlock (&comp->lock);
1204
1205   if (err != OMX_ErrorNone) {
1206     GST_ERROR_OBJECT (comp->parent,
1207         "Error setting %s state from %s to %s: %s (0x%08x)", comp->name,
1208         gst_omx_state_to_string (old_state), gst_omx_state_to_string (state),
1209         gst_omx_error_to_string (err), err);
1210   }
1211   return err;
1212 }
1213
1214 /* NOTE: Uses comp->lock and comp->messages_lock */
1215 OMX_STATETYPE
1216 gst_omx_component_get_state (GstOMXComponent * comp, GstClockTime timeout)
1217 {
1218   OMX_STATETYPE ret;
1219   gboolean signalled = TRUE;
1220
1221   g_return_val_if_fail (comp != NULL, OMX_StateInvalid);
1222
1223   GST_DEBUG_OBJECT (comp->parent, "Getting state of %s", comp->name);
1224
1225   g_mutex_lock (&comp->lock);
1226
1227   gst_omx_component_handle_messages (comp);
1228
1229   if (comp->last_error != OMX_ErrorNone) {
1230     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
1231         comp->name, gst_omx_error_to_string (comp->last_error),
1232         comp->last_error);
1233     ret = OMX_StateInvalid;
1234     goto done;
1235   }
1236
1237   ret = comp->state;
1238   if (comp->pending_state == OMX_StateInvalid)
1239     goto done;
1240
1241   while (signalled && comp->last_error == OMX_ErrorNone
1242       && comp->pending_state != OMX_StateInvalid) {
1243
1244     signalled = gst_omx_component_wait_message (comp, timeout);
1245     if (signalled)
1246       gst_omx_component_handle_messages (comp);
1247   };
1248
1249   if (signalled) {
1250     if (comp->last_error != OMX_ErrorNone) {
1251       GST_ERROR_OBJECT (comp->parent,
1252           "%s got error while waiting for state change: %s (0x%08x)",
1253           comp->name, gst_omx_error_to_string (comp->last_error),
1254           comp->last_error);
1255       ret = OMX_StateInvalid;
1256     } else if (comp->pending_state == OMX_StateInvalid) {
1257       /* State change finished and everything's fine */
1258       ret = comp->state;
1259     } else {
1260       ret = OMX_StateInvalid;
1261       g_assert_not_reached ();
1262     }
1263   } else {
1264     ret = OMX_StateInvalid;
1265     GST_WARNING_OBJECT (comp->parent, "%s timeout while waiting for state "
1266         "change", comp->name);
1267   }
1268
1269 done:
1270   g_mutex_unlock (&comp->lock);
1271
1272   GST_DEBUG_OBJECT (comp->parent, "%s returning state %s", comp->name,
1273       gst_omx_state_to_string (ret));
1274
1275   return ret;
1276 }
1277
1278 GstOMXPort *
1279 gst_omx_component_add_port (GstOMXComponent * comp, guint32 index)
1280 {
1281   gint i, n;
1282   GstOMXPort *port;
1283   OMX_PARAM_PORTDEFINITIONTYPE port_def;
1284   OMX_ERRORTYPE err;
1285
1286   g_return_val_if_fail (comp != NULL, NULL);
1287
1288   /* Check if this port exists already */
1289   n = comp->ports->len;
1290   for (i = 0; i < n; i++) {
1291     port = g_ptr_array_index (comp->ports, i);
1292     g_return_val_if_fail (port->index != index, NULL);
1293   }
1294
1295   GST_DEBUG_OBJECT (comp->parent, "%s adding port %u", comp->name, index);
1296
1297   GST_OMX_INIT_STRUCT (&port_def);
1298   port_def.nPortIndex = index;
1299
1300   err = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1301       &port_def);
1302   if (err != OMX_ErrorNone) {
1303     GST_ERROR_OBJECT (comp->parent, "%s failed to add port %u: %s (0x%08x)",
1304         comp->name, index, gst_omx_error_to_string (err), err);
1305     return NULL;
1306   }
1307
1308   port = g_slice_new0 (GstOMXPort);
1309   port->comp = comp;
1310   port->index = index;
1311
1312   port->tunneled = FALSE;
1313
1314   port->port_def = port_def;
1315
1316   g_queue_init (&port->pending_buffers);
1317   port->flushing = TRUE;
1318   port->flushed = FALSE;
1319   port->enabled_pending = FALSE;
1320   port->disabled_pending = FALSE;
1321   port->eos = FALSE;
1322   port->using_pool = FALSE;
1323
1324   if (port->port_def.eDir == OMX_DirInput)
1325     comp->n_in_ports++;
1326   else
1327     comp->n_out_ports++;
1328
1329   g_ptr_array_add (comp->ports, port);
1330
1331   return port;
1332 }
1333
1334 GstOMXPort *
1335 gst_omx_component_get_port (GstOMXComponent * comp, guint32 index)
1336 {
1337   gint i, n;
1338
1339   n = comp->ports->len;
1340   for (i = 0; i < n; i++) {
1341     GstOMXPort *tmp = g_ptr_array_index (comp->ports, i);
1342
1343     if (tmp->index == index)
1344       return tmp;
1345   }
1346   return NULL;
1347 }
1348
1349 /* NOTE: Uses comp->lock and comp->messages_lock */
1350 OMX_ERRORTYPE
1351 gst_omx_component_get_last_error (GstOMXComponent * comp)
1352 {
1353   OMX_ERRORTYPE err;
1354
1355   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1356
1357   g_mutex_lock (&comp->lock);
1358   gst_omx_component_handle_messages (comp);
1359   err = comp->last_error;
1360   g_mutex_unlock (&comp->lock);
1361
1362   GST_DEBUG_OBJECT (comp->parent, "Returning last %s error: %s (0x%08x)",
1363       comp->name, gst_omx_error_to_string (err), err);
1364
1365   return err;
1366 }
1367
1368 const gchar *
1369 gst_omx_component_get_last_error_string (GstOMXComponent * comp)
1370 {
1371   g_return_val_if_fail (comp != NULL, NULL);
1372
1373   return gst_omx_error_to_string (gst_omx_component_get_last_error (comp));
1374 }
1375
1376 #ifndef GST_DISABLE_GST_DEBUG
1377 static const gchar *
1378 omx_index_type_to_str (OMX_INDEXTYPE index)
1379 {
1380   switch (index) {
1381     case OMX_IndexComponentStartUnused:
1382       return "OMX_IndexComponentStartUnused";
1383     case OMX_IndexParamPriorityMgmt:
1384       return "OMX_IndexParamPriorityMgmt";
1385     case OMX_IndexParamAudioInit:
1386       return "OMX_IndexParamAudioInit";
1387     case OMX_IndexParamImageInit:
1388       return "OMX_IndexParamImageInit";
1389     case OMX_IndexParamVideoInit:
1390       return "OMX_IndexParamVideoInit";
1391     case OMX_IndexParamOtherInit:
1392       return "OMX_IndexParamOtherInit";
1393     case OMX_IndexParamNumAvailableStreams:
1394       return "OMX_IndexParamNumAvailableStreams";
1395     case OMX_IndexParamActiveStream:
1396       return "OMX_IndexParamActiveStream";
1397     case OMX_IndexParamSuspensionPolicy:
1398       return "OMX_IndexParamSuspensionPolicy";
1399     case OMX_IndexParamComponentSuspended:
1400       return "OMX_IndexParamComponentSuspended";
1401     case OMX_IndexConfigCapturing:
1402       return "OMX_IndexConfigCapturing";
1403     case OMX_IndexConfigCaptureMode:
1404       return "OMX_IndexConfigCaptureMode";
1405     case OMX_IndexAutoPauseAfterCapture:
1406       return "OMX_IndexAutoPauseAfterCapture";
1407     case OMX_IndexParamContentURI:
1408       return "OMX_IndexParamContentURI";
1409     case OMX_IndexParamDisableResourceConcealment:
1410       return "OMX_IndexParamDisableResourceConcealment";
1411     case OMX_IndexConfigMetadataItemCount:
1412       return "OMX_IndexConfigMetadataItemCount";
1413     case OMX_IndexConfigContainerNodeCount:
1414       return "OMX_IndexConfigContainerNodeCount";
1415     case OMX_IndexConfigMetadataItem:
1416       return "OMX_IndexConfigMetadataItem";
1417     case OMX_IndexConfigCounterNodeID:
1418       return "OMX_IndexConfigCounterNodeID";
1419     case OMX_IndexParamMetadataFilterType:
1420       return "OMX_IndexParamMetadataFilterType";
1421     case OMX_IndexParamMetadataKeyFilter:
1422       return "OMX_IndexParamMetadataKeyFilter";
1423     case OMX_IndexConfigPriorityMgmt:
1424       return "OMX_IndexConfigPriorityMgmt";
1425     case OMX_IndexParamStandardComponentRole:
1426       return "OMX_IndexParamStandardComponentRole";
1427     case OMX_IndexPortStartUnused:
1428       return "OMX_IndexPortStartUnused";
1429     case OMX_IndexParamPortDefinition:
1430       return "OMX_IndexParamPortDefinition";
1431     case OMX_IndexParamCompBufferSupplier:
1432       return "OMX_IndexParamCompBufferSupplier";
1433     case OMX_IndexReservedStartUnused:
1434       return "OMX_IndexReservedStartUnused";
1435     case OMX_IndexAudioStartUnused:
1436       return "OMX_IndexAudioStartUnused";
1437     case OMX_IndexParamAudioPortFormat:
1438       return "OMX_IndexParamAudioPortFormat";
1439     case OMX_IndexParamAudioPcm:
1440       return "OMX_IndexParamAudioPcm";
1441     case OMX_IndexParamAudioAac:
1442       return "OMX_IndexParamAudioAac";
1443     case OMX_IndexParamAudioRa:
1444       return "OMX_IndexParamAudioRa";
1445     case OMX_IndexParamAudioMp3:
1446       return "OMX_IndexParamAudioMp3";
1447     case OMX_IndexParamAudioAdpcm:
1448       return "OMX_IndexParamAudioAdpcm";
1449     case OMX_IndexParamAudioG723:
1450       return "OMX_IndexParamAudioG723";
1451     case OMX_IndexParamAudioG729:
1452       return "OMX_IndexParamAudioG729";
1453     case OMX_IndexParamAudioAmr:
1454       return "OMX_IndexParamAudioAmr";
1455     case OMX_IndexParamAudioWma:
1456       return "OMX_IndexParamAudioWma";
1457     case OMX_IndexParamAudioSbc:
1458       return "OMX_IndexParamAudioSbc";
1459     case OMX_IndexParamAudioMidi:
1460       return "OMX_IndexParamAudioMidi";
1461     case OMX_IndexParamAudioGsm_FR:
1462       return "OMX_IndexParamAudioGsm_FR";
1463     case OMX_IndexParamAudioMidiLoadUserSound:
1464       return "OMX_IndexParamAudioMidiLoadUserSound";
1465     case OMX_IndexParamAudioG726:
1466       return "OMX_IndexParamAudioG726";
1467     case OMX_IndexParamAudioGsm_EFR:
1468       return "OMX_IndexParamAudioGsm_EFR";
1469     case OMX_IndexParamAudioGsm_HR:
1470       return "OMX_IndexParamAudioGsm_HR";
1471     case OMX_IndexParamAudioPdc_FR:
1472       return "OMX_IndexParamAudioPdc_FR";
1473     case OMX_IndexParamAudioPdc_EFR:
1474       return "OMX_IndexParamAudioPdc_EFR";
1475     case OMX_IndexParamAudioPdc_HR:
1476       return "OMX_IndexParamAudioPdc_HR";
1477     case OMX_IndexParamAudioTdma_FR:
1478       return "OMX_IndexParamAudioTdma_FR";
1479     case OMX_IndexParamAudioTdma_EFR:
1480       return "OMX_IndexParamAudioTdma_EFR";
1481     case OMX_IndexParamAudioQcelp8:
1482       return "OMX_IndexParamAudioQcelp8";
1483     case OMX_IndexParamAudioQcelp13:
1484       return "OMX_IndexParamAudioQcelp13";
1485     case OMX_IndexParamAudioEvrc:
1486       return "OMX_IndexParamAudioEvrc";
1487     case OMX_IndexParamAudioSmv:
1488       return "OMX_IndexParamAudioSmv";
1489     case OMX_IndexParamAudioVorbis:
1490       return "OMX_IndexParamAudioVorbis";
1491     case OMX_IndexConfigAudioMidiImmediateEvent:
1492       return "OMX_IndexConfigAudioMidiImmediateEvent";
1493     case OMX_IndexConfigAudioMidiControl:
1494       return "OMX_IndexConfigAudioMidiControl";
1495     case OMX_IndexConfigAudioMidiSoundBankProgram:
1496       return "OMX_IndexConfigAudioMidiSoundBankProgram";
1497     case OMX_IndexConfigAudioMidiStatus:
1498       return "OMX_IndexConfigAudioMidiStatus";
1499     case OMX_IndexConfigAudioMidiMetaEvent:
1500       return "OMX_IndexConfigAudioMidiMetaEvent";
1501     case OMX_IndexConfigAudioMidiMetaEventData:
1502       return "OMX_IndexConfigAudioMidiMetaEventData";
1503     case OMX_IndexConfigAudioVolume:
1504       return "OMX_IndexConfigAudioVolume";
1505     case OMX_IndexConfigAudioBalance:
1506       return "OMX_IndexConfigAudioBalance";
1507     case OMX_IndexConfigAudioChannelMute:
1508       return "OMX_IndexConfigAudioChannelMute";
1509     case OMX_IndexConfigAudioMute:
1510       return "OMX_IndexConfigAudioMute";
1511     case OMX_IndexConfigAudioLoudness:
1512       return "OMX_IndexConfigAudioLoudness";
1513     case OMX_IndexConfigAudioEchoCancelation:
1514       return "OMX_IndexConfigAudioEchoCancelation";
1515     case OMX_IndexConfigAudioNoiseReduction:
1516       return "OMX_IndexConfigAudioNoiseReduction";
1517     case OMX_IndexConfigAudioBass:
1518       return "OMX_IndexConfigAudioBass";
1519     case OMX_IndexConfigAudioTreble:
1520       return "OMX_IndexConfigAudioTreble";
1521     case OMX_IndexConfigAudioStereoWidening:
1522       return "OMX_IndexConfigAudioStereoWidening";
1523     case OMX_IndexConfigAudioChorus:
1524       return "OMX_IndexConfigAudioChorus";
1525     case OMX_IndexConfigAudioEqualizer:
1526       return "OMX_IndexConfigAudioEqualizer";
1527     case OMX_IndexConfigAudioReverberation:
1528       return "OMX_IndexConfigAudioReverberation";
1529     case OMX_IndexConfigAudioChannelVolume:
1530       return "OMX_IndexConfigAudioChannelVolume";
1531     case OMX_IndexImageStartUnused:
1532       return "OMX_IndexImageStartUnused";
1533     case OMX_IndexParamImagePortFormat:
1534       return "OMX_IndexParamImagePortFormat";
1535     case OMX_IndexParamFlashControl:
1536       return "OMX_IndexParamFlashControl";
1537     case OMX_IndexConfigFocusControl:
1538       return "OMX_IndexConfigFocusControl";
1539     case OMX_IndexParamQFactor:
1540       return "OMX_IndexParamQFactor";
1541     case OMX_IndexParamQuantizationTable:
1542       return "OMX_IndexParamQuantizationTable";
1543     case OMX_IndexParamHuffmanTable:
1544       return "OMX_IndexParamHuffmanTable";
1545     case OMX_IndexConfigFlashControl:
1546       return "OMX_IndexConfigFlashControl";
1547     case OMX_IndexVideoStartUnused:
1548       return "OMX_IndexVideoStartUnused";
1549     case OMX_IndexParamVideoPortFormat:
1550       return "OMX_IndexParamVideoPortFormat";
1551     case OMX_IndexParamVideoQuantization:
1552       return "OMX_IndexParamVideoQuantization";
1553     case OMX_IndexParamVideoFastUpdate:
1554       return "OMX_IndexParamVideoFastUpdate";
1555     case OMX_IndexParamVideoBitrate:
1556       return "OMX_IndexParamVideoBitrate";
1557     case OMX_IndexParamVideoMotionVector:
1558       return "OMX_IndexParamVideoMotionVector";
1559     case OMX_IndexParamVideoIntraRefresh:
1560       return "OMX_IndexParamVideoIntraRefresh";
1561     case OMX_IndexParamVideoErrorCorrection:
1562       return "OMX_IndexParamVideoErrorCorrection";
1563     case OMX_IndexParamVideoVBSMC:
1564       return "OMX_IndexParamVideoVBSMC";
1565     case OMX_IndexParamVideoMpeg2:
1566       return "OMX_IndexParamVideoMpeg2";
1567     case OMX_IndexParamVideoMpeg4:
1568       return "OMX_IndexParamVideoMpeg4";
1569     case OMX_IndexParamVideoWmv:
1570       return "OMX_IndexParamVideoWmv";
1571     case OMX_IndexParamVideoRv:
1572       return "OMX_IndexParamVideoRv";
1573     case OMX_IndexParamVideoAvc:
1574       return "OMX_IndexParamVideoAvc";
1575     case OMX_IndexParamVideoH263:
1576       return "OMX_IndexParamVideoH263";
1577     case OMX_IndexParamVideoProfileLevelQuerySupported:
1578       return "OMX_IndexParamVideoProfileLevelQuerySupported";
1579     case OMX_IndexParamVideoProfileLevelCurrent:
1580       return "OMX_IndexParamVideoProfileLevelCurrent";
1581     case OMX_IndexConfigVideoBitrate:
1582       return "OMX_IndexConfigVideoBitrate";
1583     case OMX_IndexConfigVideoFramerate:
1584       return "OMX_IndexConfigVideoFramerate";
1585     case OMX_IndexConfigVideoIntraVOPRefresh:
1586       return "OMX_IndexConfigVideoIntraVOPRefresh";
1587     case OMX_IndexConfigVideoIntraMBRefresh:
1588       return "OMX_IndexConfigVideoIntraMBRefresh";
1589     case OMX_IndexConfigVideoMBErrorReporting:
1590       return "OMX_IndexConfigVideoMBErrorReporting";
1591     case OMX_IndexParamVideoMacroblocksPerFrame:
1592       return "OMX_IndexParamVideoMacroblocksPerFrame";
1593     case OMX_IndexConfigVideoMacroBlockErrorMap:
1594       return "OMX_IndexConfigVideoMacroBlockErrorMap";
1595     case OMX_IndexParamVideoSliceFMO:
1596       return "OMX_IndexParamVideoSliceFMO";
1597     case OMX_IndexConfigVideoAVCIntraPeriod:
1598       return "OMX_IndexConfigVideoAVCIntraPeriod";
1599     case OMX_IndexConfigVideoNalSize:
1600       return "OMX_IndexConfigVideoNalSize";
1601     case OMX_IndexCommonStartUnused:
1602       return "OMX_IndexCommonStartUnused";
1603     case OMX_IndexParamCommonDeblocking:
1604       return "OMX_IndexParamCommonDeblocking";
1605     case OMX_IndexParamCommonSensorMode:
1606       return "OMX_IndexParamCommonSensorMode";
1607     case OMX_IndexParamCommonInterleave:
1608       return "OMX_IndexParamCommonInterleave";
1609     case OMX_IndexConfigCommonColorFormatConversion:
1610       return "OMX_IndexConfigCommonColorFormatConversion";
1611     case OMX_IndexConfigCommonScale:
1612       return "OMX_IndexConfigCommonScale";
1613     case OMX_IndexConfigCommonImageFilter:
1614       return "OMX_IndexConfigCommonImageFilter";
1615     case OMX_IndexConfigCommonColorEnhancement:
1616       return "OMX_IndexConfigCommonColorEnhancement";
1617     case OMX_IndexConfigCommonColorKey:
1618       return "OMX_IndexConfigCommonColorKey";
1619     case OMX_IndexConfigCommonColorBlend:
1620       return "OMX_IndexConfigCommonColorBlend";
1621     case OMX_IndexConfigCommonFrameStabilisation:
1622       return "OMX_IndexConfigCommonFrameStabilisation";
1623     case OMX_IndexConfigCommonRotate:
1624       return "OMX_IndexConfigCommonRotate";
1625     case OMX_IndexConfigCommonMirror:
1626       return "OMX_IndexConfigCommonMirror";
1627     case OMX_IndexConfigCommonOutputPosition:
1628       return "OMX_IndexConfigCommonOutputPosition";
1629     case OMX_IndexConfigCommonInputCrop:
1630       return "OMX_IndexConfigCommonInputCrop";
1631     case OMX_IndexConfigCommonOutputCrop:
1632       return "OMX_IndexConfigCommonOutputCrop";
1633     case OMX_IndexConfigCommonDigitalZoom:
1634       return "OMX_IndexConfigCommonDigitalZoom";
1635     case OMX_IndexConfigCommonOpticalZoom:
1636       return "OMX_IndexConfigCommonOpticalZoom";
1637     case OMX_IndexConfigCommonWhiteBalance:
1638       return "OMX_IndexConfigCommonWhiteBalance";
1639     case OMX_IndexConfigCommonExposure:
1640       return "OMX_IndexConfigCommonExposure";
1641     case OMX_IndexConfigCommonContrast:
1642       return "OMX_IndexConfigCommonContrast";
1643     case OMX_IndexConfigCommonBrightness:
1644       return "OMX_IndexConfigCommonBrightness";
1645     case OMX_IndexConfigCommonBacklight:
1646       return "OMX_IndexConfigCommonBacklight";
1647     case OMX_IndexConfigCommonGamma:
1648       return "OMX_IndexConfigCommonGamma";
1649     case OMX_IndexConfigCommonSaturation:
1650       return "OMX_IndexConfigCommonSaturation";
1651     case OMX_IndexConfigCommonLightness:
1652       return "OMX_IndexConfigCommonLightness";
1653     case OMX_IndexConfigCommonExclusionRect:
1654       return "OMX_IndexConfigCommonExclusionRect";
1655     case OMX_IndexConfigCommonDithering:
1656       return "OMX_IndexConfigCommonDithering";
1657     case OMX_IndexConfigCommonPlaneBlend:
1658       return "OMX_IndexConfigCommonPlaneBlend";
1659     case OMX_IndexConfigCommonExposureValue:
1660       return "OMX_IndexConfigCommonExposureValue";
1661     case OMX_IndexConfigCommonOutputSize:
1662       return "OMX_IndexConfigCommonOutputSize";
1663     case OMX_IndexParamCommonExtraQuantData:
1664       return "OMX_IndexParamCommonExtraQuantData";
1665     case OMX_IndexConfigCommonTransitionEffect:
1666       return "OMX_IndexConfigCommonTransitionEffect";
1667     case OMX_IndexOtherStartUnused:
1668       return "OMX_IndexOtherStartUnused";
1669     case OMX_IndexParamOtherPortFormat:
1670       return "OMX_IndexParamOtherPortFormat";
1671     case OMX_IndexConfigOtherPower:
1672       return "OMX_IndexConfigOtherPower";
1673     case OMX_IndexConfigOtherStats:
1674       return "OMX_IndexConfigOtherStats";
1675     case OMX_IndexTimeStartUnused:
1676       return "OMX_IndexTimeStartUnused";
1677     case OMX_IndexConfigTimeScale:
1678       return "OMX_IndexConfigTimeScale";
1679     case OMX_IndexConfigTimeClockState:
1680       return "OMX_IndexConfigTimeClockState";
1681     case OMX_IndexConfigTimeCurrentMediaTime:
1682       return "OMX_IndexConfigTimeCurrentMediaTime";
1683     case OMX_IndexConfigTimeCurrentWallTime:
1684       return "OMX_IndexConfigTimeCurrentWallTime";
1685     case OMX_IndexConfigTimeMediaTimeRequest:
1686       return "OMX_IndexConfigTimeMediaTimeRequest";
1687     case OMX_IndexConfigTimeClientStartTime:
1688       return "OMX_IndexConfigTimeClientStartTime";
1689     case OMX_IndexConfigTimePosition:
1690       return "OMX_IndexConfigTimePosition";
1691     case OMX_IndexConfigTimeSeekMode:
1692       return "OMX_IndexConfigTimeSeekMode";
1693     case OMX_IndexKhronosExtensions:
1694       return "OMX_IndexKhronosExtensions";
1695     case OMX_IndexVendorStartUnused:
1696       return "OMX_IndexVendorStartUnused";
1697     case OMX_IndexMax:
1698       return "OMX_IndexMax";
1699     default:
1700       break;
1701   }
1702
1703 #if OMX_VERSION_MINOR == 1
1704   switch (index) {
1705     case OMX_IndexParamCustomContentPipe:
1706       return "OMX_IndexParamCustomContentPipe";
1707     case OMX_IndexConfigCommonFocusRegion:
1708       return "OMX_IndexConfigCommonFocusRegion";
1709     case OMX_IndexConfigCommonFocusStatus:
1710       return "OMX_IndexConfigCommonFocusStatus";
1711     case OMX_IndexConfigTimeActiveRefClock:
1712       return "OMX_IndexConfigTimeActiveRefClock";
1713     case OMX_IndexConfigTimeCurrentAudioReference:
1714       return "OMX_IndexConfigTimeCurrentAudioReference";
1715     case OMX_IndexConfigTimeCurrentVideoReference:
1716       return "OMX_IndexConfigTimeCurrentVideoReference";
1717     default:
1718       break;
1719   }
1720 #endif
1721
1722 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1723   switch ((OMX_ALG_INDEXTYPE) index) {
1724     case OMX_ALG_IndexVendorComponentStartUnused:
1725       return "OMX_ALG_IndexVendorComponentStartUnused";
1726     case OMX_ALG_IndexParamReportedLatency:
1727       return "OMX_ALG_IndexParamReportedLatency";
1728     case OMX_ALG_IndexParamPreallocation:
1729       return "OMX_ALG_IndexParamPreallocation";
1730     case OMX_ALG_IndexVendorPortStartUnused:
1731       return "OMX_ALG_IndexVendorPortStartUnused";
1732     case OMX_ALG_IndexPortParamBufferMode:
1733       return "OMX_ALG_IndexPortParamBufferMode";
1734     case OMX_ALG_IndexParamVendorVideoStartUnused:
1735       return "OMX_ALG_IndexParamVendorVideoStartUnused";
1736     case OMX_ALG_IndexParamVideoHevc:
1737       return "OMX_ALG_IndexParamVideoHevc";
1738     case OMX_ALG_IndexParamVideoVp9:
1739       return "OMX_ALG_IndexParamVideoVp9";
1740     case OMX_ALG_IndexParamVideoGopControl:
1741       return "OMX_ALG_IndexParamVideoGopControl";
1742     case OMX_ALG_IndexParamVideoSlices:
1743       return "OMX_ALG_IndexParamVideoSlices";
1744     case OMX_ALG_IndexParamVideoSceneChangeResilience:
1745       return "OMX_ALG_IndexParamVideoSceneChangeResilience";
1746     case OMX_ALG_IndexParamVideoPrefetchBuffer:
1747       return "OMX_ALG_IndexParamVideoPrefetchBuffer";
1748     case OMX_ALG_IndexParamVideoCodedPictureBuffer:
1749       return "OMX_ALG_IndexParamVideoCodedPictureBuffer";
1750     case OMX_ALG_IndexParamVideoQuantizationControl:
1751       return "OMX_ALG_IndexParamVideoQuantizationControl";
1752     case OMX_ALG_IndexParamVideoQuantizationExtension:
1753       return "OMX_ALG_IndexParamVideoQuantizationExtension";
1754     case OMX_ALG_IndexParamVideoScalingList:
1755       return "OMX_ALG_IndexParamVideoScalingList";
1756     case OMX_ALG_IndexParamVideoDecodedPictureBuffer:
1757       return "OMX_ALG_IndexParamVideoDecodedPictureBuffer";
1758     case OMX_ALG_IndexParamVideoInternalEntropyBuffers:
1759       return "OMX_ALG_IndexParamVideoInternalEntropyBuffers";
1760     case OMX_ALG_IndexParamVideoLowBandwidth:
1761       return "OMX_ALG_IndexParamVideoLowBandwidth";
1762     case OMX_ALG_IndexParamVideoAspectRatio:
1763       return "OMX_ALG_IndexParamVideoAspectRatio";
1764     case OMX_ALG_IndexParamVideoSubframe:
1765       return "OMX_ALG_IndexParamVideoSubframe";
1766     case OMX_ALG_IndexParamVideoInstantaneousDecodingRefresh:
1767       return "OMX_ALG_IndexParamVideoInstantaneousDecodingRefresh";
1768     case OMX_ALG_IndexParamVideoMaxBitrate:
1769       return "OMX_ALG_IndexParamVideoMaxBitrate";
1770     case OMX_ALG_IndexParamVideoFillerData:
1771       return "OMX_ALG_IndexParamVideoFillerData";
1772     case OMX_ALG_IndexParamVideoBufferMode:
1773       return "OMX_ALG_IndexParamVideoBufferMode";
1774     case OMX_ALG_IndexParamVideoInterlaceFormatCurrent:
1775       return "OMX_ALG_IndexParamVideoInterlaceFormatCurrent";
1776     case OMX_ALG_IndexParamVideoLongTerm:
1777       return "OMX_ALG_IndexParamVideoLongTerm";
1778     case OMX_ALG_IndexParamVideoLookAhead:
1779       return "OMX_ALG_IndexParamVideoLookAhead";
1780     case OMX_ALG_IndexConfigVendorVideoStartUnused:
1781       return "OMX_ALG_IndexConfigVendorVideoStartUnused";
1782     case OMX_ALG_IndexConfigVideoInsertInstantaneousDecodingRefresh:
1783       return "OMX_ALG_IndexConfigVideoInsertInstantaneousDecodingRefresh";
1784     case OMX_ALG_IndexConfigVideoGroupOfPictures:
1785       return "OMX_ALG_IndexConfigVideoGroupOfPictures";
1786     case OMX_ALG_IndexConfigVideoRegionOfInterest:
1787       return "OMX_ALG_IndexConfigVideoRegionOfInterest";
1788     case OMX_ALG_IndexConfigVideoNotifySceneChange:
1789       return "OMX_ALG_IndexConfigVideoNotifySceneChange";
1790     case OMX_ALG_IndexConfigVideoInsertLongTerm:
1791       return "OMX_ALG_IndexConfigVideoInsertLongTerm";
1792     case OMX_ALG_IndexConfigVideoUseLongTerm:
1793       return "OMX_ALG_IndexConfigVideoUseLongTerm";
1794     case OMX_ALG_IndexVendorCommonStartUnused:
1795       return "OMX_ALG_IndexVendorCommonStartUnused";
1796     case OMX_ALG_IndexParamCommonSequencePictureModeCurrent:
1797       return "OMX_ALG_IndexParamCommonSequencePictureModeCurrent";
1798     case OMX_ALG_IndexParamCommonSequencePictureModeQuerySupported:
1799       return "OMX_ALG_IndexParamCommonSequencePictureModeQuerySupported";
1800     case OMX_ALG_IndexParamVideoTwoPass:
1801       return "OMX_ALG_IndexParamVideoTwoPass";
1802     case OMX_ALG_IndexParamVideoColorPrimaries:
1803       return "OMX_ALG_IndexParamVideoColorPrimaries";
1804     case OMX_ALG_IndexParamVideoSkipFrame:
1805       return "OMX_ALG_IndexParamVideoSkipFrame";
1806     case OMX_ALG_IndexConfigVideoNotifyResolutionChange:
1807       return "OMX_ALG_IndexConfigVideoNotifyResolutionChange";
1808     case OMX_ALG_IndexConfigVideoInsertPrefixSEI:
1809       return "OMX_ALG_IndexConfigVideoInsertPrefixSEI";
1810     case OMX_ALG_IndexConfigVideoInsertSuffixSEI:
1811       return "OMX_ALG_IndexConfigVideoInsertSuffixSEI";
1812     case OMX_ALG_IndexConfigVideoQuantizationParameterTable:
1813       return "OMX_ALG_IndexConfigVideoQuantizationParameterTable";
1814     case OMX_ALG_IndexParamVideoTransferCharacteristics:
1815       return "OMX_ALG_IndexParamVideoTransferCharacteristics";
1816     case OMX_ALG_IndexParamVideoColorMatrix:
1817       return "OMX_ALG_IndexParamVideoColorMatrix";
1818     case OMX_ALG_IndexParamVideoInputParsed:
1819       return "OMX_ALG_IndexParamVideoInputParsed";
1820     case OMX_ALG_IndexParamVideoMaxPictureSize:
1821       return "OMX_ALG_IndexParamVideoMaxPictureSize";
1822     case OMX_ALG_IndexParamVideoMaxPictureSizes:
1823       return "OMX_ALG_IndexParamVideoMaxPictureSizes";
1824     case OMX_ALG_IndexParamVideoLoopFilterBeta:
1825       return "OMX_ALG_IndexParamVideoLoopFilterBeta";
1826     case OMX_ALG_IndexParamVideoLoopFilterTc:
1827       return "OMX_ALG_IndexParamVideoLoopFilterTc";
1828     case OMX_ALG_IndexParamVideoQuantizationTable:
1829       return "OMX_ALG_IndexParamVideoQuantizationTable";
1830     case OMX_ALG_IndexConfigVideoTransferCharacteristics:
1831       return "OMX_ALG_IndexConfigVideoTransferCharacteristics";
1832     case OMX_ALG_IndexConfigVideoColorMatrix:
1833       return "OMX_ALG_IndexConfigVideoColorMatrix";
1834     case OMX_ALG_IndexConfigVideoLoopFilterBeta:
1835       return "OMX_ALG_IndexConfigVideoLoopFilterBeta";
1836     case OMX_ALG_IndexConfigVideoLoopFilterTc:
1837       return "OMX_ALG_IndexConfigVideoLoopFilterTc";
1838     case OMX_ALG_IndexConfigVideoHighDynamicRangeSEIs:
1839       return "OMX_ALG_IndexConfigVideoHighDynamicRangeSEIs";
1840     case OMX_ALG_IndexConfigVideoMaxResolutionChange:
1841       return "OMX_ALG_IndexConfigVideoMaxResolutionChange";
1842     case OMX_ALG_IndexPortParamEarlyCallback:
1843       return "OMX_ALG_IndexPortParamEarlyCallback";
1844     case OMX_ALG_IndexMaxEnum:
1845       return "OMX_ALG_IndexMaxEnum";
1846   }
1847 #endif
1848
1849 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1850   /* Not part of the enum in OMX_IndexAlg.h */
1851   if (index == OMX_ALG_IndexParamVideoInterlaceFormatSupported)
1852     return "OMX_ALG_IndexParamVideoInterlaceFormatSupported";
1853 #endif
1854
1855   return NULL;
1856 }
1857 #endif /* GST_DISABLE_GST_DEBUG */
1858
1859 static void
1860 log_omx_api_trace_call (GstOMXComponent * comp, const gchar * function,
1861     OMX_INDEXTYPE index, GstDebugLevel level)
1862 {
1863 #ifndef GST_DISABLE_GST_DEBUG
1864   GstStructure *s;
1865   const gchar *index_name;
1866
1867   /* Don't bother creating useless structs if not needed */
1868   if (gst_debug_category_get_threshold (OMX_API_TRACE) < level)
1869     return;
1870
1871   index_name = omx_index_type_to_str (index);
1872   if (!index_name) {
1873     GST_CAT_WARNING_OBJECT (OMX_API_TRACE, comp->parent,
1874         "unknown call of %s with index 0x%08x", function, index);
1875     return;
1876   }
1877
1878   s = gst_structure_new (function, "index", G_TYPE_STRING, index_name, NULL);
1879   GST_CAT_LEVEL_LOG (OMX_API_TRACE, level, comp->parent, "%" GST_PTR_FORMAT, s);
1880   gst_structure_free (s);
1881 #endif /* GST_DISABLE_GST_DEBUG */
1882 }
1883
1884 /* comp->lock must be unlocked while calling this */
1885 OMX_ERRORTYPE
1886 gst_omx_component_get_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1887     gpointer param)
1888 {
1889   OMX_ERRORTYPE err;
1890
1891   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1892   g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1893
1894   GST_DEBUG_OBJECT (comp->parent, "Getting %s parameter at index 0x%08x",
1895       comp->name, index);
1896   log_omx_api_trace_call (comp, "GetParameter", index, GST_LEVEL_LOG);
1897   err = OMX_GetParameter (comp->handle, index, param);
1898   DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1899       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1900
1901   return err;
1902 }
1903
1904 /* comp->lock must be unlocked while calling this */
1905 OMX_ERRORTYPE
1906 gst_omx_component_set_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1907     gpointer param)
1908 {
1909   OMX_ERRORTYPE err;
1910
1911   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1912   g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1913
1914   GST_DEBUG_OBJECT (comp->parent, "Setting %s parameter at index 0x%08x",
1915       comp->name, index);
1916
1917   log_omx_api_trace_call (comp, "SetParameter", index, GST_LEVEL_DEBUG);
1918   err = OMX_SetParameter (comp->handle, index, param);
1919   DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1920       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1921
1922   return err;
1923 }
1924
1925 /* comp->lock must be unlocked while calling this */
1926 OMX_ERRORTYPE
1927 gst_omx_component_get_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1928     gpointer config)
1929 {
1930   OMX_ERRORTYPE err;
1931
1932   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1933   g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1934
1935   GST_DEBUG_OBJECT (comp->parent, "Getting %s configuration at index 0x%08x",
1936       comp->name, index);
1937   log_omx_api_trace_call (comp, "GetConfig", index, GST_LEVEL_LOG);
1938   err = OMX_GetConfig (comp->handle, index, config);
1939   DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1940       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1941
1942   return err;
1943 }
1944
1945 /* comp->lock must be unlocked while calling this */
1946 OMX_ERRORTYPE
1947 gst_omx_component_set_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1948     gpointer config)
1949 {
1950   OMX_ERRORTYPE err;
1951
1952   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1953   g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1954
1955   GST_DEBUG_OBJECT (comp->parent, "Setting %s configuration at index 0x%08x",
1956       comp->name, index);
1957   log_omx_api_trace_call (comp, "SetConfig", index, GST_LEVEL_DEBUG);
1958   err = OMX_SetConfig (comp->handle, index, config);
1959   DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1960       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1961
1962   return err;
1963 }
1964
1965 OMX_ERRORTYPE
1966 gst_omx_setup_tunnel (GstOMXPort * port1, GstOMXPort * port2)
1967 {
1968   GstOMXComponent *comp1;
1969   GstOMXComponent *comp2;
1970   OMX_ERRORTYPE err;
1971
1972   g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
1973   g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
1974       OMX_ErrorUndefined);
1975   comp1 = port1->comp;
1976
1977   g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
1978   g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
1979       OMX_ErrorUndefined);
1980   comp2 = port2->comp;
1981
1982   g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
1983
1984   g_mutex_lock (&comp1->lock);
1985   g_mutex_lock (&comp2->lock);
1986   GST_DEBUG_OBJECT (comp1->parent,
1987       "Setup tunnel between %s port %u and %s port %u",
1988       comp1->name, port1->index, comp2->name, port2->index);
1989
1990   err = comp1->core->setup_tunnel (comp1->handle, port1->index, comp2->handle,
1991       port2->index);
1992
1993   if (err == OMX_ErrorNone) {
1994     port1->tunneled = TRUE;
1995     port2->tunneled = TRUE;
1996   }
1997
1998   DEBUG_IF_OK (comp1->parent, err,
1999       "Setup tunnel between %s port %u and %s port %u: %s (0x%08x)",
2000       comp1->name, port1->index,
2001       comp2->name, port2->index, gst_omx_error_to_string (err), err);
2002
2003   g_mutex_unlock (&comp2->lock);
2004   g_mutex_unlock (&comp1->lock);
2005
2006   return err;
2007 }
2008
2009 OMX_ERRORTYPE
2010 gst_omx_close_tunnel (GstOMXPort * port1, GstOMXPort * port2)
2011 {
2012   GstOMXComponent *comp1;
2013   GstOMXComponent *comp2;
2014   OMX_ERRORTYPE err;
2015
2016   g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
2017   g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
2018       OMX_ErrorUndefined);
2019   comp1 = port1->comp;
2020
2021   g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
2022   g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
2023       OMX_ErrorUndefined);
2024   comp2 = port2->comp;
2025
2026   g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
2027   g_return_val_if_fail (port1->tunneled && port2->tunneled, OMX_ErrorUndefined);
2028
2029   g_mutex_lock (&comp1->lock);
2030   g_mutex_lock (&comp2->lock);
2031   GST_DEBUG_OBJECT (comp1->parent,
2032       "Closing tunnel between %s port %u and %s port %u",
2033       comp1->name, port1->index, comp2->name, port2->index);
2034
2035   err = comp1->core->setup_tunnel (comp1->handle, port1->index, 0, 0);
2036   if (err != OMX_ErrorNone) {
2037     GST_ERROR_OBJECT (comp1->parent,
2038         "Failed to close tunnel on output side %s (0x%08x)",
2039         gst_omx_error_to_string (err), err);
2040   }
2041   err = comp2->core->setup_tunnel (0, 0, comp2->handle, port2->index);
2042   if (err != OMX_ErrorNone) {
2043     GST_ERROR_OBJECT (comp2->parent,
2044         "Failed to close tunnel on input side %s (0x%08x)",
2045         gst_omx_error_to_string (err), err);
2046   }
2047
2048   port1->tunneled = FALSE;
2049   port2->tunneled = FALSE;
2050
2051   GST_DEBUG_OBJECT (comp1->parent,
2052       "Closed tunnel between %s port %u and %s port %u",
2053       comp1->name, port1->index, comp2->name, port2->index);
2054
2055   g_mutex_unlock (&comp2->lock);
2056   g_mutex_unlock (&comp1->lock);
2057
2058   return err;
2059 }
2060
2061 OMX_ERRORTYPE
2062 gst_omx_port_get_port_definition (GstOMXPort * port,
2063     OMX_PARAM_PORTDEFINITIONTYPE * port_def)
2064 {
2065   GstOMXComponent *comp;
2066   OMX_ERRORTYPE err;
2067
2068   g_return_val_if_fail (port != NULL, OMX_ErrorBadParameter);
2069
2070   comp = port->comp;
2071
2072   GST_OMX_INIT_STRUCT (port_def);
2073   port_def->nPortIndex = port->index;
2074
2075   err = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
2076       port_def);
2077
2078   return err;
2079 }
2080
2081 OMX_ERRORTYPE
2082 gst_omx_port_update_port_definition (GstOMXPort * port,
2083     OMX_PARAM_PORTDEFINITIONTYPE * port_def)
2084 {
2085   OMX_ERRORTYPE err_get, err_set = OMX_ErrorNone;
2086   GstOMXComponent *comp;
2087
2088   g_return_val_if_fail (port != NULL, FALSE);
2089
2090   comp = port->comp;
2091
2092   if (port_def)
2093     err_set =
2094         gst_omx_component_set_parameter (comp, OMX_IndexParamPortDefinition,
2095         port_def);
2096   err_get = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
2097       &port->port_def);
2098
2099   DEBUG_IF_OK (comp->parent, err_set,
2100       "Updated %s port %u definition: %s (0x%08x)", comp->name, port->index,
2101       gst_omx_error_to_string (err_set), err_set);
2102
2103   if (err_set != OMX_ErrorNone)
2104     return err_set;
2105   else
2106     return err_get;
2107 }
2108
2109 /* NOTE: Uses comp->lock and comp->messages_lock */
2110 GstOMXAcquireBufferReturn
2111 gst_omx_port_acquire_buffer (GstOMXPort * port, GstOMXBuffer ** buf,
2112     GstOMXWait wait)
2113 {
2114   GstOMXAcquireBufferReturn ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2115   GstOMXComponent *comp;
2116   OMX_ERRORTYPE err;
2117   GstOMXBuffer *_buf = NULL;
2118   gint64 timeout = GST_CLOCK_TIME_NONE;
2119
2120   g_return_val_if_fail (port != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
2121   g_return_val_if_fail (!port->tunneled, GST_OMX_ACQUIRE_BUFFER_ERROR);
2122   g_return_val_if_fail (buf != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
2123
2124   *buf = NULL;
2125
2126   comp = port->comp;
2127
2128   g_mutex_lock (&comp->lock);
2129   GST_DEBUG_OBJECT (comp->parent, "Acquiring %s buffer from port %u",
2130       comp->name, port->index);
2131
2132 retry:
2133   gst_omx_component_handle_messages (comp);
2134
2135   /* If we are in the case where we waited for a buffer after EOS,
2136    * make sure we don't do that again */
2137   if (timeout != -1)
2138     timeout = -2;
2139
2140   /* Check if the component is in an error state */
2141   if ((err = comp->last_error) != OMX_ErrorNone) {
2142     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s",
2143         comp->name, gst_omx_error_to_string (err));
2144     ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2145     goto done;
2146   }
2147
2148   /* Check if the port is flushing */
2149   if (port->flushing) {
2150     GST_DEBUG_OBJECT (comp->parent, "Component %s port %d is flushing",
2151         comp->name, port->index);
2152     ret = GST_OMX_ACQUIRE_BUFFER_FLUSHING;
2153     goto done;
2154   }
2155
2156   /* If this is an input port and at least one of the output ports
2157    * needs to be reconfigured, we wait until all output ports are
2158    * reconfigured. Afterwards this port is reconfigured if required
2159    * or buffers are returned to be filled as usual.
2160    */
2161   if (port->port_def.eDir == OMX_DirInput) {
2162     if (comp->pending_reconfigure_outports) {
2163       gst_omx_component_handle_messages (comp);
2164       while (comp->pending_reconfigure_outports &&
2165           (err = comp->last_error) == OMX_ErrorNone && !port->flushing) {
2166         GST_DEBUG_OBJECT (comp->parent,
2167             "Waiting for %s output ports to reconfigure", comp->name);
2168         gst_omx_component_wait_message (comp, GST_CLOCK_TIME_NONE);
2169         gst_omx_component_handle_messages (comp);
2170       }
2171       goto retry;
2172     }
2173
2174     /* Only if this port needs to be reconfigured too notify
2175      * the caller about it */
2176     if (port->settings_cookie != port->configured_settings_cookie) {
2177       GST_DEBUG_OBJECT (comp->parent,
2178           "Component %s port %d needs reconfiguring", comp->name, port->index);
2179       ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
2180       goto done;
2181     }
2182   }
2183
2184   /* If we have an output port that needs to be reconfigured
2185    * and it still has buffers pending for the old configuration
2186    * we first return them.
2187    * NOTE: If buffers for this configuration arrive later
2188    * we have to drop them... */
2189   if (port->port_def.eDir == OMX_DirOutput &&
2190       port->settings_cookie != port->configured_settings_cookie) {
2191     if (!g_queue_is_empty (&port->pending_buffers)) {
2192       GST_DEBUG_OBJECT (comp->parent,
2193           "%s output port %u needs reconfiguration but has buffers pending",
2194           comp->name, port->index);
2195       _buf = g_queue_pop_head (&port->pending_buffers);
2196
2197       ret = GST_OMX_ACQUIRE_BUFFER_OK;
2198       goto done;
2199     }
2200
2201     GST_DEBUG_OBJECT (comp->parent, "Component %s port %d needs reconfiguring",
2202         comp->name, port->index);
2203     ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
2204     goto done;
2205   }
2206
2207   if (port->port_def.eDir == OMX_DirOutput && port->eos) {
2208     if (!g_queue_is_empty (&port->pending_buffers)) {
2209       GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but has "
2210           "%d buffers pending", comp->name, port->index,
2211           g_queue_get_length (&port->pending_buffers));
2212       _buf = g_queue_pop_head (&port->pending_buffers);
2213
2214       ret = GST_OMX_ACQUIRE_BUFFER_OK;
2215       goto done;
2216     }
2217
2218     if (comp->hacks & GST_OMX_HACK_SIGNALS_PREMATURE_EOS && timeout != -2) {
2219       timeout = 33 * GST_MSECOND;
2220
2221       GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but waiting "
2222           "in case it spits out more buffers", comp->name, port->index);
2223     } else {
2224       GST_DEBUG_OBJECT (comp->parent, "Component %s port %d signalled EOS",
2225           comp->name, port->index);
2226       ret = GST_OMX_ACQUIRE_BUFFER_EOS;
2227       port->eos = FALSE;
2228       goto done;
2229     }
2230   }
2231
2232   /*
2233    * At this point we have no error or flushing/eos port
2234    * and a properly configured port.
2235    *
2236    */
2237
2238   /* If the queue is empty we wait until a buffer
2239    * arrives, an error happens, the port is flushing
2240    * or the port needs to be reconfigured.
2241    */
2242   if (g_queue_is_empty (&port->pending_buffers)) {
2243     GST_DEBUG_OBJECT (comp->parent, "Queue of %s port %u is empty",
2244         comp->name, port->index);
2245
2246     if (wait == GST_OMX_WAIT) {
2247       gst_omx_component_wait_message (comp,
2248           timeout == -2 ? GST_CLOCK_TIME_NONE : timeout);
2249
2250       /* And now check everything again and maybe get a buffer */
2251       goto retry;
2252     } else {
2253       ret = GST_OMX_ACQUIRE_BUFFER_NO_AVAILABLE;
2254       goto done;
2255     }
2256   }
2257
2258   GST_DEBUG_OBJECT (comp->parent, "%s port %u has pending buffers",
2259       comp->name, port->index);
2260   _buf = g_queue_pop_head (&port->pending_buffers);
2261   ret = GST_OMX_ACQUIRE_BUFFER_OK;
2262
2263 done:
2264   g_mutex_unlock (&comp->lock);
2265
2266   if (_buf) {
2267     g_assert (_buf == _buf->omx_buf->pAppPrivate);
2268     *buf = _buf;
2269   }
2270
2271   GST_DEBUG_OBJECT (comp->parent, "Acquired buffer %p (%p) from %s port %u: %d",
2272       _buf, (_buf ? _buf->omx_buf->pBuffer : NULL), comp->name, port->index,
2273       ret);
2274
2275   return ret;
2276 }
2277
2278 /* NOTE: Uses comp->lock and comp->messages_lock */
2279 OMX_ERRORTYPE
2280 gst_omx_port_release_buffer (GstOMXPort * port, GstOMXBuffer * buf)
2281 {
2282   GstOMXComponent *comp;
2283   OMX_ERRORTYPE err = OMX_ErrorNone;
2284
2285   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2286   g_return_val_if_fail (!port->tunneled, OMX_ErrorUndefined);
2287   g_return_val_if_fail (buf != NULL, OMX_ErrorUndefined);
2288   g_return_val_if_fail (buf->port == port, OMX_ErrorUndefined);
2289
2290   comp = port->comp;
2291
2292   g_mutex_lock (&comp->lock);
2293
2294   GST_DEBUG_OBJECT (comp->parent, "Releasing buffer %p (%p) to %s port %u",
2295       buf, buf->omx_buf->pBuffer, comp->name, port->index);
2296
2297   gst_omx_component_handle_messages (comp);
2298
2299   if (port->port_def.eDir == OMX_DirOutput) {
2300     /* Reset all flags, some implementations don't
2301      * reset them themselves and the flags are not
2302      * valid anymore after the buffer was consumed
2303      */
2304     gst_omx_buffer_reset (buf);
2305   }
2306
2307   if ((err = comp->last_error) != OMX_ErrorNone) {
2308     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
2309         "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
2310     g_queue_push_tail (&port->pending_buffers, buf);
2311     gst_omx_component_send_message (comp, NULL);
2312     goto done;
2313   }
2314
2315   if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
2316     GST_DEBUG_OBJECT (comp->parent,
2317         "%s port %u is flushing or disabled, not releasing " "buffer",
2318         comp->name, port->index);
2319     g_queue_push_tail (&port->pending_buffers, buf);
2320     gst_omx_component_send_message (comp, NULL);
2321     goto done;
2322   }
2323
2324   g_assert (buf == buf->omx_buf->pAppPrivate);
2325
2326   /* FIXME: What if the settings cookies don't match? */
2327
2328   buf->used = TRUE;
2329
2330   if (port->port_def.eDir == OMX_DirInput) {
2331     log_omx_api_trace_buffer (comp, "EmptyThisBuffer", buf);
2332     err = OMX_EmptyThisBuffer (comp->handle, buf->omx_buf);
2333   } else {
2334     log_omx_api_trace_buffer (comp, "FillThisBuffer", buf);
2335     err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
2336   }
2337   DEBUG_IF_OK (comp->parent, err, "Released buffer %p to %s port %u: %s "
2338       "(0x%08x)", buf, comp->name, port->index, gst_omx_error_to_string (err),
2339       err);
2340
2341 done:
2342   gst_omx_component_handle_messages (comp);
2343   g_mutex_unlock (&comp->lock);
2344
2345   return err;
2346 }
2347
2348 /* NOTE: Must be called while holding comp->lock */
2349 static gboolean
2350 should_wait_until_flushed (GstOMXPort * port)
2351 {
2352   if (!port->flushed)
2353     /* Flush command hasn't been completed yet by OMX */
2354     return TRUE;
2355
2356   if (port->buffers) {
2357     guint i;
2358
2359     /* Wait for all the buffers used by OMX to be released */
2360     for (i = 0; i < port->buffers->len; i++) {
2361       GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
2362
2363       if (buf->used)
2364         return TRUE;
2365     }
2366   }
2367
2368   return FALSE;
2369 }
2370
2371 /* NOTE: Uses comp->lock and comp->messages_lock */
2372 OMX_ERRORTYPE
2373 gst_omx_port_set_flushing (GstOMXPort * port, GstClockTime timeout,
2374     gboolean flush)
2375 {
2376   GstOMXComponent *comp;
2377   OMX_ERRORTYPE err = OMX_ErrorNone;
2378
2379   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2380
2381   comp = port->comp;
2382
2383   g_mutex_lock (&comp->lock);
2384
2385   GST_DEBUG_OBJECT (comp->parent, "Setting %s port %d to %sflushing",
2386       comp->name, port->index, (flush ? "" : "not "));
2387
2388   gst_omx_component_handle_messages (comp);
2389
2390   if (flush == port->flushing) {
2391     GST_DEBUG_OBJECT (comp->parent, "%s port %u was %sflushing already",
2392         comp->name, port->index, (flush ? "" : "not "));
2393     goto done;
2394   }
2395
2396   if ((err = comp->last_error) != OMX_ErrorNone) {
2397     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
2398         "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
2399     goto done;
2400   }
2401
2402   port->flushing = flush;
2403   if (flush) {
2404     gboolean signalled;
2405     OMX_ERRORTYPE last_error;
2406
2407     gst_omx_component_send_message (comp, NULL);
2408
2409     /* Now flush the port */
2410     port->flushed = FALSE;
2411
2412     err =
2413         gst_omx_component_send_command (comp, OMX_CommandFlush, port->index,
2414         NULL);
2415
2416     if (err != OMX_ErrorNone) {
2417       GST_ERROR_OBJECT (comp->parent,
2418           "Error sending flush command to %s port %u: %s (0x%08x)", comp->name,
2419           port->index, gst_omx_error_to_string (err), err);
2420       goto done;
2421     }
2422
2423     if ((err = comp->last_error) != OMX_ErrorNone) {
2424       GST_ERROR_OBJECT (comp->parent,
2425           "Component %s is in error state: %s (0x%08x)", comp->name,
2426           gst_omx_error_to_string (err), err);
2427       goto done;
2428     }
2429
2430     if (port->flushing != flush) {
2431       GST_ERROR_OBJECT (comp->parent, "%s: another flush happened in the "
2432           " meantime", comp->name);
2433       goto done;
2434     }
2435
2436     if (timeout == 0) {
2437       if (should_wait_until_flushed (port))
2438         err = OMX_ErrorTimeout;
2439       goto done;
2440     }
2441
2442     /* Retry until timeout or until an error happend or
2443      * until all buffers were released by the component and
2444      * the flush command completed */
2445     signalled = TRUE;
2446     last_error = OMX_ErrorNone;
2447     gst_omx_component_handle_messages (comp);
2448     while (should_wait_until_flushed (port)) {
2449       signalled = gst_omx_component_wait_message (comp, timeout);
2450       if (signalled)
2451         gst_omx_component_handle_messages (comp);
2452
2453       last_error = comp->last_error;
2454
2455       if (!signalled || last_error != OMX_ErrorNone)
2456         /* Something gone wrong or we timed out */
2457         break;
2458     }
2459     port->flushed = FALSE;
2460
2461     GST_DEBUG_OBJECT (comp->parent, "%s port %d flushed", comp->name,
2462         port->index);
2463     if (last_error != OMX_ErrorNone) {
2464       GST_ERROR_OBJECT (comp->parent,
2465           "Got error while flushing %s port %u: %s (0x%08x)", comp->name,
2466           port->index, gst_omx_error_to_string (last_error), last_error);
2467       err = last_error;
2468       goto done;
2469     } else if (!signalled) {
2470       GST_ERROR_OBJECT (comp->parent, "Timeout while flushing %s port %u",
2471           comp->name, port->index);
2472       err = OMX_ErrorTimeout;
2473       goto done;
2474     }
2475   }
2476
2477   /* Reset EOS flag */
2478   port->eos = FALSE;
2479
2480 done:
2481   gst_omx_port_update_port_definition (port, NULL);
2482
2483   DEBUG_IF_OK (comp->parent, err, "Set %s port %u to %sflushing: %s (0x%08x)",
2484       comp->name, port->index, (flush ? "" : "not "),
2485       gst_omx_error_to_string (err), err);
2486   gst_omx_component_handle_messages (comp);
2487   g_mutex_unlock (&comp->lock);
2488
2489   return err;
2490 }
2491
2492 /* NOTE: Uses comp->lock and comp->messages_lock */
2493 gboolean
2494 gst_omx_port_is_flushing (GstOMXPort * port)
2495 {
2496   GstOMXComponent *comp;
2497   gboolean flushing;
2498
2499   g_return_val_if_fail (port != NULL, FALSE);
2500
2501   comp = port->comp;
2502
2503   g_mutex_lock (&comp->lock);
2504   gst_omx_component_handle_messages (port->comp);
2505   flushing = port->flushing;
2506   g_mutex_unlock (&comp->lock);
2507
2508   GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing: %d", comp->name,
2509       port->index, flushing);
2510
2511   return flushing;
2512 }
2513
2514 static OMX_ERRORTYPE gst_omx_port_deallocate_buffers_unlocked (GstOMXPort *
2515     port);
2516
2517 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2518 static OMX_ERRORTYPE
2519 gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port,
2520     const GList * buffers, const GList * images, guint n)
2521 {
2522   GstOMXComponent *comp;
2523   OMX_ERRORTYPE err = OMX_ErrorNone;
2524   gint i;
2525   const GList *l;
2526
2527   g_assert (!port->buffers || port->buffers->len == 0);
2528
2529   g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
2530
2531   comp = port->comp;
2532
2533   gst_omx_component_handle_messages (port->comp);
2534   if ((err = comp->last_error) != OMX_ErrorNone) {
2535     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2536         comp->name, gst_omx_error_to_string (err), err);
2537     goto done;
2538   }
2539
2540   /* Update the port definition to check if we need more
2541    * buffers after the port configuration was done and to
2542    * update the buffer size
2543    */
2544   gst_omx_port_update_port_definition (port, NULL);
2545
2546   g_return_val_if_fail (n != -1 || (!buffers
2547           && !images), OMX_ErrorBadParameter);
2548
2549   if (n == -1)
2550     n = port->port_def.nBufferCountActual;
2551
2552   g_return_val_if_fail (n == port->port_def.nBufferCountActual,
2553       OMX_ErrorBadParameter);
2554
2555   GST_INFO_OBJECT (comp->parent,
2556       "Allocating %d buffers of size %" G_GSIZE_FORMAT " for %s port %u", n,
2557       (size_t) port->port_def.nBufferSize, comp->name, (guint) port->index);
2558
2559   if (!port->buffers)
2560     port->buffers = g_ptr_array_sized_new (n);
2561
2562   l = (buffers ? buffers : images);
2563   for (i = 0; i < n; i++) {
2564     GstOMXBuffer *buf;
2565
2566     buf = g_slice_new0 (GstOMXBuffer);
2567     buf->port = port;
2568     buf->used = FALSE;
2569     buf->settings_cookie = port->settings_cookie;
2570     g_ptr_array_add (port->buffers, buf);
2571
2572     if (buffers) {
2573       err =
2574           OMX_UseBuffer (comp->handle, &buf->omx_buf, port->index, buf,
2575           port->port_def.nBufferSize, l->data);
2576       buf->eglimage = FALSE;
2577     } else if (images) {
2578       err =
2579           OMX_UseEGLImage (comp->handle, &buf->omx_buf, port->index, buf,
2580           l->data);
2581       buf->eglimage = TRUE;
2582     } else {
2583       err =
2584           OMX_AllocateBuffer (comp->handle, &buf->omx_buf, port->index, buf,
2585           port->port_def.nBufferSize);
2586       buf->eglimage = FALSE;
2587     }
2588
2589     /* Let the caller decide to print an error when OMX_UseBuffer or
2590      * OMX_UseEGLImage fail. Indeed it can be part of a trial path. So
2591      * it is not necessary to warn the user if the fallback path succeeds.
2592      */
2593     if (err != OMX_ErrorNone) {
2594       GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, (buffers
2595               || images) ? GST_LEVEL_INFO : GST_LEVEL_ERROR, comp->parent,
2596           "Failed to allocate buffer for %s port %u: %s (0x%08x)", comp->name,
2597           port->index, gst_omx_error_to_string (err), err);
2598       gst_omx_port_deallocate_buffers_unlocked (port);
2599       goto done;
2600     }
2601
2602     GST_DEBUG_OBJECT (comp->parent, "%s: allocated buffer %p (%p)",
2603         comp->name, buf, buf->omx_buf->pBuffer);
2604
2605     g_assert (buf->omx_buf->pAppPrivate == buf);
2606
2607     /* In the beginning all buffers are not owned by the component */
2608     g_queue_push_tail (&port->pending_buffers, buf);
2609     if (buffers || images)
2610       l = l->next;
2611   }
2612
2613   gst_omx_component_handle_messages (comp);
2614
2615 done:
2616   gst_omx_port_update_port_definition (port, NULL);
2617
2618   INFO_IF_OK (comp->parent, err, "Allocated buffers for %s port %u: %s "
2619       "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2620
2621   return err;
2622 }
2623
2624 /* NOTE: Uses comp->lock and comp->messages_lock */
2625 OMX_ERRORTYPE
2626 gst_omx_port_allocate_buffers (GstOMXPort * port)
2627 {
2628   OMX_ERRORTYPE err;
2629
2630   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2631
2632   g_mutex_lock (&port->comp->lock);
2633   err = gst_omx_port_allocate_buffers_unlocked (port, NULL, NULL, -1);
2634   port->allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2635   g_mutex_unlock (&port->comp->lock);
2636
2637   return err;
2638 }
2639
2640 /* NOTE: Uses comp->lock and comp->messages_lock */
2641 OMX_ERRORTYPE
2642 gst_omx_port_use_buffers (GstOMXPort * port, const GList * buffers)
2643 {
2644   OMX_ERRORTYPE err;
2645   guint n;
2646
2647   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2648
2649   g_mutex_lock (&port->comp->lock);
2650   n = g_list_length ((GList *) buffers);
2651   err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
2652   port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER;
2653   g_mutex_unlock (&port->comp->lock);
2654
2655   return err;
2656 }
2657
2658 gboolean
2659 gst_omx_is_dynamic_allocation_supported (void)
2660 {
2661   /* The Zynqultrascaleplus stack implements OMX 1.1.0 but supports the dynamic
2662    * allocation mode from 1.2.0 as an extension. */
2663 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2664   return TRUE;
2665 #endif
2666
2667 #if OMX_VERSION_MINOR == 2
2668   return TRUE;
2669 #else
2670   return FALSE;
2671 #endif
2672 }
2673
2674 /* OMX 1.2.0 introduced a dynamic allocation mode where only buffer headers are
2675  * being allocated during component's initialization. The actual buffers are
2676  * allocated upstream and passed to OMX by setting the pBuffer dynamically
2677  * for each input buffer.
2678  *
2679  * This function takes care of allocating the buffer headers. Element should
2680  * then use one of the gst_omx_buffer_map_*() method to update buffer's pBuffer
2681  * pointers for each incoming buffer.
2682  *
2683  * NOTE: Uses comp->lock and comp->messages_lock */
2684 OMX_ERRORTYPE
2685 gst_omx_port_use_dynamic_buffers (GstOMXPort * port)
2686 {
2687   OMX_ERRORTYPE err;
2688   GList *buffers = NULL;
2689   guint i, n;
2690
2691   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2692
2693   n = port->port_def.nBufferCountActual;
2694   for (i = 0; i < port->port_def.nBufferCountActual; i++)
2695     /* Pass NULL to UseBuffer() as the buffer is dynamic and so its payload
2696      * will be set each time before being passed to OMX. */
2697     buffers = g_list_prepend (buffers, GUINT_TO_POINTER (NULL));
2698
2699   g_mutex_lock (&port->comp->lock);
2700   err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
2701   port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
2702   g_mutex_unlock (&port->comp->lock);
2703
2704   g_list_free (buffers);
2705
2706   return err;
2707 }
2708
2709 /* gst_omx_buffer_map_* methods are used in dynamic buffer mode to map
2710  * a frame/memory/buffer and update @buffer so its pBuffer points to the
2711  * mapped data. It also ensures that the input will stay alive until
2712  * gst_omx_buffer_unmap() is called.
2713  * This is used in OMX 1.2.0 dynamic allocation mode so an OMX component can
2714  * safely process @buffer's content without having to copy it.
2715  * The input will be automatically unmapped when @buffer is released by OMX.
2716  */
2717 gboolean
2718 gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input,
2719     GstVideoInfo * info)
2720 {
2721   g_return_val_if_fail (buffer != NULL, FALSE);
2722   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2723   g_return_val_if_fail (!buffer->input_mem, FALSE);
2724   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2725   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2726
2727   if (!gst_video_frame_map (&buffer->input_frame, info, input, GST_MAP_READ))
2728     return FALSE;
2729
2730   buffer->input_frame_mapped = TRUE;
2731   buffer->omx_buf->pBuffer =
2732       GST_VIDEO_FRAME_PLANE_DATA (&buffer->input_frame, 0);
2733   buffer->omx_buf->nAllocLen = gst_buffer_get_size (input);
2734   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2735
2736   return TRUE;
2737 }
2738
2739 gboolean
2740 gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
2741 {
2742   g_return_val_if_fail (buffer != NULL, FALSE);
2743   g_return_val_if_fail (mem != NULL, FALSE);
2744   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2745   g_return_val_if_fail (!buffer->input_mem, FALSE);
2746   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2747   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2748
2749   if (!gst_memory_map (mem, &buffer->map, GST_MAP_READ))
2750     return FALSE;
2751
2752   buffer->input_mem = gst_memory_ref (mem);
2753   buffer->omx_buf->pBuffer = buffer->map.data;
2754   buffer->omx_buf->nAllocLen = buffer->map.size;
2755   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2756
2757   return TRUE;
2758 }
2759
2760 gboolean
2761 gst_omx_buffer_import_fd (GstOMXBuffer * buffer, GstBuffer * input)
2762 {
2763   gint fd;
2764   GstMemory *mem;
2765
2766   g_return_val_if_fail (buffer != NULL, FALSE);
2767   g_return_val_if_fail (input != NULL, FALSE);
2768   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2769   g_return_val_if_fail (!buffer->input_mem, FALSE);
2770   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2771   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2772
2773   mem = gst_buffer_peek_memory (input, 0);
2774   g_return_val_if_fail (gst_is_dmabuf_memory (mem), FALSE);
2775
2776   fd = gst_dmabuf_memory_get_fd (mem);
2777
2778   buffer->input_buffer = gst_buffer_ref (input);
2779   buffer->omx_buf->pBuffer = GUINT_TO_POINTER (fd);
2780   buffer->omx_buf->nAllocLen = gst_memory_get_sizes (mem, NULL, NULL);
2781   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2782
2783   return TRUE;
2784 }
2785
2786 gboolean
2787 gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
2788 {
2789   g_return_val_if_fail (buffer != NULL, FALSE);
2790   g_return_val_if_fail (input != NULL, FALSE);
2791   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2792   g_return_val_if_fail (!buffer->input_mem, FALSE);
2793   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2794   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2795
2796   if (!gst_buffer_map (input, &buffer->map, GST_MAP_READ))
2797     return FALSE;
2798
2799   buffer->input_buffer_mapped = TRUE;
2800   buffer->input_buffer = gst_buffer_ref (input);
2801   buffer->omx_buf->pBuffer = buffer->map.data;
2802   buffer->omx_buf->nAllocLen = buffer->map.size;
2803   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2804
2805   return TRUE;
2806 }
2807
2808 /* NOTE: Uses comp->lock and comp->messages_lock */
2809 OMX_ERRORTYPE
2810 gst_omx_port_use_eglimages (GstOMXPort * port, const GList * images)
2811 {
2812   OMX_ERRORTYPE err;
2813   guint n;
2814
2815   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2816
2817   g_mutex_lock (&port->comp->lock);
2818   n = g_list_length ((GList *) images);
2819   err = gst_omx_port_allocate_buffers_unlocked (port, NULL, images, n);
2820   g_mutex_unlock (&port->comp->lock);
2821
2822   return err;
2823 }
2824
2825 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2826 static OMX_ERRORTYPE
2827 gst_omx_port_deallocate_buffers_unlocked (GstOMXPort * port)
2828 {
2829   GstOMXComponent *comp;
2830   OMX_ERRORTYPE err = OMX_ErrorNone;
2831   gint i, n;
2832
2833   g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
2834
2835   comp = port->comp;
2836
2837   GST_INFO_OBJECT (comp->parent, "Deallocating buffers of %s port %u",
2838       comp->name, port->index);
2839
2840   gst_omx_component_handle_messages (port->comp);
2841
2842   if (!port->buffers) {
2843     GST_DEBUG_OBJECT (comp->parent, "No buffers allocated for %s port %u",
2844         comp->name, port->index);
2845     goto done;
2846   }
2847
2848   if ((err = comp->last_error) != OMX_ErrorNone) {
2849     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2850         comp->name, gst_omx_error_to_string (err), err);
2851     /* We still try to deallocate all buffers */
2852   }
2853
2854   /* We only allow deallocation of buffers after they
2855    * were all released from the port, either by flushing
2856    * the port or by disabling it.
2857    */
2858   n = port->buffers->len;
2859   for (i = 0; i < n; i++) {
2860     GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
2861     OMX_ERRORTYPE tmp = OMX_ErrorNone;
2862
2863     if (buf->used) {
2864       GST_ERROR_OBJECT (comp->parent, "Trying to free used buffer %p of %s "
2865           "port %u", buf, comp->name, port->index);
2866     }
2867
2868     /* omx_buf can be NULL if allocation failed earlier
2869      * and we're just shutting down
2870      *
2871      * errors do not cause exiting this loop because we want
2872      * to deallocate as much as possible.
2873      */
2874     if (buf->omx_buf) {
2875       g_assert (buf == buf->omx_buf->pAppPrivate);
2876       buf->omx_buf->pAppPrivate = NULL;
2877       GST_DEBUG_OBJECT (comp->parent, "%s: deallocating buffer %p (%p)",
2878           comp->name, buf, buf->omx_buf->pBuffer);
2879
2880       tmp = OMX_FreeBuffer (comp->handle, port->index, buf->omx_buf);
2881
2882       if (tmp != OMX_ErrorNone) {
2883         GST_ERROR_OBJECT (comp->parent,
2884             "Failed to deallocate buffer %d of %s port %u: %s (0x%08x)", i,
2885             comp->name, port->index, gst_omx_error_to_string (tmp), tmp);
2886         if (err == OMX_ErrorNone)
2887           err = tmp;
2888       }
2889     }
2890     g_slice_free (GstOMXBuffer, buf);
2891   }
2892   g_queue_clear (&port->pending_buffers);
2893   g_ptr_array_unref (port->buffers);
2894   port->buffers = NULL;
2895
2896   gst_omx_component_handle_messages (comp);
2897
2898 done:
2899   gst_omx_port_update_port_definition (port, NULL);
2900
2901   DEBUG_IF_OK (comp->parent, err, "Deallocated buffers of %s port %u: %s "
2902       "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2903
2904   return err;
2905 }
2906
2907 /* NOTE: Uses comp->lock and comp->messages_lock */
2908 OMX_ERRORTYPE
2909 gst_omx_port_deallocate_buffers (GstOMXPort * port)
2910 {
2911   OMX_ERRORTYPE err;
2912
2913   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2914
2915   g_mutex_lock (&port->comp->lock);
2916   err = gst_omx_port_deallocate_buffers_unlocked (port);
2917   g_mutex_unlock (&port->comp->lock);
2918
2919   return err;
2920 }
2921
2922 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2923 static OMX_ERRORTYPE
2924 gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled)
2925 {
2926   GstOMXComponent *comp;
2927   OMX_ERRORTYPE err = OMX_ErrorNone;
2928
2929   comp = port->comp;
2930
2931   gst_omx_component_handle_messages (comp);
2932
2933   if ((err = comp->last_error) != OMX_ErrorNone) {
2934     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2935         comp->name, gst_omx_error_to_string (err), err);
2936     goto done;
2937   }
2938
2939   if (port->enabled_pending || port->disabled_pending) {
2940     GST_ERROR_OBJECT (comp->parent, "%s port %d enabled/disabled pending "
2941         "already", comp->name, port->index);
2942 #if OMX_VERSION_MINOR == 2
2943     err = OMX_ErrorBadParameter;
2944 #else
2945     err = OMX_ErrorInvalidState;
2946 #endif
2947     goto done;
2948   }
2949
2950   GST_INFO_OBJECT (comp->parent, "Setting %s port %u to %s", comp->name,
2951       port->index, (enabled ? "enabled" : "disabled"));
2952
2953   /* Check if the port is already enabled/disabled first */
2954   gst_omx_port_update_port_definition (port, NULL);
2955   if (! !port->port_def.bEnabled == ! !enabled)
2956     goto done;
2957
2958   if (enabled)
2959     port->enabled_pending = TRUE;
2960   else
2961     port->disabled_pending = TRUE;
2962
2963   if (enabled)
2964     err =
2965         gst_omx_component_send_command (comp, OMX_CommandPortEnable,
2966         port->index, NULL);
2967   else
2968     err =
2969         gst_omx_component_send_command (comp, OMX_CommandPortDisable,
2970         port->index, NULL);
2971
2972   if (err != OMX_ErrorNone) {
2973     GST_ERROR_OBJECT (comp->parent,
2974         "Failed to send enable/disable command to %s port %u: %s (0x%08x)",
2975         comp->name, port->index, gst_omx_error_to_string (err), err);
2976     goto done;
2977   }
2978
2979   if ((err = comp->last_error) != OMX_ErrorNone) {
2980     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2981         comp->name, gst_omx_error_to_string (err), err);
2982     goto done;
2983   }
2984
2985 done:
2986   gst_omx_component_handle_messages (comp);
2987
2988   gst_omx_port_update_port_definition (port, NULL);
2989
2990   INFO_IF_OK (comp->parent, err, "Set %s port %u to %s%s: %s (0x%08x)",
2991       comp->name, port->index, (err == OMX_ErrorNone ? "" : "not "),
2992       (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
2993
2994   return err;
2995 }
2996
2997 static OMX_ERRORTYPE
2998 gst_omx_port_wait_buffers_released_unlocked (GstOMXPort * port,
2999     GstClockTime timeout)
3000 {
3001   GstOMXComponent *comp;
3002   OMX_ERRORTYPE err = OMX_ErrorNone;
3003   OMX_ERRORTYPE last_error;
3004   gboolean signalled;
3005
3006   comp = port->comp;
3007
3008   gst_omx_component_handle_messages (comp);
3009
3010   if ((err = comp->last_error) != OMX_ErrorNone) {
3011     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
3012         comp->name, gst_omx_error_to_string (err), err);
3013     goto done;
3014   }
3015
3016   GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to release all "
3017       "buffers", comp->name, port->index);
3018
3019   if (timeout == 0) {
3020     if (!port->flushed || (port->buffers
3021             && port->buffers->len >
3022             g_queue_get_length (&port->pending_buffers)))
3023       err = OMX_ErrorTimeout;
3024     goto done;
3025   }
3026
3027   /* Wait until all buffers are released by the port */
3028   signalled = TRUE;
3029   last_error = OMX_ErrorNone;
3030   gst_omx_component_handle_messages (comp);
3031   while (signalled && last_error == OMX_ErrorNone && (port->buffers
3032           && port->buffers->len >
3033           g_queue_get_length (&port->pending_buffers))) {
3034     signalled = gst_omx_component_wait_message (comp, timeout);
3035     if (signalled)
3036       gst_omx_component_handle_messages (comp);
3037     last_error = comp->last_error;
3038   }
3039
3040   if (last_error != OMX_ErrorNone) {
3041     err = last_error;
3042     GST_ERROR_OBJECT (comp->parent,
3043         "Got error while waiting for %s port %u to release all buffers: %s "
3044         "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err),
3045         err);
3046     goto done;
3047   } else if (!signalled) {
3048     GST_ERROR_OBJECT (comp->parent, "Timeout waiting for %s port %u to "
3049         "release all buffers", comp->name, port->index);
3050     err = OMX_ErrorTimeout;
3051     goto done;
3052   }
3053
3054 done:
3055   gst_omx_component_handle_messages (comp);
3056
3057   gst_omx_port_update_port_definition (port, NULL);
3058
3059   DEBUG_IF_OK (comp->parent, err,
3060       "Waited for %s port %u to release all buffers: %s (0x%08x)", comp->name,
3061       port->index, gst_omx_error_to_string (err), err);
3062
3063   return err;
3064 }
3065
3066 /* NOTE: Uses comp->lock and comp->messages_lock */
3067 OMX_ERRORTYPE
3068 gst_omx_port_wait_buffers_released (GstOMXPort * port, GstClockTime timeout)
3069 {
3070   OMX_ERRORTYPE err;
3071
3072   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3073
3074   g_mutex_lock (&port->comp->lock);
3075   err = gst_omx_port_wait_buffers_released_unlocked (port, timeout);
3076   g_mutex_unlock (&port->comp->lock);
3077
3078   return err;
3079 }
3080
3081 void
3082 gst_omx_port_requeue_buffer (GstOMXPort * port, GstOMXBuffer * buf)
3083 {
3084   g_mutex_lock (&port->comp->lock);
3085   g_queue_push_tail (&port->pending_buffers, buf);
3086   g_mutex_unlock (&port->comp->lock);
3087
3088   /* awake gst_omx_port_acquire_buffer() */
3089   gst_omx_component_send_message (port->comp, NULL);
3090 }
3091
3092 /* NOTE: Uses comp->lock and comp->messages_lock */
3093 OMX_ERRORTYPE
3094 gst_omx_port_set_enabled (GstOMXPort * port, gboolean enabled)
3095 {
3096   OMX_ERRORTYPE err;
3097
3098   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3099
3100   g_mutex_lock (&port->comp->lock);
3101   err = gst_omx_port_set_enabled_unlocked (port, enabled);
3102   g_mutex_unlock (&port->comp->lock);
3103
3104   return err;
3105 }
3106
3107 static OMX_ERRORTYPE
3108 gst_omx_port_populate_unlocked (GstOMXPort * port)
3109 {
3110   GstOMXComponent *comp;
3111   OMX_ERRORTYPE err = OMX_ErrorNone;
3112   GstOMXBuffer *buf;
3113
3114   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3115
3116   comp = port->comp;
3117
3118   GST_DEBUG_OBJECT (comp->parent, "Populating %s port %d", comp->name,
3119       port->index);
3120
3121   gst_omx_component_handle_messages (comp);
3122
3123   if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
3124     GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing or disabled",
3125         comp->name, port->index);
3126     err = OMX_ErrorIncorrectStateOperation;
3127     goto done;
3128   }
3129
3130   if ((err = comp->last_error) != OMX_ErrorNone) {
3131     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s"
3132         "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
3133     goto done;
3134   }
3135
3136   if (port->port_def.eDir == OMX_DirOutput && port->buffers && !port->tunneled) {
3137     /* Enqueue all buffers for the component to fill */
3138     while ((buf = g_queue_pop_head (&port->pending_buffers))) {
3139       g_assert (!buf->used);
3140
3141       /* Reset all flags, some implementations don't
3142        * reset them themselves and the flags are not
3143        * valid anymore after the buffer was consumed.
3144        * Also reset nFilledLen as FillThisBuffer() expects an empty buffer.
3145        */
3146       gst_omx_buffer_reset (buf);
3147
3148       log_omx_api_trace_buffer (comp, "FillThisBuffer", buf);
3149       err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
3150
3151       if (err != OMX_ErrorNone) {
3152         GST_ERROR_OBJECT (comp->parent,
3153             "Failed to pass buffer %p (%p) to %s port %u: %s (0x%08x)", buf,
3154             buf->omx_buf->pBuffer, comp->name, port->index,
3155             gst_omx_error_to_string (err), err);
3156         goto done;
3157       }
3158       GST_DEBUG_OBJECT (comp->parent, "Passed buffer %p (%p) to component %s",
3159           buf, buf->omx_buf->pBuffer, comp->name);
3160     }
3161   }
3162
3163 done:
3164   gst_omx_port_update_port_definition (port, NULL);
3165
3166   DEBUG_IF_OK (comp->parent, err, "Populated %s port %u: %s (0x%08x)",
3167       comp->name, port->index, gst_omx_error_to_string (err), err);
3168   gst_omx_component_handle_messages (comp);
3169
3170   return err;
3171 }
3172
3173 /* NOTE: Uses comp->lock and comp->messages_lock */
3174 OMX_ERRORTYPE
3175 gst_omx_port_populate (GstOMXPort * port)
3176 {
3177   OMX_ERRORTYPE err;
3178
3179   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3180
3181   g_mutex_lock (&port->comp->lock);
3182   err = gst_omx_port_populate_unlocked (port);
3183   g_mutex_unlock (&port->comp->lock);
3184
3185   return err;
3186 }
3187
3188 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
3189 static OMX_ERRORTYPE
3190 gst_omx_port_wait_enabled_unlocked (GstOMXPort * port, GstClockTime timeout)
3191 {
3192   GstOMXComponent *comp;
3193   OMX_ERRORTYPE err = OMX_ErrorNone;
3194   gboolean signalled;
3195   OMX_ERRORTYPE last_error;
3196   gboolean enabled;
3197
3198   comp = port->comp;
3199
3200   /* Check the current port status */
3201   gst_omx_port_update_port_definition (port, NULL);
3202
3203   if (port->enabled_pending)
3204     enabled = TRUE;
3205   else if (port->disabled_pending)
3206     enabled = FALSE;
3207   else
3208     enabled = port->port_def.bEnabled;
3209
3210   gst_omx_component_handle_messages (comp);
3211
3212   if ((err = comp->last_error) != OMX_ErrorNone) {
3213     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
3214         comp->name, gst_omx_error_to_string (err), err);
3215     goto done;
3216   }
3217
3218   GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to be %s",
3219       comp->name, port->index, (enabled ? "enabled" : "disabled"));
3220
3221   if (timeout == 0) {
3222     if (port->enabled_pending || port->disabled_pending)
3223       err = OMX_ErrorTimeout;
3224     goto done;
3225   }
3226
3227   /* And now wait until the enable/disable command is finished */
3228   signalled = TRUE;
3229   last_error = OMX_ErrorNone;
3230   gst_omx_port_update_port_definition (port, NULL);
3231   gst_omx_component_handle_messages (comp);
3232   while (signalled && last_error == OMX_ErrorNone &&
3233       (! !port->port_def.bEnabled != ! !enabled || port->enabled_pending
3234           || port->disabled_pending)) {
3235     signalled = gst_omx_component_wait_message (comp, timeout);
3236     if (signalled)
3237       gst_omx_component_handle_messages (comp);
3238     last_error = comp->last_error;
3239     gst_omx_port_update_port_definition (port, NULL);
3240   }
3241   port->enabled_pending = FALSE;
3242   port->disabled_pending = FALSE;
3243
3244   if (!signalled) {
3245     GST_ERROR_OBJECT (comp->parent,
3246         "Timeout waiting for %s port %u to be %s", comp->name, port->index,
3247         (enabled ? "enabled" : "disabled"));
3248     err = OMX_ErrorTimeout;
3249     goto done;
3250   } else if (last_error != OMX_ErrorNone) {
3251     GST_ERROR_OBJECT (comp->parent,
3252         "Got error while waiting for %s port %u to be %s: %s (0x%08x)",
3253         comp->name, port->index, (enabled ? "enabled" : "disabled"),
3254         gst_omx_error_to_string (err), err);
3255     err = last_error;
3256   } else {
3257     if (enabled) {
3258       /* Reset EOS flag */
3259       port->eos = FALSE;
3260     }
3261   }
3262
3263   gst_omx_component_handle_messages (comp);
3264
3265 done:
3266   gst_omx_port_update_port_definition (port, NULL);
3267
3268   GST_INFO_OBJECT (comp->parent, "%s port %u is %s%s: %s (0x%08x)", comp->name,
3269       port->index, (err == OMX_ErrorNone ? "" : "not "),
3270       (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
3271
3272   return err;
3273 }
3274
3275 /* NOTE: Uses comp->lock and comp->messages_lock */
3276 OMX_ERRORTYPE
3277 gst_omx_port_wait_enabled (GstOMXPort * port, GstClockTime timeout)
3278 {
3279   OMX_ERRORTYPE err;
3280
3281   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3282
3283   g_mutex_lock (&port->comp->lock);
3284   err = gst_omx_port_wait_enabled_unlocked (port, timeout);
3285   g_mutex_unlock (&port->comp->lock);
3286
3287   return err;
3288 }
3289
3290 gboolean
3291 gst_omx_port_is_enabled (GstOMXPort * port)
3292 {
3293   gboolean enabled;
3294
3295   g_return_val_if_fail (port != NULL, FALSE);
3296
3297   gst_omx_port_update_port_definition (port, NULL);
3298   enabled = ! !port->port_def.bEnabled;
3299
3300   GST_DEBUG_OBJECT (port->comp->parent, "%s port %u is enabled: %d",
3301       port->comp->name, port->index, enabled);
3302
3303   return enabled;
3304 }
3305
3306 /* NOTE: Uses comp->lock and comp->messages_lock */
3307 OMX_ERRORTYPE
3308 gst_omx_port_mark_reconfigured (GstOMXPort * port)
3309 {
3310   GstOMXComponent *comp;
3311   OMX_ERRORTYPE err = OMX_ErrorNone;
3312
3313   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3314
3315   comp = port->comp;
3316
3317   g_mutex_lock (&comp->lock);
3318   GST_INFO_OBJECT (comp->parent, "Marking %s port %u is reconfigured",
3319       comp->name, port->index);
3320
3321   gst_omx_component_handle_messages (comp);
3322
3323   if ((err = comp->last_error) != OMX_ErrorNone)
3324     goto done;
3325
3326   port->configured_settings_cookie = port->settings_cookie;
3327
3328   if (port->port_def.eDir == OMX_DirOutput) {
3329     GList *l;
3330
3331     for (l = comp->pending_reconfigure_outports; l; l = l->next) {
3332       if (l->data == (gpointer) port) {
3333         comp->pending_reconfigure_outports =
3334             g_list_delete_link (comp->pending_reconfigure_outports, l);
3335         break;
3336       }
3337     }
3338     if (!comp->pending_reconfigure_outports)
3339       gst_omx_component_send_message (comp, NULL);
3340   }
3341
3342 done:
3343   gst_omx_port_update_port_definition (port, NULL);
3344
3345   INFO_IF_OK (comp->parent, err, "Marked %s port %u as reconfigured: %s "
3346       "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
3347
3348   g_mutex_unlock (&comp->lock);
3349
3350   return err;
3351 }
3352
3353 /* The OMX specs states that the nBufferCountActual of a port has to default
3354  * to its nBufferCountMin. If we don't change nBufferCountActual we purely rely
3355  * on this default. But in some cases, OMX may change nBufferCountMin before we
3356  * allocate buffers. Like for example when configuring the input ports with the
3357  * actual format, it may decrease the number of minimal buffers required.
3358  * This method checks this and update nBufferCountActual if needed so we'll use
3359  * less buffers than the worst case in such scenarios.
3360  */
3361 gboolean
3362 gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port, guint extra)
3363 {
3364   OMX_PARAM_PORTDEFINITIONTYPE port_def;
3365   guint nb;
3366
3367   gst_omx_port_get_port_definition (port, &port_def);
3368
3369   nb = port_def.nBufferCountMin + extra;
3370   if (port_def.nBufferCountActual != nb) {
3371     port_def.nBufferCountActual = nb;
3372
3373     GST_DEBUG_OBJECT (port->comp->parent,
3374         "set port %d nBufferCountActual to %d", (guint) port->index, nb);
3375
3376     if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
3377       return FALSE;
3378   }
3379
3380   return TRUE;
3381 }
3382
3383 gboolean
3384 gst_omx_port_update_buffer_count_actual (GstOMXPort * port, guint nb)
3385 {
3386   OMX_PARAM_PORTDEFINITIONTYPE port_def;
3387
3388   gst_omx_port_get_port_definition (port, &port_def);
3389
3390   if (nb < port_def.nBufferCountMin) {
3391     GST_DEBUG_OBJECT (port->comp->parent,
3392         "Requested to use %d buffers on port %d but it's minimum is %d", nb,
3393         (guint) port->index, (guint) port_def.nBufferCountMin);
3394
3395     nb = port_def.nBufferCountMin;
3396   }
3397
3398   if (port_def.nBufferCountActual != nb) {
3399     port_def.nBufferCountActual = nb;
3400
3401     GST_DEBUG_OBJECT (port->comp->parent,
3402         "set port %d nBufferCountActual to %d", (guint) port->index, nb);
3403
3404     if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
3405       return FALSE;
3406   }
3407
3408   return TRUE;
3409 }
3410
3411 gboolean
3412 gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf)
3413 {
3414 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3415   OMX_ALG_PORT_PARAM_BUFFER_MODE buffer_mode;
3416   OMX_ERRORTYPE err;
3417
3418   GST_OMX_INIT_STRUCT (&buffer_mode);
3419   buffer_mode.nPortIndex = port->index;
3420
3421   if (dmabuf)
3422     buffer_mode.eMode = OMX_ALG_BUF_DMA;
3423   else
3424     buffer_mode.eMode = OMX_ALG_BUF_NORMAL;
3425
3426   err =
3427       gst_omx_component_set_parameter (port->comp,
3428       (OMX_INDEXTYPE) OMX_ALG_IndexPortParamBufferMode, &buffer_mode);
3429   if (err != OMX_ErrorNone) {
3430     GST_WARNING_OBJECT (port->comp->parent,
3431         "Failed to set port %d in %sdmabuf mode: %s (0x%08x)",
3432         port->index, dmabuf ? "" : "non-", gst_omx_error_to_string (err), err);
3433     return FALSE;
3434   }
3435
3436   return TRUE;
3437 #else
3438   /* dmabuf not supported for this platform */
3439   return FALSE;
3440 #endif
3441 }
3442
3443 gboolean
3444 gst_omx_port_set_subframe (GstOMXPort * port, gboolean enabled)
3445 {
3446 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3447   OMX_ALG_VIDEO_PARAM_SUBFRAME subframe_mode;
3448   OMX_ERRORTYPE err;
3449
3450   GST_OMX_INIT_STRUCT (&subframe_mode);
3451   subframe_mode.nPortIndex = port->index;
3452
3453   subframe_mode.bEnableSubframe = enabled;
3454
3455   err = gst_omx_component_set_parameter (port->comp,
3456       (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSubframe, &subframe_mode);
3457   if (err != OMX_ErrorNone) {
3458     GST_WARNING_OBJECT (port->comp->parent,
3459         "Failed to %s subframe mode on port %d: %s (0x%08x)",
3460         enabled ? "enable" : "disable", port->index,
3461         gst_omx_error_to_string (err), err);
3462     return FALSE;
3463   }
3464
3465   return TRUE;
3466 #else
3467   /* subframe mode is not supported on this platform */
3468   return FALSE;
3469 #endif
3470 }
3471
3472 gboolean
3473 gst_omx_port_get_subframe (GstOMXPort * port)
3474 {
3475 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3476   OMX_ALG_VIDEO_PARAM_SUBFRAME subframe_mode;
3477   OMX_ERRORTYPE err;
3478
3479   GST_OMX_INIT_STRUCT (&subframe_mode);
3480   subframe_mode.nPortIndex = port->index;
3481
3482   err = gst_omx_component_get_parameter (port->comp,
3483       (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSubframe, &subframe_mode);
3484   if (err != OMX_ErrorNone) {
3485     GST_WARNING_OBJECT (port->comp->parent,
3486         "Failed to get subframe mode on port %d: %s (0x%08x)",
3487         port->index, gst_omx_error_to_string (err), err);
3488     return FALSE;
3489   }
3490
3491   return subframe_mode.bEnableSubframe;
3492 #else
3493   /* subframe mode is not supported on this platform */
3494   return FALSE;
3495 #endif
3496 }
3497
3498 typedef GType (*GGetTypeFunction) (void);
3499
3500 static const GGetTypeFunction types[] = {
3501   gst_omx_analog_audio_sink_get_type, gst_omx_hdmi_audio_sink_get_type,
3502   gst_omx_mpeg2_video_dec_get_type, gst_omx_mpeg4_video_dec_get_type,
3503   gst_omx_h264_dec_get_type, gst_omx_h263_dec_get_type,
3504   gst_omx_wmv_dec_get_type, gst_omx_mpeg4_video_enc_get_type,
3505   gst_omx_h264_enc_get_type, gst_omx_h263_enc_get_type,
3506   gst_omx_aac_enc_get_type, gst_omx_mjpeg_dec_get_type,
3507   gst_omx_aac_dec_get_type, gst_omx_mp3_dec_get_type,
3508   gst_omx_aac_dec_get_type, gst_omx_mp3_enc_get_type,
3509   gst_omx_amr_dec_get_type
3510 #ifdef HAVE_VP8
3511       , gst_omx_vp8_dec_get_type
3512 #endif
3513 #ifdef HAVE_THEORA
3514       , gst_omx_theora_dec_get_type
3515 #endif
3516 #ifdef HAVE_HEVC
3517       , gst_omx_h265_enc_get_type, gst_omx_h265_dec_get_type
3518 #endif
3519 };
3520
3521 struct TypeOffest
3522 {
3523   GType (*get_type) (void);
3524   glong offset;
3525 };
3526
3527 static const struct TypeOffest base_types[] = {
3528   {gst_omx_audio_sink_get_type, G_STRUCT_OFFSET (GstOMXAudioSinkClass, cdata)},
3529   {gst_omx_video_dec_get_type, G_STRUCT_OFFSET (GstOMXVideoDecClass, cdata)},
3530   {gst_omx_video_enc_get_type, G_STRUCT_OFFSET (GstOMXVideoEncClass, cdata)},
3531   {gst_omx_audio_dec_get_type, G_STRUCT_OFFSET (GstOMXAudioDecClass, cdata)},
3532   {gst_omx_audio_enc_get_type, G_STRUCT_OFFSET (GstOMXAudioEncClass, cdata)},
3533 };
3534
3535 static GKeyFile *config = NULL;
3536 GKeyFile *
3537 gst_omx_get_configuration (void)
3538 {
3539   return config;
3540 }
3541
3542 const gchar *
3543 gst_omx_error_to_string (OMX_ERRORTYPE err)
3544 {
3545   guint err_u = (guint) err;
3546
3547   switch (err_u) {
3548     case OMX_ErrorNone:
3549       return "None";
3550     case OMX_ErrorInsufficientResources:
3551       return "Insufficient resources";
3552     case OMX_ErrorUndefined:
3553       return "Undefined";
3554     case OMX_ErrorInvalidComponentName:
3555       return "Invalid component name";
3556     case OMX_ErrorComponentNotFound:
3557       return "Component not found";
3558     case OMX_ErrorBadParameter:
3559       return "Bad parameter";
3560     case OMX_ErrorNotImplemented:
3561       return "Not implemented";
3562     case OMX_ErrorUnderflow:
3563       return "Underflow";
3564     case OMX_ErrorOverflow:
3565       return "Overflow";
3566     case OMX_ErrorHardware:
3567       return "Hardware";
3568     case OMX_ErrorStreamCorrupt:
3569       return "Stream corrupt";
3570     case OMX_ErrorPortsNotCompatible:
3571       return "Ports not compatible";
3572     case OMX_ErrorResourcesLost:
3573       return "Resources lost";
3574     case OMX_ErrorNoMore:
3575       return "No more";
3576     case OMX_ErrorVersionMismatch:
3577       return "Version mismatch";
3578     case OMX_ErrorNotReady:
3579       return "Not ready";
3580     case OMX_ErrorTimeout:
3581       return "Timeout";
3582     case OMX_ErrorSameState:
3583       return "Same state";
3584     case OMX_ErrorResourcesPreempted:
3585       return "Resources preempted";
3586     case OMX_ErrorIncorrectStateTransition:
3587       return "Incorrect state transition";
3588     case OMX_ErrorIncorrectStateOperation:
3589       return "Incorrect state operation";
3590     case OMX_ErrorUnsupportedSetting:
3591       return "Unsupported setting";
3592     case OMX_ErrorUnsupportedIndex:
3593       return "Unsupported index";
3594     case OMX_ErrorBadPortIndex:
3595       return "Bad port index";
3596     case OMX_ErrorPortUnpopulated:
3597       return "Port unpopulated";
3598     case OMX_ErrorComponentSuspended:
3599       return "Component suspended";
3600     case OMX_ErrorDynamicResourcesUnavailable:
3601       return "Dynamic resources unavailable";
3602     case OMX_ErrorMbErrorsInFrame:
3603       return "Macroblock errors in frame";
3604     case OMX_ErrorFormatNotDetected:
3605       return "Format not detected";
3606     case OMX_ErrorSeperateTablesUsed:
3607       return "Separate tables used";
3608     case OMX_ErrorTunnelingUnsupported:
3609       return "Tunneling unsupported";
3610 #if OMX_VERSION_MINOR == 1
3611     case OMX_ErrorInvalidComponent:
3612       return "Invalid component";
3613     case OMX_ErrorInvalidState:
3614       return "Invalid state";
3615     case OMX_ErrorPortUnresponsiveDuringAllocation:
3616       return "Port unresponsive during allocation";
3617     case OMX_ErrorPortUnresponsiveDuringDeallocation:
3618       return "Port unresponsive during deallocation";
3619     case OMX_ErrorPortUnresponsiveDuringStop:
3620       return "Port unresponsive during stop";
3621     case OMX_ErrorContentPipeOpenFailed:
3622       return "Content pipe open failed";
3623     case OMX_ErrorContentPipeCreationFailed:
3624       return "Content pipe creation failed";
3625 #endif
3626     default:
3627       if (err_u >= (guint) OMX_ErrorKhronosExtensions
3628           && err_u < (guint) OMX_ErrorVendorStartUnused) {
3629         return "Khronos extension error";
3630       } else if (err_u >= (guint) OMX_ErrorVendorStartUnused
3631           && err_u < (guint) OMX_ErrorMax) {
3632         return "Vendor specific error";
3633       } else {
3634         return "Unknown error";
3635       }
3636   }
3637 }
3638
3639 const gchar *
3640 gst_omx_state_to_string (OMX_STATETYPE state)
3641 {
3642   switch (state) {
3643     case OMX_StateInvalid:
3644       return "Invalid";
3645     case OMX_StateLoaded:
3646       return "Loaded";
3647     case OMX_StateIdle:
3648       return "Idle";
3649     case OMX_StateExecuting:
3650       return "Executing";
3651     case OMX_StatePause:
3652       return "Pause";
3653     case OMX_StateWaitForResources:
3654       return "WaitForResources";
3655     default:
3656       if (state >= OMX_StateKhronosExtensions
3657           && state < OMX_StateVendorStartUnused)
3658         return "KhronosExtensionState";
3659       else if (state >= OMX_StateVendorStartUnused && state < OMX_StateMax)
3660         return "CustomVendorState";
3661       break;
3662   }
3663   return "Unknown state";
3664 }
3665
3666 const gchar *
3667 gst_omx_command_to_string (OMX_COMMANDTYPE cmd)
3668 {
3669   switch (cmd) {
3670     case OMX_CommandStateSet:
3671       return "SetState";
3672     case OMX_CommandFlush:
3673       return "Flush";
3674     case OMX_CommandPortDisable:
3675       return "DisablePort";
3676     case OMX_CommandPortEnable:
3677       return "EnablePort";
3678     case OMX_CommandMarkBuffer:
3679       return "MarkBuffer";
3680     default:
3681       if (cmd >= OMX_CommandKhronosExtensions
3682           && cmd < OMX_CommandVendorStartUnused)
3683         return "KhronosExtensionCommand";
3684       if (cmd >= OMX_CommandVendorStartUnused && cmd < OMX_CommandMax)
3685         return "VendorExtensionCommand";
3686       break;
3687   }
3688   return "Unknown command";
3689 }
3690
3691 struct BufferFlagString
3692 {
3693   guint32 flag;
3694   const gchar *str;
3695 };
3696
3697 struct BufferFlagString buffer_flags_map[] = {
3698   {OMX_BUFFERFLAG_EOS, "eos"},
3699   {OMX_BUFFERFLAG_STARTTIME, "start-time"},
3700   {OMX_BUFFERFLAG_DECODEONLY, "decode-only"},
3701   {OMX_BUFFERFLAG_DATACORRUPT, "data-corrupt"},
3702   {OMX_BUFFERFLAG_ENDOFFRAME, "end-of-frame"},
3703   {OMX_BUFFERFLAG_SYNCFRAME, "sync-frame"},
3704   {OMX_BUFFERFLAG_EXTRADATA, "extra-data"},
3705   {OMX_BUFFERFLAG_CODECCONFIG, "codec-config"},
3706   /* Introduced in OMX 1.2.0 */
3707 #ifdef OMX_BUFFERFLAG_TIMESTAMPINVALID
3708   {OMX_BUFFERFLAG_TIMESTAMPINVALID, "timestamp-invalid"},
3709 #endif
3710 #ifdef OMX_BUFFERFLAG_READONLY
3711   {OMX_BUFFERFLAG_READONLY, "read-only"},
3712 #endif
3713 #ifdef OMX_BUFFERFLAG_ENDOFSUBFRAME
3714   {OMX_BUFFERFLAG_ENDOFSUBFRAME, "end-of-subframe"},
3715 #endif
3716 #ifdef OMX_BUFFERFLAG_SKIPFRAME
3717   {OMX_BUFFERFLAG_SKIPFRAME, "skip-frame"},
3718 #endif
3719   {0, NULL},
3720 };
3721
3722
3723 const gchar *
3724 gst_omx_buffer_flags_to_string (guint32 flags)
3725 {
3726   GString *s = NULL;
3727   guint i;
3728   const gchar *str;
3729
3730   if (flags == 0)
3731     return "";
3732
3733   /* Keep a cache of the string representation of the flags so we don't allocate
3734    * and free strings for each buffer. In practice we should only have a handfull
3735    * of flags so the cache won't consume much memory. */
3736   if (!buffer_flags_str) {
3737     G_LOCK (buffer_flags_str);
3738     buffer_flags_str = g_hash_table_new_full (NULL, NULL, NULL, g_free);
3739     G_UNLOCK (buffer_flags_str);
3740   }
3741
3742   str = g_hash_table_lookup (buffer_flags_str, GUINT_TO_POINTER (flags));
3743   if (str)
3744     return str;
3745
3746   for (i = 0; buffer_flags_map[i].str != NULL; i++) {
3747     if ((flags & buffer_flags_map[i].flag) == 0)
3748       continue;
3749
3750     if (!s)
3751       s = g_string_new (buffer_flags_map[i].str);
3752     else
3753       g_string_append_printf (s, ", %s", buffer_flags_map[i].str);
3754   }
3755
3756   if (!s)
3757     return "<unknown>";
3758
3759   str = g_string_free (s, FALSE);
3760
3761   G_LOCK (buffer_flags_str);
3762   /* Transfer ownership of str to hash table */
3763   g_hash_table_insert (buffer_flags_str, GUINT_TO_POINTER (flags),
3764       (gchar *) str);
3765   G_UNLOCK (buffer_flags_str);
3766
3767   return str;
3768 }
3769
3770 #if defined(USE_OMX_TARGET_RPI)
3771 #define DEFAULT_HACKS (GST_OMX_HACK_NO_COMPONENT_ROLE | GST_OMX_HACK_HEIGHT_MULTIPLE_16)
3772 #else
3773 #define DEFAULT_HACKS (0)
3774 #endif
3775
3776 guint64
3777 gst_omx_parse_hacks (gchar ** hacks)
3778 {
3779   guint64 hacks_flags = DEFAULT_HACKS;
3780
3781   if (!hacks)
3782     return 0;
3783
3784   while (*hacks) {
3785     if (g_str_equal (*hacks,
3786             "event-port-settings-changed-ndata-parameter-swap"))
3787       hacks_flags |=
3788           GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_NDATA_PARAMETER_SWAP;
3789     else if (g_str_equal (*hacks, "event-port-settings-changed-port-0-to-1"))
3790       hacks_flags |= GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_PORT_0_TO_1;
3791     else if (g_str_equal (*hacks, "video-framerate-integer"))
3792       hacks_flags |= GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER;
3793     else if (g_str_equal (*hacks, "syncframe-flag-not-used"))
3794       hacks_flags |= GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED;
3795     else if (g_str_equal (*hacks, "no-component-reconfigure"))
3796       hacks_flags |= GST_OMX_HACK_NO_COMPONENT_RECONFIGURE;
3797     else if (g_str_equal (*hacks, "no-empty-eos-buffer"))
3798       hacks_flags |= GST_OMX_HACK_NO_EMPTY_EOS_BUFFER;
3799     else if (g_str_equal (*hacks, "drain-may-not-return"))
3800       hacks_flags |= GST_OMX_HACK_DRAIN_MAY_NOT_RETURN;
3801     else if (g_str_equal (*hacks, "no-component-role"))
3802       hacks_flags |= GST_OMX_HACK_NO_COMPONENT_ROLE;
3803     else if (g_str_equal (*hacks, "no-disable-outport"))
3804       hacks_flags |= GST_OMX_HACK_NO_DISABLE_OUTPORT;
3805     else if (g_str_equal (*hacks, "signals-premature-eos"))
3806       hacks_flags |= GST_OMX_HACK_SIGNALS_PREMATURE_EOS;
3807     else if (g_str_equal (*hacks, "height-multiple-16"))
3808       hacks_flags |= GST_OMX_HACK_HEIGHT_MULTIPLE_16;
3809     else if (g_str_equal (*hacks, "pass-profile-to-decoder"))
3810       hacks_flags |= GST_OMX_HACK_PASS_PROFILE_TO_DECODER;
3811     else if (g_str_equal (*hacks, "pass-color-format-to-decoder"))
3812       hacks_flags |= GST_OMX_HACK_PASS_COLOR_FORMAT_TO_DECODER;
3813     else if (g_str_equal (*hacks, "ensure-buffer-count-actual"))
3814       hacks_flags |= GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL;
3815     else
3816       GST_WARNING ("Unknown hack: %s", *hacks);
3817     hacks++;
3818   }
3819
3820   return hacks_flags;
3821 }
3822
3823
3824 void
3825 gst_omx_set_default_role (GstOMXClassData * class_data,
3826     const gchar * default_role)
3827 {
3828   if (!class_data->component_role)
3829     class_data->component_role = default_role;
3830 }
3831
3832 static void
3833 _class_init (gpointer g_class, gpointer data)
3834 {
3835   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3836   GstOMXClassData *class_data = NULL;
3837   GKeyFile *config;
3838   const gchar *element_name = data;
3839   GError *err;
3840   gchar *core_name, *component_name, *component_role;
3841   gint in_port_index, out_port_index;
3842   gchar *template_caps;
3843   GstPadTemplate *templ;
3844   GstCaps *caps;
3845   gchar **hacks;
3846   int i;
3847
3848   if (!element_name)
3849     return;
3850
3851   /* Find the GstOMXClassData for this class */
3852   for (i = 0; i < G_N_ELEMENTS (base_types); i++) {
3853     GType gtype = base_types[i].get_type ();
3854
3855     if (G_TYPE_CHECK_CLASS_TYPE (g_class, gtype)) {
3856       class_data = (GstOMXClassData *)
3857           (((guint8 *) g_class) + base_types[i].offset);
3858       break;
3859     }
3860   }
3861
3862   g_assert (class_data != NULL);
3863
3864   config = gst_omx_get_configuration ();
3865
3866   /* This will alwaxys succeed, see check in plugin_init */
3867   core_name = g_key_file_get_string (config, element_name, "core-name", NULL);
3868   g_assert (core_name != NULL);
3869   class_data->core_name = core_name;
3870   component_name =
3871       g_key_file_get_string (config, element_name, "component-name", NULL);
3872   g_assert (component_name != NULL);
3873   class_data->component_name = component_name;
3874
3875   /* If this fails we simply don't set a role */
3876   if ((component_role =
3877           g_key_file_get_string (config, element_name, "component-role",
3878               NULL))) {
3879     GST_DEBUG ("Using component-role '%s' for element '%s'", component_role,
3880         element_name);
3881     class_data->component_role = component_role;
3882   }
3883
3884
3885   /* Now set the inport/outport indizes and assume sane defaults */
3886   err = NULL;
3887   in_port_index =
3888       g_key_file_get_integer (config, element_name, "in-port-index", &err);
3889   if (err != NULL) {
3890     GST_DEBUG ("No 'in-port-index' set for element '%s', auto-detecting: %s",
3891         element_name, err->message);
3892     in_port_index = -1;
3893     g_error_free (err);
3894   }
3895   class_data->in_port_index = in_port_index;
3896
3897   err = NULL;
3898   out_port_index =
3899       g_key_file_get_integer (config, element_name, "out-port-index", &err);
3900   if (err != NULL) {
3901     GST_DEBUG ("No 'out-port-index' set for element '%s', auto-detecting: %s",
3902         element_name, err->message);
3903     out_port_index = -1;
3904     g_error_free (err);
3905   }
3906   class_data->out_port_index = out_port_index;
3907
3908   /* Add pad templates */
3909   err = NULL;
3910   if (class_data->type != GST_OMX_COMPONENT_TYPE_SOURCE) {
3911     if (!(template_caps =
3912             g_key_file_get_string (config, element_name, "sink-template-caps",
3913                 &err))) {
3914       GST_DEBUG
3915           ("No sink template caps specified for element '%s', using default '%s'",
3916           element_name, class_data->default_sink_template_caps);
3917       caps = gst_caps_from_string (class_data->default_sink_template_caps);
3918       g_assert (caps != NULL);
3919       g_error_free (err);
3920     } else {
3921       caps = gst_caps_from_string (template_caps);
3922       if (!caps) {
3923         GST_DEBUG
3924             ("Could not parse sink template caps '%s' for element '%s', using default '%s'",
3925             template_caps, element_name,
3926             class_data->default_sink_template_caps);
3927         caps = gst_caps_from_string (class_data->default_sink_template_caps);
3928         g_assert (caps != NULL);
3929       }
3930     }
3931     templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
3932     g_free (template_caps);
3933     gst_element_class_add_pad_template (element_class, templ);
3934     gst_caps_unref (caps);
3935   }
3936
3937   err = NULL;
3938   if (class_data->type != GST_OMX_COMPONENT_TYPE_SINK) {
3939     if (!(template_caps =
3940             g_key_file_get_string (config, element_name, "src-template-caps",
3941                 &err))) {
3942       GST_DEBUG
3943           ("No src template caps specified for element '%s', using default '%s'",
3944           element_name, class_data->default_src_template_caps);
3945       caps = gst_caps_from_string (class_data->default_src_template_caps);
3946       g_assert (caps != NULL);
3947       g_error_free (err);
3948     } else {
3949       caps = gst_caps_from_string (template_caps);
3950       if (!caps) {
3951         GST_DEBUG
3952             ("Could not parse src template caps '%s' for element '%s', using default '%s'",
3953             template_caps, element_name, class_data->default_src_template_caps);
3954         caps = gst_caps_from_string (class_data->default_src_template_caps);
3955         g_assert (caps != NULL);
3956       }
3957     }
3958     templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
3959     g_free (template_caps);
3960     gst_element_class_add_pad_template (element_class, templ);
3961     gst_caps_unref (caps);
3962   }
3963
3964   if ((hacks =
3965           g_key_file_get_string_list (config, element_name, "hacks", NULL,
3966               NULL))) {
3967 #ifndef GST_DISABLE_GST_DEBUG
3968     gchar **walk = hacks;
3969
3970     while (*walk) {
3971       GST_DEBUG ("Using hack: %s", *walk);
3972       walk++;
3973     }
3974 #endif
3975
3976     class_data->hacks = gst_omx_parse_hacks (hacks);
3977     g_strfreev (hacks);
3978   }
3979 }
3980
3981 static gboolean
3982 plugin_init (GstPlugin * plugin)
3983 {
3984   GError *err = NULL;
3985   gchar **config_dirs;
3986   gchar **elements;
3987   gchar *env_config_dir;
3988   const gchar *user_config_dir;
3989   const gchar *const *system_config_dirs;
3990   gint i, j;
3991   gsize n_elements;
3992   static const gchar *config_name[] = { "gstomx.conf", NULL };
3993   static const gchar *env_config_name[] = { "GST_OMX_CONFIG_DIR", NULL };
3994   static const gchar *gst_omx_config_dir = GST_OMX_CONFIG_DIR;
3995
3996   GST_DEBUG_CATEGORY_INIT (gstomx_debug, "omx", 0, "gst-omx");
3997   GST_DEBUG_CATEGORY_INIT (gst_omx_video_debug_category, "omxvideo", 0,
3998       "gst-omx-video");
3999   GST_DEBUG_CATEGORY_INIT (OMX_API_TRACE, "OMX_API_TRACE", 0,
4000       "gst-omx performace");
4001
4002   /* Read configuration file gstomx.conf from the preferred
4003    * configuration directories */
4004   env_config_dir = g_strdup (g_getenv (*env_config_name));
4005   user_config_dir = g_get_user_config_dir ();
4006   system_config_dirs = g_get_system_config_dirs ();
4007   config_dirs =
4008       g_new (gchar *, g_strv_length ((gchar **) system_config_dirs) + 4);
4009
4010   i = 0;
4011   j = 0;
4012   if (env_config_dir)
4013     config_dirs[i++] = (gchar *) env_config_dir;
4014   config_dirs[i++] = (gchar *) user_config_dir;
4015   while (system_config_dirs[j])
4016     config_dirs[i++] = (gchar *) system_config_dirs[j++];
4017   config_dirs[i++] = (gchar *) gst_omx_config_dir;
4018   config_dirs[i++] = NULL;
4019
4020   gst_plugin_add_dependency (plugin, env_config_name,
4021       (const gchar **) (config_dirs + (env_config_dir ? 1 : 0)), config_name,
4022       GST_PLUGIN_DEPENDENCY_FLAG_NONE);
4023
4024   config = g_key_file_new ();
4025   if (!g_key_file_load_from_dirs (config, *config_name,
4026           (const gchar **) config_dirs, NULL, G_KEY_FILE_NONE, &err)) {
4027     gchar *paths;
4028
4029     paths = g_strjoinv (":", config_dirs);
4030     GST_ERROR ("Failed to load configuration file: %s (searched in: %s as per "
4031         "GST_OMX_CONFIG_DIR environment variable, the xdg user config "
4032         "directory (or XDG_CONFIG_HOME) and the system config directory "
4033         "(or XDG_CONFIG_DIRS)", err->message, paths);
4034     g_free (paths);
4035     g_error_free (err);
4036     goto done;
4037   }
4038
4039   /* Initialize all types */
4040   for (i = 0; i < G_N_ELEMENTS (types); i++)
4041     types[i] ();
4042
4043   elements = g_key_file_get_groups (config, &n_elements);
4044   for (i = 0; i < n_elements; i++) {
4045     GTypeQuery type_query;
4046     GTypeInfo type_info = { 0, };
4047     GType type, subtype;
4048     gchar *type_name, *core_name, *component_name;
4049     gint rank;
4050
4051     GST_DEBUG ("Registering element '%s'", elements[i]);
4052
4053     err = NULL;
4054     if (!(type_name =
4055             g_key_file_get_string (config, elements[i], "type-name", &err))) {
4056       GST_ERROR
4057           ("Unable to read 'type-name' configuration for element '%s': %s",
4058           elements[i], err->message);
4059       g_error_free (err);
4060       continue;
4061     }
4062
4063     type = g_type_from_name (type_name);
4064     if (type == G_TYPE_INVALID) {
4065       GST_ERROR ("Invalid type name '%s' for element '%s'", type_name,
4066           elements[i]);
4067       g_free (type_name);
4068       continue;
4069     }
4070     if (!g_type_is_a (type, GST_TYPE_ELEMENT)) {
4071       GST_ERROR ("Type '%s' is no GstElement subtype for element '%s'",
4072           type_name, elements[i]);
4073       g_free (type_name);
4074       continue;
4075     }
4076     g_free (type_name);
4077
4078     /* And now some sanity checking */
4079     err = NULL;
4080     if (!(core_name =
4081             g_key_file_get_string (config, elements[i], "core-name", &err))) {
4082       GST_ERROR
4083           ("Unable to read 'core-name' configuration for element '%s': %s",
4084           elements[i], err->message);
4085       g_error_free (err);
4086       continue;
4087     }
4088     if (!g_file_test (core_name, G_FILE_TEST_IS_REGULAR)) {
4089       GST_ERROR ("Core '%s' does not exist for element '%s'", core_name,
4090           elements[i]);
4091       g_free (core_name);
4092       continue;
4093     }
4094     g_free (core_name);
4095
4096     err = NULL;
4097     if (!(component_name =
4098             g_key_file_get_string (config, elements[i], "component-name",
4099                 &err))) {
4100       GST_ERROR
4101           ("Unable to read 'component-name' configuration for element '%s': %s",
4102           elements[i], err->message);
4103       g_error_free (err);
4104       continue;
4105     }
4106     g_free (component_name);
4107
4108     err = NULL;
4109     rank = g_key_file_get_integer (config, elements[i], "rank", &err);
4110     if (err != NULL) {
4111       GST_ERROR ("No rank set for element '%s': %s", elements[i], err->message);
4112       g_error_free (err);
4113       continue;
4114     }
4115
4116     /* And now register the type, all other configuration will
4117      * be handled by the type itself */
4118     g_type_query (type, &type_query);
4119     memset (&type_info, 0, sizeof (type_info));
4120     type_info.class_size = type_query.class_size;
4121     type_info.instance_size = type_query.instance_size;
4122     type_info.class_init = _class_init;
4123     type_info.class_data = g_strdup (elements[i]);
4124     type_name = g_strdup_printf ("%s-%s", g_type_name (type), elements[i]);
4125     if (g_type_from_name (type_name) != G_TYPE_INVALID) {
4126       GST_ERROR ("Type '%s' already exists for element '%s'", type_name,
4127           elements[i]);
4128       g_free (type_name);
4129       continue;
4130     }
4131     subtype = g_type_register_static (type, type_name, &type_info, 0);
4132     g_free (type_name);
4133     gst_element_register (plugin, elements[i], rank, subtype);
4134   }
4135   g_strfreev (elements);
4136
4137 done:
4138   g_free (env_config_dir);
4139   g_free (config_dirs);
4140
4141   return TRUE;
4142 }
4143
4144 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
4145     GST_VERSION_MINOR,
4146     omx,
4147     "GStreamer OpenMAX Plug-ins",
4148     plugin_init,
4149     PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)