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