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