omxvideodec: support interlace-mode=interleaved input
[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_IndexParamVideoInputParsed:
1815       return "OMX_ALG_IndexParamVideoInputParsed";
1816     case OMX_ALG_IndexParamVideoMaxPictureSize:
1817       return "OMX_ALG_IndexParamVideoMaxPictureSize";
1818     case OMX_ALG_IndexParamVideoMaxPictureSizes:
1819       return "OMX_ALG_IndexParamVideoMaxPictureSizes";
1820     case OMX_ALG_IndexConfigVideoLoopFilterBeta:
1821       return "OMX_ALG_IndexConfigVideoLoopFilterBeta";
1822     case OMX_ALG_IndexConfigVideoLoopFilterTc:
1823       return "OMX_ALG_IndexConfigVideoLoopFilterTc";
1824     case OMX_ALG_IndexParamVideoLoopFilterBeta:
1825       return "OMX_ALG_IndexParamVideoLoopFilterBeta";
1826     case OMX_ALG_IndexParamVideoLoopFilterTc:
1827       return "OMX_ALG_IndexParamVideoLoopFilterTc";
1828     case OMX_ALG_IndexPortParamEarlyCallback:
1829       return "OMX_ALG_IndexPortParamEarlyCallback";
1830     case OMX_ALG_IndexParamVideoTransferCharacteristics:
1831       return "OMX_ALG_IndexParamVideoTransferCharacteristics";
1832     case OMX_ALG_IndexParamVideoColorMatrix:
1833       return "OMX_ALG_IndexParamVideoColorMatrix";
1834     case OMX_ALG_IndexConfigVideoTransferCharacteristics:
1835       return "OMX_ALG_IndexConfigVideoTransferCharacteristics";
1836     case OMX_ALG_IndexConfigVideoColorMatrix:
1837       return "OMX_ALG_IndexConfigVideoColorMatrix";
1838     case OMX_ALG_IndexConfigVideoHighDynamicRangeSEI:
1839       return "OMX_ALG_IndexConfigVideoHighDynamicRangeSEI";
1840     case OMX_ALG_IndexConfigVideoMaxResolutionChange:
1841       return "OMX_ALG_IndexConfigVideoMaxResolutionChange";
1842     case OMX_ALG_IndexParamVideoQuantizationTable:
1843       return "OMX_ALG_IndexParamVideoQuantizationTable";
1844     case OMX_ALG_IndexParamVideoAccessUnitDelimiter:
1845       return "OMX_ALG_IndexParamVideoAccessUnitDelimiter";
1846     case OMX_ALG_IndexParamVideoBufferingPeriodSEI:
1847       return "OMX_ALG_IndexParamVideoBufferingPeriodSEI";
1848     case OMX_ALG_IndexParamVideoPictureTimingSEI:
1849       return "OMX_ALG_IndexParamVideoPictureTimingSEI";
1850     case OMX_ALG_IndexParamVideoRecoveryPointSEI:
1851       return "OMX_ALG_IndexParamVideoRecoveryPointSEI";
1852     case OMX_ALG_IndexParamVideoMasteringDisplayColourVolumeSEI:
1853       return "OMX_ALG_IndexParamVideoMasteringDisplayColourVolumeSEI";
1854     case OMX_ALG_IndexParamVideoContentLightLevelSEI:
1855       return "OMX_ALG_IndexParamVideoContentLightLevelSEI";
1856     case OMX_ALG_IndexConfigVideoRegionOfInterestByValue:
1857       return "OMX_ALG_IndexConfigVideoRegionOfInterestByValue";
1858     case OMX_ALG_IndexConfigVideoColorPrimaries:
1859       return "OMX_ALG_IndexConfigVideoColorPrimaries";
1860     case OMX_ALG_IndexMaxEnum:
1861       return "OMX_ALG_IndexMaxEnum";
1862   }
1863 #endif
1864
1865 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1866   /* Not part of the enum in OMX_IndexAlg.h */
1867   if (index == OMX_ALG_IndexParamVideoInterlaceFormatSupported)
1868     return "OMX_ALG_IndexParamVideoInterlaceFormatSupported";
1869 #endif
1870
1871   return NULL;
1872 }
1873 #endif /* GST_DISABLE_GST_DEBUG */
1874
1875 static void
1876 log_omx_api_trace_call (GstOMXComponent * comp, const gchar * function,
1877     OMX_INDEXTYPE index, GstDebugLevel level)
1878 {
1879 #ifndef GST_DISABLE_GST_DEBUG
1880   GstStructure *s;
1881   const gchar *index_name;
1882
1883   /* Don't bother creating useless structs if not needed */
1884   if (gst_debug_category_get_threshold (OMX_API_TRACE) < level)
1885     return;
1886
1887   index_name = omx_index_type_to_str (index);
1888   if (!index_name) {
1889     GST_CAT_WARNING_OBJECT (OMX_API_TRACE, comp->parent,
1890         "unknown call of %s with index 0x%08x", function, index);
1891     return;
1892   }
1893
1894   s = gst_structure_new (function, "index", G_TYPE_STRING, index_name, NULL);
1895   GST_CAT_LEVEL_LOG (OMX_API_TRACE, level, comp->parent, "%" GST_PTR_FORMAT, s);
1896   gst_structure_free (s);
1897 #endif /* GST_DISABLE_GST_DEBUG */
1898 }
1899
1900 /* comp->lock must be unlocked while calling this */
1901 OMX_ERRORTYPE
1902 gst_omx_component_get_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1903     gpointer param)
1904 {
1905   OMX_ERRORTYPE err;
1906
1907   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1908   g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1909
1910   GST_DEBUG_OBJECT (comp->parent, "Getting %s parameter at index 0x%08x",
1911       comp->name, index);
1912   log_omx_api_trace_call (comp, "GetParameter", index, GST_LEVEL_LOG);
1913   err = OMX_GetParameter (comp->handle, index, param);
1914   DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1915       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1916
1917   return err;
1918 }
1919
1920 /* comp->lock must be unlocked while calling this */
1921 OMX_ERRORTYPE
1922 gst_omx_component_set_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1923     gpointer param)
1924 {
1925   OMX_ERRORTYPE err;
1926
1927   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1928   g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1929
1930   GST_DEBUG_OBJECT (comp->parent, "Setting %s parameter at index 0x%08x",
1931       comp->name, index);
1932
1933   log_omx_api_trace_call (comp, "SetParameter", index, GST_LEVEL_DEBUG);
1934   err = OMX_SetParameter (comp->handle, index, param);
1935   DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1936       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1937
1938   return err;
1939 }
1940
1941 /* comp->lock must be unlocked while calling this */
1942 OMX_ERRORTYPE
1943 gst_omx_component_get_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1944     gpointer config)
1945 {
1946   OMX_ERRORTYPE err;
1947
1948   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1949   g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1950
1951   GST_DEBUG_OBJECT (comp->parent, "Getting %s configuration at index 0x%08x",
1952       comp->name, index);
1953   log_omx_api_trace_call (comp, "GetConfig", index, GST_LEVEL_LOG);
1954   err = OMX_GetConfig (comp->handle, index, config);
1955   DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1956       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1957
1958   return err;
1959 }
1960
1961 /* comp->lock must be unlocked while calling this */
1962 OMX_ERRORTYPE
1963 gst_omx_component_set_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1964     gpointer config)
1965 {
1966   OMX_ERRORTYPE err;
1967
1968   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1969   g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1970
1971   GST_DEBUG_OBJECT (comp->parent, "Setting %s configuration at index 0x%08x",
1972       comp->name, index);
1973   log_omx_api_trace_call (comp, "SetConfig", index, GST_LEVEL_DEBUG);
1974   err = OMX_SetConfig (comp->handle, index, config);
1975   DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1976       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1977
1978   return err;
1979 }
1980
1981 OMX_ERRORTYPE
1982 gst_omx_setup_tunnel (GstOMXPort * port1, GstOMXPort * port2)
1983 {
1984   GstOMXComponent *comp1;
1985   GstOMXComponent *comp2;
1986   OMX_ERRORTYPE err;
1987
1988   g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
1989   g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
1990       OMX_ErrorUndefined);
1991   comp1 = port1->comp;
1992
1993   g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
1994   g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
1995       OMX_ErrorUndefined);
1996   comp2 = port2->comp;
1997
1998   g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
1999
2000   g_mutex_lock (&comp1->lock);
2001   g_mutex_lock (&comp2->lock);
2002   GST_DEBUG_OBJECT (comp1->parent,
2003       "Setup tunnel between %s port %u and %s port %u",
2004       comp1->name, port1->index, comp2->name, port2->index);
2005
2006   err = comp1->core->setup_tunnel (comp1->handle, port1->index, comp2->handle,
2007       port2->index);
2008
2009   if (err == OMX_ErrorNone) {
2010     port1->tunneled = TRUE;
2011     port2->tunneled = TRUE;
2012   }
2013
2014   DEBUG_IF_OK (comp1->parent, err,
2015       "Setup tunnel between %s port %u and %s port %u: %s (0x%08x)",
2016       comp1->name, port1->index,
2017       comp2->name, port2->index, gst_omx_error_to_string (err), err);
2018
2019   g_mutex_unlock (&comp2->lock);
2020   g_mutex_unlock (&comp1->lock);
2021
2022   return err;
2023 }
2024
2025 OMX_ERRORTYPE
2026 gst_omx_close_tunnel (GstOMXPort * port1, GstOMXPort * port2)
2027 {
2028   GstOMXComponent *comp1;
2029   GstOMXComponent *comp2;
2030   OMX_ERRORTYPE err;
2031
2032   g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
2033   g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
2034       OMX_ErrorUndefined);
2035   comp1 = port1->comp;
2036
2037   g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
2038   g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
2039       OMX_ErrorUndefined);
2040   comp2 = port2->comp;
2041
2042   g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
2043   g_return_val_if_fail (port1->tunneled && port2->tunneled, OMX_ErrorUndefined);
2044
2045   g_mutex_lock (&comp1->lock);
2046   g_mutex_lock (&comp2->lock);
2047   GST_DEBUG_OBJECT (comp1->parent,
2048       "Closing tunnel between %s port %u and %s port %u",
2049       comp1->name, port1->index, comp2->name, port2->index);
2050
2051   err = comp1->core->setup_tunnel (comp1->handle, port1->index, 0, 0);
2052   if (err != OMX_ErrorNone) {
2053     GST_ERROR_OBJECT (comp1->parent,
2054         "Failed to close tunnel on output side %s (0x%08x)",
2055         gst_omx_error_to_string (err), err);
2056   }
2057   err = comp2->core->setup_tunnel (0, 0, comp2->handle, port2->index);
2058   if (err != OMX_ErrorNone) {
2059     GST_ERROR_OBJECT (comp2->parent,
2060         "Failed to close tunnel on input side %s (0x%08x)",
2061         gst_omx_error_to_string (err), err);
2062   }
2063
2064   port1->tunneled = FALSE;
2065   port2->tunneled = FALSE;
2066
2067   GST_DEBUG_OBJECT (comp1->parent,
2068       "Closed tunnel between %s port %u and %s port %u",
2069       comp1->name, port1->index, comp2->name, port2->index);
2070
2071   g_mutex_unlock (&comp2->lock);
2072   g_mutex_unlock (&comp1->lock);
2073
2074   return err;
2075 }
2076
2077 OMX_ERRORTYPE
2078 gst_omx_port_get_port_definition (GstOMXPort * port,
2079     OMX_PARAM_PORTDEFINITIONTYPE * port_def)
2080 {
2081   GstOMXComponent *comp;
2082   OMX_ERRORTYPE err;
2083
2084   g_return_val_if_fail (port != NULL, OMX_ErrorBadParameter);
2085
2086   comp = port->comp;
2087
2088   GST_OMX_INIT_STRUCT (port_def);
2089   port_def->nPortIndex = port->index;
2090
2091   err = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
2092       port_def);
2093
2094   return err;
2095 }
2096
2097 OMX_ERRORTYPE
2098 gst_omx_port_update_port_definition (GstOMXPort * port,
2099     OMX_PARAM_PORTDEFINITIONTYPE * port_def)
2100 {
2101   OMX_ERRORTYPE err_get, err_set = OMX_ErrorNone;
2102   GstOMXComponent *comp;
2103
2104   g_return_val_if_fail (port != NULL, FALSE);
2105
2106   comp = port->comp;
2107
2108   if (port_def)
2109     err_set =
2110         gst_omx_component_set_parameter (comp, OMX_IndexParamPortDefinition,
2111         port_def);
2112   err_get = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
2113       &port->port_def);
2114
2115   DEBUG_IF_OK (comp->parent, err_set,
2116       "Updated %s port %u definition: %s (0x%08x)", comp->name, port->index,
2117       gst_omx_error_to_string (err_set), err_set);
2118
2119   if (err_set != OMX_ErrorNone)
2120     return err_set;
2121   else
2122     return err_get;
2123 }
2124
2125 /* NOTE: Uses comp->lock and comp->messages_lock */
2126 GstOMXAcquireBufferReturn
2127 gst_omx_port_acquire_buffer (GstOMXPort * port, GstOMXBuffer ** buf,
2128     GstOMXWait wait)
2129 {
2130   GstOMXAcquireBufferReturn ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2131   GstOMXComponent *comp;
2132   OMX_ERRORTYPE err;
2133   GstOMXBuffer *_buf = NULL;
2134   gint64 timeout = GST_CLOCK_TIME_NONE;
2135
2136   g_return_val_if_fail (port != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
2137   g_return_val_if_fail (!port->tunneled, GST_OMX_ACQUIRE_BUFFER_ERROR);
2138   g_return_val_if_fail (buf != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
2139
2140   *buf = NULL;
2141
2142   comp = port->comp;
2143
2144   g_mutex_lock (&comp->lock);
2145   GST_DEBUG_OBJECT (comp->parent, "Acquiring %s buffer from port %u",
2146       comp->name, port->index);
2147
2148 retry:
2149   gst_omx_component_handle_messages (comp);
2150
2151   /* If we are in the case where we waited for a buffer after EOS,
2152    * make sure we don't do that again */
2153   if (timeout != -1)
2154     timeout = -2;
2155
2156   /* Check if the component is in an error state */
2157   if ((err = comp->last_error) != OMX_ErrorNone) {
2158     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s",
2159         comp->name, gst_omx_error_to_string (err));
2160     ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2161     goto done;
2162   }
2163
2164   /* Check if the port is flushing */
2165   if (port->flushing) {
2166     GST_DEBUG_OBJECT (comp->parent, "Component %s port %d is flushing",
2167         comp->name, port->index);
2168     ret = GST_OMX_ACQUIRE_BUFFER_FLUSHING;
2169     goto done;
2170   }
2171
2172   /* If this is an input port and at least one of the output ports
2173    * needs to be reconfigured, we wait until all output ports are
2174    * reconfigured. Afterwards this port is reconfigured if required
2175    * or buffers are returned to be filled as usual.
2176    */
2177   if (port->port_def.eDir == OMX_DirInput) {
2178     if (comp->pending_reconfigure_outports) {
2179       gst_omx_component_handle_messages (comp);
2180       while (comp->pending_reconfigure_outports &&
2181           (err = comp->last_error) == OMX_ErrorNone && !port->flushing) {
2182         GST_DEBUG_OBJECT (comp->parent,
2183             "Waiting for %s output ports to reconfigure", comp->name);
2184         gst_omx_component_wait_message (comp, GST_CLOCK_TIME_NONE);
2185         gst_omx_component_handle_messages (comp);
2186       }
2187       goto retry;
2188     }
2189
2190     /* Only if this port needs to be reconfigured too notify
2191      * the caller about it */
2192     if (port->settings_cookie != port->configured_settings_cookie) {
2193       GST_DEBUG_OBJECT (comp->parent,
2194           "Component %s port %d needs reconfiguring", comp->name, port->index);
2195       ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
2196       goto done;
2197     }
2198   }
2199
2200   /* If we have an output port that needs to be reconfigured
2201    * and it still has buffers pending for the old configuration
2202    * we first return them.
2203    * NOTE: If buffers for this configuration arrive later
2204    * we have to drop them... */
2205   if (port->port_def.eDir == OMX_DirOutput &&
2206       port->settings_cookie != port->configured_settings_cookie) {
2207     if (!g_queue_is_empty (&port->pending_buffers)) {
2208       GST_DEBUG_OBJECT (comp->parent,
2209           "%s output port %u needs reconfiguration but has buffers pending",
2210           comp->name, port->index);
2211       _buf = g_queue_pop_head (&port->pending_buffers);
2212
2213       ret = GST_OMX_ACQUIRE_BUFFER_OK;
2214       goto done;
2215     }
2216
2217     GST_DEBUG_OBJECT (comp->parent, "Component %s port %d needs reconfiguring",
2218         comp->name, port->index);
2219     ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
2220     goto done;
2221   }
2222
2223   if (port->port_def.eDir == OMX_DirOutput && port->eos) {
2224     if (!g_queue_is_empty (&port->pending_buffers)) {
2225       GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but has "
2226           "%d buffers pending", comp->name, port->index,
2227           g_queue_get_length (&port->pending_buffers));
2228       _buf = g_queue_pop_head (&port->pending_buffers);
2229
2230       ret = GST_OMX_ACQUIRE_BUFFER_OK;
2231       goto done;
2232     }
2233
2234     if (comp->hacks & GST_OMX_HACK_SIGNALS_PREMATURE_EOS && timeout != -2) {
2235       timeout = 33 * GST_MSECOND;
2236
2237       GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but waiting "
2238           "in case it spits out more buffers", comp->name, port->index);
2239     } else {
2240       GST_DEBUG_OBJECT (comp->parent, "Component %s port %d signalled EOS",
2241           comp->name, port->index);
2242       ret = GST_OMX_ACQUIRE_BUFFER_EOS;
2243       port->eos = FALSE;
2244       goto done;
2245     }
2246   }
2247
2248   /*
2249    * At this point we have no error or flushing/eos port
2250    * and a properly configured port.
2251    *
2252    */
2253
2254   /* If the queue is empty we wait until a buffer
2255    * arrives, an error happens, the port is flushing
2256    * or the port needs to be reconfigured.
2257    */
2258   if (g_queue_is_empty (&port->pending_buffers)) {
2259     GST_DEBUG_OBJECT (comp->parent, "Queue of %s port %u is empty",
2260         comp->name, port->index);
2261
2262     if (wait == GST_OMX_WAIT) {
2263       gst_omx_component_wait_message (comp,
2264           timeout == -2 ? GST_CLOCK_TIME_NONE : timeout);
2265
2266       /* And now check everything again and maybe get a buffer */
2267       goto retry;
2268     } else {
2269       ret = GST_OMX_ACQUIRE_BUFFER_NO_AVAILABLE;
2270       goto done;
2271     }
2272   }
2273
2274   GST_DEBUG_OBJECT (comp->parent, "%s port %u has pending buffers",
2275       comp->name, port->index);
2276   _buf = g_queue_pop_head (&port->pending_buffers);
2277   ret = GST_OMX_ACQUIRE_BUFFER_OK;
2278
2279 done:
2280   g_mutex_unlock (&comp->lock);
2281
2282   if (_buf) {
2283     g_assert (_buf == _buf->omx_buf->pAppPrivate);
2284     *buf = _buf;
2285   }
2286
2287   GST_DEBUG_OBJECT (comp->parent, "Acquired buffer %p (%p) from %s port %u: %d",
2288       _buf, (_buf ? _buf->omx_buf->pBuffer : NULL), comp->name, port->index,
2289       ret);
2290
2291   return ret;
2292 }
2293
2294 /* NOTE: Uses comp->lock and comp->messages_lock */
2295 OMX_ERRORTYPE
2296 gst_omx_port_release_buffer (GstOMXPort * port, GstOMXBuffer * buf)
2297 {
2298   GstOMXComponent *comp;
2299   OMX_ERRORTYPE err = OMX_ErrorNone;
2300
2301   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2302   g_return_val_if_fail (!port->tunneled, OMX_ErrorUndefined);
2303   g_return_val_if_fail (buf != NULL, OMX_ErrorUndefined);
2304   g_return_val_if_fail (buf->port == port, OMX_ErrorUndefined);
2305
2306   comp = port->comp;
2307
2308   g_mutex_lock (&comp->lock);
2309
2310   GST_DEBUG_OBJECT (comp->parent, "Releasing buffer %p (%p) to %s port %u",
2311       buf, buf->omx_buf->pBuffer, comp->name, port->index);
2312
2313   gst_omx_component_handle_messages (comp);
2314
2315   if (port->port_def.eDir == OMX_DirOutput) {
2316     /* Reset all flags, some implementations don't
2317      * reset them themselves and the flags are not
2318      * valid anymore after the buffer was consumed
2319      */
2320     gst_omx_buffer_reset (buf);
2321   }
2322
2323   if ((err = comp->last_error) != OMX_ErrorNone) {
2324     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
2325         "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
2326     g_queue_push_tail (&port->pending_buffers, buf);
2327     gst_omx_component_send_message (comp, NULL);
2328     goto done;
2329   }
2330
2331   if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
2332     GST_DEBUG_OBJECT (comp->parent,
2333         "%s port %u is flushing or disabled, not releasing " "buffer",
2334         comp->name, port->index);
2335     g_queue_push_tail (&port->pending_buffers, buf);
2336     gst_omx_component_send_message (comp, NULL);
2337     goto done;
2338   }
2339
2340   g_assert (buf == buf->omx_buf->pAppPrivate);
2341
2342   /* FIXME: What if the settings cookies don't match? */
2343
2344   buf->used = TRUE;
2345
2346   if (port->port_def.eDir == OMX_DirInput) {
2347     log_omx_api_trace_buffer (comp, "EmptyThisBuffer", buf);
2348     err = OMX_EmptyThisBuffer (comp->handle, buf->omx_buf);
2349   } else {
2350     log_omx_api_trace_buffer (comp, "FillThisBuffer", buf);
2351     err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
2352   }
2353   DEBUG_IF_OK (comp->parent, err, "Released buffer %p to %s port %u: %s "
2354       "(0x%08x)", buf, comp->name, port->index, gst_omx_error_to_string (err),
2355       err);
2356
2357 done:
2358   gst_omx_component_handle_messages (comp);
2359   g_mutex_unlock (&comp->lock);
2360
2361   return err;
2362 }
2363
2364 /* NOTE: Must be called while holding comp->lock */
2365 static gboolean
2366 should_wait_until_flushed (GstOMXPort * port)
2367 {
2368   if (!port->flushed)
2369     /* Flush command hasn't been completed yet by OMX */
2370     return TRUE;
2371
2372   if (port->buffers) {
2373     guint i;
2374
2375     /* Wait for all the buffers used by OMX to be released */
2376     for (i = 0; i < port->buffers->len; i++) {
2377       GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
2378
2379       if (buf->used)
2380         return TRUE;
2381     }
2382   }
2383
2384   return FALSE;
2385 }
2386
2387 /* NOTE: Uses comp->lock and comp->messages_lock */
2388 OMX_ERRORTYPE
2389 gst_omx_port_set_flushing (GstOMXPort * port, GstClockTime timeout,
2390     gboolean flush)
2391 {
2392   GstOMXComponent *comp;
2393   OMX_ERRORTYPE err = OMX_ErrorNone;
2394
2395   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2396
2397   comp = port->comp;
2398
2399   g_mutex_lock (&comp->lock);
2400
2401   GST_DEBUG_OBJECT (comp->parent, "Setting %s port %d to %sflushing",
2402       comp->name, port->index, (flush ? "" : "not "));
2403
2404   gst_omx_component_handle_messages (comp);
2405
2406   if (flush == port->flushing) {
2407     GST_DEBUG_OBJECT (comp->parent, "%s port %u was %sflushing already",
2408         comp->name, port->index, (flush ? "" : "not "));
2409     goto done;
2410   }
2411
2412   if ((err = comp->last_error) != OMX_ErrorNone) {
2413     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
2414         "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
2415     goto done;
2416   }
2417
2418   port->flushing = flush;
2419   if (flush) {
2420     gboolean signalled;
2421     OMX_ERRORTYPE last_error;
2422
2423     gst_omx_component_send_message (comp, NULL);
2424
2425     /* Now flush the port */
2426     port->flushed = FALSE;
2427
2428     err =
2429         gst_omx_component_send_command (comp, OMX_CommandFlush, port->index,
2430         NULL);
2431
2432     if (err != OMX_ErrorNone) {
2433       GST_ERROR_OBJECT (comp->parent,
2434           "Error sending flush command to %s port %u: %s (0x%08x)", comp->name,
2435           port->index, gst_omx_error_to_string (err), err);
2436       goto done;
2437     }
2438
2439     if ((err = comp->last_error) != OMX_ErrorNone) {
2440       GST_ERROR_OBJECT (comp->parent,
2441           "Component %s is in error state: %s (0x%08x)", comp->name,
2442           gst_omx_error_to_string (err), err);
2443       goto done;
2444     }
2445
2446     if (port->flushing != flush) {
2447       GST_ERROR_OBJECT (comp->parent, "%s: another flush happened in the "
2448           " meantime", comp->name);
2449       goto done;
2450     }
2451
2452     if (timeout == 0) {
2453       if (should_wait_until_flushed (port))
2454         err = OMX_ErrorTimeout;
2455       goto done;
2456     }
2457
2458     /* Retry until timeout or until an error happend or
2459      * until all buffers were released by the component and
2460      * the flush command completed */
2461     signalled = TRUE;
2462     last_error = OMX_ErrorNone;
2463     gst_omx_component_handle_messages (comp);
2464     while (should_wait_until_flushed (port)) {
2465       signalled = gst_omx_component_wait_message (comp, timeout);
2466       if (signalled)
2467         gst_omx_component_handle_messages (comp);
2468
2469       last_error = comp->last_error;
2470
2471       if (!signalled || last_error != OMX_ErrorNone)
2472         /* Something gone wrong or we timed out */
2473         break;
2474     }
2475     port->flushed = FALSE;
2476
2477     GST_DEBUG_OBJECT (comp->parent, "%s port %d flushed", comp->name,
2478         port->index);
2479     if (last_error != OMX_ErrorNone) {
2480       GST_ERROR_OBJECT (comp->parent,
2481           "Got error while flushing %s port %u: %s (0x%08x)", comp->name,
2482           port->index, gst_omx_error_to_string (last_error), last_error);
2483       err = last_error;
2484       goto done;
2485     } else if (!signalled) {
2486       GST_ERROR_OBJECT (comp->parent, "Timeout while flushing %s port %u",
2487           comp->name, port->index);
2488       err = OMX_ErrorTimeout;
2489       goto done;
2490     }
2491   }
2492
2493   /* Reset EOS flag */
2494   port->eos = FALSE;
2495
2496 done:
2497   gst_omx_port_update_port_definition (port, NULL);
2498
2499   DEBUG_IF_OK (comp->parent, err, "Set %s port %u to %sflushing: %s (0x%08x)",
2500       comp->name, port->index, (flush ? "" : "not "),
2501       gst_omx_error_to_string (err), err);
2502   gst_omx_component_handle_messages (comp);
2503   g_mutex_unlock (&comp->lock);
2504
2505   return err;
2506 }
2507
2508 /* NOTE: Uses comp->lock and comp->messages_lock */
2509 gboolean
2510 gst_omx_port_is_flushing (GstOMXPort * port)
2511 {
2512   GstOMXComponent *comp;
2513   gboolean flushing;
2514
2515   g_return_val_if_fail (port != NULL, FALSE);
2516
2517   comp = port->comp;
2518
2519   g_mutex_lock (&comp->lock);
2520   gst_omx_component_handle_messages (port->comp);
2521   flushing = port->flushing;
2522   g_mutex_unlock (&comp->lock);
2523
2524   GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing: %d", comp->name,
2525       port->index, flushing);
2526
2527   return flushing;
2528 }
2529
2530 static OMX_ERRORTYPE gst_omx_port_deallocate_buffers_unlocked (GstOMXPort *
2531     port);
2532
2533 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2534 static OMX_ERRORTYPE
2535 gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port,
2536     const GList * buffers, const GList * images, guint n)
2537 {
2538   GstOMXComponent *comp;
2539   OMX_ERRORTYPE err = OMX_ErrorNone;
2540   gint i;
2541   const GList *l;
2542
2543   g_assert (!port->buffers || port->buffers->len == 0);
2544
2545   g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
2546
2547   comp = port->comp;
2548
2549   gst_omx_component_handle_messages (port->comp);
2550   if ((err = comp->last_error) != OMX_ErrorNone) {
2551     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2552         comp->name, gst_omx_error_to_string (err), err);
2553     goto done;
2554   }
2555
2556   /* Update the port definition to check if we need more
2557    * buffers after the port configuration was done and to
2558    * update the buffer size
2559    */
2560   gst_omx_port_update_port_definition (port, NULL);
2561
2562   g_return_val_if_fail (n != -1 || (!buffers
2563           && !images), OMX_ErrorBadParameter);
2564
2565   if (n == -1)
2566     n = port->port_def.nBufferCountActual;
2567
2568   g_return_val_if_fail (n == port->port_def.nBufferCountActual,
2569       OMX_ErrorBadParameter);
2570
2571   GST_INFO_OBJECT (comp->parent,
2572       "Allocating %d buffers of size %" G_GSIZE_FORMAT " for %s port %u", n,
2573       (size_t) port->port_def.nBufferSize, comp->name, (guint) port->index);
2574
2575   if (!port->buffers)
2576     port->buffers = g_ptr_array_sized_new (n);
2577
2578   l = (buffers ? buffers : images);
2579   for (i = 0; i < n; i++) {
2580     GstOMXBuffer *buf;
2581
2582     buf = g_slice_new0 (GstOMXBuffer);
2583     buf->port = port;
2584     buf->used = FALSE;
2585     buf->settings_cookie = port->settings_cookie;
2586     g_ptr_array_add (port->buffers, buf);
2587
2588     if (buffers) {
2589       err =
2590           OMX_UseBuffer (comp->handle, &buf->omx_buf, port->index, buf,
2591           port->port_def.nBufferSize, l->data);
2592       buf->eglimage = FALSE;
2593     } else if (images) {
2594       err =
2595           OMX_UseEGLImage (comp->handle, &buf->omx_buf, port->index, buf,
2596           l->data);
2597       buf->eglimage = TRUE;
2598     } else {
2599       err =
2600           OMX_AllocateBuffer (comp->handle, &buf->omx_buf, port->index, buf,
2601           port->port_def.nBufferSize);
2602       buf->eglimage = FALSE;
2603     }
2604
2605     /* Let the caller decide to print an error when OMX_UseBuffer or
2606      * OMX_UseEGLImage fail. Indeed it can be part of a trial path. So
2607      * it is not necessary to warn the user if the fallback path succeeds.
2608      */
2609     if (err != OMX_ErrorNone) {
2610       GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, (buffers
2611               || images) ? GST_LEVEL_INFO : GST_LEVEL_ERROR, comp->parent,
2612           "Failed to allocate buffer for %s port %u: %s (0x%08x)", comp->name,
2613           port->index, gst_omx_error_to_string (err), err);
2614       gst_omx_port_deallocate_buffers_unlocked (port);
2615       goto done;
2616     }
2617
2618     GST_DEBUG_OBJECT (comp->parent, "%s: allocated buffer %p (%p)",
2619         comp->name, buf, buf->omx_buf->pBuffer);
2620
2621     g_assert (buf->omx_buf->pAppPrivate == buf);
2622
2623     /* In the beginning all buffers are not owned by the component */
2624     g_queue_push_tail (&port->pending_buffers, buf);
2625     if (buffers || images)
2626       l = l->next;
2627   }
2628
2629   gst_omx_component_handle_messages (comp);
2630
2631 done:
2632   gst_omx_port_update_port_definition (port, NULL);
2633
2634   INFO_IF_OK (comp->parent, err, "Allocated buffers for %s port %u: %s "
2635       "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2636
2637   return err;
2638 }
2639
2640 /* NOTE: Uses comp->lock and comp->messages_lock */
2641 OMX_ERRORTYPE
2642 gst_omx_port_allocate_buffers (GstOMXPort * port)
2643 {
2644   OMX_ERRORTYPE err;
2645
2646   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2647
2648   g_mutex_lock (&port->comp->lock);
2649   err = gst_omx_port_allocate_buffers_unlocked (port, NULL, NULL, -1);
2650   port->allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2651   g_mutex_unlock (&port->comp->lock);
2652
2653   return err;
2654 }
2655
2656 /* NOTE: Uses comp->lock and comp->messages_lock */
2657 OMX_ERRORTYPE
2658 gst_omx_port_use_buffers (GstOMXPort * port, const GList * buffers)
2659 {
2660   OMX_ERRORTYPE err;
2661   guint n;
2662
2663   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2664
2665   g_mutex_lock (&port->comp->lock);
2666   n = g_list_length ((GList *) buffers);
2667   err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
2668   port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER;
2669   g_mutex_unlock (&port->comp->lock);
2670
2671   return err;
2672 }
2673
2674 gboolean
2675 gst_omx_is_dynamic_allocation_supported (void)
2676 {
2677   /* The Zynqultrascaleplus stack implements OMX 1.1.0 but supports the dynamic
2678    * allocation mode from 1.2.0 as an extension. */
2679 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2680   return TRUE;
2681 #endif
2682
2683 #if OMX_VERSION_MINOR == 2
2684   return TRUE;
2685 #else
2686   return FALSE;
2687 #endif
2688 }
2689
2690 /* OMX 1.2.0 introduced a dynamic allocation mode where only buffer headers are
2691  * being allocated during component's initialization. The actual buffers are
2692  * allocated upstream and passed to OMX by setting the pBuffer dynamically
2693  * for each input buffer.
2694  *
2695  * This function takes care of allocating the buffer headers. Element should
2696  * then use one of the gst_omx_buffer_map_*() method to update buffer's pBuffer
2697  * pointers for each incoming buffer.
2698  *
2699  * NOTE: Uses comp->lock and comp->messages_lock */
2700 OMX_ERRORTYPE
2701 gst_omx_port_use_dynamic_buffers (GstOMXPort * port)
2702 {
2703   OMX_ERRORTYPE err;
2704   GList *buffers = NULL;
2705   guint i, n;
2706
2707   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2708
2709   n = port->port_def.nBufferCountActual;
2710   for (i = 0; i < port->port_def.nBufferCountActual; i++)
2711     /* Pass NULL to UseBuffer() as the buffer is dynamic and so its payload
2712      * will be set each time before being passed to OMX. */
2713     buffers = g_list_prepend (buffers, GUINT_TO_POINTER (NULL));
2714
2715   g_mutex_lock (&port->comp->lock);
2716   err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
2717   port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
2718   g_mutex_unlock (&port->comp->lock);
2719
2720   g_list_free (buffers);
2721
2722   return err;
2723 }
2724
2725 /* gst_omx_buffer_map_* methods are used in dynamic buffer mode to map
2726  * a frame/memory/buffer and update @buffer so its pBuffer points to the
2727  * mapped data. It also ensures that the input will stay alive until
2728  * gst_omx_buffer_unmap() is called.
2729  * This is used in OMX 1.2.0 dynamic allocation mode so an OMX component can
2730  * safely process @buffer's content without having to copy it.
2731  * The input will be automatically unmapped when @buffer is released by OMX.
2732  */
2733 gboolean
2734 gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input,
2735     GstVideoInfo * info)
2736 {
2737   g_return_val_if_fail (buffer != NULL, FALSE);
2738   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2739   g_return_val_if_fail (!buffer->input_mem, FALSE);
2740   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2741   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2742
2743   if (!gst_video_frame_map (&buffer->input_frame, info, input, GST_MAP_READ))
2744     return FALSE;
2745
2746   buffer->input_frame_mapped = TRUE;
2747   buffer->omx_buf->pBuffer =
2748       GST_VIDEO_FRAME_PLANE_DATA (&buffer->input_frame, 0);
2749   buffer->omx_buf->nAllocLen = gst_buffer_get_size (input);
2750   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2751
2752   return TRUE;
2753 }
2754
2755 gboolean
2756 gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
2757 {
2758   g_return_val_if_fail (buffer != NULL, FALSE);
2759   g_return_val_if_fail (mem != NULL, FALSE);
2760   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2761   g_return_val_if_fail (!buffer->input_mem, FALSE);
2762   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2763   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2764
2765   if (!gst_memory_map (mem, &buffer->map, GST_MAP_READ))
2766     return FALSE;
2767
2768   buffer->input_mem = gst_memory_ref (mem);
2769   buffer->omx_buf->pBuffer = buffer->map.data;
2770   buffer->omx_buf->nAllocLen = buffer->map.size;
2771   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2772
2773   return TRUE;
2774 }
2775
2776 gboolean
2777 gst_omx_buffer_import_fd (GstOMXBuffer * buffer, GstBuffer * input)
2778 {
2779   gint fd;
2780   GstMemory *mem;
2781
2782   g_return_val_if_fail (buffer != NULL, FALSE);
2783   g_return_val_if_fail (input != NULL, FALSE);
2784   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2785   g_return_val_if_fail (!buffer->input_mem, FALSE);
2786   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2787   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2788
2789   mem = gst_buffer_peek_memory (input, 0);
2790   g_return_val_if_fail (gst_is_dmabuf_memory (mem), FALSE);
2791
2792   fd = gst_dmabuf_memory_get_fd (mem);
2793
2794   buffer->input_buffer = gst_buffer_ref (input);
2795   buffer->omx_buf->pBuffer = GUINT_TO_POINTER (fd);
2796   buffer->omx_buf->nAllocLen = gst_memory_get_sizes (mem, NULL, NULL);
2797   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2798
2799   return TRUE;
2800 }
2801
2802 gboolean
2803 gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
2804 {
2805   g_return_val_if_fail (buffer != NULL, FALSE);
2806   g_return_val_if_fail (input != NULL, FALSE);
2807   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2808   g_return_val_if_fail (!buffer->input_mem, FALSE);
2809   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2810   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2811
2812   if (!gst_buffer_map (input, &buffer->map, GST_MAP_READ))
2813     return FALSE;
2814
2815   buffer->input_buffer_mapped = TRUE;
2816   buffer->input_buffer = gst_buffer_ref (input);
2817   buffer->omx_buf->pBuffer = buffer->map.data;
2818   buffer->omx_buf->nAllocLen = buffer->map.size;
2819   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2820
2821   return TRUE;
2822 }
2823
2824 /* NOTE: Uses comp->lock and comp->messages_lock */
2825 OMX_ERRORTYPE
2826 gst_omx_port_use_eglimages (GstOMXPort * port, const GList * images)
2827 {
2828   OMX_ERRORTYPE err;
2829   guint n;
2830
2831   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2832
2833   g_mutex_lock (&port->comp->lock);
2834   n = g_list_length ((GList *) images);
2835   err = gst_omx_port_allocate_buffers_unlocked (port, NULL, images, n);
2836   g_mutex_unlock (&port->comp->lock);
2837
2838   return err;
2839 }
2840
2841 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2842 static OMX_ERRORTYPE
2843 gst_omx_port_deallocate_buffers_unlocked (GstOMXPort * port)
2844 {
2845   GstOMXComponent *comp;
2846   OMX_ERRORTYPE err = OMX_ErrorNone;
2847   gint i, n;
2848
2849   g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
2850
2851   comp = port->comp;
2852
2853   GST_INFO_OBJECT (comp->parent, "Deallocating buffers of %s port %u",
2854       comp->name, port->index);
2855
2856   gst_omx_component_handle_messages (port->comp);
2857
2858   if (!port->buffers) {
2859     GST_DEBUG_OBJECT (comp->parent, "No buffers allocated for %s port %u",
2860         comp->name, port->index);
2861     goto done;
2862   }
2863
2864   if ((err = comp->last_error) != OMX_ErrorNone) {
2865     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2866         comp->name, gst_omx_error_to_string (err), err);
2867     /* We still try to deallocate all buffers */
2868   }
2869
2870   /* We only allow deallocation of buffers after they
2871    * were all released from the port, either by flushing
2872    * the port or by disabling it.
2873    */
2874   n = port->buffers->len;
2875   for (i = 0; i < n; i++) {
2876     GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
2877     OMX_ERRORTYPE tmp = OMX_ErrorNone;
2878
2879     if (buf->used) {
2880       GST_ERROR_OBJECT (comp->parent, "Trying to free used buffer %p of %s "
2881           "port %u", buf, comp->name, port->index);
2882     }
2883
2884     /* omx_buf can be NULL if allocation failed earlier
2885      * and we're just shutting down
2886      *
2887      * errors do not cause exiting this loop because we want
2888      * to deallocate as much as possible.
2889      */
2890     if (buf->omx_buf) {
2891       g_assert (buf == buf->omx_buf->pAppPrivate);
2892       buf->omx_buf->pAppPrivate = NULL;
2893       GST_DEBUG_OBJECT (comp->parent, "%s: deallocating buffer %p (%p)",
2894           comp->name, buf, buf->omx_buf->pBuffer);
2895
2896       tmp = OMX_FreeBuffer (comp->handle, port->index, buf->omx_buf);
2897
2898       if (tmp != OMX_ErrorNone) {
2899         GST_ERROR_OBJECT (comp->parent,
2900             "Failed to deallocate buffer %d of %s port %u: %s (0x%08x)", i,
2901             comp->name, port->index, gst_omx_error_to_string (tmp), tmp);
2902         if (err == OMX_ErrorNone)
2903           err = tmp;
2904       }
2905     }
2906     g_slice_free (GstOMXBuffer, buf);
2907   }
2908   g_queue_clear (&port->pending_buffers);
2909   g_ptr_array_unref (port->buffers);
2910   port->buffers = NULL;
2911
2912   gst_omx_component_handle_messages (comp);
2913
2914 done:
2915   gst_omx_port_update_port_definition (port, NULL);
2916
2917   DEBUG_IF_OK (comp->parent, err, "Deallocated buffers of %s port %u: %s "
2918       "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2919
2920   return err;
2921 }
2922
2923 /* NOTE: Uses comp->lock and comp->messages_lock */
2924 OMX_ERRORTYPE
2925 gst_omx_port_deallocate_buffers (GstOMXPort * port)
2926 {
2927   OMX_ERRORTYPE err;
2928
2929   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2930
2931   g_mutex_lock (&port->comp->lock);
2932   err = gst_omx_port_deallocate_buffers_unlocked (port);
2933   g_mutex_unlock (&port->comp->lock);
2934
2935   return err;
2936 }
2937
2938 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2939 static OMX_ERRORTYPE
2940 gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled)
2941 {
2942   GstOMXComponent *comp;
2943   OMX_ERRORTYPE err = OMX_ErrorNone;
2944
2945   comp = port->comp;
2946
2947   gst_omx_component_handle_messages (comp);
2948
2949   if ((err = comp->last_error) != OMX_ErrorNone) {
2950     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2951         comp->name, gst_omx_error_to_string (err), err);
2952     goto done;
2953   }
2954
2955   if (port->enabled_pending || port->disabled_pending) {
2956     GST_ERROR_OBJECT (comp->parent, "%s port %d enabled/disabled pending "
2957         "already", comp->name, port->index);
2958 #if OMX_VERSION_MINOR == 2
2959     err = OMX_ErrorBadParameter;
2960 #else
2961     err = OMX_ErrorInvalidState;
2962 #endif
2963     goto done;
2964   }
2965
2966   GST_INFO_OBJECT (comp->parent, "Setting %s port %u to %s", comp->name,
2967       port->index, (enabled ? "enabled" : "disabled"));
2968
2969   /* Check if the port is already enabled/disabled first */
2970   gst_omx_port_update_port_definition (port, NULL);
2971   if (! !port->port_def.bEnabled == ! !enabled)
2972     goto done;
2973
2974   if (enabled)
2975     port->enabled_pending = TRUE;
2976   else
2977     port->disabled_pending = TRUE;
2978
2979   if (enabled)
2980     err =
2981         gst_omx_component_send_command (comp, OMX_CommandPortEnable,
2982         port->index, NULL);
2983   else
2984     err =
2985         gst_omx_component_send_command (comp, OMX_CommandPortDisable,
2986         port->index, NULL);
2987
2988   if (err != OMX_ErrorNone) {
2989     GST_ERROR_OBJECT (comp->parent,
2990         "Failed to send enable/disable command to %s port %u: %s (0x%08x)",
2991         comp->name, port->index, gst_omx_error_to_string (err), err);
2992     goto done;
2993   }
2994
2995   if ((err = comp->last_error) != OMX_ErrorNone) {
2996     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2997         comp->name, gst_omx_error_to_string (err), err);
2998     goto done;
2999   }
3000
3001 done:
3002   gst_omx_component_handle_messages (comp);
3003
3004   gst_omx_port_update_port_definition (port, NULL);
3005
3006   INFO_IF_OK (comp->parent, err, "Set %s port %u to %s%s: %s (0x%08x)",
3007       comp->name, port->index, (err == OMX_ErrorNone ? "" : "not "),
3008       (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
3009
3010   return err;
3011 }
3012
3013 static OMX_ERRORTYPE
3014 gst_omx_port_wait_buffers_released_unlocked (GstOMXPort * port,
3015     GstClockTime timeout)
3016 {
3017   GstOMXComponent *comp;
3018   OMX_ERRORTYPE err = OMX_ErrorNone;
3019   OMX_ERRORTYPE last_error;
3020   gboolean signalled;
3021
3022   comp = port->comp;
3023
3024   gst_omx_component_handle_messages (comp);
3025
3026   if ((err = comp->last_error) != OMX_ErrorNone) {
3027     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
3028         comp->name, gst_omx_error_to_string (err), err);
3029     goto done;
3030   }
3031
3032   GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to release all "
3033       "buffers", comp->name, port->index);
3034
3035   if (timeout == 0) {
3036     if (!port->flushed || (port->buffers
3037             && port->buffers->len >
3038             g_queue_get_length (&port->pending_buffers)))
3039       err = OMX_ErrorTimeout;
3040     goto done;
3041   }
3042
3043   /* Wait until all buffers are released by the port */
3044   signalled = TRUE;
3045   last_error = OMX_ErrorNone;
3046   gst_omx_component_handle_messages (comp);
3047   while (signalled && last_error == OMX_ErrorNone && (port->buffers
3048           && port->buffers->len >
3049           g_queue_get_length (&port->pending_buffers))) {
3050     signalled = gst_omx_component_wait_message (comp, timeout);
3051     if (signalled)
3052       gst_omx_component_handle_messages (comp);
3053     last_error = comp->last_error;
3054   }
3055
3056   if (last_error != OMX_ErrorNone) {
3057     err = last_error;
3058     GST_ERROR_OBJECT (comp->parent,
3059         "Got error while waiting for %s port %u to release all buffers: %s "
3060         "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err),
3061         err);
3062     goto done;
3063   } else if (!signalled) {
3064     GST_ERROR_OBJECT (comp->parent, "Timeout waiting for %s port %u to "
3065         "release all buffers", comp->name, port->index);
3066     err = OMX_ErrorTimeout;
3067     goto done;
3068   }
3069
3070 done:
3071   gst_omx_component_handle_messages (comp);
3072
3073   gst_omx_port_update_port_definition (port, NULL);
3074
3075   DEBUG_IF_OK (comp->parent, err,
3076       "Waited for %s port %u to release all buffers: %s (0x%08x)", comp->name,
3077       port->index, gst_omx_error_to_string (err), err);
3078
3079   return err;
3080 }
3081
3082 /* NOTE: Uses comp->lock and comp->messages_lock */
3083 OMX_ERRORTYPE
3084 gst_omx_port_wait_buffers_released (GstOMXPort * port, GstClockTime timeout)
3085 {
3086   OMX_ERRORTYPE err;
3087
3088   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3089
3090   g_mutex_lock (&port->comp->lock);
3091   err = gst_omx_port_wait_buffers_released_unlocked (port, timeout);
3092   g_mutex_unlock (&port->comp->lock);
3093
3094   return err;
3095 }
3096
3097 void
3098 gst_omx_port_requeue_buffer (GstOMXPort * port, GstOMXBuffer * buf)
3099 {
3100   g_mutex_lock (&port->comp->lock);
3101   g_queue_push_tail (&port->pending_buffers, buf);
3102   g_mutex_unlock (&port->comp->lock);
3103
3104   /* awake gst_omx_port_acquire_buffer() */
3105   gst_omx_component_send_message (port->comp, NULL);
3106 }
3107
3108 /* NOTE: Uses comp->lock and comp->messages_lock */
3109 OMX_ERRORTYPE
3110 gst_omx_port_set_enabled (GstOMXPort * port, gboolean enabled)
3111 {
3112   OMX_ERRORTYPE err;
3113
3114   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3115
3116   g_mutex_lock (&port->comp->lock);
3117   err = gst_omx_port_set_enabled_unlocked (port, enabled);
3118   g_mutex_unlock (&port->comp->lock);
3119
3120   return err;
3121 }
3122
3123 static OMX_ERRORTYPE
3124 gst_omx_port_populate_unlocked (GstOMXPort * port)
3125 {
3126   GstOMXComponent *comp;
3127   OMX_ERRORTYPE err = OMX_ErrorNone;
3128   GstOMXBuffer *buf;
3129
3130   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3131
3132   comp = port->comp;
3133
3134   GST_DEBUG_OBJECT (comp->parent, "Populating %s port %d", comp->name,
3135       port->index);
3136
3137   gst_omx_component_handle_messages (comp);
3138
3139   if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
3140     GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing or disabled",
3141         comp->name, port->index);
3142     err = OMX_ErrorIncorrectStateOperation;
3143     goto done;
3144   }
3145
3146   if ((err = comp->last_error) != OMX_ErrorNone) {
3147     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s"
3148         "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
3149     goto done;
3150   }
3151
3152   if (port->port_def.eDir == OMX_DirOutput && port->buffers && !port->tunneled) {
3153     /* Enqueue all buffers for the component to fill */
3154     while ((buf = g_queue_pop_head (&port->pending_buffers))) {
3155       g_assert (!buf->used);
3156
3157       /* Reset all flags, some implementations don't
3158        * reset them themselves and the flags are not
3159        * valid anymore after the buffer was consumed.
3160        * Also reset nFilledLen as FillThisBuffer() expects an empty buffer.
3161        */
3162       gst_omx_buffer_reset (buf);
3163
3164       log_omx_api_trace_buffer (comp, "FillThisBuffer", buf);
3165       err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
3166
3167       if (err != OMX_ErrorNone) {
3168         GST_ERROR_OBJECT (comp->parent,
3169             "Failed to pass buffer %p (%p) to %s port %u: %s (0x%08x)", buf,
3170             buf->omx_buf->pBuffer, comp->name, port->index,
3171             gst_omx_error_to_string (err), err);
3172         goto done;
3173       }
3174       GST_DEBUG_OBJECT (comp->parent, "Passed buffer %p (%p) to component %s",
3175           buf, buf->omx_buf->pBuffer, comp->name);
3176     }
3177   }
3178
3179 done:
3180   gst_omx_port_update_port_definition (port, NULL);
3181
3182   DEBUG_IF_OK (comp->parent, err, "Populated %s port %u: %s (0x%08x)",
3183       comp->name, port->index, gst_omx_error_to_string (err), err);
3184   gst_omx_component_handle_messages (comp);
3185
3186   return err;
3187 }
3188
3189 /* NOTE: Uses comp->lock and comp->messages_lock */
3190 OMX_ERRORTYPE
3191 gst_omx_port_populate (GstOMXPort * port)
3192 {
3193   OMX_ERRORTYPE err;
3194
3195   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3196
3197   g_mutex_lock (&port->comp->lock);
3198   err = gst_omx_port_populate_unlocked (port);
3199   g_mutex_unlock (&port->comp->lock);
3200
3201   return err;
3202 }
3203
3204 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
3205 static OMX_ERRORTYPE
3206 gst_omx_port_wait_enabled_unlocked (GstOMXPort * port, GstClockTime timeout)
3207 {
3208   GstOMXComponent *comp;
3209   OMX_ERRORTYPE err = OMX_ErrorNone;
3210   gboolean signalled;
3211   OMX_ERRORTYPE last_error;
3212   gboolean enabled;
3213
3214   comp = port->comp;
3215
3216   /* Check the current port status */
3217   gst_omx_port_update_port_definition (port, NULL);
3218
3219   if (port->enabled_pending)
3220     enabled = TRUE;
3221   else if (port->disabled_pending)
3222     enabled = FALSE;
3223   else
3224     enabled = port->port_def.bEnabled;
3225
3226   gst_omx_component_handle_messages (comp);
3227
3228   if ((err = comp->last_error) != OMX_ErrorNone) {
3229     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
3230         comp->name, gst_omx_error_to_string (err), err);
3231     goto done;
3232   }
3233
3234   GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to be %s",
3235       comp->name, port->index, (enabled ? "enabled" : "disabled"));
3236
3237   if (timeout == 0) {
3238     if (port->enabled_pending || port->disabled_pending)
3239       err = OMX_ErrorTimeout;
3240     goto done;
3241   }
3242
3243   /* And now wait until the enable/disable command is finished */
3244   signalled = TRUE;
3245   last_error = OMX_ErrorNone;
3246   gst_omx_port_update_port_definition (port, NULL);
3247   gst_omx_component_handle_messages (comp);
3248   while (signalled && last_error == OMX_ErrorNone &&
3249       (! !port->port_def.bEnabled != ! !enabled || port->enabled_pending
3250           || port->disabled_pending)) {
3251     signalled = gst_omx_component_wait_message (comp, timeout);
3252     if (signalled)
3253       gst_omx_component_handle_messages (comp);
3254     last_error = comp->last_error;
3255     gst_omx_port_update_port_definition (port, NULL);
3256   }
3257   port->enabled_pending = FALSE;
3258   port->disabled_pending = FALSE;
3259
3260   if (!signalled) {
3261     GST_ERROR_OBJECT (comp->parent,
3262         "Timeout waiting for %s port %u to be %s", comp->name, port->index,
3263         (enabled ? "enabled" : "disabled"));
3264     err = OMX_ErrorTimeout;
3265     goto done;
3266   } else if (last_error != OMX_ErrorNone) {
3267     GST_ERROR_OBJECT (comp->parent,
3268         "Got error while waiting for %s port %u to be %s: %s (0x%08x)",
3269         comp->name, port->index, (enabled ? "enabled" : "disabled"),
3270         gst_omx_error_to_string (err), err);
3271     err = last_error;
3272   } else {
3273     if (enabled) {
3274       /* Reset EOS flag */
3275       port->eos = FALSE;
3276     }
3277   }
3278
3279   gst_omx_component_handle_messages (comp);
3280
3281 done:
3282   gst_omx_port_update_port_definition (port, NULL);
3283
3284   GST_INFO_OBJECT (comp->parent, "%s port %u is %s%s: %s (0x%08x)", comp->name,
3285       port->index, (err == OMX_ErrorNone ? "" : "not "),
3286       (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
3287
3288   return err;
3289 }
3290
3291 /* NOTE: Uses comp->lock and comp->messages_lock */
3292 OMX_ERRORTYPE
3293 gst_omx_port_wait_enabled (GstOMXPort * port, GstClockTime timeout)
3294 {
3295   OMX_ERRORTYPE err;
3296
3297   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3298
3299   g_mutex_lock (&port->comp->lock);
3300   err = gst_omx_port_wait_enabled_unlocked (port, timeout);
3301   g_mutex_unlock (&port->comp->lock);
3302
3303   return err;
3304 }
3305
3306 gboolean
3307 gst_omx_port_is_enabled (GstOMXPort * port)
3308 {
3309   gboolean enabled;
3310
3311   g_return_val_if_fail (port != NULL, FALSE);
3312
3313   gst_omx_port_update_port_definition (port, NULL);
3314   enabled = ! !port->port_def.bEnabled;
3315
3316   GST_DEBUG_OBJECT (port->comp->parent, "%s port %u is enabled: %d",
3317       port->comp->name, port->index, enabled);
3318
3319   return enabled;
3320 }
3321
3322 /* NOTE: Uses comp->lock and comp->messages_lock */
3323 OMX_ERRORTYPE
3324 gst_omx_port_mark_reconfigured (GstOMXPort * port)
3325 {
3326   GstOMXComponent *comp;
3327   OMX_ERRORTYPE err = OMX_ErrorNone;
3328
3329   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
3330
3331   comp = port->comp;
3332
3333   g_mutex_lock (&comp->lock);
3334   GST_INFO_OBJECT (comp->parent, "Marking %s port %u is reconfigured",
3335       comp->name, port->index);
3336
3337   gst_omx_component_handle_messages (comp);
3338
3339   if ((err = comp->last_error) != OMX_ErrorNone)
3340     goto done;
3341
3342   port->configured_settings_cookie = port->settings_cookie;
3343
3344   if (port->port_def.eDir == OMX_DirOutput) {
3345     GList *l;
3346
3347     for (l = comp->pending_reconfigure_outports; l; l = l->next) {
3348       if (l->data == (gpointer) port) {
3349         comp->pending_reconfigure_outports =
3350             g_list_delete_link (comp->pending_reconfigure_outports, l);
3351         break;
3352       }
3353     }
3354     if (!comp->pending_reconfigure_outports)
3355       gst_omx_component_send_message (comp, NULL);
3356   }
3357
3358 done:
3359   gst_omx_port_update_port_definition (port, NULL);
3360
3361   INFO_IF_OK (comp->parent, err, "Marked %s port %u as reconfigured: %s "
3362       "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
3363
3364   g_mutex_unlock (&comp->lock);
3365
3366   return err;
3367 }
3368
3369 /* The OMX specs states that the nBufferCountActual of a port has to default
3370  * to its nBufferCountMin. If we don't change nBufferCountActual we purely rely
3371  * on this default. But in some cases, OMX may change nBufferCountMin before we
3372  * allocate buffers. Like for example when configuring the input ports with the
3373  * actual format, it may decrease the number of minimal buffers required.
3374  * This method checks this and update nBufferCountActual if needed so we'll use
3375  * less buffers than the worst case in such scenarios.
3376  */
3377 gboolean
3378 gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port, guint extra)
3379 {
3380   OMX_PARAM_PORTDEFINITIONTYPE port_def;
3381   guint nb;
3382
3383   gst_omx_port_get_port_definition (port, &port_def);
3384
3385   nb = port_def.nBufferCountMin + extra;
3386   if (port_def.nBufferCountActual != nb) {
3387     port_def.nBufferCountActual = nb;
3388
3389     GST_DEBUG_OBJECT (port->comp->parent,
3390         "set port %d nBufferCountActual to %d", (guint) port->index, nb);
3391
3392     if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
3393       return FALSE;
3394   }
3395
3396   return TRUE;
3397 }
3398
3399 gboolean
3400 gst_omx_port_update_buffer_count_actual (GstOMXPort * port, guint nb)
3401 {
3402   OMX_PARAM_PORTDEFINITIONTYPE port_def;
3403
3404   gst_omx_port_get_port_definition (port, &port_def);
3405
3406   if (nb < port_def.nBufferCountMin) {
3407     GST_DEBUG_OBJECT (port->comp->parent,
3408         "Requested to use %d buffers on port %d but it's minimum is %d", nb,
3409         (guint) port->index, (guint) port_def.nBufferCountMin);
3410
3411     nb = port_def.nBufferCountMin;
3412   }
3413
3414   if (port_def.nBufferCountActual != nb) {
3415     port_def.nBufferCountActual = nb;
3416
3417     GST_DEBUG_OBJECT (port->comp->parent,
3418         "set port %d nBufferCountActual to %d", (guint) port->index, nb);
3419
3420     if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
3421       return FALSE;
3422   }
3423
3424   return TRUE;
3425 }
3426
3427 gboolean
3428 gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf)
3429 {
3430 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3431   OMX_ALG_PORT_PARAM_BUFFER_MODE buffer_mode;
3432   OMX_ERRORTYPE err;
3433
3434   GST_OMX_INIT_STRUCT (&buffer_mode);
3435   buffer_mode.nPortIndex = port->index;
3436
3437   if (dmabuf)
3438     buffer_mode.eMode = OMX_ALG_BUF_DMA;
3439   else
3440     buffer_mode.eMode = OMX_ALG_BUF_NORMAL;
3441
3442   err =
3443       gst_omx_component_set_parameter (port->comp,
3444       (OMX_INDEXTYPE) OMX_ALG_IndexPortParamBufferMode, &buffer_mode);
3445   if (err != OMX_ErrorNone) {
3446     GST_WARNING_OBJECT (port->comp->parent,
3447         "Failed to set port %d in %sdmabuf mode: %s (0x%08x)",
3448         port->index, dmabuf ? "" : "non-", gst_omx_error_to_string (err), err);
3449     return FALSE;
3450   }
3451
3452   return TRUE;
3453 #else
3454   /* dmabuf not supported for this platform */
3455   return FALSE;
3456 #endif
3457 }
3458
3459 gboolean
3460 gst_omx_port_set_subframe (GstOMXPort * port, gboolean enabled)
3461 {
3462 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3463   OMX_ALG_VIDEO_PARAM_SUBFRAME subframe_mode;
3464   OMX_ERRORTYPE err;
3465
3466   GST_OMX_INIT_STRUCT (&subframe_mode);
3467   subframe_mode.nPortIndex = port->index;
3468
3469   subframe_mode.bEnableSubframe = enabled;
3470
3471   err = gst_omx_component_set_parameter (port->comp,
3472       (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSubframe, &subframe_mode);
3473   if (err != OMX_ErrorNone) {
3474     GST_WARNING_OBJECT (port->comp->parent,
3475         "Failed to %s subframe mode on port %d: %s (0x%08x)",
3476         enabled ? "enable" : "disable", port->index,
3477         gst_omx_error_to_string (err), err);
3478     return FALSE;
3479   }
3480
3481   return TRUE;
3482 #else
3483   /* subframe mode is not supported on this platform */
3484   return FALSE;
3485 #endif
3486 }
3487
3488 gboolean
3489 gst_omx_port_get_subframe (GstOMXPort * port)
3490 {
3491 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3492   OMX_ALG_VIDEO_PARAM_SUBFRAME subframe_mode;
3493   OMX_ERRORTYPE err;
3494
3495   GST_OMX_INIT_STRUCT (&subframe_mode);
3496   subframe_mode.nPortIndex = port->index;
3497
3498   err = gst_omx_component_get_parameter (port->comp,
3499       (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoSubframe, &subframe_mode);
3500   if (err != OMX_ErrorNone) {
3501     GST_WARNING_OBJECT (port->comp->parent,
3502         "Failed to get subframe mode on port %d: %s (0x%08x)",
3503         port->index, gst_omx_error_to_string (err), err);
3504     return FALSE;
3505   }
3506
3507   return subframe_mode.bEnableSubframe;
3508 #else
3509   /* subframe mode is not supported on this platform */
3510   return FALSE;
3511 #endif
3512 }
3513
3514 typedef GType (*GGetTypeFunction) (void);
3515
3516 static const GGetTypeFunction types[] = {
3517   gst_omx_analog_audio_sink_get_type, gst_omx_hdmi_audio_sink_get_type,
3518   gst_omx_mpeg2_video_dec_get_type, gst_omx_mpeg4_video_dec_get_type,
3519   gst_omx_h264_dec_get_type, gst_omx_h263_dec_get_type,
3520   gst_omx_wmv_dec_get_type, gst_omx_mpeg4_video_enc_get_type,
3521   gst_omx_h264_enc_get_type, gst_omx_h263_enc_get_type,
3522   gst_omx_aac_enc_get_type, gst_omx_mjpeg_dec_get_type,
3523   gst_omx_aac_dec_get_type, gst_omx_mp3_dec_get_type,
3524   gst_omx_aac_dec_get_type, gst_omx_mp3_enc_get_type,
3525   gst_omx_amr_dec_get_type
3526 #ifdef HAVE_VP8
3527       , gst_omx_vp8_dec_get_type
3528 #endif
3529 #ifdef HAVE_THEORA
3530       , gst_omx_theora_dec_get_type
3531 #endif
3532 #ifdef HAVE_HEVC
3533       , gst_omx_h265_enc_get_type, gst_omx_h265_dec_get_type
3534 #endif
3535 };
3536
3537 struct TypeOffest
3538 {
3539   GType (*get_type) (void);
3540   glong offset;
3541 };
3542
3543 static const struct TypeOffest base_types[] = {
3544   {gst_omx_audio_sink_get_type, G_STRUCT_OFFSET (GstOMXAudioSinkClass, cdata)},
3545   {gst_omx_video_dec_get_type, G_STRUCT_OFFSET (GstOMXVideoDecClass, cdata)},
3546   {gst_omx_video_enc_get_type, G_STRUCT_OFFSET (GstOMXVideoEncClass, cdata)},
3547   {gst_omx_audio_dec_get_type, G_STRUCT_OFFSET (GstOMXAudioDecClass, cdata)},
3548   {gst_omx_audio_enc_get_type, G_STRUCT_OFFSET (GstOMXAudioEncClass, cdata)},
3549 };
3550
3551 static GKeyFile *config = NULL;
3552 GKeyFile *
3553 gst_omx_get_configuration (void)
3554 {
3555   return config;
3556 }
3557
3558 const gchar *
3559 gst_omx_error_to_string (OMX_ERRORTYPE err)
3560 {
3561   guint err_u = (guint) err;
3562
3563   switch (err_u) {
3564     case OMX_ErrorNone:
3565       return "None";
3566     case OMX_ErrorInsufficientResources:
3567       return "Insufficient resources";
3568     case OMX_ErrorUndefined:
3569       return "Undefined";
3570     case OMX_ErrorInvalidComponentName:
3571       return "Invalid component name";
3572     case OMX_ErrorComponentNotFound:
3573       return "Component not found";
3574     case OMX_ErrorBadParameter:
3575       return "Bad parameter";
3576     case OMX_ErrorNotImplemented:
3577       return "Not implemented";
3578     case OMX_ErrorUnderflow:
3579       return "Underflow";
3580     case OMX_ErrorOverflow:
3581       return "Overflow";
3582     case OMX_ErrorHardware:
3583       return "Hardware";
3584     case OMX_ErrorStreamCorrupt:
3585       return "Stream corrupt";
3586     case OMX_ErrorPortsNotCompatible:
3587       return "Ports not compatible";
3588     case OMX_ErrorResourcesLost:
3589       return "Resources lost";
3590     case OMX_ErrorNoMore:
3591       return "No more";
3592     case OMX_ErrorVersionMismatch:
3593       return "Version mismatch";
3594     case OMX_ErrorNotReady:
3595       return "Not ready";
3596     case OMX_ErrorTimeout:
3597       return "Timeout";
3598     case OMX_ErrorSameState:
3599       return "Same state";
3600     case OMX_ErrorResourcesPreempted:
3601       return "Resources preempted";
3602     case OMX_ErrorIncorrectStateTransition:
3603       return "Incorrect state transition";
3604     case OMX_ErrorIncorrectStateOperation:
3605       return "Incorrect state operation";
3606     case OMX_ErrorUnsupportedSetting:
3607       return "Unsupported setting";
3608     case OMX_ErrorUnsupportedIndex:
3609       return "Unsupported index";
3610     case OMX_ErrorBadPortIndex:
3611       return "Bad port index";
3612     case OMX_ErrorPortUnpopulated:
3613       return "Port unpopulated";
3614     case OMX_ErrorComponentSuspended:
3615       return "Component suspended";
3616     case OMX_ErrorDynamicResourcesUnavailable:
3617       return "Dynamic resources unavailable";
3618     case OMX_ErrorMbErrorsInFrame:
3619       return "Macroblock errors in frame";
3620     case OMX_ErrorFormatNotDetected:
3621       return "Format not detected";
3622     case OMX_ErrorSeperateTablesUsed:
3623       return "Separate tables used";
3624     case OMX_ErrorTunnelingUnsupported:
3625       return "Tunneling unsupported";
3626 #if OMX_VERSION_MINOR == 1
3627     case OMX_ErrorInvalidComponent:
3628       return "Invalid component";
3629     case OMX_ErrorInvalidState:
3630       return "Invalid state";
3631     case OMX_ErrorPortUnresponsiveDuringAllocation:
3632       return "Port unresponsive during allocation";
3633     case OMX_ErrorPortUnresponsiveDuringDeallocation:
3634       return "Port unresponsive during deallocation";
3635     case OMX_ErrorPortUnresponsiveDuringStop:
3636       return "Port unresponsive during stop";
3637     case OMX_ErrorContentPipeOpenFailed:
3638       return "Content pipe open failed";
3639     case OMX_ErrorContentPipeCreationFailed:
3640       return "Content pipe creation failed";
3641 #endif
3642     default:
3643       if (err_u >= (guint) OMX_ErrorKhronosExtensions
3644           && err_u < (guint) OMX_ErrorVendorStartUnused) {
3645         return "Khronos extension error";
3646       } else if (err_u >= (guint) OMX_ErrorVendorStartUnused
3647           && err_u < (guint) OMX_ErrorMax) {
3648         return "Vendor specific error";
3649       } else {
3650         return "Unknown error";
3651       }
3652   }
3653 }
3654
3655 const gchar *
3656 gst_omx_state_to_string (OMX_STATETYPE state)
3657 {
3658   switch (state) {
3659     case OMX_StateInvalid:
3660       return "Invalid";
3661     case OMX_StateLoaded:
3662       return "Loaded";
3663     case OMX_StateIdle:
3664       return "Idle";
3665     case OMX_StateExecuting:
3666       return "Executing";
3667     case OMX_StatePause:
3668       return "Pause";
3669     case OMX_StateWaitForResources:
3670       return "WaitForResources";
3671     default:
3672       if (state >= OMX_StateKhronosExtensions
3673           && state < OMX_StateVendorStartUnused)
3674         return "KhronosExtensionState";
3675       else if (state >= OMX_StateVendorStartUnused && state < OMX_StateMax)
3676         return "CustomVendorState";
3677       break;
3678   }
3679   return "Unknown state";
3680 }
3681
3682 const gchar *
3683 gst_omx_command_to_string (OMX_COMMANDTYPE cmd)
3684 {
3685   switch (cmd) {
3686     case OMX_CommandStateSet:
3687       return "SetState";
3688     case OMX_CommandFlush:
3689       return "Flush";
3690     case OMX_CommandPortDisable:
3691       return "DisablePort";
3692     case OMX_CommandPortEnable:
3693       return "EnablePort";
3694     case OMX_CommandMarkBuffer:
3695       return "MarkBuffer";
3696     default:
3697       if (cmd >= OMX_CommandKhronosExtensions
3698           && cmd < OMX_CommandVendorStartUnused)
3699         return "KhronosExtensionCommand";
3700       if (cmd >= OMX_CommandVendorStartUnused && cmd < OMX_CommandMax)
3701         return "VendorExtensionCommand";
3702       break;
3703   }
3704   return "Unknown command";
3705 }
3706
3707 struct BufferFlagString
3708 {
3709   guint32 flag;
3710   const gchar *str;
3711 };
3712
3713 struct BufferFlagString buffer_flags_map[] = {
3714   {OMX_BUFFERFLAG_EOS, "eos"},
3715   {OMX_BUFFERFLAG_STARTTIME, "start-time"},
3716   {OMX_BUFFERFLAG_DECODEONLY, "decode-only"},
3717   {OMX_BUFFERFLAG_DATACORRUPT, "data-corrupt"},
3718   {OMX_BUFFERFLAG_ENDOFFRAME, "end-of-frame"},
3719   {OMX_BUFFERFLAG_SYNCFRAME, "sync-frame"},
3720   {OMX_BUFFERFLAG_EXTRADATA, "extra-data"},
3721   {OMX_BUFFERFLAG_CODECCONFIG, "codec-config"},
3722   /* Introduced in OMX 1.2.0 */
3723 #ifdef OMX_BUFFERFLAG_TIMESTAMPINVALID
3724   {OMX_BUFFERFLAG_TIMESTAMPINVALID, "timestamp-invalid"},
3725 #endif
3726 #ifdef OMX_BUFFERFLAG_READONLY
3727   {OMX_BUFFERFLAG_READONLY, "read-only"},
3728 #endif
3729 #ifdef OMX_BUFFERFLAG_ENDOFSUBFRAME
3730   {OMX_BUFFERFLAG_ENDOFSUBFRAME, "end-of-subframe"},
3731 #endif
3732 #ifdef OMX_BUFFERFLAG_SKIPFRAME
3733   {OMX_BUFFERFLAG_SKIPFRAME, "skip-frame"},
3734 #endif
3735 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
3736   {OMX_ALG_BUFFERFLAG_TOP_FIELD, "top-field"},
3737   {OMX_ALG_BUFFERFLAG_BOT_FIELD, "bottom-field"},
3738 #endif
3739   {0, NULL},
3740 };
3741
3742
3743 const gchar *
3744 gst_omx_buffer_flags_to_string (guint32 flags)
3745 {
3746   GString *s = NULL;
3747   guint i;
3748   const gchar *str;
3749
3750   if (flags == 0)
3751     return "";
3752
3753   /* Keep a cache of the string representation of the flags so we don't allocate
3754    * and free strings for each buffer. In practice we should only have a handfull
3755    * of flags so the cache won't consume much memory. */
3756   if (!buffer_flags_str) {
3757     G_LOCK (buffer_flags_str);
3758     buffer_flags_str = g_hash_table_new_full (NULL, NULL, NULL, g_free);
3759     G_UNLOCK (buffer_flags_str);
3760   }
3761
3762   str = g_hash_table_lookup (buffer_flags_str, GUINT_TO_POINTER (flags));
3763   if (str)
3764     return str;
3765
3766   for (i = 0; buffer_flags_map[i].str != NULL; i++) {
3767     if ((flags & buffer_flags_map[i].flag) == 0)
3768       continue;
3769
3770     if (!s)
3771       s = g_string_new (buffer_flags_map[i].str);
3772     else
3773       g_string_append_printf (s, ", %s", buffer_flags_map[i].str);
3774   }
3775
3776   if (!s)
3777     return "<unknown>";
3778
3779   str = g_string_free (s, FALSE);
3780
3781   G_LOCK (buffer_flags_str);
3782   /* Transfer ownership of str to hash table */
3783   g_hash_table_insert (buffer_flags_str, GUINT_TO_POINTER (flags),
3784       (gchar *) str);
3785   G_UNLOCK (buffer_flags_str);
3786
3787   return str;
3788 }
3789
3790 #if defined(USE_OMX_TARGET_RPI)
3791 #define DEFAULT_HACKS (GST_OMX_HACK_NO_COMPONENT_ROLE | GST_OMX_HACK_HEIGHT_MULTIPLE_16)
3792 #else
3793 #define DEFAULT_HACKS (0)
3794 #endif
3795
3796 guint64
3797 gst_omx_parse_hacks (gchar ** hacks)
3798 {
3799   guint64 hacks_flags = DEFAULT_HACKS;
3800
3801   if (!hacks)
3802     return 0;
3803
3804   while (*hacks) {
3805     if (g_str_equal (*hacks,
3806             "event-port-settings-changed-ndata-parameter-swap"))
3807       hacks_flags |=
3808           GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_NDATA_PARAMETER_SWAP;
3809     else if (g_str_equal (*hacks, "event-port-settings-changed-port-0-to-1"))
3810       hacks_flags |= GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_PORT_0_TO_1;
3811     else if (g_str_equal (*hacks, "video-framerate-integer"))
3812       hacks_flags |= GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER;
3813     else if (g_str_equal (*hacks, "syncframe-flag-not-used"))
3814       hacks_flags |= GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED;
3815     else if (g_str_equal (*hacks, "no-component-reconfigure"))
3816       hacks_flags |= GST_OMX_HACK_NO_COMPONENT_RECONFIGURE;
3817     else if (g_str_equal (*hacks, "no-empty-eos-buffer"))
3818       hacks_flags |= GST_OMX_HACK_NO_EMPTY_EOS_BUFFER;
3819     else if (g_str_equal (*hacks, "drain-may-not-return"))
3820       hacks_flags |= GST_OMX_HACK_DRAIN_MAY_NOT_RETURN;
3821     else if (g_str_equal (*hacks, "no-component-role"))
3822       hacks_flags |= GST_OMX_HACK_NO_COMPONENT_ROLE;
3823     else if (g_str_equal (*hacks, "no-disable-outport"))
3824       hacks_flags |= GST_OMX_HACK_NO_DISABLE_OUTPORT;
3825     else if (g_str_equal (*hacks, "signals-premature-eos"))
3826       hacks_flags |= GST_OMX_HACK_SIGNALS_PREMATURE_EOS;
3827     else if (g_str_equal (*hacks, "height-multiple-16"))
3828       hacks_flags |= GST_OMX_HACK_HEIGHT_MULTIPLE_16;
3829     else if (g_str_equal (*hacks, "pass-profile-to-decoder"))
3830       hacks_flags |= GST_OMX_HACK_PASS_PROFILE_TO_DECODER;
3831     else if (g_str_equal (*hacks, "pass-color-format-to-decoder"))
3832       hacks_flags |= GST_OMX_HACK_PASS_COLOR_FORMAT_TO_DECODER;
3833     else if (g_str_equal (*hacks, "ensure-buffer-count-actual"))
3834       hacks_flags |= GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL;
3835     else
3836       GST_WARNING ("Unknown hack: %s", *hacks);
3837     hacks++;
3838   }
3839
3840   return hacks_flags;
3841 }
3842
3843
3844 void
3845 gst_omx_set_default_role (GstOMXClassData * class_data,
3846     const gchar * default_role)
3847 {
3848   if (!class_data->component_role)
3849     class_data->component_role = default_role;
3850 }
3851
3852 static void
3853 _class_init (gpointer g_class, gpointer data)
3854 {
3855   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3856   GstOMXClassData *class_data = NULL;
3857   GKeyFile *config;
3858   const gchar *element_name = data;
3859   GError *err;
3860   gchar *core_name, *component_name, *component_role;
3861   gint in_port_index, out_port_index;
3862   gchar *template_caps;
3863   GstPadTemplate *templ;
3864   GstCaps *caps;
3865   gchar **hacks;
3866   int i;
3867
3868   if (!element_name)
3869     return;
3870
3871   /* Find the GstOMXClassData for this class */
3872   for (i = 0; i < G_N_ELEMENTS (base_types); i++) {
3873     GType gtype = base_types[i].get_type ();
3874
3875     if (G_TYPE_CHECK_CLASS_TYPE (g_class, gtype)) {
3876       class_data = (GstOMXClassData *)
3877           (((guint8 *) g_class) + base_types[i].offset);
3878       break;
3879     }
3880   }
3881
3882   g_assert (class_data != NULL);
3883
3884   config = gst_omx_get_configuration ();
3885
3886   /* This will alwaxys succeed, see check in plugin_init */
3887   core_name = g_key_file_get_string (config, element_name, "core-name", NULL);
3888   g_assert (core_name != NULL);
3889   class_data->core_name = core_name;
3890   component_name =
3891       g_key_file_get_string (config, element_name, "component-name", NULL);
3892   g_assert (component_name != NULL);
3893   class_data->component_name = component_name;
3894
3895   /* If this fails we simply don't set a role */
3896   if ((component_role =
3897           g_key_file_get_string (config, element_name, "component-role",
3898               NULL))) {
3899     GST_DEBUG ("Using component-role '%s' for element '%s'", component_role,
3900         element_name);
3901     class_data->component_role = component_role;
3902   }
3903
3904
3905   /* Now set the inport/outport indizes and assume sane defaults */
3906   err = NULL;
3907   in_port_index =
3908       g_key_file_get_integer (config, element_name, "in-port-index", &err);
3909   if (err != NULL) {
3910     GST_DEBUG ("No 'in-port-index' set for element '%s', auto-detecting: %s",
3911         element_name, err->message);
3912     in_port_index = -1;
3913     g_error_free (err);
3914   }
3915   class_data->in_port_index = in_port_index;
3916
3917   err = NULL;
3918   out_port_index =
3919       g_key_file_get_integer (config, element_name, "out-port-index", &err);
3920   if (err != NULL) {
3921     GST_DEBUG ("No 'out-port-index' set for element '%s', auto-detecting: %s",
3922         element_name, err->message);
3923     out_port_index = -1;
3924     g_error_free (err);
3925   }
3926   class_data->out_port_index = out_port_index;
3927
3928   /* Add pad templates */
3929   err = NULL;
3930   if (class_data->type != GST_OMX_COMPONENT_TYPE_SOURCE) {
3931     if (!(template_caps =
3932             g_key_file_get_string (config, element_name, "sink-template-caps",
3933                 &err))) {
3934       GST_DEBUG
3935           ("No sink template caps specified for element '%s', using default '%s'",
3936           element_name, class_data->default_sink_template_caps);
3937       caps = gst_caps_from_string (class_data->default_sink_template_caps);
3938       g_assert (caps != NULL);
3939       g_error_free (err);
3940     } else {
3941       caps = gst_caps_from_string (template_caps);
3942       if (!caps) {
3943         GST_DEBUG
3944             ("Could not parse sink template caps '%s' for element '%s', using default '%s'",
3945             template_caps, element_name,
3946             class_data->default_sink_template_caps);
3947         caps = gst_caps_from_string (class_data->default_sink_template_caps);
3948         g_assert (caps != NULL);
3949       }
3950     }
3951     templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
3952     g_free (template_caps);
3953     gst_element_class_add_pad_template (element_class, templ);
3954     gst_caps_unref (caps);
3955   }
3956
3957   err = NULL;
3958   if (class_data->type != GST_OMX_COMPONENT_TYPE_SINK) {
3959     if (!(template_caps =
3960             g_key_file_get_string (config, element_name, "src-template-caps",
3961                 &err))) {
3962       GST_DEBUG
3963           ("No src template caps specified for element '%s', using default '%s'",
3964           element_name, class_data->default_src_template_caps);
3965       caps = gst_caps_from_string (class_data->default_src_template_caps);
3966       g_assert (caps != NULL);
3967       g_error_free (err);
3968     } else {
3969       caps = gst_caps_from_string (template_caps);
3970       if (!caps) {
3971         GST_DEBUG
3972             ("Could not parse src template caps '%s' for element '%s', using default '%s'",
3973             template_caps, element_name, class_data->default_src_template_caps);
3974         caps = gst_caps_from_string (class_data->default_src_template_caps);
3975         g_assert (caps != NULL);
3976       }
3977     }
3978     templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
3979     g_free (template_caps);
3980     gst_element_class_add_pad_template (element_class, templ);
3981     gst_caps_unref (caps);
3982   }
3983
3984   if ((hacks =
3985           g_key_file_get_string_list (config, element_name, "hacks", NULL,
3986               NULL))) {
3987 #ifndef GST_DISABLE_GST_DEBUG
3988     gchar **walk = hacks;
3989
3990     while (*walk) {
3991       GST_DEBUG ("Using hack: %s", *walk);
3992       walk++;
3993     }
3994 #endif
3995
3996     class_data->hacks = gst_omx_parse_hacks (hacks);
3997     g_strfreev (hacks);
3998   }
3999 }
4000
4001 static gboolean
4002 plugin_init (GstPlugin * plugin)
4003 {
4004   GError *err = NULL;
4005   gchar **config_dirs;
4006   gchar **elements;
4007   gchar *env_config_dir;
4008   const gchar *user_config_dir;
4009   const gchar *const *system_config_dirs;
4010   gint i, j;
4011   gsize n_elements;
4012   static const gchar *config_name[] = { "gstomx.conf", NULL };
4013   static const gchar *env_config_name[] = { "GST_OMX_CONFIG_DIR", NULL };
4014   static const gchar *gst_omx_config_dir = GST_OMX_CONFIG_DIR;
4015
4016   GST_DEBUG_CATEGORY_INIT (gstomx_debug, "omx", 0, "gst-omx");
4017   GST_DEBUG_CATEGORY_INIT (gst_omx_video_debug_category, "omxvideo", 0,
4018       "gst-omx-video");
4019   GST_DEBUG_CATEGORY_INIT (OMX_API_TRACE, "OMX_API_TRACE", 0,
4020       "gst-omx performace");
4021
4022   /* Read configuration file gstomx.conf from the preferred
4023    * configuration directories */
4024   env_config_dir = g_strdup (g_getenv (*env_config_name));
4025   user_config_dir = g_get_user_config_dir ();
4026   system_config_dirs = g_get_system_config_dirs ();
4027   config_dirs =
4028       g_new (gchar *, g_strv_length ((gchar **) system_config_dirs) + 4);
4029
4030   i = 0;
4031   j = 0;
4032   if (env_config_dir)
4033     config_dirs[i++] = (gchar *) env_config_dir;
4034   config_dirs[i++] = (gchar *) user_config_dir;
4035   while (system_config_dirs[j])
4036     config_dirs[i++] = (gchar *) system_config_dirs[j++];
4037   config_dirs[i++] = (gchar *) gst_omx_config_dir;
4038   config_dirs[i++] = NULL;
4039
4040   gst_plugin_add_dependency (plugin, env_config_name,
4041       (const gchar **) (config_dirs + (env_config_dir ? 1 : 0)), config_name,
4042       GST_PLUGIN_DEPENDENCY_FLAG_NONE);
4043
4044   config = g_key_file_new ();
4045   if (!g_key_file_load_from_dirs (config, *config_name,
4046           (const gchar **) config_dirs, NULL, G_KEY_FILE_NONE, &err)) {
4047 #ifdef USE_OMX_TARGET_GENERIC
4048     GST_INFO ("No configuration file found; "
4049         "ignore as gst-omx has been built with the generic target used only for testing");
4050 #else
4051     {
4052       gchar *paths;
4053
4054       paths = g_strjoinv (":", config_dirs);
4055       GST_ERROR
4056           ("Failed to load configuration file: %s (searched in: %s as per "
4057           "GST_OMX_CONFIG_DIR environment variable, the xdg user config "
4058           "directory (or XDG_CONFIG_HOME) and the system config directory "
4059           "(or XDG_CONFIG_DIRS)", err->message, paths);
4060       g_free (paths);
4061     }
4062 #endif /* USE_OMX_TARGET_GENERIC */
4063
4064     g_error_free (err);
4065     goto done;
4066   }
4067
4068   /* Initialize all types */
4069   for (i = 0; i < G_N_ELEMENTS (types); i++)
4070     types[i] ();
4071
4072   elements = g_key_file_get_groups (config, &n_elements);
4073   for (i = 0; i < n_elements; i++) {
4074     GTypeQuery type_query;
4075     GTypeInfo type_info = { 0, };
4076     GType type, subtype;
4077     gchar *type_name, *core_name, *component_name;
4078     gint rank;
4079
4080     GST_DEBUG ("Registering element '%s'", elements[i]);
4081
4082     err = NULL;
4083     if (!(type_name =
4084             g_key_file_get_string (config, elements[i], "type-name", &err))) {
4085       GST_ERROR
4086           ("Unable to read 'type-name' configuration for element '%s': %s",
4087           elements[i], err->message);
4088       g_error_free (err);
4089       continue;
4090     }
4091
4092     type = g_type_from_name (type_name);
4093     if (type == G_TYPE_INVALID) {
4094       GST_ERROR ("Invalid type name '%s' for element '%s'", type_name,
4095           elements[i]);
4096       g_free (type_name);
4097       continue;
4098     }
4099     if (!g_type_is_a (type, GST_TYPE_ELEMENT)) {
4100       GST_ERROR ("Type '%s' is no GstElement subtype for element '%s'",
4101           type_name, elements[i]);
4102       g_free (type_name);
4103       continue;
4104     }
4105     g_free (type_name);
4106
4107     /* And now some sanity checking */
4108     err = NULL;
4109     if (!(core_name =
4110             g_key_file_get_string (config, elements[i], "core-name", &err))) {
4111       GST_ERROR
4112           ("Unable to read 'core-name' configuration for element '%s': %s",
4113           elements[i], err->message);
4114       g_error_free (err);
4115       continue;
4116     }
4117     if (!g_file_test (core_name, G_FILE_TEST_IS_REGULAR)) {
4118       GST_ERROR ("Core '%s' does not exist for element '%s'", core_name,
4119           elements[i]);
4120       g_free (core_name);
4121       continue;
4122     }
4123     g_free (core_name);
4124
4125     err = NULL;
4126     if (!(component_name =
4127             g_key_file_get_string (config, elements[i], "component-name",
4128                 &err))) {
4129       GST_ERROR
4130           ("Unable to read 'component-name' configuration for element '%s': %s",
4131           elements[i], err->message);
4132       g_error_free (err);
4133       continue;
4134     }
4135     g_free (component_name);
4136
4137     err = NULL;
4138     rank = g_key_file_get_integer (config, elements[i], "rank", &err);
4139     if (err != NULL) {
4140       GST_ERROR ("No rank set for element '%s': %s", elements[i], err->message);
4141       g_error_free (err);
4142       continue;
4143     }
4144
4145     /* And now register the type, all other configuration will
4146      * be handled by the type itself */
4147     g_type_query (type, &type_query);
4148     memset (&type_info, 0, sizeof (type_info));
4149     type_info.class_size = type_query.class_size;
4150     type_info.instance_size = type_query.instance_size;
4151     type_info.class_init = _class_init;
4152     type_info.class_data = g_strdup (elements[i]);
4153     type_name = g_strdup_printf ("%s-%s", g_type_name (type), elements[i]);
4154     if (g_type_from_name (type_name) != G_TYPE_INVALID) {
4155       GST_ERROR ("Type '%s' already exists for element '%s'", type_name,
4156           elements[i]);
4157       g_free (type_name);
4158       continue;
4159     }
4160     subtype = g_type_register_static (type, type_name, &type_info, 0);
4161     g_free (type_name);
4162     gst_element_register (plugin, elements[i], rank, subtype);
4163   }
4164   g_strfreev (elements);
4165
4166 done:
4167   g_free (env_config_dir);
4168   g_free (config_dirs);
4169
4170   return TRUE;
4171 }
4172
4173 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
4174     GST_VERSION_MINOR,
4175     omx,
4176     "GStreamer OpenMAX Plug-ins",
4177     plugin_init,
4178     PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)