bea3e59d00ae3960d164395f44c163531fb2a5dc
[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 OMX_ERRORTYPE
1074 gst_omx_component_send_command (GstOMXComponent * comp, OMX_COMMANDTYPE cmd,
1075     guint32 param, gpointer cmd_data)
1076 {
1077   OMX_ERRORTYPE err;
1078
1079   err = OMX_SendCommand (comp->handle, cmd, param, cmd_data);
1080
1081   return err;
1082 }
1083
1084 /* NOTE: Uses comp->lock and comp->messages_lock */
1085 OMX_ERRORTYPE
1086 gst_omx_component_set_state (GstOMXComponent * comp, OMX_STATETYPE state)
1087 {
1088   OMX_STATETYPE old_state;
1089   OMX_ERRORTYPE err = OMX_ErrorNone;
1090
1091   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1092
1093   g_mutex_lock (&comp->lock);
1094
1095   gst_omx_component_handle_messages (comp);
1096
1097   old_state = comp->state;
1098   GST_INFO_OBJECT (comp->parent, "Setting %s state from %s to %s", comp->name,
1099       gst_omx_state_to_string (old_state), gst_omx_state_to_string (state));
1100
1101   if ((err = comp->last_error) != OMX_ErrorNone && state > old_state) {
1102     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
1103         comp->name, gst_omx_error_to_string (err), err);
1104     goto done;
1105   }
1106
1107   if (old_state == state || comp->pending_state == state) {
1108     GST_DEBUG_OBJECT (comp->parent, "Component %s already in state %s",
1109         comp->name, gst_omx_state_to_string (state));
1110     goto done;
1111   }
1112
1113   comp->pending_state = state;
1114
1115   /* Reset some things */
1116   if ((old_state == OMX_StateExecuting || old_state == OMX_StatePause)
1117       && state < old_state) {
1118     g_list_free (comp->pending_reconfigure_outports);
1119     comp->pending_reconfigure_outports = NULL;
1120     /* Notify all inports that are still waiting */
1121     gst_omx_component_send_message (comp, NULL);
1122   }
1123
1124   err = gst_omx_component_send_command (comp, OMX_CommandStateSet, state, NULL);
1125   /* No need to check if anything has changed here */
1126
1127 done:
1128
1129   gst_omx_component_handle_messages (comp);
1130
1131   if (err != OMX_ErrorNone && comp->last_error == OMX_ErrorNone) {
1132     GST_ERROR_OBJECT (comp->parent,
1133         "Last operation returned an error. Setting last_error manually.");
1134     comp->last_error = err;
1135   }
1136
1137   g_mutex_unlock (&comp->lock);
1138
1139   if (err != OMX_ErrorNone) {
1140     GST_ERROR_OBJECT (comp->parent,
1141         "Error setting %s state from %s to %s: %s (0x%08x)", comp->name,
1142         gst_omx_state_to_string (old_state), gst_omx_state_to_string (state),
1143         gst_omx_error_to_string (err), err);
1144   }
1145   return err;
1146 }
1147
1148 /* NOTE: Uses comp->lock and comp->messages_lock */
1149 OMX_STATETYPE
1150 gst_omx_component_get_state (GstOMXComponent * comp, GstClockTime timeout)
1151 {
1152   OMX_STATETYPE ret;
1153   gboolean signalled = TRUE;
1154
1155   g_return_val_if_fail (comp != NULL, OMX_StateInvalid);
1156
1157   GST_DEBUG_OBJECT (comp->parent, "Getting state of %s", comp->name);
1158
1159   g_mutex_lock (&comp->lock);
1160
1161   gst_omx_component_handle_messages (comp);
1162
1163   if (comp->last_error != OMX_ErrorNone) {
1164     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
1165         comp->name, gst_omx_error_to_string (comp->last_error),
1166         comp->last_error);
1167     ret = OMX_StateInvalid;
1168     goto done;
1169   }
1170
1171   ret = comp->state;
1172   if (comp->pending_state == OMX_StateInvalid)
1173     goto done;
1174
1175   while (signalled && comp->last_error == OMX_ErrorNone
1176       && comp->pending_state != OMX_StateInvalid) {
1177
1178     signalled = gst_omx_component_wait_message (comp, timeout);
1179     if (signalled)
1180       gst_omx_component_handle_messages (comp);
1181   };
1182
1183   if (signalled) {
1184     if (comp->last_error != OMX_ErrorNone) {
1185       GST_ERROR_OBJECT (comp->parent,
1186           "%s got error while waiting for state change: %s (0x%08x)",
1187           comp->name, gst_omx_error_to_string (comp->last_error),
1188           comp->last_error);
1189       ret = OMX_StateInvalid;
1190     } else if (comp->pending_state == OMX_StateInvalid) {
1191       /* State change finished and everything's fine */
1192       ret = comp->state;
1193     } else {
1194       ret = OMX_StateInvalid;
1195       g_assert_not_reached ();
1196     }
1197   } else {
1198     ret = OMX_StateInvalid;
1199     GST_WARNING_OBJECT (comp->parent, "%s timeout while waiting for state "
1200         "change", comp->name);
1201   }
1202
1203 done:
1204   g_mutex_unlock (&comp->lock);
1205
1206   GST_DEBUG_OBJECT (comp->parent, "%s returning state %s", comp->name,
1207       gst_omx_state_to_string (ret));
1208
1209   return ret;
1210 }
1211
1212 GstOMXPort *
1213 gst_omx_component_add_port (GstOMXComponent * comp, guint32 index)
1214 {
1215   gint i, n;
1216   GstOMXPort *port;
1217   OMX_PARAM_PORTDEFINITIONTYPE port_def;
1218   OMX_ERRORTYPE err;
1219
1220   g_return_val_if_fail (comp != NULL, NULL);
1221
1222   /* Check if this port exists already */
1223   n = comp->ports->len;
1224   for (i = 0; i < n; i++) {
1225     port = g_ptr_array_index (comp->ports, i);
1226     g_return_val_if_fail (port->index != index, NULL);
1227   }
1228
1229   GST_DEBUG_OBJECT (comp->parent, "%s adding port %u", comp->name, index);
1230
1231   GST_OMX_INIT_STRUCT (&port_def);
1232   port_def.nPortIndex = index;
1233
1234   err = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1235       &port_def);
1236   if (err != OMX_ErrorNone) {
1237     GST_ERROR_OBJECT (comp->parent, "%s failed to add port %u: %s (0x%08x)",
1238         comp->name, index, gst_omx_error_to_string (err), err);
1239     return NULL;
1240   }
1241
1242   port = g_slice_new0 (GstOMXPort);
1243   port->comp = comp;
1244   port->index = index;
1245
1246   port->tunneled = FALSE;
1247
1248   port->port_def = port_def;
1249
1250   g_queue_init (&port->pending_buffers);
1251   port->flushing = TRUE;
1252   port->flushed = FALSE;
1253   port->enabled_pending = FALSE;
1254   port->disabled_pending = FALSE;
1255   port->eos = FALSE;
1256   port->using_pool = FALSE;
1257
1258   if (port->port_def.eDir == OMX_DirInput)
1259     comp->n_in_ports++;
1260   else
1261     comp->n_out_ports++;
1262
1263   g_ptr_array_add (comp->ports, port);
1264
1265   return port;
1266 }
1267
1268 GstOMXPort *
1269 gst_omx_component_get_port (GstOMXComponent * comp, guint32 index)
1270 {
1271   gint i, n;
1272
1273   n = comp->ports->len;
1274   for (i = 0; i < n; i++) {
1275     GstOMXPort *tmp = g_ptr_array_index (comp->ports, i);
1276
1277     if (tmp->index == index)
1278       return tmp;
1279   }
1280   return NULL;
1281 }
1282
1283 /* NOTE: Uses comp->lock and comp->messages_lock */
1284 OMX_ERRORTYPE
1285 gst_omx_component_get_last_error (GstOMXComponent * comp)
1286 {
1287   OMX_ERRORTYPE err;
1288
1289   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1290
1291   g_mutex_lock (&comp->lock);
1292   gst_omx_component_handle_messages (comp);
1293   err = comp->last_error;
1294   g_mutex_unlock (&comp->lock);
1295
1296   GST_DEBUG_OBJECT (comp->parent, "Returning last %s error: %s (0x%08x)",
1297       comp->name, gst_omx_error_to_string (err), err);
1298
1299   return err;
1300 }
1301
1302 const gchar *
1303 gst_omx_component_get_last_error_string (GstOMXComponent * comp)
1304 {
1305   g_return_val_if_fail (comp != NULL, NULL);
1306
1307   return gst_omx_error_to_string (gst_omx_component_get_last_error (comp));
1308 }
1309
1310 /* comp->lock must be unlocked while calling this */
1311 OMX_ERRORTYPE
1312 gst_omx_component_get_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1313     gpointer param)
1314 {
1315   OMX_ERRORTYPE err;
1316
1317   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1318   g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1319
1320   GST_DEBUG_OBJECT (comp->parent, "Getting %s parameter at index 0x%08x",
1321       comp->name, index);
1322   err = OMX_GetParameter (comp->handle, index, param);
1323   DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1324       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1325
1326   return err;
1327 }
1328
1329 /* comp->lock must be unlocked while calling this */
1330 OMX_ERRORTYPE
1331 gst_omx_component_set_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1332     gpointer param)
1333 {
1334   OMX_ERRORTYPE err;
1335
1336   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1337   g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1338
1339   GST_DEBUG_OBJECT (comp->parent, "Setting %s parameter at index 0x%08x",
1340       comp->name, index);
1341   err = OMX_SetParameter (comp->handle, index, param);
1342   DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1343       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1344
1345   return err;
1346 }
1347
1348 /* comp->lock must be unlocked while calling this */
1349 OMX_ERRORTYPE
1350 gst_omx_component_get_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1351     gpointer config)
1352 {
1353   OMX_ERRORTYPE err;
1354
1355   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1356   g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1357
1358   GST_DEBUG_OBJECT (comp->parent, "Getting %s configuration at index 0x%08x",
1359       comp->name, index);
1360   err = OMX_GetConfig (comp->handle, index, config);
1361   DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1362       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1363
1364   return err;
1365 }
1366
1367 /* comp->lock must be unlocked while calling this */
1368 OMX_ERRORTYPE
1369 gst_omx_component_set_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1370     gpointer config)
1371 {
1372   OMX_ERRORTYPE err;
1373
1374   g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1375   g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1376
1377   GST_DEBUG_OBJECT (comp->parent, "Setting %s configuration at index 0x%08x",
1378       comp->name, index);
1379   err = OMX_SetConfig (comp->handle, index, config);
1380   DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1381       "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1382
1383   return err;
1384 }
1385
1386 OMX_ERRORTYPE
1387 gst_omx_setup_tunnel (GstOMXPort * port1, GstOMXPort * port2)
1388 {
1389   GstOMXComponent *comp1;
1390   GstOMXComponent *comp2;
1391   OMX_ERRORTYPE err;
1392
1393   g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
1394   g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
1395       OMX_ErrorUndefined);
1396   comp1 = port1->comp;
1397
1398   g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
1399   g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
1400       OMX_ErrorUndefined);
1401   comp2 = port2->comp;
1402
1403   g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
1404
1405   g_mutex_lock (&comp1->lock);
1406   g_mutex_lock (&comp2->lock);
1407   GST_DEBUG_OBJECT (comp1->parent,
1408       "Setup tunnel between %s port %u and %s port %u",
1409       comp1->name, port1->index, comp2->name, port2->index);
1410
1411   err = comp1->core->setup_tunnel (comp1->handle, port1->index, comp2->handle,
1412       port2->index);
1413
1414   if (err == OMX_ErrorNone) {
1415     port1->tunneled = TRUE;
1416     port2->tunneled = TRUE;
1417   }
1418
1419   DEBUG_IF_OK (comp1->parent, err,
1420       "Setup tunnel between %s port %u and %s port %u: %s (0x%08x)",
1421       comp1->name, port1->index,
1422       comp2->name, port2->index, gst_omx_error_to_string (err), err);
1423
1424   g_mutex_unlock (&comp2->lock);
1425   g_mutex_unlock (&comp1->lock);
1426
1427   return err;
1428 }
1429
1430 OMX_ERRORTYPE
1431 gst_omx_close_tunnel (GstOMXPort * port1, GstOMXPort * port2)
1432 {
1433   GstOMXComponent *comp1;
1434   GstOMXComponent *comp2;
1435   OMX_ERRORTYPE err;
1436
1437   g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
1438   g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
1439       OMX_ErrorUndefined);
1440   comp1 = port1->comp;
1441
1442   g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
1443   g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
1444       OMX_ErrorUndefined);
1445   comp2 = port2->comp;
1446
1447   g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
1448   g_return_val_if_fail (port1->tunneled && port2->tunneled, OMX_ErrorUndefined);
1449
1450   g_mutex_lock (&comp1->lock);
1451   g_mutex_lock (&comp2->lock);
1452   GST_DEBUG_OBJECT (comp1->parent,
1453       "Closing tunnel between %s port %u and %s port %u",
1454       comp1->name, port1->index, comp2->name, port2->index);
1455
1456   err = comp1->core->setup_tunnel (comp1->handle, port1->index, 0, 0);
1457   if (err != OMX_ErrorNone) {
1458     GST_ERROR_OBJECT (comp1->parent,
1459         "Failed to close tunnel on output side %s (0x%08x)",
1460         gst_omx_error_to_string (err), err);
1461   }
1462   err = comp2->core->setup_tunnel (0, 0, comp2->handle, port2->index);
1463   if (err != OMX_ErrorNone) {
1464     GST_ERROR_OBJECT (comp2->parent,
1465         "Failed to close tunnel on input side %s (0x%08x)",
1466         gst_omx_error_to_string (err), err);
1467   }
1468
1469   port1->tunneled = FALSE;
1470   port2->tunneled = FALSE;
1471
1472   GST_DEBUG_OBJECT (comp1->parent,
1473       "Closed tunnel between %s port %u and %s port %u",
1474       comp1->name, port1->index, comp2->name, port2->index);
1475
1476   g_mutex_unlock (&comp2->lock);
1477   g_mutex_unlock (&comp1->lock);
1478
1479   return err;
1480 }
1481
1482 OMX_ERRORTYPE
1483 gst_omx_port_get_port_definition (GstOMXPort * port,
1484     OMX_PARAM_PORTDEFINITIONTYPE * port_def)
1485 {
1486   GstOMXComponent *comp;
1487   OMX_ERRORTYPE err;
1488
1489   g_return_val_if_fail (port != NULL, OMX_ErrorBadParameter);
1490
1491   comp = port->comp;
1492
1493   GST_OMX_INIT_STRUCT (port_def);
1494   port_def->nPortIndex = port->index;
1495
1496   err = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1497       port_def);
1498
1499   return err;
1500 }
1501
1502 OMX_ERRORTYPE
1503 gst_omx_port_update_port_definition (GstOMXPort * port,
1504     OMX_PARAM_PORTDEFINITIONTYPE * port_def)
1505 {
1506   OMX_ERRORTYPE err_get, err_set = OMX_ErrorNone;
1507   GstOMXComponent *comp;
1508
1509   g_return_val_if_fail (port != NULL, FALSE);
1510
1511   comp = port->comp;
1512
1513   if (port_def)
1514     err_set =
1515         gst_omx_component_set_parameter (comp, OMX_IndexParamPortDefinition,
1516         port_def);
1517   err_get = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1518       &port->port_def);
1519
1520   DEBUG_IF_OK (comp->parent, err_set,
1521       "Updated %s port %u definition: %s (0x%08x)", comp->name, port->index,
1522       gst_omx_error_to_string (err_set), err_set);
1523
1524   if (err_set != OMX_ErrorNone)
1525     return err_set;
1526   else
1527     return err_get;
1528 }
1529
1530 /* NOTE: Uses comp->lock and comp->messages_lock */
1531 GstOMXAcquireBufferReturn
1532 gst_omx_port_acquire_buffer (GstOMXPort * port, GstOMXBuffer ** buf,
1533     GstOMXWait wait)
1534 {
1535   GstOMXAcquireBufferReturn ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
1536   GstOMXComponent *comp;
1537   OMX_ERRORTYPE err;
1538   GstOMXBuffer *_buf = NULL;
1539   gint64 timeout = GST_CLOCK_TIME_NONE;
1540
1541   g_return_val_if_fail (port != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
1542   g_return_val_if_fail (!port->tunneled, GST_OMX_ACQUIRE_BUFFER_ERROR);
1543   g_return_val_if_fail (buf != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
1544
1545   *buf = NULL;
1546
1547   comp = port->comp;
1548
1549   g_mutex_lock (&comp->lock);
1550   GST_DEBUG_OBJECT (comp->parent, "Acquiring %s buffer from port %u",
1551       comp->name, port->index);
1552
1553 retry:
1554   gst_omx_component_handle_messages (comp);
1555
1556   /* If we are in the case where we waited for a buffer after EOS,
1557    * make sure we don't do that again */
1558   if (timeout != -1)
1559     timeout = -2;
1560
1561   /* Check if the component is in an error state */
1562   if ((err = comp->last_error) != OMX_ErrorNone) {
1563     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s",
1564         comp->name, gst_omx_error_to_string (err));
1565     ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
1566     goto done;
1567   }
1568
1569   /* Check if the port is flushing */
1570   if (port->flushing) {
1571     GST_DEBUG_OBJECT (comp->parent, "Component %s port %d is flushing",
1572         comp->name, port->index);
1573     ret = GST_OMX_ACQUIRE_BUFFER_FLUSHING;
1574     goto done;
1575   }
1576
1577   /* If this is an input port and at least one of the output ports
1578    * needs to be reconfigured, we wait until all output ports are
1579    * reconfigured. Afterwards this port is reconfigured if required
1580    * or buffers are returned to be filled as usual.
1581    */
1582   if (port->port_def.eDir == OMX_DirInput) {
1583     if (comp->pending_reconfigure_outports) {
1584       gst_omx_component_handle_messages (comp);
1585       while (comp->pending_reconfigure_outports &&
1586           (err = comp->last_error) == OMX_ErrorNone && !port->flushing) {
1587         GST_DEBUG_OBJECT (comp->parent,
1588             "Waiting for %s output ports to reconfigure", comp->name);
1589         gst_omx_component_wait_message (comp, GST_CLOCK_TIME_NONE);
1590         gst_omx_component_handle_messages (comp);
1591       }
1592       goto retry;
1593     }
1594
1595     /* Only if this port needs to be reconfigured too notify
1596      * the caller about it */
1597     if (port->settings_cookie != port->configured_settings_cookie) {
1598       GST_DEBUG_OBJECT (comp->parent,
1599           "Component %s port %d needs reconfiguring", comp->name, port->index);
1600       ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
1601       goto done;
1602     }
1603   }
1604
1605   /* If we have an output port that needs to be reconfigured
1606    * and it still has buffers pending for the old configuration
1607    * we first return them.
1608    * NOTE: If buffers for this configuration arrive later
1609    * we have to drop them... */
1610   if (port->port_def.eDir == OMX_DirOutput &&
1611       port->settings_cookie != port->configured_settings_cookie) {
1612     if (!g_queue_is_empty (&port->pending_buffers)) {
1613       GST_DEBUG_OBJECT (comp->parent,
1614           "%s output port %u needs reconfiguration but has buffers pending",
1615           comp->name, port->index);
1616       _buf = g_queue_pop_head (&port->pending_buffers);
1617
1618       ret = GST_OMX_ACQUIRE_BUFFER_OK;
1619       goto done;
1620     }
1621
1622     GST_DEBUG_OBJECT (comp->parent, "Component %s port %d needs reconfiguring",
1623         comp->name, port->index);
1624     ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
1625     goto done;
1626   }
1627
1628   if (port->port_def.eDir == OMX_DirOutput && port->eos) {
1629     if (!g_queue_is_empty (&port->pending_buffers)) {
1630       GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but has "
1631           "buffers pending", comp->name, port->index);
1632       _buf = g_queue_pop_head (&port->pending_buffers);
1633
1634       ret = GST_OMX_ACQUIRE_BUFFER_OK;
1635       goto done;
1636     }
1637
1638     if (comp->hacks & GST_OMX_HACK_SIGNALS_PREMATURE_EOS && timeout != -2) {
1639       timeout = 33 * GST_MSECOND;
1640
1641       GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but waiting "
1642           "in case it spits out more buffers", comp->name, port->index);
1643     } else {
1644       GST_DEBUG_OBJECT (comp->parent, "Component %s port %d signalled EOS",
1645           comp->name, port->index);
1646       ret = GST_OMX_ACQUIRE_BUFFER_EOS;
1647       port->eos = FALSE;
1648       goto done;
1649     }
1650   }
1651
1652   /*
1653    * At this point we have no error or flushing/eos port
1654    * and a properly configured port.
1655    *
1656    */
1657
1658   /* If the queue is empty we wait until a buffer
1659    * arrives, an error happens, the port is flushing
1660    * or the port needs to be reconfigured.
1661    */
1662   if (g_queue_is_empty (&port->pending_buffers)) {
1663     GST_DEBUG_OBJECT (comp->parent, "Queue of %s port %u is empty",
1664         comp->name, port->index);
1665
1666     if (wait == GST_OMX_WAIT) {
1667       gst_omx_component_wait_message (comp,
1668           timeout == -2 ? GST_CLOCK_TIME_NONE : timeout);
1669
1670       /* And now check everything again and maybe get a buffer */
1671       goto retry;
1672     } else {
1673       ret = GST_OMX_ACQUIRE_BUFFER_NO_AVAILABLE;
1674       goto done;
1675     }
1676   }
1677
1678   GST_DEBUG_OBJECT (comp->parent, "%s port %u has pending buffers",
1679       comp->name, port->index);
1680   _buf = g_queue_pop_head (&port->pending_buffers);
1681   ret = GST_OMX_ACQUIRE_BUFFER_OK;
1682
1683 done:
1684   g_mutex_unlock (&comp->lock);
1685
1686   if (_buf) {
1687     g_assert (_buf == _buf->omx_buf->pAppPrivate);
1688     *buf = _buf;
1689   }
1690
1691   GST_DEBUG_OBJECT (comp->parent, "Acquired buffer %p (%p) from %s port %u: %d",
1692       _buf, (_buf ? _buf->omx_buf->pBuffer : NULL), comp->name, port->index,
1693       ret);
1694
1695   return ret;
1696 }
1697
1698 /* NOTE: Uses comp->lock and comp->messages_lock */
1699 OMX_ERRORTYPE
1700 gst_omx_port_release_buffer (GstOMXPort * port, GstOMXBuffer * buf)
1701 {
1702   GstOMXComponent *comp;
1703   OMX_ERRORTYPE err = OMX_ErrorNone;
1704
1705   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
1706   g_return_val_if_fail (!port->tunneled, OMX_ErrorUndefined);
1707   g_return_val_if_fail (buf != NULL, OMX_ErrorUndefined);
1708   g_return_val_if_fail (buf->port == port, OMX_ErrorUndefined);
1709
1710   comp = port->comp;
1711
1712   g_mutex_lock (&comp->lock);
1713
1714   GST_DEBUG_OBJECT (comp->parent, "Releasing buffer %p (%p) to %s port %u",
1715       buf, buf->omx_buf->pBuffer, comp->name, port->index);
1716
1717   gst_omx_component_handle_messages (comp);
1718
1719   if (port->port_def.eDir == OMX_DirOutput) {
1720     /* Reset all flags, some implementations don't
1721      * reset them themselves and the flags are not
1722      * valid anymore after the buffer was consumed
1723      */
1724     gst_omx_buffer_reset (buf);
1725   }
1726
1727   if ((err = comp->last_error) != OMX_ErrorNone) {
1728     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
1729         "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
1730     g_queue_push_tail (&port->pending_buffers, buf);
1731     gst_omx_component_send_message (comp, NULL);
1732     goto done;
1733   }
1734
1735   if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
1736     GST_DEBUG_OBJECT (comp->parent,
1737         "%s port %u is flushing or disabled, not releasing " "buffer",
1738         comp->name, port->index);
1739     g_queue_push_tail (&port->pending_buffers, buf);
1740     gst_omx_component_send_message (comp, NULL);
1741     goto done;
1742   }
1743
1744   g_assert (buf == buf->omx_buf->pAppPrivate);
1745
1746   /* FIXME: What if the settings cookies don't match? */
1747
1748   buf->used = TRUE;
1749
1750   if (port->port_def.eDir == OMX_DirInput) {
1751     log_omx_performance_buffer (comp, "EmptyThisBuffer", buf);
1752     err = OMX_EmptyThisBuffer (comp->handle, buf->omx_buf);
1753   } else {
1754     log_omx_performance_buffer (comp, "FillThisBuffer", buf);
1755     err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
1756   }
1757   DEBUG_IF_OK (comp->parent, err, "Released buffer %p to %s port %u: %s "
1758       "(0x%08x)", buf, comp->name, port->index, gst_omx_error_to_string (err),
1759       err);
1760
1761 done:
1762   gst_omx_component_handle_messages (comp);
1763   g_mutex_unlock (&comp->lock);
1764
1765   return err;
1766 }
1767
1768 /* NOTE: Must be called while holding comp->lock */
1769 static gboolean
1770 should_wait_until_flushed (GstOMXPort * port)
1771 {
1772   if (!port->flushed)
1773     /* Flush command hasn't been completed yet by OMX */
1774     return TRUE;
1775
1776   if (port->buffers) {
1777     guint i;
1778
1779     /* Wait for all the buffers used by OMX to be released */
1780     for (i = 0; i < port->buffers->len; i++) {
1781       GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
1782
1783       if (buf->used)
1784         return TRUE;
1785     }
1786   }
1787
1788   return FALSE;
1789 }
1790
1791 /* NOTE: Uses comp->lock and comp->messages_lock */
1792 OMX_ERRORTYPE
1793 gst_omx_port_set_flushing (GstOMXPort * port, GstClockTime timeout,
1794     gboolean flush)
1795 {
1796   GstOMXComponent *comp;
1797   OMX_ERRORTYPE err = OMX_ErrorNone;
1798
1799   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
1800
1801   comp = port->comp;
1802
1803   g_mutex_lock (&comp->lock);
1804
1805   GST_DEBUG_OBJECT (comp->parent, "Setting %s port %d to %sflushing",
1806       comp->name, port->index, (flush ? "" : "not "));
1807
1808   gst_omx_component_handle_messages (comp);
1809
1810   if (! !flush == ! !port->flushing) {
1811     GST_DEBUG_OBJECT (comp->parent, "%s port %u was %sflushing already",
1812         comp->name, port->index, (flush ? "" : "not "));
1813     goto done;
1814   }
1815
1816   if ((err = comp->last_error) != OMX_ErrorNone) {
1817     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
1818         "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
1819     goto done;
1820   }
1821
1822   port->flushing = flush;
1823   if (flush) {
1824     gboolean signalled;
1825     OMX_ERRORTYPE last_error;
1826
1827     gst_omx_component_send_message (comp, NULL);
1828
1829     /* Now flush the port */
1830     port->flushed = FALSE;
1831
1832     err =
1833         gst_omx_component_send_command (comp, OMX_CommandFlush, port->index,
1834         NULL);
1835
1836     if (err != OMX_ErrorNone) {
1837       GST_ERROR_OBJECT (comp->parent,
1838           "Error sending flush command to %s port %u: %s (0x%08x)", comp->name,
1839           port->index, gst_omx_error_to_string (err), err);
1840       goto done;
1841     }
1842
1843     if ((err = comp->last_error) != OMX_ErrorNone) {
1844       GST_ERROR_OBJECT (comp->parent,
1845           "Component %s is in error state: %s (0x%08x)", comp->name,
1846           gst_omx_error_to_string (err), err);
1847       goto done;
1848     }
1849
1850     if (! !port->flushing != ! !flush) {
1851       GST_ERROR_OBJECT (comp->parent, "%s: another flush happened in the "
1852           " meantime", comp->name);
1853       goto done;
1854     }
1855
1856     if (timeout == 0) {
1857       if (should_wait_until_flushed (port))
1858         err = OMX_ErrorTimeout;
1859       goto done;
1860     }
1861
1862     /* Retry until timeout or until an error happend or
1863      * until all buffers were released by the component and
1864      * the flush command completed */
1865     signalled = TRUE;
1866     last_error = OMX_ErrorNone;
1867     gst_omx_component_handle_messages (comp);
1868     while (should_wait_until_flushed (port)) {
1869       signalled = gst_omx_component_wait_message (comp, timeout);
1870       if (signalled)
1871         gst_omx_component_handle_messages (comp);
1872
1873       last_error = comp->last_error;
1874
1875       if (!signalled || last_error != OMX_ErrorNone)
1876         /* Something gone wrong or we timed out */
1877         break;
1878     }
1879     port->flushed = FALSE;
1880
1881     GST_DEBUG_OBJECT (comp->parent, "%s port %d flushed", comp->name,
1882         port->index);
1883     if (last_error != OMX_ErrorNone) {
1884       GST_ERROR_OBJECT (comp->parent,
1885           "Got error while flushing %s port %u: %s (0x%08x)", comp->name,
1886           port->index, gst_omx_error_to_string (last_error), last_error);
1887       err = last_error;
1888       goto done;
1889     } else if (!signalled) {
1890       GST_ERROR_OBJECT (comp->parent, "Timeout while flushing %s port %u",
1891           comp->name, port->index);
1892       err = OMX_ErrorTimeout;
1893       goto done;
1894     }
1895   }
1896
1897   /* Reset EOS flag */
1898   port->eos = FALSE;
1899
1900 done:
1901   gst_omx_port_update_port_definition (port, NULL);
1902
1903   DEBUG_IF_OK (comp->parent, err, "Set %s port %u to %sflushing: %s (0x%08x)",
1904       comp->name, port->index, (flush ? "" : "not "),
1905       gst_omx_error_to_string (err), err);
1906   gst_omx_component_handle_messages (comp);
1907   g_mutex_unlock (&comp->lock);
1908
1909   return err;
1910 }
1911
1912 /* NOTE: Uses comp->lock and comp->messages_lock */
1913 gboolean
1914 gst_omx_port_is_flushing (GstOMXPort * port)
1915 {
1916   GstOMXComponent *comp;
1917   gboolean flushing;
1918
1919   g_return_val_if_fail (port != NULL, FALSE);
1920
1921   comp = port->comp;
1922
1923   g_mutex_lock (&comp->lock);
1924   gst_omx_component_handle_messages (port->comp);
1925   flushing = port->flushing;
1926   g_mutex_unlock (&comp->lock);
1927
1928   GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing: %d", comp->name,
1929       port->index, flushing);
1930
1931   return flushing;
1932 }
1933
1934 static OMX_ERRORTYPE gst_omx_port_deallocate_buffers_unlocked (GstOMXPort *
1935     port);
1936
1937 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
1938 static OMX_ERRORTYPE
1939 gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port,
1940     const GList * buffers, const GList * images, guint n)
1941 {
1942   GstOMXComponent *comp;
1943   OMX_ERRORTYPE err = OMX_ErrorNone;
1944   gint i;
1945   const GList *l;
1946
1947   g_assert (!port->buffers || port->buffers->len == 0);
1948
1949   g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
1950
1951   comp = port->comp;
1952
1953   gst_omx_component_handle_messages (port->comp);
1954   if ((err = comp->last_error) != OMX_ErrorNone) {
1955     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
1956         comp->name, gst_omx_error_to_string (err), err);
1957     goto done;
1958   }
1959
1960   /* Update the port definition to check if we need more
1961    * buffers after the port configuration was done and to
1962    * update the buffer size
1963    */
1964   gst_omx_port_update_port_definition (port, NULL);
1965
1966   g_return_val_if_fail (n != -1 || (!buffers
1967           && !images), OMX_ErrorBadParameter);
1968
1969   if (n == -1)
1970     n = port->port_def.nBufferCountActual;
1971
1972   g_return_val_if_fail (n == port->port_def.nBufferCountActual,
1973       OMX_ErrorBadParameter);
1974
1975   GST_INFO_OBJECT (comp->parent,
1976       "Allocating %d buffers of size %" G_GSIZE_FORMAT " for %s port %u", n,
1977       (size_t) port->port_def.nBufferSize, comp->name, (guint) port->index);
1978
1979   if (!port->buffers)
1980     port->buffers = g_ptr_array_sized_new (n);
1981
1982   l = (buffers ? buffers : images);
1983   for (i = 0; i < n; i++) {
1984     GstOMXBuffer *buf;
1985
1986     buf = g_slice_new0 (GstOMXBuffer);
1987     buf->port = port;
1988     buf->used = FALSE;
1989     buf->settings_cookie = port->settings_cookie;
1990     g_ptr_array_add (port->buffers, buf);
1991
1992     if (buffers) {
1993       err =
1994           OMX_UseBuffer (comp->handle, &buf->omx_buf, port->index, buf,
1995           port->port_def.nBufferSize, l->data);
1996       buf->eglimage = FALSE;
1997     } else if (images) {
1998       err =
1999           OMX_UseEGLImage (comp->handle, &buf->omx_buf, port->index, buf,
2000           l->data);
2001       buf->eglimage = TRUE;
2002     } else {
2003       err =
2004           OMX_AllocateBuffer (comp->handle, &buf->omx_buf, port->index, buf,
2005           port->port_def.nBufferSize);
2006       buf->eglimage = FALSE;
2007     }
2008
2009     /* Let the caller decide to print an error when OMX_UseBuffer or
2010      * OMX_UseEGLImage fail. Indeed it can be part of a trial path. So
2011      * it is not necessary to warn the user if the fallback path succeeds.
2012      */
2013     if (err != OMX_ErrorNone) {
2014       GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, (buffers
2015               || images) ? GST_LEVEL_INFO : GST_LEVEL_ERROR, comp->parent,
2016           "Failed to allocate buffer for %s port %u: %s (0x%08x)", comp->name,
2017           port->index, gst_omx_error_to_string (err), err);
2018       gst_omx_port_deallocate_buffers_unlocked (port);
2019       goto done;
2020     }
2021
2022     GST_DEBUG_OBJECT (comp->parent, "%s: allocated buffer %p (%p)",
2023         comp->name, buf, buf->omx_buf->pBuffer);
2024
2025     g_assert (buf->omx_buf->pAppPrivate == buf);
2026
2027     /* In the beginning all buffers are not owned by the component */
2028     g_queue_push_tail (&port->pending_buffers, buf);
2029     if (buffers || images)
2030       l = l->next;
2031   }
2032
2033   gst_omx_component_handle_messages (comp);
2034
2035 done:
2036   gst_omx_port_update_port_definition (port, NULL);
2037
2038   INFO_IF_OK (comp->parent, err, "Allocated buffers for %s port %u: %s "
2039       "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2040
2041   return err;
2042 }
2043
2044 /* NOTE: Uses comp->lock and comp->messages_lock */
2045 OMX_ERRORTYPE
2046 gst_omx_port_allocate_buffers (GstOMXPort * port)
2047 {
2048   OMX_ERRORTYPE err;
2049
2050   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2051
2052   g_mutex_lock (&port->comp->lock);
2053   err = gst_omx_port_allocate_buffers_unlocked (port, NULL, NULL, -1);
2054   port->allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2055   g_mutex_unlock (&port->comp->lock);
2056
2057   return err;
2058 }
2059
2060 /* NOTE: Uses comp->lock and comp->messages_lock */
2061 OMX_ERRORTYPE
2062 gst_omx_port_use_buffers (GstOMXPort * port, const GList * buffers)
2063 {
2064   OMX_ERRORTYPE err;
2065   guint n;
2066
2067   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2068
2069   g_mutex_lock (&port->comp->lock);
2070   n = g_list_length ((GList *) buffers);
2071   err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
2072   port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER;
2073   g_mutex_unlock (&port->comp->lock);
2074
2075   return err;
2076 }
2077
2078 gboolean
2079 gst_omx_is_dynamic_allocation_supported (void)
2080 {
2081   /* The Zynqultrascaleplus stack implements OMX 1.1.0 but supports the dynamic
2082    * allocation mode from 1.2.0 as an extension. */
2083 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2084   return TRUE;
2085 #endif
2086
2087 #if OMX_VERSION_MINOR == 2
2088   return TRUE;
2089 #else
2090   return FALSE;
2091 #endif
2092 }
2093
2094 /* OMX 1.2.0 introduced a dynamic allocation mode where only buffer headers are
2095  * being allocated during component's initialization. The actual buffers are
2096  * allocated upstream and passed to OMX by setting the pBuffer dynamically
2097  * for each input buffer.
2098  *
2099  * This function takes care of allocating the buffer headers. Element should
2100  * then use one of the gst_omx_buffer_map_*() method to update buffer's pBuffer
2101  * pointers for each incoming buffer.
2102  *
2103  * NOTE: Uses comp->lock and comp->messages_lock */
2104 OMX_ERRORTYPE
2105 gst_omx_port_use_dynamic_buffers (GstOMXPort * port)
2106 {
2107   OMX_ERRORTYPE err;
2108   GList *buffers = NULL;
2109   guint i, n;
2110
2111   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2112
2113   n = port->port_def.nBufferCountActual;
2114   for (i = 0; i < port->port_def.nBufferCountActual; i++)
2115     /* Pass NULL to UseBuffer() as the buffer is dynamic and so its payload
2116      * will be set each time before being passed to OMX. */
2117     buffers = g_list_prepend (buffers, GUINT_TO_POINTER (NULL));
2118
2119   g_mutex_lock (&port->comp->lock);
2120   err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
2121   port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
2122   g_mutex_unlock (&port->comp->lock);
2123
2124   g_list_free (buffers);
2125
2126   return err;
2127 }
2128
2129 /* gst_omx_buffer_map_* methods are used in dynamic buffer mode to map
2130  * a frame/memory/buffer and update @buffer so its pBuffer points to the
2131  * mapped data. It also ensures that the input will stay alive until
2132  * gst_omx_buffer_unmap() is called.
2133  * This is used in OMX 1.2.0 dynamic allocation mode so an OMX component can
2134  * safely process @buffer's content without having to copy it.
2135  * The input will be automatically unmapped when @buffer is released by OMX.
2136  */
2137 gboolean
2138 gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input,
2139     GstVideoInfo * info)
2140 {
2141   g_return_val_if_fail (buffer != NULL, FALSE);
2142   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2143   g_return_val_if_fail (!buffer->input_mem, FALSE);
2144   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2145   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2146
2147   if (!gst_video_frame_map (&buffer->input_frame, info, input, GST_MAP_READ))
2148     return FALSE;
2149
2150   buffer->input_frame_mapped = TRUE;
2151   buffer->omx_buf->pBuffer =
2152       GST_VIDEO_FRAME_PLANE_DATA (&buffer->input_frame, 0);
2153   buffer->omx_buf->nAllocLen = gst_buffer_get_size (input);
2154   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2155
2156   return TRUE;
2157 }
2158
2159 gboolean
2160 gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
2161 {
2162   g_return_val_if_fail (buffer != NULL, FALSE);
2163   g_return_val_if_fail (mem != NULL, FALSE);
2164   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2165   g_return_val_if_fail (!buffer->input_mem, FALSE);
2166   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2167   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2168
2169   if (!gst_memory_map (mem, &buffer->map, GST_MAP_READ))
2170     return FALSE;
2171
2172   buffer->input_mem = gst_memory_ref (mem);
2173   buffer->omx_buf->pBuffer = buffer->map.data;
2174   buffer->omx_buf->nAllocLen = buffer->map.size;
2175   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2176
2177   return TRUE;
2178 }
2179
2180 gboolean
2181 gst_omx_buffer_import_fd (GstOMXBuffer * buffer, GstBuffer * input)
2182 {
2183   gint fd;
2184   GstMemory *mem;
2185
2186   g_return_val_if_fail (buffer != NULL, FALSE);
2187   g_return_val_if_fail (input != NULL, FALSE);
2188   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2189   g_return_val_if_fail (!buffer->input_mem, FALSE);
2190   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2191   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2192
2193   mem = gst_buffer_peek_memory (input, 0);
2194   g_return_val_if_fail (gst_is_dmabuf_memory (mem), FALSE);
2195
2196   fd = gst_dmabuf_memory_get_fd (mem);
2197
2198   buffer->input_buffer = gst_buffer_ref (input);
2199   buffer->omx_buf->pBuffer = GUINT_TO_POINTER (fd);
2200   buffer->omx_buf->nAllocLen = gst_memory_get_sizes (mem, NULL, NULL);
2201   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2202
2203   return TRUE;
2204 }
2205
2206 gboolean
2207 gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
2208 {
2209   g_return_val_if_fail (buffer != NULL, FALSE);
2210   g_return_val_if_fail (input != NULL, FALSE);
2211   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2212   g_return_val_if_fail (!buffer->input_mem, FALSE);
2213   g_return_val_if_fail (!buffer->input_buffer, FALSE);
2214   g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2215
2216   if (!gst_buffer_map (input, &buffer->map, GST_MAP_READ))
2217     return FALSE;
2218
2219   buffer->input_buffer_mapped = TRUE;
2220   buffer->input_buffer = gst_buffer_ref (input);
2221   buffer->omx_buf->pBuffer = buffer->map.data;
2222   buffer->omx_buf->nAllocLen = buffer->map.size;
2223   buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2224
2225   return TRUE;
2226 }
2227
2228 /* NOTE: Uses comp->lock and comp->messages_lock */
2229 OMX_ERRORTYPE
2230 gst_omx_port_use_eglimages (GstOMXPort * port, const GList * images)
2231 {
2232   OMX_ERRORTYPE err;
2233   guint n;
2234
2235   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2236
2237   g_mutex_lock (&port->comp->lock);
2238   n = g_list_length ((GList *) images);
2239   err = gst_omx_port_allocate_buffers_unlocked (port, NULL, images, n);
2240   g_mutex_unlock (&port->comp->lock);
2241
2242   return err;
2243 }
2244
2245 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2246 static OMX_ERRORTYPE
2247 gst_omx_port_deallocate_buffers_unlocked (GstOMXPort * port)
2248 {
2249   GstOMXComponent *comp;
2250   OMX_ERRORTYPE err = OMX_ErrorNone;
2251   gint i, n;
2252
2253   g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
2254
2255   comp = port->comp;
2256
2257   GST_INFO_OBJECT (comp->parent, "Deallocating buffers of %s port %u",
2258       comp->name, port->index);
2259
2260   gst_omx_component_handle_messages (port->comp);
2261
2262   if (!port->buffers) {
2263     GST_DEBUG_OBJECT (comp->parent, "No buffers allocated for %s port %u",
2264         comp->name, port->index);
2265     goto done;
2266   }
2267
2268   if ((err = comp->last_error) != OMX_ErrorNone) {
2269     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2270         comp->name, gst_omx_error_to_string (err), err);
2271     /* We still try to deallocate all buffers */
2272   }
2273
2274   /* We only allow deallocation of buffers after they
2275    * were all released from the port, either by flushing
2276    * the port or by disabling it.
2277    */
2278   n = port->buffers->len;
2279   for (i = 0; i < n; i++) {
2280     GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
2281     OMX_ERRORTYPE tmp = OMX_ErrorNone;
2282
2283     if (buf->used) {
2284       GST_ERROR_OBJECT (comp->parent, "Trying to free used buffer %p of %s "
2285           "port %u", buf, comp->name, port->index);
2286     }
2287
2288     /* omx_buf can be NULL if allocation failed earlier
2289      * and we're just shutting down
2290      *
2291      * errors do not cause exiting this loop because we want
2292      * to deallocate as much as possible.
2293      */
2294     if (buf->omx_buf) {
2295       g_assert (buf == buf->omx_buf->pAppPrivate);
2296       buf->omx_buf->pAppPrivate = NULL;
2297       GST_DEBUG_OBJECT (comp->parent, "%s: deallocating buffer %p (%p)",
2298           comp->name, buf, buf->omx_buf->pBuffer);
2299
2300       tmp = OMX_FreeBuffer (comp->handle, port->index, buf->omx_buf);
2301
2302       if (tmp != OMX_ErrorNone) {
2303         GST_ERROR_OBJECT (comp->parent,
2304             "Failed to deallocate buffer %d of %s port %u: %s (0x%08x)", i,
2305             comp->name, port->index, gst_omx_error_to_string (tmp), tmp);
2306         if (err == OMX_ErrorNone)
2307           err = tmp;
2308       }
2309     }
2310     g_slice_free (GstOMXBuffer, buf);
2311   }
2312   g_queue_clear (&port->pending_buffers);
2313   g_ptr_array_unref (port->buffers);
2314   port->buffers = NULL;
2315
2316   gst_omx_component_handle_messages (comp);
2317
2318 done:
2319   gst_omx_port_update_port_definition (port, NULL);
2320
2321   DEBUG_IF_OK (comp->parent, err, "Deallocated buffers of %s port %u: %s "
2322       "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2323
2324   return err;
2325 }
2326
2327 /* NOTE: Uses comp->lock and comp->messages_lock */
2328 OMX_ERRORTYPE
2329 gst_omx_port_deallocate_buffers (GstOMXPort * port)
2330 {
2331   OMX_ERRORTYPE err;
2332
2333   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2334
2335   g_mutex_lock (&port->comp->lock);
2336   err = gst_omx_port_deallocate_buffers_unlocked (port);
2337   g_mutex_unlock (&port->comp->lock);
2338
2339   return err;
2340 }
2341
2342 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2343 static OMX_ERRORTYPE
2344 gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled)
2345 {
2346   GstOMXComponent *comp;
2347   OMX_ERRORTYPE err = OMX_ErrorNone;
2348
2349   comp = port->comp;
2350
2351   gst_omx_component_handle_messages (comp);
2352
2353   if ((err = comp->last_error) != OMX_ErrorNone) {
2354     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2355         comp->name, gst_omx_error_to_string (err), err);
2356     goto done;
2357   }
2358
2359   if (port->enabled_pending || port->disabled_pending) {
2360     GST_ERROR_OBJECT (comp->parent, "%s port %d enabled/disabled pending "
2361         "already", comp->name, port->index);
2362 #if OMX_VERSION_MINOR == 2
2363     err = OMX_ErrorBadParameter;
2364 #else
2365     err = OMX_ErrorInvalidState;
2366 #endif
2367     goto done;
2368   }
2369
2370   GST_INFO_OBJECT (comp->parent, "Setting %s port %u to %s", comp->name,
2371       port->index, (enabled ? "enabled" : "disabled"));
2372
2373   /* Check if the port is already enabled/disabled first */
2374   gst_omx_port_update_port_definition (port, NULL);
2375   if (! !port->port_def.bEnabled == ! !enabled)
2376     goto done;
2377
2378   if (enabled)
2379     port->enabled_pending = TRUE;
2380   else
2381     port->disabled_pending = TRUE;
2382
2383   if (enabled)
2384     err =
2385         gst_omx_component_send_command (comp, OMX_CommandPortEnable,
2386         port->index, NULL);
2387   else
2388     err =
2389         gst_omx_component_send_command (comp, OMX_CommandPortDisable,
2390         port->index, NULL);
2391
2392   if (err != OMX_ErrorNone) {
2393     GST_ERROR_OBJECT (comp->parent,
2394         "Failed to send enable/disable command to %s port %u: %s (0x%08x)",
2395         comp->name, port->index, gst_omx_error_to_string (err), err);
2396     goto done;
2397   }
2398
2399   if ((err = comp->last_error) != OMX_ErrorNone) {
2400     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2401         comp->name, gst_omx_error_to_string (err), err);
2402     goto done;
2403   }
2404
2405 done:
2406   gst_omx_component_handle_messages (comp);
2407
2408   gst_omx_port_update_port_definition (port, NULL);
2409
2410   INFO_IF_OK (comp->parent, err, "Set %s port %u to %s%s: %s (0x%08x)",
2411       comp->name, port->index, (err == OMX_ErrorNone ? "" : "not "),
2412       (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
2413
2414   return err;
2415 }
2416
2417 static OMX_ERRORTYPE
2418 gst_omx_port_wait_buffers_released_unlocked (GstOMXPort * port,
2419     GstClockTime timeout)
2420 {
2421   GstOMXComponent *comp;
2422   OMX_ERRORTYPE err = OMX_ErrorNone;
2423   OMX_ERRORTYPE last_error;
2424   gboolean signalled;
2425
2426   comp = port->comp;
2427
2428   gst_omx_component_handle_messages (comp);
2429
2430   if ((err = comp->last_error) != OMX_ErrorNone) {
2431     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2432         comp->name, gst_omx_error_to_string (err), err);
2433     goto done;
2434   }
2435
2436   GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to release all "
2437       "buffers", comp->name, port->index);
2438
2439   if (timeout == 0) {
2440     if (!port->flushed || (port->buffers
2441             && port->buffers->len >
2442             g_queue_get_length (&port->pending_buffers)))
2443       err = OMX_ErrorTimeout;
2444     goto done;
2445   }
2446
2447   /* Wait until all buffers are released by the port */
2448   signalled = TRUE;
2449   last_error = OMX_ErrorNone;
2450   gst_omx_component_handle_messages (comp);
2451   while (signalled && last_error == OMX_ErrorNone && (port->buffers
2452           && port->buffers->len >
2453           g_queue_get_length (&port->pending_buffers))) {
2454     signalled = gst_omx_component_wait_message (comp, timeout);
2455     if (signalled)
2456       gst_omx_component_handle_messages (comp);
2457     last_error = comp->last_error;
2458   }
2459
2460   if (last_error != OMX_ErrorNone) {
2461     err = last_error;
2462     GST_ERROR_OBJECT (comp->parent,
2463         "Got error while waiting for %s port %u to release all buffers: %s "
2464         "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err),
2465         err);
2466     goto done;
2467   } else if (!signalled) {
2468     GST_ERROR_OBJECT (comp->parent, "Timeout waiting for %s port %u to "
2469         "release all buffers", comp->name, port->index);
2470     err = OMX_ErrorTimeout;
2471     goto done;
2472   }
2473
2474 done:
2475   gst_omx_component_handle_messages (comp);
2476
2477   gst_omx_port_update_port_definition (port, NULL);
2478
2479   DEBUG_IF_OK (comp->parent, err,
2480       "Waited for %s port %u to release all buffers: %s (0x%08x)", comp->name,
2481       port->index, gst_omx_error_to_string (err), err);
2482
2483   return err;
2484 }
2485
2486 /* NOTE: Uses comp->lock and comp->messages_lock */
2487 OMX_ERRORTYPE
2488 gst_omx_port_wait_buffers_released (GstOMXPort * port, GstClockTime timeout)
2489 {
2490   OMX_ERRORTYPE err;
2491
2492   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2493
2494   g_mutex_lock (&port->comp->lock);
2495   err = gst_omx_port_wait_buffers_released_unlocked (port, timeout);
2496   g_mutex_unlock (&port->comp->lock);
2497
2498   return err;
2499 }
2500
2501 /* NOTE: Uses comp->lock and comp->messages_lock */
2502 OMX_ERRORTYPE
2503 gst_omx_port_set_enabled (GstOMXPort * port, gboolean enabled)
2504 {
2505   OMX_ERRORTYPE err;
2506
2507   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2508
2509   g_mutex_lock (&port->comp->lock);
2510   err = gst_omx_port_set_enabled_unlocked (port, enabled);
2511   g_mutex_unlock (&port->comp->lock);
2512
2513   return err;
2514 }
2515
2516 static OMX_ERRORTYPE
2517 gst_omx_port_populate_unlocked (GstOMXPort * port)
2518 {
2519   GstOMXComponent *comp;
2520   OMX_ERRORTYPE err = OMX_ErrorNone;
2521   GstOMXBuffer *buf;
2522
2523   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2524
2525   comp = port->comp;
2526
2527   GST_DEBUG_OBJECT (comp->parent, "Populating %s port %d", comp->name,
2528       port->index);
2529
2530   gst_omx_component_handle_messages (comp);
2531
2532   if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
2533     GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing or disabled",
2534         comp->name, port->index);
2535     err = OMX_ErrorIncorrectStateOperation;
2536     goto done;
2537   }
2538
2539   if ((err = comp->last_error) != OMX_ErrorNone) {
2540     GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s"
2541         "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
2542     goto done;
2543   }
2544
2545   if (port->port_def.eDir == OMX_DirOutput && port->buffers && !port->tunneled) {
2546     /* Enqueue all buffers for the component to fill */
2547     while ((buf = g_queue_pop_head (&port->pending_buffers))) {
2548       g_assert (!buf->used);
2549
2550       /* Reset all flags, some implementations don't
2551        * reset them themselves and the flags are not
2552        * valid anymore after the buffer was consumed.
2553        * Also reset nFilledLen as FillThisBuffer() expects an empty buffer.
2554        */
2555       gst_omx_buffer_reset (buf);
2556
2557       log_omx_performance_buffer (comp, "FillThisBuffer", buf);
2558       err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
2559
2560       if (err != OMX_ErrorNone) {
2561         GST_ERROR_OBJECT (comp->parent,
2562             "Failed to pass buffer %p (%p) to %s port %u: %s (0x%08x)", buf,
2563             buf->omx_buf->pBuffer, comp->name, port->index,
2564             gst_omx_error_to_string (err), err);
2565         goto done;
2566       }
2567       GST_DEBUG_OBJECT (comp->parent, "Passed buffer %p (%p) to component %s",
2568           buf, buf->omx_buf->pBuffer, comp->name);
2569     }
2570   }
2571
2572 done:
2573   gst_omx_port_update_port_definition (port, NULL);
2574
2575   DEBUG_IF_OK (comp->parent, err, "Populated %s port %u: %s (0x%08x)",
2576       comp->name, port->index, gst_omx_error_to_string (err), err);
2577   gst_omx_component_handle_messages (comp);
2578
2579   return err;
2580 }
2581
2582 /* NOTE: Uses comp->lock and comp->messages_lock */
2583 OMX_ERRORTYPE
2584 gst_omx_port_populate (GstOMXPort * port)
2585 {
2586   OMX_ERRORTYPE err;
2587
2588   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2589
2590   g_mutex_lock (&port->comp->lock);
2591   err = gst_omx_port_populate_unlocked (port);
2592   g_mutex_unlock (&port->comp->lock);
2593
2594   return err;
2595 }
2596
2597 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2598 static OMX_ERRORTYPE
2599 gst_omx_port_wait_enabled_unlocked (GstOMXPort * port, GstClockTime timeout)
2600 {
2601   GstOMXComponent *comp;
2602   OMX_ERRORTYPE err = OMX_ErrorNone;
2603   gboolean signalled;
2604   OMX_ERRORTYPE last_error;
2605   gboolean enabled;
2606
2607   comp = port->comp;
2608
2609   /* Check the current port status */
2610   gst_omx_port_update_port_definition (port, NULL);
2611
2612   if (port->enabled_pending)
2613     enabled = TRUE;
2614   else if (port->disabled_pending)
2615     enabled = FALSE;
2616   else
2617     enabled = port->port_def.bEnabled;
2618
2619   gst_omx_component_handle_messages (comp);
2620
2621   if ((err = comp->last_error) != OMX_ErrorNone) {
2622     GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2623         comp->name, gst_omx_error_to_string (err), err);
2624     goto done;
2625   }
2626
2627   GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to be %s",
2628       comp->name, port->index, (enabled ? "enabled" : "disabled"));
2629
2630   if (timeout == 0) {
2631     if (port->enabled_pending || port->disabled_pending)
2632       err = OMX_ErrorTimeout;
2633     goto done;
2634   }
2635
2636   /* And now wait until the enable/disable command is finished */
2637   signalled = TRUE;
2638   last_error = OMX_ErrorNone;
2639   gst_omx_port_update_port_definition (port, NULL);
2640   gst_omx_component_handle_messages (comp);
2641   while (signalled && last_error == OMX_ErrorNone &&
2642       (! !port->port_def.bEnabled != ! !enabled || port->enabled_pending
2643           || port->disabled_pending)) {
2644     signalled = gst_omx_component_wait_message (comp, timeout);
2645     if (signalled)
2646       gst_omx_component_handle_messages (comp);
2647     last_error = comp->last_error;
2648     gst_omx_port_update_port_definition (port, NULL);
2649   }
2650   port->enabled_pending = FALSE;
2651   port->disabled_pending = FALSE;
2652
2653   if (!signalled) {
2654     GST_ERROR_OBJECT (comp->parent,
2655         "Timeout waiting for %s port %u to be %s", comp->name, port->index,
2656         (enabled ? "enabled" : "disabled"));
2657     err = OMX_ErrorTimeout;
2658     goto done;
2659   } else if (last_error != OMX_ErrorNone) {
2660     GST_ERROR_OBJECT (comp->parent,
2661         "Got error while waiting for %s port %u to be %s: %s (0x%08x)",
2662         comp->name, port->index, (enabled ? "enabled" : "disabled"),
2663         gst_omx_error_to_string (err), err);
2664     err = last_error;
2665   } else {
2666     if (enabled) {
2667       /* Reset EOS flag */
2668       port->eos = FALSE;
2669     }
2670   }
2671
2672   gst_omx_component_handle_messages (comp);
2673
2674 done:
2675   gst_omx_port_update_port_definition (port, NULL);
2676
2677   GST_INFO_OBJECT (comp->parent, "%s port %u is %s%s: %s (0x%08x)", comp->name,
2678       port->index, (err == OMX_ErrorNone ? "" : "not "),
2679       (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
2680
2681   return err;
2682 }
2683
2684 /* NOTE: Uses comp->lock and comp->messages_lock */
2685 OMX_ERRORTYPE
2686 gst_omx_port_wait_enabled (GstOMXPort * port, GstClockTime timeout)
2687 {
2688   OMX_ERRORTYPE err;
2689
2690   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2691
2692   g_mutex_lock (&port->comp->lock);
2693   err = gst_omx_port_wait_enabled_unlocked (port, timeout);
2694   g_mutex_unlock (&port->comp->lock);
2695
2696   return err;
2697 }
2698
2699 gboolean
2700 gst_omx_port_is_enabled (GstOMXPort * port)
2701 {
2702   gboolean enabled;
2703
2704   g_return_val_if_fail (port != NULL, FALSE);
2705
2706   gst_omx_port_update_port_definition (port, NULL);
2707   enabled = ! !port->port_def.bEnabled;
2708
2709   GST_DEBUG_OBJECT (port->comp->parent, "%s port %u is enabled: %d",
2710       port->comp->name, port->index, enabled);
2711
2712   return enabled;
2713 }
2714
2715 /* NOTE: Uses comp->lock and comp->messages_lock */
2716 OMX_ERRORTYPE
2717 gst_omx_port_mark_reconfigured (GstOMXPort * port)
2718 {
2719   GstOMXComponent *comp;
2720   OMX_ERRORTYPE err = OMX_ErrorNone;
2721
2722   g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2723
2724   comp = port->comp;
2725
2726   g_mutex_lock (&comp->lock);
2727   GST_INFO_OBJECT (comp->parent, "Marking %s port %u is reconfigured",
2728       comp->name, port->index);
2729
2730   gst_omx_component_handle_messages (comp);
2731
2732   if ((err = comp->last_error) != OMX_ErrorNone)
2733     goto done;
2734
2735   port->configured_settings_cookie = port->settings_cookie;
2736
2737   if (port->port_def.eDir == OMX_DirOutput) {
2738     GList *l;
2739
2740     for (l = comp->pending_reconfigure_outports; l; l = l->next) {
2741       if (l->data == (gpointer) port) {
2742         comp->pending_reconfigure_outports =
2743             g_list_delete_link (comp->pending_reconfigure_outports, l);
2744         break;
2745       }
2746     }
2747     if (!comp->pending_reconfigure_outports)
2748       gst_omx_component_send_message (comp, NULL);
2749   }
2750
2751 done:
2752   gst_omx_port_update_port_definition (port, NULL);
2753
2754   INFO_IF_OK (comp->parent, err, "Marked %s port %u as reconfigured: %s "
2755       "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2756
2757   g_mutex_unlock (&comp->lock);
2758
2759   return err;
2760 }
2761
2762 /* The OMX specs states that the nBufferCountActual of a port has to default
2763  * to its nBufferCountMin. If we don't change nBufferCountActual we purely rely
2764  * on this default. But in some cases, OMX may change nBufferCountMin before we
2765  * allocate buffers. Like for example when configuring the input ports with the
2766  * actual format, it may decrease the number of minimal buffers required.
2767  * This method checks this and update nBufferCountActual if needed so we'll use
2768  * less buffers than the worst case in such scenarios.
2769  */
2770 gboolean
2771 gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port, guint extra)
2772 {
2773   OMX_PARAM_PORTDEFINITIONTYPE port_def;
2774   guint nb;
2775
2776   gst_omx_port_get_port_definition (port, &port_def);
2777
2778   nb = port_def.nBufferCountMin + extra;
2779   if (port_def.nBufferCountActual != nb) {
2780     port_def.nBufferCountActual = nb;
2781
2782     GST_DEBUG_OBJECT (port->comp->parent,
2783         "set port %d nBufferCountActual to %d", (guint) port->index, nb);
2784
2785     if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
2786       return FALSE;
2787   }
2788
2789   return TRUE;
2790 }
2791
2792 gboolean
2793 gst_omx_port_update_buffer_count_actual (GstOMXPort * port, guint nb)
2794 {
2795   OMX_PARAM_PORTDEFINITIONTYPE port_def;
2796
2797   gst_omx_port_get_port_definition (port, &port_def);
2798
2799   if (nb < port_def.nBufferCountMin) {
2800     GST_DEBUG_OBJECT (port->comp->parent,
2801         "Requested to use %d buffers on port %d but it's minimum is %d", nb,
2802         (guint) port->index, (guint) port_def.nBufferCountMin);
2803
2804     nb = port_def.nBufferCountMin;
2805   }
2806
2807   if (port_def.nBufferCountActual != nb) {
2808     port_def.nBufferCountActual = nb;
2809
2810     GST_DEBUG_OBJECT (port->comp->parent,
2811         "set port %d nBufferCountActual to %d", (guint) port->index, nb);
2812
2813     if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
2814       return FALSE;
2815   }
2816
2817   return TRUE;
2818 }
2819
2820 gboolean
2821 gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf)
2822 {
2823 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2824   OMX_ALG_PORT_PARAM_BUFFER_MODE buffer_mode;
2825   OMX_ERRORTYPE err;
2826
2827   GST_OMX_INIT_STRUCT (&buffer_mode);
2828   buffer_mode.nPortIndex = port->index;
2829
2830   if (dmabuf)
2831     buffer_mode.eMode = OMX_ALG_BUF_DMA;
2832   else
2833     buffer_mode.eMode = OMX_ALG_BUF_NORMAL;
2834
2835   err =
2836       gst_omx_component_set_parameter (port->comp,
2837       (OMX_INDEXTYPE) OMX_ALG_IndexPortParamBufferMode, &buffer_mode);
2838   if (err != OMX_ErrorNone) {
2839     GST_WARNING_OBJECT (port->comp->parent,
2840         "Failed to set port %d in %sdmabuf mode: %s (0x%08x)",
2841         port->index, dmabuf ? "" : "non-", gst_omx_error_to_string (err), err);
2842     return FALSE;
2843   }
2844
2845   return TRUE;
2846 #else
2847   /* dmabuf not supported for this platform */
2848   return FALSE;
2849 #endif
2850 }
2851
2852 typedef GType (*GGetTypeFunction) (void);
2853
2854 static const GGetTypeFunction types[] = {
2855   gst_omx_analog_audio_sink_get_type, gst_omx_hdmi_audio_sink_get_type,
2856   gst_omx_mpeg2_video_dec_get_type, gst_omx_mpeg4_video_dec_get_type,
2857   gst_omx_h264_dec_get_type, gst_omx_h263_dec_get_type,
2858   gst_omx_wmv_dec_get_type, gst_omx_mpeg4_video_enc_get_type,
2859   gst_omx_h264_enc_get_type, gst_omx_h263_enc_get_type,
2860   gst_omx_aac_enc_get_type, gst_omx_mjpeg_dec_get_type,
2861   gst_omx_aac_dec_get_type, gst_omx_mp3_dec_get_type,
2862   gst_omx_aac_dec_get_type, gst_omx_mp3_enc_get_type,
2863   gst_omx_amr_dec_get_type
2864 #ifdef HAVE_VP8
2865       , gst_omx_vp8_dec_get_type
2866 #endif
2867 #ifdef HAVE_THEORA
2868       , gst_omx_theora_dec_get_type
2869 #endif
2870 #ifdef HAVE_HEVC
2871       , gst_omx_h265_enc_get_type, gst_omx_h265_dec_get_type
2872 #endif
2873 };
2874
2875 struct TypeOffest
2876 {
2877   GType (*get_type) (void);
2878   glong offset;
2879 };
2880
2881 static const struct TypeOffest base_types[] = {
2882   {gst_omx_audio_sink_get_type, G_STRUCT_OFFSET (GstOMXAudioSinkClass, cdata)},
2883   {gst_omx_video_dec_get_type, G_STRUCT_OFFSET (GstOMXVideoDecClass, cdata)},
2884   {gst_omx_video_enc_get_type, G_STRUCT_OFFSET (GstOMXVideoEncClass, cdata)},
2885   {gst_omx_audio_dec_get_type, G_STRUCT_OFFSET (GstOMXAudioDecClass, cdata)},
2886   {gst_omx_audio_enc_get_type, G_STRUCT_OFFSET (GstOMXAudioEncClass, cdata)},
2887 };
2888
2889 static GKeyFile *config = NULL;
2890 GKeyFile *
2891 gst_omx_get_configuration (void)
2892 {
2893   return config;
2894 }
2895
2896 const gchar *
2897 gst_omx_error_to_string (OMX_ERRORTYPE err)
2898 {
2899   guint err_u = (guint) err;
2900
2901   switch (err_u) {
2902     case OMX_ErrorNone:
2903       return "None";
2904     case OMX_ErrorInsufficientResources:
2905       return "Insufficient resources";
2906     case OMX_ErrorUndefined:
2907       return "Undefined";
2908     case OMX_ErrorInvalidComponentName:
2909       return "Invalid component name";
2910     case OMX_ErrorComponentNotFound:
2911       return "Component not found";
2912     case OMX_ErrorBadParameter:
2913       return "Bad parameter";
2914     case OMX_ErrorNotImplemented:
2915       return "Not implemented";
2916     case OMX_ErrorUnderflow:
2917       return "Underflow";
2918     case OMX_ErrorOverflow:
2919       return "Overflow";
2920     case OMX_ErrorHardware:
2921       return "Hardware";
2922     case OMX_ErrorStreamCorrupt:
2923       return "Stream corrupt";
2924     case OMX_ErrorPortsNotCompatible:
2925       return "Ports not compatible";
2926     case OMX_ErrorResourcesLost:
2927       return "Resources lost";
2928     case OMX_ErrorNoMore:
2929       return "No more";
2930     case OMX_ErrorVersionMismatch:
2931       return "Version mismatch";
2932     case OMX_ErrorNotReady:
2933       return "Not ready";
2934     case OMX_ErrorTimeout:
2935       return "Timeout";
2936     case OMX_ErrorSameState:
2937       return "Same state";
2938     case OMX_ErrorResourcesPreempted:
2939       return "Resources preempted";
2940     case OMX_ErrorIncorrectStateTransition:
2941       return "Incorrect state transition";
2942     case OMX_ErrorIncorrectStateOperation:
2943       return "Incorrect state operation";
2944     case OMX_ErrorUnsupportedSetting:
2945       return "Unsupported setting";
2946     case OMX_ErrorUnsupportedIndex:
2947       return "Unsupported index";
2948     case OMX_ErrorBadPortIndex:
2949       return "Bad port index";
2950     case OMX_ErrorPortUnpopulated:
2951       return "Port unpopulated";
2952     case OMX_ErrorComponentSuspended:
2953       return "Component suspended";
2954     case OMX_ErrorDynamicResourcesUnavailable:
2955       return "Dynamic resources unavailable";
2956     case OMX_ErrorMbErrorsInFrame:
2957       return "Macroblock errors in frame";
2958     case OMX_ErrorFormatNotDetected:
2959       return "Format not detected";
2960     case OMX_ErrorSeperateTablesUsed:
2961       return "Separate tables used";
2962     case OMX_ErrorTunnelingUnsupported:
2963       return "Tunneling unsupported";
2964 #if OMX_VERSION_MINOR == 1
2965     case OMX_ErrorInvalidComponent:
2966       return "Invalid component";
2967     case OMX_ErrorInvalidState:
2968       return "Invalid state";
2969     case OMX_ErrorPortUnresponsiveDuringAllocation:
2970       return "Port unresponsive during allocation";
2971     case OMX_ErrorPortUnresponsiveDuringDeallocation:
2972       return "Port unresponsive during deallocation";
2973     case OMX_ErrorPortUnresponsiveDuringStop:
2974       return "Port unresponsive during stop";
2975     case OMX_ErrorContentPipeOpenFailed:
2976       return "Content pipe open failed";
2977     case OMX_ErrorContentPipeCreationFailed:
2978       return "Content pipe creation failed";
2979 #endif
2980     default:
2981       if (err_u >= (guint) OMX_ErrorKhronosExtensions
2982           && err_u < (guint) OMX_ErrorVendorStartUnused) {
2983         return "Khronos extension error";
2984       } else if (err_u >= (guint) OMX_ErrorVendorStartUnused
2985           && err_u < (guint) OMX_ErrorMax) {
2986         return "Vendor specific error";
2987       } else {
2988         return "Unknown error";
2989       }
2990   }
2991 }
2992
2993 const gchar *
2994 gst_omx_state_to_string (OMX_STATETYPE state)
2995 {
2996   switch (state) {
2997     case OMX_StateInvalid:
2998       return "Invalid";
2999     case OMX_StateLoaded:
3000       return "Loaded";
3001     case OMX_StateIdle:
3002       return "Idle";
3003     case OMX_StateExecuting:
3004       return "Executing";
3005     case OMX_StatePause:
3006       return "Pause";
3007     case OMX_StateWaitForResources:
3008       return "WaitForResources";
3009     default:
3010       if (state >= OMX_StateKhronosExtensions
3011           && state < OMX_StateVendorStartUnused)
3012         return "KhronosExtensionState";
3013       else if (state >= OMX_StateVendorStartUnused && state < OMX_StateMax)
3014         return "CustomVendorState";
3015       break;
3016   }
3017   return "Unknown state";
3018 }
3019
3020 const gchar *
3021 gst_omx_command_to_string (OMX_COMMANDTYPE cmd)
3022 {
3023   switch (cmd) {
3024     case OMX_CommandStateSet:
3025       return "SetState";
3026     case OMX_CommandFlush:
3027       return "Flush";
3028     case OMX_CommandPortDisable:
3029       return "DisablePort";
3030     case OMX_CommandPortEnable:
3031       return "EnablePort";
3032     case OMX_CommandMarkBuffer:
3033       return "MarkBuffer";
3034     default:
3035       if (cmd >= OMX_CommandKhronosExtensions
3036           && cmd < OMX_CommandVendorStartUnused)
3037         return "KhronosExtensionCommand";
3038       if (cmd >= OMX_CommandVendorStartUnused && cmd < OMX_CommandMax)
3039         return "VendorExtensionCommand";
3040       break;
3041   }
3042   return "Unknown command";
3043 }
3044
3045 struct BufferFlagString
3046 {
3047   guint32 flag;
3048   const gchar *str;
3049 };
3050
3051 struct BufferFlagString buffer_flags_map[] = {
3052   {OMX_BUFFERFLAG_EOS, "eos"},
3053   {OMX_BUFFERFLAG_STARTTIME, "start-time"},
3054   {OMX_BUFFERFLAG_DECODEONLY, "decode-only"},
3055   {OMX_BUFFERFLAG_DATACORRUPT, "data-corrupt"},
3056   {OMX_BUFFERFLAG_ENDOFFRAME, "end-of-frame"},
3057   {OMX_BUFFERFLAG_SYNCFRAME, "sync-frame"},
3058   {OMX_BUFFERFLAG_EXTRADATA, "extra-data"},
3059   {OMX_BUFFERFLAG_CODECCONFIG, "codec-config"},
3060   /* Introduced in OMX 1.2.0 */
3061 #ifdef OMX_BUFFERFLAG_TIMESTAMPINVALID
3062   {OMX_BUFFERFLAG_TIMESTAMPINVALID, "timestamp-invalid"},
3063 #endif
3064 #ifdef OMX_BUFFERFLAG_READONLY
3065   {OMX_BUFFERFLAG_READONLY, "read-only"},
3066 #endif
3067 #ifdef OMX_BUFFERFLAG_ENDOFSUBFRAME
3068   {OMX_BUFFERFLAG_ENDOFSUBFRAME, "end-of-subframe"},
3069 #endif
3070 #ifdef OMX_BUFFERFLAG_SKIPFRAME
3071   {OMX_BUFFERFLAG_SKIPFRAME, "skip-frame"},
3072 #endif
3073   {0, NULL},
3074 };
3075
3076
3077 const gchar *
3078 gst_omx_buffer_flags_to_string (guint32 flags)
3079 {
3080   GString *s = NULL;
3081   guint i;
3082   const gchar *str;
3083
3084   if (flags == 0)
3085     return "";
3086
3087   /* Keep a cache of the string representation of the flags so we don't allocate
3088    * and free strings for each buffer. In practice we should only have a handfull
3089    * of flags so the cache won't consume much memory. */
3090   if (!buffer_flags_str) {
3091     G_LOCK (buffer_flags_str);
3092     buffer_flags_str = g_hash_table_new_full (NULL, NULL, NULL, g_free);
3093     G_UNLOCK (buffer_flags_str);
3094   }
3095
3096   str = g_hash_table_lookup (buffer_flags_str, GUINT_TO_POINTER (flags));
3097   if (str)
3098     return str;
3099
3100   for (i = 0; buffer_flags_map[i].str != NULL; i++) {
3101     if ((flags & buffer_flags_map[i].flag) == 0)
3102       continue;
3103
3104     if (!s)
3105       s = g_string_new (buffer_flags_map[i].str);
3106     else
3107       g_string_append_printf (s, ", %s", buffer_flags_map[i].str);
3108   }
3109
3110   if (!s)
3111     return "<unknown>";
3112
3113   str = g_string_free (s, FALSE);
3114
3115   G_LOCK (buffer_flags_str);
3116   /* Transfer ownership of str to hash table */
3117   g_hash_table_insert (buffer_flags_str, GUINT_TO_POINTER (flags),
3118       (gchar *) str);
3119   G_UNLOCK (buffer_flags_str);
3120
3121   return str;
3122 }
3123
3124 #if defined(USE_OMX_TARGET_RPI)
3125 #define DEFAULT_HACKS (GST_OMX_HACK_NO_COMPONENT_ROLE | GST_OMX_HACK_HEIGHT_MULTIPLE_16)
3126 #else
3127 #define DEFAULT_HACKS (0)
3128 #endif
3129
3130 guint64
3131 gst_omx_parse_hacks (gchar ** hacks)
3132 {
3133   guint64 hacks_flags = DEFAULT_HACKS;
3134
3135   if (!hacks)
3136     return 0;
3137
3138   while (*hacks) {
3139     if (g_str_equal (*hacks,
3140             "event-port-settings-changed-ndata-parameter-swap"))
3141       hacks_flags |=
3142           GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_NDATA_PARAMETER_SWAP;
3143     else if (g_str_equal (*hacks, "event-port-settings-changed-port-0-to-1"))
3144       hacks_flags |= GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_PORT_0_TO_1;
3145     else if (g_str_equal (*hacks, "video-framerate-integer"))
3146       hacks_flags |= GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER;
3147     else if (g_str_equal (*hacks, "syncframe-flag-not-used"))
3148       hacks_flags |= GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED;
3149     else if (g_str_equal (*hacks, "no-component-reconfigure"))
3150       hacks_flags |= GST_OMX_HACK_NO_COMPONENT_RECONFIGURE;
3151     else if (g_str_equal (*hacks, "no-empty-eos-buffer"))
3152       hacks_flags |= GST_OMX_HACK_NO_EMPTY_EOS_BUFFER;
3153     else if (g_str_equal (*hacks, "drain-may-not-return"))
3154       hacks_flags |= GST_OMX_HACK_DRAIN_MAY_NOT_RETURN;
3155     else if (g_str_equal (*hacks, "no-component-role"))
3156       hacks_flags |= GST_OMX_HACK_NO_COMPONENT_ROLE;
3157     else if (g_str_equal (*hacks, "no-disable-outport"))
3158       hacks_flags |= GST_OMX_HACK_NO_DISABLE_OUTPORT;
3159     else if (g_str_equal (*hacks, "signals-premature-eos"))
3160       hacks_flags |= GST_OMX_HACK_SIGNALS_PREMATURE_EOS;
3161     else if (g_str_equal (*hacks, "height-multiple-16"))
3162       hacks_flags |= GST_OMX_HACK_HEIGHT_MULTIPLE_16;
3163     else if (g_str_equal (*hacks, "pass-profile-to-decoder"))
3164       hacks_flags |= GST_OMX_HACK_PASS_PROFILE_TO_DECODER;
3165     else if (g_str_equal (*hacks, "pass-color-format-to-decoder"))
3166       hacks_flags |= GST_OMX_HACK_PASS_COLOR_FORMAT_TO_DECODER;
3167     else if (g_str_equal (*hacks, "ensure-buffer-count-actual"))
3168       hacks_flags |= GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL;
3169     else
3170       GST_WARNING ("Unknown hack: %s", *hacks);
3171     hacks++;
3172   }
3173
3174   return hacks_flags;
3175 }
3176
3177
3178 void
3179 gst_omx_set_default_role (GstOMXClassData * class_data,
3180     const gchar * default_role)
3181 {
3182   if (!class_data->component_role)
3183     class_data->component_role = default_role;
3184 }
3185
3186 void
3187 gst_omx_buffer_set_omx_buf (GstBuffer * buffer, GstOMXBuffer * omx_buf)
3188 {
3189   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer),
3190       gst_omx_buffer_data_quark, omx_buf, NULL);
3191 }
3192
3193 GstOMXBuffer *
3194 gst_omx_buffer_get_omx_buf (GstBuffer * buffer)
3195 {
3196   return gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer),
3197       gst_omx_buffer_data_quark);
3198 }
3199
3200 static void
3201 _class_init (gpointer g_class, gpointer data)
3202 {
3203   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3204   GstOMXClassData *class_data = NULL;
3205   GKeyFile *config;
3206   const gchar *element_name = data;
3207   GError *err;
3208   gchar *core_name, *component_name, *component_role;
3209   gint in_port_index, out_port_index;
3210   gchar *template_caps;
3211   GstPadTemplate *templ;
3212   GstCaps *caps;
3213   gchar **hacks;
3214   int i;
3215
3216   if (!element_name)
3217     return;
3218
3219   /* Find the GstOMXClassData for this class */
3220   for (i = 0; i < G_N_ELEMENTS (base_types); i++) {
3221     GType gtype = base_types[i].get_type ();
3222
3223     if (G_TYPE_CHECK_CLASS_TYPE (g_class, gtype)) {
3224       class_data = (GstOMXClassData *)
3225           (((guint8 *) g_class) + base_types[i].offset);
3226       break;
3227     }
3228   }
3229
3230   g_assert (class_data != NULL);
3231
3232   config = gst_omx_get_configuration ();
3233
3234   /* This will alwaxys succeed, see check in plugin_init */
3235   core_name = g_key_file_get_string (config, element_name, "core-name", NULL);
3236   g_assert (core_name != NULL);
3237   class_data->core_name = core_name;
3238   component_name =
3239       g_key_file_get_string (config, element_name, "component-name", NULL);
3240   g_assert (component_name != NULL);
3241   class_data->component_name = component_name;
3242
3243   /* If this fails we simply don't set a role */
3244   if ((component_role =
3245           g_key_file_get_string (config, element_name, "component-role",
3246               NULL))) {
3247     GST_DEBUG ("Using component-role '%s' for element '%s'", component_role,
3248         element_name);
3249     class_data->component_role = component_role;
3250   }
3251
3252
3253   /* Now set the inport/outport indizes and assume sane defaults */
3254   err = NULL;
3255   in_port_index =
3256       g_key_file_get_integer (config, element_name, "in-port-index", &err);
3257   if (err != NULL) {
3258     GST_DEBUG ("No 'in-port-index' set for element '%s', auto-detecting: %s",
3259         element_name, err->message);
3260     in_port_index = -1;
3261     g_error_free (err);
3262   }
3263   class_data->in_port_index = in_port_index;
3264
3265   err = NULL;
3266   out_port_index =
3267       g_key_file_get_integer (config, element_name, "out-port-index", &err);
3268   if (err != NULL) {
3269     GST_DEBUG ("No 'out-port-index' set for element '%s', auto-detecting: %s",
3270         element_name, err->message);
3271     out_port_index = -1;
3272     g_error_free (err);
3273   }
3274   class_data->out_port_index = out_port_index;
3275
3276   /* Add pad templates */
3277   err = NULL;
3278   if (class_data->type != GST_OMX_COMPONENT_TYPE_SOURCE) {
3279     if (!(template_caps =
3280             g_key_file_get_string (config, element_name, "sink-template-caps",
3281                 &err))) {
3282       GST_DEBUG
3283           ("No sink template caps specified for element '%s', using default '%s'",
3284           element_name, class_data->default_sink_template_caps);
3285       caps = gst_caps_from_string (class_data->default_sink_template_caps);
3286       g_assert (caps != NULL);
3287       g_error_free (err);
3288     } else {
3289       caps = gst_caps_from_string (template_caps);
3290       if (!caps) {
3291         GST_DEBUG
3292             ("Could not parse sink template caps '%s' for element '%s', using default '%s'",
3293             template_caps, element_name,
3294             class_data->default_sink_template_caps);
3295         caps = gst_caps_from_string (class_data->default_sink_template_caps);
3296         g_assert (caps != NULL);
3297       }
3298     }
3299     templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
3300     g_free (template_caps);
3301     gst_element_class_add_pad_template (element_class, templ);
3302     gst_caps_unref (caps);
3303   }
3304
3305   err = NULL;
3306   if (class_data->type != GST_OMX_COMPONENT_TYPE_SINK) {
3307     if (!(template_caps =
3308             g_key_file_get_string (config, element_name, "src-template-caps",
3309                 &err))) {
3310       GST_DEBUG
3311           ("No src template caps specified for element '%s', using default '%s'",
3312           element_name, class_data->default_src_template_caps);
3313       caps = gst_caps_from_string (class_data->default_src_template_caps);
3314       g_assert (caps != NULL);
3315       g_error_free (err);
3316     } else {
3317       caps = gst_caps_from_string (template_caps);
3318       if (!caps) {
3319         GST_DEBUG
3320             ("Could not parse src template caps '%s' for element '%s', using default '%s'",
3321             template_caps, element_name, class_data->default_src_template_caps);
3322         caps = gst_caps_from_string (class_data->default_src_template_caps);
3323         g_assert (caps != NULL);
3324       }
3325     }
3326     templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
3327     g_free (template_caps);
3328     gst_element_class_add_pad_template (element_class, templ);
3329     gst_caps_unref (caps);
3330   }
3331
3332   if ((hacks =
3333           g_key_file_get_string_list (config, element_name, "hacks", NULL,
3334               NULL))) {
3335 #ifndef GST_DISABLE_GST_DEBUG
3336     gchar **walk = hacks;
3337
3338     while (*walk) {
3339       GST_DEBUG ("Using hack: %s", *walk);
3340       walk++;
3341     }
3342 #endif
3343
3344     class_data->hacks = gst_omx_parse_hacks (hacks);
3345     g_strfreev (hacks);
3346   }
3347 }
3348
3349 static gboolean
3350 plugin_init (GstPlugin * plugin)
3351 {
3352   GError *err = NULL;
3353   gchar **config_dirs;
3354   gchar **elements;
3355   gchar *env_config_dir;
3356   const gchar *user_config_dir;
3357   const gchar *const *system_config_dirs;
3358   gint i, j;
3359   gsize n_elements;
3360   static const gchar *config_name[] = { "gstomx.conf", NULL };
3361   static const gchar *env_config_name[] = { "GST_OMX_CONFIG_DIR", NULL };
3362   static const gchar *gst_omx_config_dir = GST_OMX_CONFIG_DIR;
3363
3364   GST_DEBUG_CATEGORY_INIT (gstomx_debug, "omx", 0, "gst-omx");
3365   GST_DEBUG_CATEGORY_INIT (gst_omx_video_debug_category, "omxvideo", 0,
3366       "gst-omx-video");
3367   GST_DEBUG_CATEGORY_INIT (OMX_PERFORMANCE, "OMX_PERFORMANCE", 0,
3368       "gst-omx performace");
3369
3370   gst_omx_buffer_data_quark = g_quark_from_static_string ("GstOMXBufferData");
3371
3372   /* Read configuration file gstomx.conf from the preferred
3373    * configuration directories */
3374   env_config_dir = g_strdup (g_getenv (*env_config_name));
3375   user_config_dir = g_get_user_config_dir ();
3376   system_config_dirs = g_get_system_config_dirs ();
3377   config_dirs =
3378       g_new (gchar *, g_strv_length ((gchar **) system_config_dirs) + 4);
3379
3380   i = 0;
3381   j = 0;
3382   if (env_config_dir)
3383     config_dirs[i++] = (gchar *) env_config_dir;
3384   config_dirs[i++] = (gchar *) user_config_dir;
3385   while (system_config_dirs[j])
3386     config_dirs[i++] = (gchar *) system_config_dirs[j++];
3387   config_dirs[i++] = (gchar *) gst_omx_config_dir;
3388   config_dirs[i++] = NULL;
3389
3390   gst_plugin_add_dependency (plugin, env_config_name,
3391       (const gchar **) (config_dirs + (env_config_dir ? 1 : 0)), config_name,
3392       GST_PLUGIN_DEPENDENCY_FLAG_NONE);
3393
3394   config = g_key_file_new ();
3395   if (!g_key_file_load_from_dirs (config, *config_name,
3396           (const gchar **) config_dirs, NULL, G_KEY_FILE_NONE, &err)) {
3397     gchar *paths;
3398
3399     paths = g_strjoinv (":", config_dirs);
3400     GST_ERROR ("Failed to load configuration file: %s (searched in: %s as per "
3401         "GST_OMX_CONFIG_DIR environment variable, the xdg user config "
3402         "directory (or XDG_CONFIG_HOME) and the system config directory "
3403         "(or XDG_CONFIG_DIRS)", err->message, paths);
3404     g_free (paths);
3405     g_error_free (err);
3406     goto done;
3407   }
3408
3409   /* Initialize all types */
3410   for (i = 0; i < G_N_ELEMENTS (types); i++)
3411     types[i] ();
3412
3413   elements = g_key_file_get_groups (config, &n_elements);
3414   for (i = 0; i < n_elements; i++) {
3415     GTypeQuery type_query;
3416     GTypeInfo type_info = { 0, };
3417     GType type, subtype;
3418     gchar *type_name, *core_name, *component_name;
3419     gint rank;
3420
3421     GST_DEBUG ("Registering element '%s'", elements[i]);
3422
3423     err = NULL;
3424     if (!(type_name =
3425             g_key_file_get_string (config, elements[i], "type-name", &err))) {
3426       GST_ERROR
3427           ("Unable to read 'type-name' configuration for element '%s': %s",
3428           elements[i], err->message);
3429       g_error_free (err);
3430       continue;
3431     }
3432
3433     type = g_type_from_name (type_name);
3434     if (type == G_TYPE_INVALID) {
3435       GST_ERROR ("Invalid type name '%s' for element '%s'", type_name,
3436           elements[i]);
3437       g_free (type_name);
3438       continue;
3439     }
3440     if (!g_type_is_a (type, GST_TYPE_ELEMENT)) {
3441       GST_ERROR ("Type '%s' is no GstElement subtype for element '%s'",
3442           type_name, elements[i]);
3443       g_free (type_name);
3444       continue;
3445     }
3446     g_free (type_name);
3447
3448     /* And now some sanity checking */
3449     err = NULL;
3450     if (!(core_name =
3451             g_key_file_get_string (config, elements[i], "core-name", &err))) {
3452       GST_ERROR
3453           ("Unable to read 'core-name' configuration for element '%s': %s",
3454           elements[i], err->message);
3455       g_error_free (err);
3456       continue;
3457     }
3458     if (!g_file_test (core_name, G_FILE_TEST_IS_REGULAR)) {
3459       GST_ERROR ("Core '%s' does not exist for element '%s'", core_name,
3460           elements[i]);
3461       g_free (core_name);
3462       continue;
3463     }
3464     g_free (core_name);
3465
3466     err = NULL;
3467     if (!(component_name =
3468             g_key_file_get_string (config, elements[i], "component-name",
3469                 &err))) {
3470       GST_ERROR
3471           ("Unable to read 'component-name' configuration for element '%s': %s",
3472           elements[i], err->message);
3473       g_error_free (err);
3474       continue;
3475     }
3476     g_free (component_name);
3477
3478     err = NULL;
3479     rank = g_key_file_get_integer (config, elements[i], "rank", &err);
3480     if (err != NULL) {
3481       GST_ERROR ("No rank set for element '%s': %s", elements[i], err->message);
3482       g_error_free (err);
3483       continue;
3484     }
3485
3486     /* And now register the type, all other configuration will
3487      * be handled by the type itself */
3488     g_type_query (type, &type_query);
3489     memset (&type_info, 0, sizeof (type_info));
3490     type_info.class_size = type_query.class_size;
3491     type_info.instance_size = type_query.instance_size;
3492     type_info.class_init = _class_init;
3493     type_info.class_data = g_strdup (elements[i]);
3494     type_name = g_strdup_printf ("%s-%s", g_type_name (type), elements[i]);
3495     if (g_type_from_name (type_name) != G_TYPE_INVALID) {
3496       GST_ERROR ("Type '%s' already exists for element '%s'", type_name,
3497           elements[i]);
3498       g_free (type_name);
3499       continue;
3500     }
3501     subtype = g_type_register_static (type, type_name, &type_info, 0);
3502     g_free (type_name);
3503     gst_element_register (plugin, elements[i], rank, subtype);
3504   }
3505   g_strfreev (elements);
3506
3507 done:
3508   g_free (env_config_dir);
3509   g_free (config_dirs);
3510
3511   return TRUE;
3512 }
3513
3514 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
3515     GST_VERSION_MINOR,
3516     omx,
3517     "GStreamer OpenMAX Plug-ins",
3518     plugin_init,
3519     PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)