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