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>
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.
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.
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
28 #include <gst/allocators/gstdmabuf.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"
53 GST_DEBUG_CATEGORY (gstomx_debug);
54 #define GST_CAT_DEFAULT gstomx_debug
56 GST_DEBUG_CATEGORY_STATIC (OMX_PERFORMANCE);
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__)
66 G_LOCK_DEFINE_STATIC (core_handles);
67 static GHashTable *core_handles;
69 /* Cache used by gst_omx_buffer_flags_to_string() */
70 G_LOCK_DEFINE_STATIC (buffer_flags_str);
71 static GHashTable *buffer_flags_str;
73 static GQuark gst_omx_buffer_data_quark = 0;
76 gst_omx_core_acquire (const gchar * filename)
80 G_LOCK (core_handles);
83 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
85 core = g_hash_table_lookup (core_handles, filename);
87 core = g_slice_new0 (GstOMXCore);
88 g_mutex_init (&core->lock);
90 g_hash_table_insert (core_handles, g_strdup (filename), core);
92 /* Hack for the Broadcom OpenMAX IL implementation */
93 #ifdef USE_OMX_TARGET_RPI
96 if (g_str_has_suffix (filename, "vc/lib/libopenmaxil.so")) {
98 gchar *bcm_host_filename;
100 GModule *bcm_host_module;
101 void (*bcm_host_init) (void);
103 bcm_host_path = g_path_get_dirname (filename);
105 g_build_filename (bcm_host_path, "libbcm_host.so", NULL);
108 g_module_open (bcm_host_filename,
109 G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
111 g_free (bcm_host_filename);
112 g_free (bcm_host_path);
114 if (!bcm_host_module) {
115 /* Retry without an absolute path */
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");
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");
135 g_module_open (filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
139 if (!g_module_symbol (core->module, "OMX_Init", (gpointer *) & core->init))
141 if (!g_module_symbol (core->module, "OMX_Deinit",
142 (gpointer *) & core->deinit))
144 if (!g_module_symbol (core->module, "OMX_GetHandle",
145 (gpointer *) & core->get_handle))
147 if (!g_module_symbol (core->module, "OMX_FreeHandle",
148 (gpointer *) & core->free_handle))
150 if (!g_module_symbol (core->module, "OMX_SetupTunnel",
151 (gpointer *) & core->setup_tunnel))
154 GST_DEBUG ("Successfully loaded core '%s'", filename);
157 g_mutex_lock (&core->lock);
159 if (core->user_count == 1) {
163 if (err != OMX_ErrorNone) {
164 GST_ERROR ("Failed to initialize core '%s': 0x%08x", filename, err);
165 g_mutex_unlock (&core->lock);
169 GST_DEBUG ("Successfully initialized core '%s'", filename);
172 g_mutex_unlock (&core->lock);
173 G_UNLOCK (core_handles);
179 GST_ERROR ("Failed to load module '%s': %s", filename, g_module_error ());
184 GST_ERROR ("Failed to locate required OpenMAX symbol in '%s': %s", filename,
186 g_module_close (core->module);
192 g_hash_table_remove (core_handles, filename);
193 g_mutex_clear (&core->lock);
194 g_slice_free (GstOMXCore, core);
196 G_UNLOCK (core_handles);
203 gst_omx_core_release (GstOMXCore * core)
205 g_return_if_fail (core != NULL);
207 G_LOCK (core_handles);
209 g_mutex_lock (&core->lock);
211 GST_DEBUG ("Releasing core %p", core);
214 if (core->user_count == 0) {
215 GST_DEBUG ("Deinit core %p", core);
218 G_LOCK (buffer_flags_str);
219 g_clear_pointer (&buffer_flags_str, g_hash_table_unref);
220 G_UNLOCK (buffer_flags_str);
223 g_mutex_unlock (&core->lock);
225 G_UNLOCK (core_handles);
228 /* NOTE: comp->messages_lock will be used */
230 gst_omx_component_flush_messages (GstOMXComponent * comp)
234 g_mutex_lock (&comp->messages_lock);
235 while ((msg = g_queue_pop_head (&comp->messages))) {
236 g_slice_free (GstOMXMessage, msg);
238 g_mutex_unlock (&comp->messages_lock);
242 gst_omx_buffer_reset (GstOMXBuffer * buf)
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));
250 static void gst_omx_buffer_unmap (GstOMXBuffer * buffer);
252 /* NOTE: Call with comp->lock, comp->messages_lock will be used */
254 gst_omx_component_handle_messages (GstOMXComponent * comp)
258 g_mutex_lock (&comp->messages_lock);
259 while ((msg = g_queue_pop_head (&comp->messages))) {
260 g_mutex_unlock (&comp->messages_lock);
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;
271 case GST_OMX_MESSAGE_FLUSH:{
272 GstOMXPort *port = NULL;
273 OMX_U32 index = msg->content.flush.port;
275 port = gst_omx_component_get_port (comp, index);
279 GST_DEBUG_OBJECT (comp->parent, "%s port %u flushed", comp->name,
282 if (port->flushing) {
283 port->flushed = TRUE;
285 GST_ERROR_OBJECT (comp->parent, "%s port %u was not flushing",
286 comp->name, port->index);
291 case GST_OMX_MESSAGE_ERROR:{
292 OMX_ERRORTYPE error = msg->content.error.error;
294 if (error == OMX_ErrorNone)
297 GST_ERROR_OBJECT (comp->parent, "%s got error: %s (0x%08x)", comp->name,
298 gst_omx_error_to_string (error), error);
300 /* We only set the first error ever from which
301 * we can't recover anymore.
303 if (comp->last_error == OMX_ErrorNone)
304 comp->last_error = error;
305 g_cond_broadcast (&comp->messages_cond);
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;
314 port = gst_omx_component_get_port (comp, index);
318 GST_DEBUG_OBJECT (comp->parent, "%s port %u %s", comp->name,
319 port->index, (enable ? "enabled" : "disabled"));
322 port->enabled_pending = FALSE;
324 port->disabled_pending = FALSE;
327 case GST_OMX_MESSAGE_PORT_SETTINGS_CHANGED:{
329 OMX_U32 index = msg->content.port_settings_changed.port;
330 GList *outports = NULL, *l, *k;
332 GST_DEBUG_OBJECT (comp->parent, "%s settings changed (port %u)",
333 comp->name, (guint) index);
335 /* FIXME: This probably can be done better */
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);
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);
350 for (k = outports; k; k = k->next) {
351 gboolean found = FALSE;
353 for (l = comp->pending_reconfigure_outports; l; l = l->next) {
354 if (l->data == k->data) {
361 comp->pending_reconfigure_outports =
362 g_list_prepend (comp->pending_reconfigure_outports, k->data);
365 g_list_free (outports);
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;
374 port = gst_omx_component_get_port (comp, index);
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)
387 case GST_OMX_MESSAGE_BUFFER_DONE:{
388 GstOMXBuffer *buf = msg->content.buffer_done.buffer->pAppPrivate;
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);
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
405 gst_omx_buffer_reset (buf);
407 /* Release and unmap the parent buffer, if any */
408 gst_omx_buffer_unmap (buf);
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);
416 if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS)
417 && port->port_def.eDir == OMX_DirOutput)
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);
430 g_assert_not_reached ();
435 g_slice_free (GstOMXMessage, msg);
437 g_mutex_lock (&comp->messages_lock);
440 g_mutex_unlock (&comp->messages_lock);
443 /* NOTE: comp->messages_lock will be used */
445 gst_omx_component_send_message (GstOMXComponent * comp, GstOMXMessage * msg)
447 g_mutex_lock (&comp->messages_lock);
449 g_queue_push_tail (&comp->messages, msg);
450 g_cond_broadcast (&comp->messages_cond);
451 g_mutex_unlock (&comp->messages_lock);
454 /* NOTE: Call with comp->lock, comp->messages_lock will be used */
456 gst_omx_component_wait_message (GstOMXComponent * comp, GstClockTime timeout)
459 gint64 wait_until = -1;
461 if (timeout != GST_CLOCK_TIME_NONE) {
462 gint64 add = timeout / (GST_SECOND / G_TIME_SPAN_SECOND);
467 wait_until = g_get_monotonic_time () + add;
468 GST_DEBUG_OBJECT (comp->parent, "%s waiting for %" G_GINT64_FORMAT "us",
471 GST_DEBUG_OBJECT (comp->parent, "%s waiting for signal", comp->name);
474 g_mutex_lock (&comp->messages_lock);
475 g_mutex_unlock (&comp->lock);
477 if (!g_queue_is_empty (&comp->messages)) {
479 } else if (timeout == GST_CLOCK_TIME_NONE) {
480 g_cond_wait (&comp->messages_cond, &comp->messages_lock);
484 g_cond_wait_until (&comp->messages_cond, &comp->messages_lock,
488 g_mutex_unlock (&comp->messages_lock);
489 g_mutex_lock (&comp->lock);
495 omx_event_type_to_str (OMX_EVENTTYPE event)
498 case OMX_EventCmdComplete:
499 return "EventCmdComplete";
504 case OMX_EventPortSettingsChanged:
505 return "EventPortSettingsChanged";
506 case OMX_EventBufferFlag:
507 return "EventBufferFlag";
508 case OMX_EventResourcesAcquired:
509 return "EventResourcesAcquired";
510 case OMX_EventComponentResumed:
511 return "EventComponentResumed";
512 case OMX_EventDynamicResourcesAvailable:
513 return "EventDynamicResourcesAvailable";
514 case OMX_EventPortFormatDetected:
515 return "EventPortFormatDetected";
516 #ifdef OMX_EventIndexSettingChanged
517 case OMX_EventIndexSettingChanged:
518 return "EventIndexSettingChanged";
520 #ifdef OMX_EventPortNeedsDisable
521 case OMX_EventPortNeedsDisable:
522 return "EventPortNeedsDisable";
524 #ifdef OMX_EventPortNeedsFlush
525 case OMX_EventPortNeedsFlush:
526 return "EventPortNeedsFlush";
528 case OMX_EventKhronosExtensions:
529 case OMX_EventVendorStartUnused:
538 /* See "Table 3-11: Event Parameter Usage" */
539 static GstStructure *
540 omx_event_to_debug_struct (OMX_EVENTTYPE event,
541 guint32 data1, guint32 data2, gpointer event_data)
545 name = omx_event_type_to_str (event);
547 case OMX_EventCmdComplete:
549 const gchar *cmd = gst_omx_command_to_string (data1);
555 case OMX_CommandStateSet:
556 return gst_structure_new (name,
557 "command", G_TYPE_STRING, cmd,
558 "state-reached", G_TYPE_STRING, gst_omx_state_to_string (data2),
560 case OMX_CommandFlush:
561 case OMX_CommandPortDisable:
562 case OMX_CommandPortEnable:
563 case OMX_CommandMarkBuffer:
564 return gst_structure_new (name,
565 "command", G_TYPE_STRING, cmd, "port", G_TYPE_UINT, data2,
566 "error", G_TYPE_STRING,
567 gst_omx_error_to_string (GPOINTER_TO_UINT (event_data)), NULL);
568 case OMX_CommandKhronosExtensions:
569 case OMX_CommandVendorStartUnused:
576 return gst_structure_new (name, "error", G_TYPE_STRING,
577 gst_omx_error_to_string (data1), "extra-info", G_TYPE_STRING,
578 gst_omx_error_to_string (data2), NULL);
580 case OMX_EventComponentResumed:
581 case OMX_EventResourcesAcquired:
582 case OMX_EventDynamicResourcesAvailable:
583 case OMX_EventPortFormatDetected:
584 return gst_structure_new_empty (name);
585 case OMX_EventPortSettingsChanged:
586 #ifdef OMX_EventIndexSettingChanged
587 case OMX_EventIndexSettingChanged:
589 #ifdef OMX_EventPortNeedsDisable
590 case OMX_EventPortNeedsDisable:
592 #ifdef OMX_EventPortNeedsFlush
593 case OMX_EventPortNeedsFlush:
595 return gst_structure_new (name, "port", G_TYPE_UINT,
596 data1, "param-config", G_TYPE_UINT, data2, NULL);
597 case OMX_EventBufferFlag:
598 return gst_structure_new (name, "port", G_TYPE_UINT,
599 data1, "flags", gst_omx_buffer_flags_to_string (data2), NULL);
600 case OMX_EventKhronosExtensions:
601 case OMX_EventVendorStartUnused:
611 log_omx_performance_event (GstOMXComponent * comp, OMX_EVENTTYPE event,
612 guint32 data1, guint32 data2, gpointer event_data)
616 /* Don't bother creating useless structs if not needed */
617 if (gst_debug_category_get_threshold (OMX_PERFORMANCE) < GST_LEVEL_DEBUG)
620 s = omx_event_to_debug_struct (event, data1, data2, event_data);
622 GST_CAT_WARNING_OBJECT (OMX_PERFORMANCE, comp->parent,
623 "invalid event 0x%08x Data1 %u Data2 %u EventData %p", event, data1,
628 GST_CAT_DEBUG_OBJECT (OMX_PERFORMANCE, comp->parent, "%" GST_PTR_FORMAT, s);
630 gst_structure_free (s);
634 EventHandler (OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_EVENTTYPE eEvent,
635 OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData)
637 GstOMXComponent *comp = (GstOMXComponent *) pAppData;
639 log_omx_performance_event (comp, eEvent, nData1, nData2, pEventData);
642 case OMX_EventCmdComplete:
644 OMX_COMMANDTYPE cmd = (OMX_COMMANDTYPE) nData1;
646 GST_DEBUG_OBJECT (comp->parent, "%s %s command complete (%d)",
647 comp->name, gst_omx_command_to_string (cmd), cmd);
650 case OMX_CommandStateSet:{
651 GstOMXMessage *msg = g_slice_new (GstOMXMessage);
653 msg->type = GST_OMX_MESSAGE_STATE_SET;
654 msg->content.state_set.state = nData2;
656 GST_DEBUG_OBJECT (comp->parent, "%s state change to %s finished",
658 gst_omx_state_to_string (msg->content.state_set.state));
660 gst_omx_component_send_message (comp, msg);
663 case OMX_CommandFlush:{
664 GstOMXMessage *msg = g_slice_new (GstOMXMessage);
666 msg->type = GST_OMX_MESSAGE_FLUSH;
667 msg->content.flush.port = nData2;
668 GST_DEBUG_OBJECT (comp->parent, "%s port %u flushed", comp->name,
669 (guint) msg->content.flush.port);
671 gst_omx_component_send_message (comp, msg);
674 case OMX_CommandPortEnable:
675 case OMX_CommandPortDisable:{
676 GstOMXMessage *msg = g_slice_new (GstOMXMessage);
678 msg->type = GST_OMX_MESSAGE_PORT_ENABLE;
679 msg->content.port_enable.port = nData2;
680 msg->content.port_enable.enable = (cmd == OMX_CommandPortEnable);
681 GST_DEBUG_OBJECT (comp->parent, "%s port %u %s", comp->name,
682 (guint) msg->content.port_enable.port,
683 (msg->content.port_enable.enable ? "enabled" : "disabled"));
685 gst_omx_component_send_message (comp, msg);
696 OMX_ERRORTYPE error_type = nData1;
698 /* Yes, this really happens... */
699 if (error_type == OMX_ErrorNone)
702 /* Always ignore PortUnpopulated error. This error is informational
703 * at best but it is useful for debugging some strange scenarios.
705 if (error_type == OMX_ErrorPortUnpopulated) {
706 GST_DEBUG_OBJECT (comp->parent, "%s got error: %s (0x%08x)",
707 comp->name, gst_omx_error_to_string (error_type), error_type);
711 msg = g_slice_new (GstOMXMessage);
713 msg->type = GST_OMX_MESSAGE_ERROR;
714 msg->content.error.error = error_type;
715 GST_ERROR_OBJECT (comp->parent, "%s got error: %s (0x%08x)", comp->name,
716 gst_omx_error_to_string (msg->content.error.error),
717 msg->content.error.error);
719 gst_omx_component_send_message (comp, msg);
722 case OMX_EventPortSettingsChanged:
724 GstOMXMessage *msg = g_slice_new (GstOMXMessage);
728 GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_NDATA_PARAMETER_SWAP)) {
737 GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_PORT_0_TO_1))
741 msg->type = GST_OMX_MESSAGE_PORT_SETTINGS_CHANGED;
742 msg->content.port_settings_changed.port = index;
743 GST_DEBUG_OBJECT (comp->parent, "%s settings changed (port index: %u)",
744 comp->name, (guint) msg->content.port_settings_changed.port);
746 gst_omx_component_send_message (comp, msg);
749 case OMX_EventBufferFlag:{
752 msg = g_slice_new (GstOMXMessage);
754 msg->type = GST_OMX_MESSAGE_BUFFER_FLAG;
755 msg->content.buffer_flag.port = nData1;
756 msg->content.buffer_flag.flags = nData2;
757 GST_DEBUG_OBJECT (comp->parent, "%s port %u got buffer flags 0x%08x (%s)",
758 comp->name, (guint) msg->content.buffer_flag.port,
759 (guint) msg->content.buffer_flag.flags,
760 gst_omx_buffer_flags_to_string (msg->content.buffer_flag.flags));
762 gst_omx_component_send_message (comp, msg);
765 case OMX_EventPortFormatDetected:
767 GST_DEBUG_OBJECT (comp->parent, "%s unknown event 0x%08x", comp->name,
772 return OMX_ErrorNone;
776 gst_omx_buffer_unmap (GstOMXBuffer * buffer)
778 g_return_if_fail (buffer != NULL);
780 if (buffer->input_frame_mapped) {
781 g_assert (!buffer->input_mem);
782 g_assert (!buffer->input_buffer);
783 g_assert (!buffer->input_buffer_mapped);
784 gst_video_frame_unmap (&buffer->input_frame);
785 buffer->input_frame_mapped = FALSE;
786 } else if (buffer->input_mem) {
787 g_assert (!buffer->input_buffer);
788 g_assert (!buffer->input_buffer_mapped);
789 gst_memory_unmap (buffer->input_mem, &buffer->map);
790 g_clear_pointer (&buffer->input_mem, gst_memory_unref);
791 } else if (buffer->input_buffer) {
792 if (buffer->input_buffer_mapped)
793 gst_buffer_unmap (buffer->input_buffer, &buffer->map);
794 buffer->input_buffer_mapped = FALSE;
795 g_clear_pointer (&buffer->input_buffer, gst_buffer_unref);
800 log_omx_performance_buffer (GstOMXComponent * comp, const gchar * event,
805 /* Don't bother creating useless structs if not needed */
806 if (gst_debug_category_get_threshold (OMX_PERFORMANCE) < GST_LEVEL_TRACE)
810 gchar *buf_str, *omx_buf_str, *pbuffer_str;
812 /* GST_PTR_FORMAT won't serialize G_TYPE_POINTER fields so stringify pointers */
813 buf_str = g_strdup_printf ("%p", buf);
814 omx_buf_str = g_strdup_printf ("%p", buf->omx_buf);
815 pbuffer_str = g_strdup_printf ("%p", buf->omx_buf->pBuffer);
818 s = gst_structure_new (event,
819 "GstOMXBuffer", G_TYPE_STRING, buf_str,
820 "OMX-buffer", G_TYPE_STRING, omx_buf_str,
821 "pBuffer", G_TYPE_STRING, pbuffer_str,
822 "TimeStamp", G_TYPE_UINT64, GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp),
823 "AllocLen", G_TYPE_UINT, buf->omx_buf->nAllocLen,
824 "FilledLen", G_TYPE_UINT, buf->omx_buf->nFilledLen,
825 "flags", G_TYPE_UINT, buf->omx_buf->nFlags,
826 "flags-str", G_TYPE_STRING, gst_omx_buffer_flags_to_string (buf->omx_buf->nFlags),
831 g_free (omx_buf_str);
832 g_free (pbuffer_str);
834 s = gst_structure_new_empty (event);
837 GST_CAT_TRACE_OBJECT (OMX_PERFORMANCE, comp->parent, "%" GST_PTR_FORMAT, s);
839 gst_structure_free (s);
843 EmptyBufferDone (OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
844 OMX_BUFFERHEADERTYPE * pBuffer)
847 GstOMXComponent *comp;
850 buf = pBuffer->pAppPrivate;
852 GST_ERROR ("Have unknown or deallocated buffer %p", pBuffer);
853 return OMX_ErrorNone;
856 g_assert (buf->omx_buf == pBuffer);
858 if (buf->port->tunneled) {
859 GST_ERROR ("EmptyBufferDone on tunneled port");
860 return OMX_ErrorBadParameter;
863 comp = buf->port->comp;
865 msg = g_slice_new (GstOMXMessage);
866 msg->type = GST_OMX_MESSAGE_BUFFER_DONE;
867 msg->content.buffer_done.component = hComponent;
868 msg->content.buffer_done.app_data = pAppData;
869 msg->content.buffer_done.buffer = pBuffer;
870 msg->content.buffer_done.empty = OMX_TRUE;
872 log_omx_performance_buffer (comp, "EmptyBufferDone", buf);
873 GST_LOG_OBJECT (comp->parent, "%s port %u emptied buffer %p (%p)",
874 comp->name, buf->port->index, buf, buf->omx_buf->pBuffer);
876 gst_omx_component_send_message (comp, msg);
878 return OMX_ErrorNone;
882 FillBufferDone (OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
883 OMX_BUFFERHEADERTYPE * pBuffer)
886 GstOMXComponent *comp;
889 buf = pBuffer->pAppPrivate;
891 GST_ERROR ("Have unknown or deallocated buffer %p", pBuffer);
892 return OMX_ErrorNone;
895 g_assert (buf->omx_buf == pBuffer);
897 if (buf->port->tunneled) {
898 GST_ERROR ("FillBufferDone on tunneled port");
899 return OMX_ErrorBadParameter;
902 comp = buf->port->comp;
904 msg = g_slice_new (GstOMXMessage);
905 msg->type = GST_OMX_MESSAGE_BUFFER_DONE;
906 msg->content.buffer_done.component = hComponent;
907 msg->content.buffer_done.app_data = pAppData;
908 msg->content.buffer_done.buffer = pBuffer;
909 msg->content.buffer_done.empty = OMX_FALSE;
911 log_omx_performance_buffer (comp, "FillBufferDone", buf);
912 GST_LOG_OBJECT (comp->parent, "%s port %u filled buffer %p (%p)", comp->name,
913 buf->port->index, buf, buf->omx_buf->pBuffer);
915 gst_omx_component_send_message (comp, msg);
917 return OMX_ErrorNone;
920 static OMX_CALLBACKTYPE callbacks =
921 { EventHandler, EmptyBufferDone, FillBufferDone };
923 GST_DEFINE_MINI_OBJECT_TYPE (GstOMXComponent, gst_omx_component);
925 static void gst_omx_component_free (GstOMXComponent * comp);
927 /* NOTE: Uses comp->lock and comp->messages_lock */
929 gst_omx_component_new (GstObject * parent, const gchar * core_name,
930 const gchar * component_name, const gchar * component_role, guint64 hacks)
934 GstOMXComponent *comp;
937 core = gst_omx_core_acquire (core_name);
941 comp = g_slice_new0 (GstOMXComponent);
944 gst_mini_object_init (GST_MINI_OBJECT_CAST (comp), 0,
945 gst_omx_component_get_type (), NULL, NULL,
946 (GstMiniObjectFreeFunction) gst_omx_component_free);
948 if ((dot = g_strrstr (component_name, ".")))
949 comp->name = g_strdup (dot + 1);
951 comp->name = g_strdup (component_name);
954 core->get_handle (&comp->handle, (OMX_STRING) component_name, comp,
956 if (err != OMX_ErrorNone) {
957 GST_ERROR_OBJECT (parent,
958 "Failed to get component handle '%s' from core '%s': 0x%08x",
959 component_name, core_name, err);
960 gst_omx_core_release (core);
962 g_slice_free (GstOMXComponent, comp);
965 GST_DEBUG_OBJECT (parent,
966 "Successfully got component handle %p (%s) from core '%s'", comp->handle,
967 component_name, core_name);
968 comp->parent = gst_object_ref (parent);
971 comp->ports = g_ptr_array_new ();
972 comp->n_in_ports = 0;
973 comp->n_out_ports = 0;
975 g_mutex_init (&comp->lock);
976 g_mutex_init (&comp->messages_lock);
977 g_cond_init (&comp->messages_cond);
979 g_queue_init (&comp->messages);
980 comp->pending_state = OMX_StateInvalid;
981 comp->last_error = OMX_ErrorNone;
983 /* Set component role if any */
984 if (component_role && !(hacks & GST_OMX_HACK_NO_COMPONENT_ROLE)) {
985 OMX_PARAM_COMPONENTROLETYPE param;
987 GST_OMX_INIT_STRUCT (¶m);
989 g_strlcpy ((gchar *) param.cRole, component_role, sizeof (param.cRole));
991 gst_omx_component_set_parameter (comp,
992 OMX_IndexParamStandardComponentRole, ¶m);
994 DEBUG_IF_OK (comp->parent, err,
995 "Setting component role to '%s': %s (0x%08x)", component_role,
996 gst_omx_error_to_string (err), err);
998 /* If setting the role failed this component is unusable */
999 if (err != OMX_ErrorNone) {
1000 gst_omx_component_free (comp);
1005 OMX_GetState (comp->handle, &comp->state);
1007 g_mutex_lock (&comp->lock);
1008 gst_omx_component_handle_messages (comp);
1009 g_mutex_unlock (&comp->lock);
1014 /* NOTE: Uses comp->messages_lock */
1016 gst_omx_component_free (GstOMXComponent * comp)
1020 g_return_if_fail (comp != NULL);
1022 GST_INFO_OBJECT (comp->parent, "Unloading component %p %s", comp, comp->name);
1025 n = comp->ports->len;
1026 for (i = 0; i < n; i++) {
1027 GstOMXPort *port = g_ptr_array_index (comp->ports, i);
1029 gst_omx_port_deallocate_buffers (port);
1030 g_assert (port->buffers == NULL);
1031 g_assert (g_queue_get_length (&port->pending_buffers) == 0);
1033 g_slice_free (GstOMXPort, port);
1035 g_ptr_array_unref (comp->ports);
1039 comp->core->free_handle (comp->handle);
1040 gst_omx_core_release (comp->core);
1042 gst_omx_component_flush_messages (comp);
1044 g_cond_clear (&comp->messages_cond);
1045 g_mutex_clear (&comp->messages_lock);
1046 g_mutex_clear (&comp->lock);
1048 gst_object_unref (comp->parent);
1050 g_free (comp->name);
1053 g_slice_free (GstOMXComponent, comp);
1057 gst_omx_component_ref (GstOMXComponent * comp)
1059 g_return_val_if_fail (comp, NULL);
1061 gst_mini_object_ref (GST_MINI_OBJECT_CAST (comp));
1066 gst_omx_component_unref (GstOMXComponent * comp)
1068 g_return_if_fail (comp);
1070 gst_mini_object_unref (GST_MINI_OBJECT_CAST (comp));
1073 static GstStructure *
1074 omx_command_to_debug_struct (OMX_COMMANDTYPE cmd,
1075 guint32 param, gpointer cmd_data)
1077 const gchar *cmd_str;
1079 cmd_str = gst_omx_command_to_string (cmd);
1082 case OMX_CommandStateSet:
1083 return gst_structure_new ("SendCommand",
1084 "command", G_TYPE_STRING, cmd_str,
1085 "state", G_TYPE_STRING, gst_omx_state_to_string (param), NULL);
1086 case OMX_CommandFlush:
1087 case OMX_CommandPortDisable:
1088 case OMX_CommandPortEnable:
1089 return gst_structure_new ("SendCommand",
1090 "command", G_TYPE_STRING, cmd_str, "port", G_TYPE_UINT, param, NULL);
1091 case OMX_CommandMarkBuffer:
1092 return gst_structure_new ("SendCommand",
1093 "command", G_TYPE_STRING, cmd_str,
1094 "mark-type", G_TYPE_POINTER, cmd_data, NULL);
1095 case OMX_CommandKhronosExtensions:
1096 case OMX_CommandVendorStartUnused:
1097 case OMX_CommandMax:
1106 log_omx_performance_send_command (GstOMXComponent * comp, OMX_COMMANDTYPE cmd,
1107 guint32 param, gpointer cmd_data)
1111 /* Don't bother creating useless structs if not needed */
1112 if (gst_debug_category_get_threshold (OMX_PERFORMANCE) < GST_LEVEL_DEBUG)
1115 s = omx_command_to_debug_struct (cmd, param, cmd_data);
1117 GST_CAT_WARNING_OBJECT (OMX_PERFORMANCE, comp->parent,
1118 "invalid command 0x%08x Param %u CmdData %p", cmd, param, cmd_data);
1122 GST_CAT_DEBUG_OBJECT (OMX_PERFORMANCE, comp->parent, "%" GST_PTR_FORMAT, s);
1124 gst_structure_free (s);
1127 static OMX_ERRORTYPE
1128 gst_omx_component_send_command (GstOMXComponent * comp, OMX_COMMANDTYPE cmd,
1129 guint32 param, gpointer cmd_data)
1133 log_omx_performance_send_command (comp, cmd, param, cmd_data);
1134 err = OMX_SendCommand (comp->handle, cmd, param, cmd_data);
1139 /* NOTE: Uses comp->lock and comp->messages_lock */
1141 gst_omx_component_set_state (GstOMXComponent * comp, OMX_STATETYPE state)
1143 OMX_STATETYPE old_state;
1144 OMX_ERRORTYPE err = OMX_ErrorNone;
1146 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1148 g_mutex_lock (&comp->lock);
1150 gst_omx_component_handle_messages (comp);
1152 old_state = comp->state;
1153 GST_INFO_OBJECT (comp->parent, "Setting %s state from %s to %s", comp->name,
1154 gst_omx_state_to_string (old_state), gst_omx_state_to_string (state));
1156 if ((err = comp->last_error) != OMX_ErrorNone && state > old_state) {
1157 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
1158 comp->name, gst_omx_error_to_string (err), err);
1162 if (old_state == state || comp->pending_state == state) {
1163 GST_DEBUG_OBJECT (comp->parent, "Component %s already in state %s",
1164 comp->name, gst_omx_state_to_string (state));
1168 comp->pending_state = state;
1170 /* Reset some things */
1171 if ((old_state == OMX_StateExecuting || old_state == OMX_StatePause)
1172 && state < old_state) {
1173 g_list_free (comp->pending_reconfigure_outports);
1174 comp->pending_reconfigure_outports = NULL;
1175 /* Notify all inports that are still waiting */
1176 gst_omx_component_send_message (comp, NULL);
1179 err = gst_omx_component_send_command (comp, OMX_CommandStateSet, state, NULL);
1180 /* No need to check if anything has changed here */
1184 gst_omx_component_handle_messages (comp);
1186 if (err != OMX_ErrorNone && comp->last_error == OMX_ErrorNone) {
1187 GST_ERROR_OBJECT (comp->parent,
1188 "Last operation returned an error. Setting last_error manually.");
1189 comp->last_error = err;
1192 g_mutex_unlock (&comp->lock);
1194 if (err != OMX_ErrorNone) {
1195 GST_ERROR_OBJECT (comp->parent,
1196 "Error setting %s state from %s to %s: %s (0x%08x)", comp->name,
1197 gst_omx_state_to_string (old_state), gst_omx_state_to_string (state),
1198 gst_omx_error_to_string (err), err);
1203 /* NOTE: Uses comp->lock and comp->messages_lock */
1205 gst_omx_component_get_state (GstOMXComponent * comp, GstClockTime timeout)
1208 gboolean signalled = TRUE;
1210 g_return_val_if_fail (comp != NULL, OMX_StateInvalid);
1212 GST_DEBUG_OBJECT (comp->parent, "Getting state of %s", comp->name);
1214 g_mutex_lock (&comp->lock);
1216 gst_omx_component_handle_messages (comp);
1218 if (comp->last_error != OMX_ErrorNone) {
1219 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
1220 comp->name, gst_omx_error_to_string (comp->last_error),
1222 ret = OMX_StateInvalid;
1227 if (comp->pending_state == OMX_StateInvalid)
1230 while (signalled && comp->last_error == OMX_ErrorNone
1231 && comp->pending_state != OMX_StateInvalid) {
1233 signalled = gst_omx_component_wait_message (comp, timeout);
1235 gst_omx_component_handle_messages (comp);
1239 if (comp->last_error != OMX_ErrorNone) {
1240 GST_ERROR_OBJECT (comp->parent,
1241 "%s got error while waiting for state change: %s (0x%08x)",
1242 comp->name, gst_omx_error_to_string (comp->last_error),
1244 ret = OMX_StateInvalid;
1245 } else if (comp->pending_state == OMX_StateInvalid) {
1246 /* State change finished and everything's fine */
1249 ret = OMX_StateInvalid;
1250 g_assert_not_reached ();
1253 ret = OMX_StateInvalid;
1254 GST_WARNING_OBJECT (comp->parent, "%s timeout while waiting for state "
1255 "change", comp->name);
1259 g_mutex_unlock (&comp->lock);
1261 GST_DEBUG_OBJECT (comp->parent, "%s returning state %s", comp->name,
1262 gst_omx_state_to_string (ret));
1268 gst_omx_component_add_port (GstOMXComponent * comp, guint32 index)
1272 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1275 g_return_val_if_fail (comp != NULL, NULL);
1277 /* Check if this port exists already */
1278 n = comp->ports->len;
1279 for (i = 0; i < n; i++) {
1280 port = g_ptr_array_index (comp->ports, i);
1281 g_return_val_if_fail (port->index != index, NULL);
1284 GST_DEBUG_OBJECT (comp->parent, "%s adding port %u", comp->name, index);
1286 GST_OMX_INIT_STRUCT (&port_def);
1287 port_def.nPortIndex = index;
1289 err = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1291 if (err != OMX_ErrorNone) {
1292 GST_ERROR_OBJECT (comp->parent, "%s failed to add port %u: %s (0x%08x)",
1293 comp->name, index, gst_omx_error_to_string (err), err);
1297 port = g_slice_new0 (GstOMXPort);
1299 port->index = index;
1301 port->tunneled = FALSE;
1303 port->port_def = port_def;
1305 g_queue_init (&port->pending_buffers);
1306 port->flushing = TRUE;
1307 port->flushed = FALSE;
1308 port->enabled_pending = FALSE;
1309 port->disabled_pending = FALSE;
1311 port->using_pool = FALSE;
1313 if (port->port_def.eDir == OMX_DirInput)
1316 comp->n_out_ports++;
1318 g_ptr_array_add (comp->ports, port);
1324 gst_omx_component_get_port (GstOMXComponent * comp, guint32 index)
1328 n = comp->ports->len;
1329 for (i = 0; i < n; i++) {
1330 GstOMXPort *tmp = g_ptr_array_index (comp->ports, i);
1332 if (tmp->index == index)
1338 /* NOTE: Uses comp->lock and comp->messages_lock */
1340 gst_omx_component_get_last_error (GstOMXComponent * comp)
1344 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1346 g_mutex_lock (&comp->lock);
1347 gst_omx_component_handle_messages (comp);
1348 err = comp->last_error;
1349 g_mutex_unlock (&comp->lock);
1351 GST_DEBUG_OBJECT (comp->parent, "Returning last %s error: %s (0x%08x)",
1352 comp->name, gst_omx_error_to_string (err), err);
1358 gst_omx_component_get_last_error_string (GstOMXComponent * comp)
1360 g_return_val_if_fail (comp != NULL, NULL);
1362 return gst_omx_error_to_string (gst_omx_component_get_last_error (comp));
1365 /* comp->lock must be unlocked while calling this */
1367 gst_omx_component_get_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1372 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1373 g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1375 GST_DEBUG_OBJECT (comp->parent, "Getting %s parameter at index 0x%08x",
1377 err = OMX_GetParameter (comp->handle, index, param);
1378 DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1379 "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1384 /* comp->lock must be unlocked while calling this */
1386 gst_omx_component_set_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1391 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1392 g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1394 GST_DEBUG_OBJECT (comp->parent, "Setting %s parameter at index 0x%08x",
1396 err = OMX_SetParameter (comp->handle, index, param);
1397 DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1398 "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1403 /* comp->lock must be unlocked while calling this */
1405 gst_omx_component_get_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1410 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1411 g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1413 GST_DEBUG_OBJECT (comp->parent, "Getting %s configuration at index 0x%08x",
1415 err = OMX_GetConfig (comp->handle, index, config);
1416 DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1417 "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1422 /* comp->lock must be unlocked while calling this */
1424 gst_omx_component_set_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1429 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1430 g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1432 GST_DEBUG_OBJECT (comp->parent, "Setting %s configuration at index 0x%08x",
1434 err = OMX_SetConfig (comp->handle, index, config);
1435 DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1436 "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1442 gst_omx_setup_tunnel (GstOMXPort * port1, GstOMXPort * port2)
1444 GstOMXComponent *comp1;
1445 GstOMXComponent *comp2;
1448 g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
1449 g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
1450 OMX_ErrorUndefined);
1451 comp1 = port1->comp;
1453 g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
1454 g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
1455 OMX_ErrorUndefined);
1456 comp2 = port2->comp;
1458 g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
1460 g_mutex_lock (&comp1->lock);
1461 g_mutex_lock (&comp2->lock);
1462 GST_DEBUG_OBJECT (comp1->parent,
1463 "Setup tunnel between %s port %u and %s port %u",
1464 comp1->name, port1->index, comp2->name, port2->index);
1466 err = comp1->core->setup_tunnel (comp1->handle, port1->index, comp2->handle,
1469 if (err == OMX_ErrorNone) {
1470 port1->tunneled = TRUE;
1471 port2->tunneled = TRUE;
1474 DEBUG_IF_OK (comp1->parent, err,
1475 "Setup tunnel between %s port %u and %s port %u: %s (0x%08x)",
1476 comp1->name, port1->index,
1477 comp2->name, port2->index, gst_omx_error_to_string (err), err);
1479 g_mutex_unlock (&comp2->lock);
1480 g_mutex_unlock (&comp1->lock);
1486 gst_omx_close_tunnel (GstOMXPort * port1, GstOMXPort * port2)
1488 GstOMXComponent *comp1;
1489 GstOMXComponent *comp2;
1492 g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
1493 g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
1494 OMX_ErrorUndefined);
1495 comp1 = port1->comp;
1497 g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
1498 g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
1499 OMX_ErrorUndefined);
1500 comp2 = port2->comp;
1502 g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
1503 g_return_val_if_fail (port1->tunneled && port2->tunneled, OMX_ErrorUndefined);
1505 g_mutex_lock (&comp1->lock);
1506 g_mutex_lock (&comp2->lock);
1507 GST_DEBUG_OBJECT (comp1->parent,
1508 "Closing tunnel between %s port %u and %s port %u",
1509 comp1->name, port1->index, comp2->name, port2->index);
1511 err = comp1->core->setup_tunnel (comp1->handle, port1->index, 0, 0);
1512 if (err != OMX_ErrorNone) {
1513 GST_ERROR_OBJECT (comp1->parent,
1514 "Failed to close tunnel on output side %s (0x%08x)",
1515 gst_omx_error_to_string (err), err);
1517 err = comp2->core->setup_tunnel (0, 0, comp2->handle, port2->index);
1518 if (err != OMX_ErrorNone) {
1519 GST_ERROR_OBJECT (comp2->parent,
1520 "Failed to close tunnel on input side %s (0x%08x)",
1521 gst_omx_error_to_string (err), err);
1524 port1->tunneled = FALSE;
1525 port2->tunneled = FALSE;
1527 GST_DEBUG_OBJECT (comp1->parent,
1528 "Closed tunnel between %s port %u and %s port %u",
1529 comp1->name, port1->index, comp2->name, port2->index);
1531 g_mutex_unlock (&comp2->lock);
1532 g_mutex_unlock (&comp1->lock);
1538 gst_omx_port_get_port_definition (GstOMXPort * port,
1539 OMX_PARAM_PORTDEFINITIONTYPE * port_def)
1541 GstOMXComponent *comp;
1544 g_return_val_if_fail (port != NULL, OMX_ErrorBadParameter);
1548 GST_OMX_INIT_STRUCT (port_def);
1549 port_def->nPortIndex = port->index;
1551 err = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1558 gst_omx_port_update_port_definition (GstOMXPort * port,
1559 OMX_PARAM_PORTDEFINITIONTYPE * port_def)
1561 OMX_ERRORTYPE err_get, err_set = OMX_ErrorNone;
1562 GstOMXComponent *comp;
1564 g_return_val_if_fail (port != NULL, FALSE);
1570 gst_omx_component_set_parameter (comp, OMX_IndexParamPortDefinition,
1572 err_get = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1575 DEBUG_IF_OK (comp->parent, err_set,
1576 "Updated %s port %u definition: %s (0x%08x)", comp->name, port->index,
1577 gst_omx_error_to_string (err_set), err_set);
1579 if (err_set != OMX_ErrorNone)
1585 /* NOTE: Uses comp->lock and comp->messages_lock */
1586 GstOMXAcquireBufferReturn
1587 gst_omx_port_acquire_buffer (GstOMXPort * port, GstOMXBuffer ** buf,
1590 GstOMXAcquireBufferReturn ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
1591 GstOMXComponent *comp;
1593 GstOMXBuffer *_buf = NULL;
1594 gint64 timeout = GST_CLOCK_TIME_NONE;
1596 g_return_val_if_fail (port != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
1597 g_return_val_if_fail (!port->tunneled, GST_OMX_ACQUIRE_BUFFER_ERROR);
1598 g_return_val_if_fail (buf != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
1604 g_mutex_lock (&comp->lock);
1605 GST_DEBUG_OBJECT (comp->parent, "Acquiring %s buffer from port %u",
1606 comp->name, port->index);
1609 gst_omx_component_handle_messages (comp);
1611 /* If we are in the case where we waited for a buffer after EOS,
1612 * make sure we don't do that again */
1616 /* Check if the component is in an error state */
1617 if ((err = comp->last_error) != OMX_ErrorNone) {
1618 GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s",
1619 comp->name, gst_omx_error_to_string (err));
1620 ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
1624 /* Check if the port is flushing */
1625 if (port->flushing) {
1626 GST_DEBUG_OBJECT (comp->parent, "Component %s port %d is flushing",
1627 comp->name, port->index);
1628 ret = GST_OMX_ACQUIRE_BUFFER_FLUSHING;
1632 /* If this is an input port and at least one of the output ports
1633 * needs to be reconfigured, we wait until all output ports are
1634 * reconfigured. Afterwards this port is reconfigured if required
1635 * or buffers are returned to be filled as usual.
1637 if (port->port_def.eDir == OMX_DirInput) {
1638 if (comp->pending_reconfigure_outports) {
1639 gst_omx_component_handle_messages (comp);
1640 while (comp->pending_reconfigure_outports &&
1641 (err = comp->last_error) == OMX_ErrorNone && !port->flushing) {
1642 GST_DEBUG_OBJECT (comp->parent,
1643 "Waiting for %s output ports to reconfigure", comp->name);
1644 gst_omx_component_wait_message (comp, GST_CLOCK_TIME_NONE);
1645 gst_omx_component_handle_messages (comp);
1650 /* Only if this port needs to be reconfigured too notify
1651 * the caller about it */
1652 if (port->settings_cookie != port->configured_settings_cookie) {
1653 GST_DEBUG_OBJECT (comp->parent,
1654 "Component %s port %d needs reconfiguring", comp->name, port->index);
1655 ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
1660 /* If we have an output port that needs to be reconfigured
1661 * and it still has buffers pending for the old configuration
1662 * we first return them.
1663 * NOTE: If buffers for this configuration arrive later
1664 * we have to drop them... */
1665 if (port->port_def.eDir == OMX_DirOutput &&
1666 port->settings_cookie != port->configured_settings_cookie) {
1667 if (!g_queue_is_empty (&port->pending_buffers)) {
1668 GST_DEBUG_OBJECT (comp->parent,
1669 "%s output port %u needs reconfiguration but has buffers pending",
1670 comp->name, port->index);
1671 _buf = g_queue_pop_head (&port->pending_buffers);
1673 ret = GST_OMX_ACQUIRE_BUFFER_OK;
1677 GST_DEBUG_OBJECT (comp->parent, "Component %s port %d needs reconfiguring",
1678 comp->name, port->index);
1679 ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
1683 if (port->port_def.eDir == OMX_DirOutput && port->eos) {
1684 if (!g_queue_is_empty (&port->pending_buffers)) {
1685 GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but has "
1686 "buffers pending", comp->name, port->index);
1687 _buf = g_queue_pop_head (&port->pending_buffers);
1689 ret = GST_OMX_ACQUIRE_BUFFER_OK;
1693 if (comp->hacks & GST_OMX_HACK_SIGNALS_PREMATURE_EOS && timeout != -2) {
1694 timeout = 33 * GST_MSECOND;
1696 GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but waiting "
1697 "in case it spits out more buffers", comp->name, port->index);
1699 GST_DEBUG_OBJECT (comp->parent, "Component %s port %d signalled EOS",
1700 comp->name, port->index);
1701 ret = GST_OMX_ACQUIRE_BUFFER_EOS;
1708 * At this point we have no error or flushing/eos port
1709 * and a properly configured port.
1713 /* If the queue is empty we wait until a buffer
1714 * arrives, an error happens, the port is flushing
1715 * or the port needs to be reconfigured.
1717 if (g_queue_is_empty (&port->pending_buffers)) {
1718 GST_DEBUG_OBJECT (comp->parent, "Queue of %s port %u is empty",
1719 comp->name, port->index);
1721 if (wait == GST_OMX_WAIT) {
1722 gst_omx_component_wait_message (comp,
1723 timeout == -2 ? GST_CLOCK_TIME_NONE : timeout);
1725 /* And now check everything again and maybe get a buffer */
1728 ret = GST_OMX_ACQUIRE_BUFFER_NO_AVAILABLE;
1733 GST_DEBUG_OBJECT (comp->parent, "%s port %u has pending buffers",
1734 comp->name, port->index);
1735 _buf = g_queue_pop_head (&port->pending_buffers);
1736 ret = GST_OMX_ACQUIRE_BUFFER_OK;
1739 g_mutex_unlock (&comp->lock);
1742 g_assert (_buf == _buf->omx_buf->pAppPrivate);
1746 GST_DEBUG_OBJECT (comp->parent, "Acquired buffer %p (%p) from %s port %u: %d",
1747 _buf, (_buf ? _buf->omx_buf->pBuffer : NULL), comp->name, port->index,
1753 /* NOTE: Uses comp->lock and comp->messages_lock */
1755 gst_omx_port_release_buffer (GstOMXPort * port, GstOMXBuffer * buf)
1757 GstOMXComponent *comp;
1758 OMX_ERRORTYPE err = OMX_ErrorNone;
1760 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
1761 g_return_val_if_fail (!port->tunneled, OMX_ErrorUndefined);
1762 g_return_val_if_fail (buf != NULL, OMX_ErrorUndefined);
1763 g_return_val_if_fail (buf->port == port, OMX_ErrorUndefined);
1767 g_mutex_lock (&comp->lock);
1769 GST_DEBUG_OBJECT (comp->parent, "Releasing buffer %p (%p) to %s port %u",
1770 buf, buf->omx_buf->pBuffer, comp->name, port->index);
1772 gst_omx_component_handle_messages (comp);
1774 if (port->port_def.eDir == OMX_DirOutput) {
1775 /* Reset all flags, some implementations don't
1776 * reset them themselves and the flags are not
1777 * valid anymore after the buffer was consumed
1779 gst_omx_buffer_reset (buf);
1782 if ((err = comp->last_error) != OMX_ErrorNone) {
1783 GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
1784 "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
1785 g_queue_push_tail (&port->pending_buffers, buf);
1786 gst_omx_component_send_message (comp, NULL);
1790 if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
1791 GST_DEBUG_OBJECT (comp->parent,
1792 "%s port %u is flushing or disabled, not releasing " "buffer",
1793 comp->name, port->index);
1794 g_queue_push_tail (&port->pending_buffers, buf);
1795 gst_omx_component_send_message (comp, NULL);
1799 g_assert (buf == buf->omx_buf->pAppPrivate);
1801 /* FIXME: What if the settings cookies don't match? */
1805 if (port->port_def.eDir == OMX_DirInput) {
1806 log_omx_performance_buffer (comp, "EmptyThisBuffer", buf);
1807 err = OMX_EmptyThisBuffer (comp->handle, buf->omx_buf);
1809 log_omx_performance_buffer (comp, "FillThisBuffer", buf);
1810 err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
1812 DEBUG_IF_OK (comp->parent, err, "Released buffer %p to %s port %u: %s "
1813 "(0x%08x)", buf, comp->name, port->index, gst_omx_error_to_string (err),
1817 gst_omx_component_handle_messages (comp);
1818 g_mutex_unlock (&comp->lock);
1823 /* NOTE: Must be called while holding comp->lock */
1825 should_wait_until_flushed (GstOMXPort * port)
1828 /* Flush command hasn't been completed yet by OMX */
1831 if (port->buffers) {
1834 /* Wait for all the buffers used by OMX to be released */
1835 for (i = 0; i < port->buffers->len; i++) {
1836 GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
1846 /* NOTE: Uses comp->lock and comp->messages_lock */
1848 gst_omx_port_set_flushing (GstOMXPort * port, GstClockTime timeout,
1851 GstOMXComponent *comp;
1852 OMX_ERRORTYPE err = OMX_ErrorNone;
1854 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
1858 g_mutex_lock (&comp->lock);
1860 GST_DEBUG_OBJECT (comp->parent, "Setting %s port %d to %sflushing",
1861 comp->name, port->index, (flush ? "" : "not "));
1863 gst_omx_component_handle_messages (comp);
1865 if (! !flush == ! !port->flushing) {
1866 GST_DEBUG_OBJECT (comp->parent, "%s port %u was %sflushing already",
1867 comp->name, port->index, (flush ? "" : "not "));
1871 if ((err = comp->last_error) != OMX_ErrorNone) {
1872 GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
1873 "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
1877 port->flushing = flush;
1880 OMX_ERRORTYPE last_error;
1882 gst_omx_component_send_message (comp, NULL);
1884 /* Now flush the port */
1885 port->flushed = FALSE;
1888 gst_omx_component_send_command (comp, OMX_CommandFlush, port->index,
1891 if (err != OMX_ErrorNone) {
1892 GST_ERROR_OBJECT (comp->parent,
1893 "Error sending flush command to %s port %u: %s (0x%08x)", comp->name,
1894 port->index, gst_omx_error_to_string (err), err);
1898 if ((err = comp->last_error) != OMX_ErrorNone) {
1899 GST_ERROR_OBJECT (comp->parent,
1900 "Component %s is in error state: %s (0x%08x)", comp->name,
1901 gst_omx_error_to_string (err), err);
1905 if (! !port->flushing != ! !flush) {
1906 GST_ERROR_OBJECT (comp->parent, "%s: another flush happened in the "
1907 " meantime", comp->name);
1912 if (should_wait_until_flushed (port))
1913 err = OMX_ErrorTimeout;
1917 /* Retry until timeout or until an error happend or
1918 * until all buffers were released by the component and
1919 * the flush command completed */
1921 last_error = OMX_ErrorNone;
1922 gst_omx_component_handle_messages (comp);
1923 while (should_wait_until_flushed (port)) {
1924 signalled = gst_omx_component_wait_message (comp, timeout);
1926 gst_omx_component_handle_messages (comp);
1928 last_error = comp->last_error;
1930 if (!signalled || last_error != OMX_ErrorNone)
1931 /* Something gone wrong or we timed out */
1934 port->flushed = FALSE;
1936 GST_DEBUG_OBJECT (comp->parent, "%s port %d flushed", comp->name,
1938 if (last_error != OMX_ErrorNone) {
1939 GST_ERROR_OBJECT (comp->parent,
1940 "Got error while flushing %s port %u: %s (0x%08x)", comp->name,
1941 port->index, gst_omx_error_to_string (last_error), last_error);
1944 } else if (!signalled) {
1945 GST_ERROR_OBJECT (comp->parent, "Timeout while flushing %s port %u",
1946 comp->name, port->index);
1947 err = OMX_ErrorTimeout;
1952 /* Reset EOS flag */
1956 gst_omx_port_update_port_definition (port, NULL);
1958 DEBUG_IF_OK (comp->parent, err, "Set %s port %u to %sflushing: %s (0x%08x)",
1959 comp->name, port->index, (flush ? "" : "not "),
1960 gst_omx_error_to_string (err), err);
1961 gst_omx_component_handle_messages (comp);
1962 g_mutex_unlock (&comp->lock);
1967 /* NOTE: Uses comp->lock and comp->messages_lock */
1969 gst_omx_port_is_flushing (GstOMXPort * port)
1971 GstOMXComponent *comp;
1974 g_return_val_if_fail (port != NULL, FALSE);
1978 g_mutex_lock (&comp->lock);
1979 gst_omx_component_handle_messages (port->comp);
1980 flushing = port->flushing;
1981 g_mutex_unlock (&comp->lock);
1983 GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing: %d", comp->name,
1984 port->index, flushing);
1989 static OMX_ERRORTYPE gst_omx_port_deallocate_buffers_unlocked (GstOMXPort *
1992 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
1993 static OMX_ERRORTYPE
1994 gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port,
1995 const GList * buffers, const GList * images, guint n)
1997 GstOMXComponent *comp;
1998 OMX_ERRORTYPE err = OMX_ErrorNone;
2002 g_assert (!port->buffers || port->buffers->len == 0);
2004 g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
2008 gst_omx_component_handle_messages (port->comp);
2009 if ((err = comp->last_error) != OMX_ErrorNone) {
2010 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2011 comp->name, gst_omx_error_to_string (err), err);
2015 /* Update the port definition to check if we need more
2016 * buffers after the port configuration was done and to
2017 * update the buffer size
2019 gst_omx_port_update_port_definition (port, NULL);
2021 g_return_val_if_fail (n != -1 || (!buffers
2022 && !images), OMX_ErrorBadParameter);
2025 n = port->port_def.nBufferCountActual;
2027 g_return_val_if_fail (n == port->port_def.nBufferCountActual,
2028 OMX_ErrorBadParameter);
2030 GST_INFO_OBJECT (comp->parent,
2031 "Allocating %d buffers of size %" G_GSIZE_FORMAT " for %s port %u", n,
2032 (size_t) port->port_def.nBufferSize, comp->name, (guint) port->index);
2035 port->buffers = g_ptr_array_sized_new (n);
2037 l = (buffers ? buffers : images);
2038 for (i = 0; i < n; i++) {
2041 buf = g_slice_new0 (GstOMXBuffer);
2044 buf->settings_cookie = port->settings_cookie;
2045 g_ptr_array_add (port->buffers, buf);
2049 OMX_UseBuffer (comp->handle, &buf->omx_buf, port->index, buf,
2050 port->port_def.nBufferSize, l->data);
2051 buf->eglimage = FALSE;
2052 } else if (images) {
2054 OMX_UseEGLImage (comp->handle, &buf->omx_buf, port->index, buf,
2056 buf->eglimage = TRUE;
2059 OMX_AllocateBuffer (comp->handle, &buf->omx_buf, port->index, buf,
2060 port->port_def.nBufferSize);
2061 buf->eglimage = FALSE;
2064 /* Let the caller decide to print an error when OMX_UseBuffer or
2065 * OMX_UseEGLImage fail. Indeed it can be part of a trial path. So
2066 * it is not necessary to warn the user if the fallback path succeeds.
2068 if (err != OMX_ErrorNone) {
2069 GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, (buffers
2070 || images) ? GST_LEVEL_INFO : GST_LEVEL_ERROR, comp->parent,
2071 "Failed to allocate buffer for %s port %u: %s (0x%08x)", comp->name,
2072 port->index, gst_omx_error_to_string (err), err);
2073 gst_omx_port_deallocate_buffers_unlocked (port);
2077 GST_DEBUG_OBJECT (comp->parent, "%s: allocated buffer %p (%p)",
2078 comp->name, buf, buf->omx_buf->pBuffer);
2080 g_assert (buf->omx_buf->pAppPrivate == buf);
2082 /* In the beginning all buffers are not owned by the component */
2083 g_queue_push_tail (&port->pending_buffers, buf);
2084 if (buffers || images)
2088 gst_omx_component_handle_messages (comp);
2091 gst_omx_port_update_port_definition (port, NULL);
2093 INFO_IF_OK (comp->parent, err, "Allocated buffers for %s port %u: %s "
2094 "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2099 /* NOTE: Uses comp->lock and comp->messages_lock */
2101 gst_omx_port_allocate_buffers (GstOMXPort * port)
2105 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2107 g_mutex_lock (&port->comp->lock);
2108 err = gst_omx_port_allocate_buffers_unlocked (port, NULL, NULL, -1);
2109 port->allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2110 g_mutex_unlock (&port->comp->lock);
2115 /* NOTE: Uses comp->lock and comp->messages_lock */
2117 gst_omx_port_use_buffers (GstOMXPort * port, const GList * buffers)
2122 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2124 g_mutex_lock (&port->comp->lock);
2125 n = g_list_length ((GList *) buffers);
2126 err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
2127 port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER;
2128 g_mutex_unlock (&port->comp->lock);
2134 gst_omx_is_dynamic_allocation_supported (void)
2136 /* The Zynqultrascaleplus stack implements OMX 1.1.0 but supports the dynamic
2137 * allocation mode from 1.2.0 as an extension. */
2138 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2142 #if OMX_VERSION_MINOR == 2
2149 /* OMX 1.2.0 introduced a dynamic allocation mode where only buffer headers are
2150 * being allocated during component's initialization. The actual buffers are
2151 * allocated upstream and passed to OMX by setting the pBuffer dynamically
2152 * for each input buffer.
2154 * This function takes care of allocating the buffer headers. Element should
2155 * then use one of the gst_omx_buffer_map_*() method to update buffer's pBuffer
2156 * pointers for each incoming buffer.
2158 * NOTE: Uses comp->lock and comp->messages_lock */
2160 gst_omx_port_use_dynamic_buffers (GstOMXPort * port)
2163 GList *buffers = NULL;
2166 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2168 n = port->port_def.nBufferCountActual;
2169 for (i = 0; i < port->port_def.nBufferCountActual; i++)
2170 /* Pass NULL to UseBuffer() as the buffer is dynamic and so its payload
2171 * will be set each time before being passed to OMX. */
2172 buffers = g_list_prepend (buffers, GUINT_TO_POINTER (NULL));
2174 g_mutex_lock (&port->comp->lock);
2175 err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
2176 port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
2177 g_mutex_unlock (&port->comp->lock);
2179 g_list_free (buffers);
2184 /* gst_omx_buffer_map_* methods are used in dynamic buffer mode to map
2185 * a frame/memory/buffer and update @buffer so its pBuffer points to the
2186 * mapped data. It also ensures that the input will stay alive until
2187 * gst_omx_buffer_unmap() is called.
2188 * This is used in OMX 1.2.0 dynamic allocation mode so an OMX component can
2189 * safely process @buffer's content without having to copy it.
2190 * The input will be automatically unmapped when @buffer is released by OMX.
2193 gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input,
2194 GstVideoInfo * info)
2196 g_return_val_if_fail (buffer != NULL, FALSE);
2197 g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2198 g_return_val_if_fail (!buffer->input_mem, FALSE);
2199 g_return_val_if_fail (!buffer->input_buffer, FALSE);
2200 g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2202 if (!gst_video_frame_map (&buffer->input_frame, info, input, GST_MAP_READ))
2205 buffer->input_frame_mapped = TRUE;
2206 buffer->omx_buf->pBuffer =
2207 GST_VIDEO_FRAME_PLANE_DATA (&buffer->input_frame, 0);
2208 buffer->omx_buf->nAllocLen = gst_buffer_get_size (input);
2209 buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2215 gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
2217 g_return_val_if_fail (buffer != NULL, FALSE);
2218 g_return_val_if_fail (mem != NULL, FALSE);
2219 g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2220 g_return_val_if_fail (!buffer->input_mem, FALSE);
2221 g_return_val_if_fail (!buffer->input_buffer, FALSE);
2222 g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2224 if (!gst_memory_map (mem, &buffer->map, GST_MAP_READ))
2227 buffer->input_mem = gst_memory_ref (mem);
2228 buffer->omx_buf->pBuffer = buffer->map.data;
2229 buffer->omx_buf->nAllocLen = buffer->map.size;
2230 buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2236 gst_omx_buffer_import_fd (GstOMXBuffer * buffer, GstBuffer * input)
2241 g_return_val_if_fail (buffer != NULL, FALSE);
2242 g_return_val_if_fail (input != NULL, FALSE);
2243 g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2244 g_return_val_if_fail (!buffer->input_mem, FALSE);
2245 g_return_val_if_fail (!buffer->input_buffer, FALSE);
2246 g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2248 mem = gst_buffer_peek_memory (input, 0);
2249 g_return_val_if_fail (gst_is_dmabuf_memory (mem), FALSE);
2251 fd = gst_dmabuf_memory_get_fd (mem);
2253 buffer->input_buffer = gst_buffer_ref (input);
2254 buffer->omx_buf->pBuffer = GUINT_TO_POINTER (fd);
2255 buffer->omx_buf->nAllocLen = gst_memory_get_sizes (mem, NULL, NULL);
2256 buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2262 gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
2264 g_return_val_if_fail (buffer != NULL, FALSE);
2265 g_return_val_if_fail (input != NULL, FALSE);
2266 g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2267 g_return_val_if_fail (!buffer->input_mem, FALSE);
2268 g_return_val_if_fail (!buffer->input_buffer, FALSE);
2269 g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2271 if (!gst_buffer_map (input, &buffer->map, GST_MAP_READ))
2274 buffer->input_buffer_mapped = TRUE;
2275 buffer->input_buffer = gst_buffer_ref (input);
2276 buffer->omx_buf->pBuffer = buffer->map.data;
2277 buffer->omx_buf->nAllocLen = buffer->map.size;
2278 buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2283 /* NOTE: Uses comp->lock and comp->messages_lock */
2285 gst_omx_port_use_eglimages (GstOMXPort * port, const GList * images)
2290 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2292 g_mutex_lock (&port->comp->lock);
2293 n = g_list_length ((GList *) images);
2294 err = gst_omx_port_allocate_buffers_unlocked (port, NULL, images, n);
2295 g_mutex_unlock (&port->comp->lock);
2300 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2301 static OMX_ERRORTYPE
2302 gst_omx_port_deallocate_buffers_unlocked (GstOMXPort * port)
2304 GstOMXComponent *comp;
2305 OMX_ERRORTYPE err = OMX_ErrorNone;
2308 g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
2312 GST_INFO_OBJECT (comp->parent, "Deallocating buffers of %s port %u",
2313 comp->name, port->index);
2315 gst_omx_component_handle_messages (port->comp);
2317 if (!port->buffers) {
2318 GST_DEBUG_OBJECT (comp->parent, "No buffers allocated for %s port %u",
2319 comp->name, port->index);
2323 if ((err = comp->last_error) != OMX_ErrorNone) {
2324 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2325 comp->name, gst_omx_error_to_string (err), err);
2326 /* We still try to deallocate all buffers */
2329 /* We only allow deallocation of buffers after they
2330 * were all released from the port, either by flushing
2331 * the port or by disabling it.
2333 n = port->buffers->len;
2334 for (i = 0; i < n; i++) {
2335 GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
2336 OMX_ERRORTYPE tmp = OMX_ErrorNone;
2339 GST_ERROR_OBJECT (comp->parent, "Trying to free used buffer %p of %s "
2340 "port %u", buf, comp->name, port->index);
2343 /* omx_buf can be NULL if allocation failed earlier
2344 * and we're just shutting down
2346 * errors do not cause exiting this loop because we want
2347 * to deallocate as much as possible.
2350 g_assert (buf == buf->omx_buf->pAppPrivate);
2351 buf->omx_buf->pAppPrivate = NULL;
2352 GST_DEBUG_OBJECT (comp->parent, "%s: deallocating buffer %p (%p)",
2353 comp->name, buf, buf->omx_buf->pBuffer);
2355 tmp = OMX_FreeBuffer (comp->handle, port->index, buf->omx_buf);
2357 if (tmp != OMX_ErrorNone) {
2358 GST_ERROR_OBJECT (comp->parent,
2359 "Failed to deallocate buffer %d of %s port %u: %s (0x%08x)", i,
2360 comp->name, port->index, gst_omx_error_to_string (tmp), tmp);
2361 if (err == OMX_ErrorNone)
2365 g_slice_free (GstOMXBuffer, buf);
2367 g_queue_clear (&port->pending_buffers);
2368 g_ptr_array_unref (port->buffers);
2369 port->buffers = NULL;
2371 gst_omx_component_handle_messages (comp);
2374 gst_omx_port_update_port_definition (port, NULL);
2376 DEBUG_IF_OK (comp->parent, err, "Deallocated buffers of %s port %u: %s "
2377 "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2382 /* NOTE: Uses comp->lock and comp->messages_lock */
2384 gst_omx_port_deallocate_buffers (GstOMXPort * port)
2388 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2390 g_mutex_lock (&port->comp->lock);
2391 err = gst_omx_port_deallocate_buffers_unlocked (port);
2392 g_mutex_unlock (&port->comp->lock);
2397 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2398 static OMX_ERRORTYPE
2399 gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled)
2401 GstOMXComponent *comp;
2402 OMX_ERRORTYPE err = OMX_ErrorNone;
2406 gst_omx_component_handle_messages (comp);
2408 if ((err = comp->last_error) != OMX_ErrorNone) {
2409 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2410 comp->name, gst_omx_error_to_string (err), err);
2414 if (port->enabled_pending || port->disabled_pending) {
2415 GST_ERROR_OBJECT (comp->parent, "%s port %d enabled/disabled pending "
2416 "already", comp->name, port->index);
2417 #if OMX_VERSION_MINOR == 2
2418 err = OMX_ErrorBadParameter;
2420 err = OMX_ErrorInvalidState;
2425 GST_INFO_OBJECT (comp->parent, "Setting %s port %u to %s", comp->name,
2426 port->index, (enabled ? "enabled" : "disabled"));
2428 /* Check if the port is already enabled/disabled first */
2429 gst_omx_port_update_port_definition (port, NULL);
2430 if (! !port->port_def.bEnabled == ! !enabled)
2434 port->enabled_pending = TRUE;
2436 port->disabled_pending = TRUE;
2440 gst_omx_component_send_command (comp, OMX_CommandPortEnable,
2444 gst_omx_component_send_command (comp, OMX_CommandPortDisable,
2447 if (err != OMX_ErrorNone) {
2448 GST_ERROR_OBJECT (comp->parent,
2449 "Failed to send enable/disable command to %s port %u: %s (0x%08x)",
2450 comp->name, port->index, gst_omx_error_to_string (err), err);
2454 if ((err = comp->last_error) != OMX_ErrorNone) {
2455 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2456 comp->name, gst_omx_error_to_string (err), err);
2461 gst_omx_component_handle_messages (comp);
2463 gst_omx_port_update_port_definition (port, NULL);
2465 INFO_IF_OK (comp->parent, err, "Set %s port %u to %s%s: %s (0x%08x)",
2466 comp->name, port->index, (err == OMX_ErrorNone ? "" : "not "),
2467 (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
2472 static OMX_ERRORTYPE
2473 gst_omx_port_wait_buffers_released_unlocked (GstOMXPort * port,
2474 GstClockTime timeout)
2476 GstOMXComponent *comp;
2477 OMX_ERRORTYPE err = OMX_ErrorNone;
2478 OMX_ERRORTYPE last_error;
2483 gst_omx_component_handle_messages (comp);
2485 if ((err = comp->last_error) != OMX_ErrorNone) {
2486 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2487 comp->name, gst_omx_error_to_string (err), err);
2491 GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to release all "
2492 "buffers", comp->name, port->index);
2495 if (!port->flushed || (port->buffers
2496 && port->buffers->len >
2497 g_queue_get_length (&port->pending_buffers)))
2498 err = OMX_ErrorTimeout;
2502 /* Wait until all buffers are released by the port */
2504 last_error = OMX_ErrorNone;
2505 gst_omx_component_handle_messages (comp);
2506 while (signalled && last_error == OMX_ErrorNone && (port->buffers
2507 && port->buffers->len >
2508 g_queue_get_length (&port->pending_buffers))) {
2509 signalled = gst_omx_component_wait_message (comp, timeout);
2511 gst_omx_component_handle_messages (comp);
2512 last_error = comp->last_error;
2515 if (last_error != OMX_ErrorNone) {
2517 GST_ERROR_OBJECT (comp->parent,
2518 "Got error while waiting for %s port %u to release all buffers: %s "
2519 "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err),
2522 } else if (!signalled) {
2523 GST_ERROR_OBJECT (comp->parent, "Timeout waiting for %s port %u to "
2524 "release all buffers", comp->name, port->index);
2525 err = OMX_ErrorTimeout;
2530 gst_omx_component_handle_messages (comp);
2532 gst_omx_port_update_port_definition (port, NULL);
2534 DEBUG_IF_OK (comp->parent, err,
2535 "Waited for %s port %u to release all buffers: %s (0x%08x)", comp->name,
2536 port->index, gst_omx_error_to_string (err), err);
2541 /* NOTE: Uses comp->lock and comp->messages_lock */
2543 gst_omx_port_wait_buffers_released (GstOMXPort * port, GstClockTime timeout)
2547 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2549 g_mutex_lock (&port->comp->lock);
2550 err = gst_omx_port_wait_buffers_released_unlocked (port, timeout);
2551 g_mutex_unlock (&port->comp->lock);
2556 /* NOTE: Uses comp->lock and comp->messages_lock */
2558 gst_omx_port_set_enabled (GstOMXPort * port, gboolean enabled)
2562 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2564 g_mutex_lock (&port->comp->lock);
2565 err = gst_omx_port_set_enabled_unlocked (port, enabled);
2566 g_mutex_unlock (&port->comp->lock);
2571 static OMX_ERRORTYPE
2572 gst_omx_port_populate_unlocked (GstOMXPort * port)
2574 GstOMXComponent *comp;
2575 OMX_ERRORTYPE err = OMX_ErrorNone;
2578 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2582 GST_DEBUG_OBJECT (comp->parent, "Populating %s port %d", comp->name,
2585 gst_omx_component_handle_messages (comp);
2587 if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
2588 GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing or disabled",
2589 comp->name, port->index);
2590 err = OMX_ErrorIncorrectStateOperation;
2594 if ((err = comp->last_error) != OMX_ErrorNone) {
2595 GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s"
2596 "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
2600 if (port->port_def.eDir == OMX_DirOutput && port->buffers && !port->tunneled) {
2601 /* Enqueue all buffers for the component to fill */
2602 while ((buf = g_queue_pop_head (&port->pending_buffers))) {
2603 g_assert (!buf->used);
2605 /* Reset all flags, some implementations don't
2606 * reset them themselves and the flags are not
2607 * valid anymore after the buffer was consumed.
2608 * Also reset nFilledLen as FillThisBuffer() expects an empty buffer.
2610 gst_omx_buffer_reset (buf);
2612 log_omx_performance_buffer (comp, "FillThisBuffer", buf);
2613 err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
2615 if (err != OMX_ErrorNone) {
2616 GST_ERROR_OBJECT (comp->parent,
2617 "Failed to pass buffer %p (%p) to %s port %u: %s (0x%08x)", buf,
2618 buf->omx_buf->pBuffer, comp->name, port->index,
2619 gst_omx_error_to_string (err), err);
2622 GST_DEBUG_OBJECT (comp->parent, "Passed buffer %p (%p) to component %s",
2623 buf, buf->omx_buf->pBuffer, comp->name);
2628 gst_omx_port_update_port_definition (port, NULL);
2630 DEBUG_IF_OK (comp->parent, err, "Populated %s port %u: %s (0x%08x)",
2631 comp->name, port->index, gst_omx_error_to_string (err), err);
2632 gst_omx_component_handle_messages (comp);
2637 /* NOTE: Uses comp->lock and comp->messages_lock */
2639 gst_omx_port_populate (GstOMXPort * port)
2643 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2645 g_mutex_lock (&port->comp->lock);
2646 err = gst_omx_port_populate_unlocked (port);
2647 g_mutex_unlock (&port->comp->lock);
2652 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2653 static OMX_ERRORTYPE
2654 gst_omx_port_wait_enabled_unlocked (GstOMXPort * port, GstClockTime timeout)
2656 GstOMXComponent *comp;
2657 OMX_ERRORTYPE err = OMX_ErrorNone;
2659 OMX_ERRORTYPE last_error;
2664 /* Check the current port status */
2665 gst_omx_port_update_port_definition (port, NULL);
2667 if (port->enabled_pending)
2669 else if (port->disabled_pending)
2672 enabled = port->port_def.bEnabled;
2674 gst_omx_component_handle_messages (comp);
2676 if ((err = comp->last_error) != OMX_ErrorNone) {
2677 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2678 comp->name, gst_omx_error_to_string (err), err);
2682 GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to be %s",
2683 comp->name, port->index, (enabled ? "enabled" : "disabled"));
2686 if (port->enabled_pending || port->disabled_pending)
2687 err = OMX_ErrorTimeout;
2691 /* And now wait until the enable/disable command is finished */
2693 last_error = OMX_ErrorNone;
2694 gst_omx_port_update_port_definition (port, NULL);
2695 gst_omx_component_handle_messages (comp);
2696 while (signalled && last_error == OMX_ErrorNone &&
2697 (! !port->port_def.bEnabled != ! !enabled || port->enabled_pending
2698 || port->disabled_pending)) {
2699 signalled = gst_omx_component_wait_message (comp, timeout);
2701 gst_omx_component_handle_messages (comp);
2702 last_error = comp->last_error;
2703 gst_omx_port_update_port_definition (port, NULL);
2705 port->enabled_pending = FALSE;
2706 port->disabled_pending = FALSE;
2709 GST_ERROR_OBJECT (comp->parent,
2710 "Timeout waiting for %s port %u to be %s", comp->name, port->index,
2711 (enabled ? "enabled" : "disabled"));
2712 err = OMX_ErrorTimeout;
2714 } else if (last_error != OMX_ErrorNone) {
2715 GST_ERROR_OBJECT (comp->parent,
2716 "Got error while waiting for %s port %u to be %s: %s (0x%08x)",
2717 comp->name, port->index, (enabled ? "enabled" : "disabled"),
2718 gst_omx_error_to_string (err), err);
2722 /* Reset EOS flag */
2727 gst_omx_component_handle_messages (comp);
2730 gst_omx_port_update_port_definition (port, NULL);
2732 GST_INFO_OBJECT (comp->parent, "%s port %u is %s%s: %s (0x%08x)", comp->name,
2733 port->index, (err == OMX_ErrorNone ? "" : "not "),
2734 (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
2739 /* NOTE: Uses comp->lock and comp->messages_lock */
2741 gst_omx_port_wait_enabled (GstOMXPort * port, GstClockTime timeout)
2745 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2747 g_mutex_lock (&port->comp->lock);
2748 err = gst_omx_port_wait_enabled_unlocked (port, timeout);
2749 g_mutex_unlock (&port->comp->lock);
2755 gst_omx_port_is_enabled (GstOMXPort * port)
2759 g_return_val_if_fail (port != NULL, FALSE);
2761 gst_omx_port_update_port_definition (port, NULL);
2762 enabled = ! !port->port_def.bEnabled;
2764 GST_DEBUG_OBJECT (port->comp->parent, "%s port %u is enabled: %d",
2765 port->comp->name, port->index, enabled);
2770 /* NOTE: Uses comp->lock and comp->messages_lock */
2772 gst_omx_port_mark_reconfigured (GstOMXPort * port)
2774 GstOMXComponent *comp;
2775 OMX_ERRORTYPE err = OMX_ErrorNone;
2777 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2781 g_mutex_lock (&comp->lock);
2782 GST_INFO_OBJECT (comp->parent, "Marking %s port %u is reconfigured",
2783 comp->name, port->index);
2785 gst_omx_component_handle_messages (comp);
2787 if ((err = comp->last_error) != OMX_ErrorNone)
2790 port->configured_settings_cookie = port->settings_cookie;
2792 if (port->port_def.eDir == OMX_DirOutput) {
2795 for (l = comp->pending_reconfigure_outports; l; l = l->next) {
2796 if (l->data == (gpointer) port) {
2797 comp->pending_reconfigure_outports =
2798 g_list_delete_link (comp->pending_reconfigure_outports, l);
2802 if (!comp->pending_reconfigure_outports)
2803 gst_omx_component_send_message (comp, NULL);
2807 gst_omx_port_update_port_definition (port, NULL);
2809 INFO_IF_OK (comp->parent, err, "Marked %s port %u as reconfigured: %s "
2810 "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2812 g_mutex_unlock (&comp->lock);
2817 /* The OMX specs states that the nBufferCountActual of a port has to default
2818 * to its nBufferCountMin. If we don't change nBufferCountActual we purely rely
2819 * on this default. But in some cases, OMX may change nBufferCountMin before we
2820 * allocate buffers. Like for example when configuring the input ports with the
2821 * actual format, it may decrease the number of minimal buffers required.
2822 * This method checks this and update nBufferCountActual if needed so we'll use
2823 * less buffers than the worst case in such scenarios.
2826 gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port, guint extra)
2828 OMX_PARAM_PORTDEFINITIONTYPE port_def;
2831 gst_omx_port_get_port_definition (port, &port_def);
2833 nb = port_def.nBufferCountMin + extra;
2834 if (port_def.nBufferCountActual != nb) {
2835 port_def.nBufferCountActual = nb;
2837 GST_DEBUG_OBJECT (port->comp->parent,
2838 "set port %d nBufferCountActual to %d", (guint) port->index, nb);
2840 if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
2848 gst_omx_port_update_buffer_count_actual (GstOMXPort * port, guint nb)
2850 OMX_PARAM_PORTDEFINITIONTYPE port_def;
2852 gst_omx_port_get_port_definition (port, &port_def);
2854 if (nb < port_def.nBufferCountMin) {
2855 GST_DEBUG_OBJECT (port->comp->parent,
2856 "Requested to use %d buffers on port %d but it's minimum is %d", nb,
2857 (guint) port->index, (guint) port_def.nBufferCountMin);
2859 nb = port_def.nBufferCountMin;
2862 if (port_def.nBufferCountActual != nb) {
2863 port_def.nBufferCountActual = nb;
2865 GST_DEBUG_OBJECT (port->comp->parent,
2866 "set port %d nBufferCountActual to %d", (guint) port->index, nb);
2868 if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
2876 gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf)
2878 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2879 OMX_ALG_PORT_PARAM_BUFFER_MODE buffer_mode;
2882 GST_OMX_INIT_STRUCT (&buffer_mode);
2883 buffer_mode.nPortIndex = port->index;
2886 buffer_mode.eMode = OMX_ALG_BUF_DMA;
2888 buffer_mode.eMode = OMX_ALG_BUF_NORMAL;
2891 gst_omx_component_set_parameter (port->comp,
2892 (OMX_INDEXTYPE) OMX_ALG_IndexPortParamBufferMode, &buffer_mode);
2893 if (err != OMX_ErrorNone) {
2894 GST_WARNING_OBJECT (port->comp->parent,
2895 "Failed to set port %d in %sdmabuf mode: %s (0x%08x)",
2896 port->index, dmabuf ? "" : "non-", gst_omx_error_to_string (err), err);
2902 /* dmabuf not supported for this platform */
2907 typedef GType (*GGetTypeFunction) (void);
2909 static const GGetTypeFunction types[] = {
2910 gst_omx_analog_audio_sink_get_type, gst_omx_hdmi_audio_sink_get_type,
2911 gst_omx_mpeg2_video_dec_get_type, gst_omx_mpeg4_video_dec_get_type,
2912 gst_omx_h264_dec_get_type, gst_omx_h263_dec_get_type,
2913 gst_omx_wmv_dec_get_type, gst_omx_mpeg4_video_enc_get_type,
2914 gst_omx_h264_enc_get_type, gst_omx_h263_enc_get_type,
2915 gst_omx_aac_enc_get_type, gst_omx_mjpeg_dec_get_type,
2916 gst_omx_aac_dec_get_type, gst_omx_mp3_dec_get_type,
2917 gst_omx_aac_dec_get_type, gst_omx_mp3_enc_get_type,
2918 gst_omx_amr_dec_get_type
2920 , gst_omx_vp8_dec_get_type
2923 , gst_omx_theora_dec_get_type
2926 , gst_omx_h265_enc_get_type, gst_omx_h265_dec_get_type
2932 GType (*get_type) (void);
2936 static const struct TypeOffest base_types[] = {
2937 {gst_omx_audio_sink_get_type, G_STRUCT_OFFSET (GstOMXAudioSinkClass, cdata)},
2938 {gst_omx_video_dec_get_type, G_STRUCT_OFFSET (GstOMXVideoDecClass, cdata)},
2939 {gst_omx_video_enc_get_type, G_STRUCT_OFFSET (GstOMXVideoEncClass, cdata)},
2940 {gst_omx_audio_dec_get_type, G_STRUCT_OFFSET (GstOMXAudioDecClass, cdata)},
2941 {gst_omx_audio_enc_get_type, G_STRUCT_OFFSET (GstOMXAudioEncClass, cdata)},
2944 static GKeyFile *config = NULL;
2946 gst_omx_get_configuration (void)
2952 gst_omx_error_to_string (OMX_ERRORTYPE err)
2954 guint err_u = (guint) err;
2959 case OMX_ErrorInsufficientResources:
2960 return "Insufficient resources";
2961 case OMX_ErrorUndefined:
2963 case OMX_ErrorInvalidComponentName:
2964 return "Invalid component name";
2965 case OMX_ErrorComponentNotFound:
2966 return "Component not found";
2967 case OMX_ErrorBadParameter:
2968 return "Bad parameter";
2969 case OMX_ErrorNotImplemented:
2970 return "Not implemented";
2971 case OMX_ErrorUnderflow:
2973 case OMX_ErrorOverflow:
2975 case OMX_ErrorHardware:
2977 case OMX_ErrorStreamCorrupt:
2978 return "Stream corrupt";
2979 case OMX_ErrorPortsNotCompatible:
2980 return "Ports not compatible";
2981 case OMX_ErrorResourcesLost:
2982 return "Resources lost";
2983 case OMX_ErrorNoMore:
2985 case OMX_ErrorVersionMismatch:
2986 return "Version mismatch";
2987 case OMX_ErrorNotReady:
2989 case OMX_ErrorTimeout:
2991 case OMX_ErrorSameState:
2992 return "Same state";
2993 case OMX_ErrorResourcesPreempted:
2994 return "Resources preempted";
2995 case OMX_ErrorIncorrectStateTransition:
2996 return "Incorrect state transition";
2997 case OMX_ErrorIncorrectStateOperation:
2998 return "Incorrect state operation";
2999 case OMX_ErrorUnsupportedSetting:
3000 return "Unsupported setting";
3001 case OMX_ErrorUnsupportedIndex:
3002 return "Unsupported index";
3003 case OMX_ErrorBadPortIndex:
3004 return "Bad port index";
3005 case OMX_ErrorPortUnpopulated:
3006 return "Port unpopulated";
3007 case OMX_ErrorComponentSuspended:
3008 return "Component suspended";
3009 case OMX_ErrorDynamicResourcesUnavailable:
3010 return "Dynamic resources unavailable";
3011 case OMX_ErrorMbErrorsInFrame:
3012 return "Macroblock errors in frame";
3013 case OMX_ErrorFormatNotDetected:
3014 return "Format not detected";
3015 case OMX_ErrorSeperateTablesUsed:
3016 return "Separate tables used";
3017 case OMX_ErrorTunnelingUnsupported:
3018 return "Tunneling unsupported";
3019 #if OMX_VERSION_MINOR == 1
3020 case OMX_ErrorInvalidComponent:
3021 return "Invalid component";
3022 case OMX_ErrorInvalidState:
3023 return "Invalid state";
3024 case OMX_ErrorPortUnresponsiveDuringAllocation:
3025 return "Port unresponsive during allocation";
3026 case OMX_ErrorPortUnresponsiveDuringDeallocation:
3027 return "Port unresponsive during deallocation";
3028 case OMX_ErrorPortUnresponsiveDuringStop:
3029 return "Port unresponsive during stop";
3030 case OMX_ErrorContentPipeOpenFailed:
3031 return "Content pipe open failed";
3032 case OMX_ErrorContentPipeCreationFailed:
3033 return "Content pipe creation failed";
3036 if (err_u >= (guint) OMX_ErrorKhronosExtensions
3037 && err_u < (guint) OMX_ErrorVendorStartUnused) {
3038 return "Khronos extension error";
3039 } else if (err_u >= (guint) OMX_ErrorVendorStartUnused
3040 && err_u < (guint) OMX_ErrorMax) {
3041 return "Vendor specific error";
3043 return "Unknown error";
3049 gst_omx_state_to_string (OMX_STATETYPE state)
3052 case OMX_StateInvalid:
3054 case OMX_StateLoaded:
3058 case OMX_StateExecuting:
3060 case OMX_StatePause:
3062 case OMX_StateWaitForResources:
3063 return "WaitForResources";
3065 if (state >= OMX_StateKhronosExtensions
3066 && state < OMX_StateVendorStartUnused)
3067 return "KhronosExtensionState";
3068 else if (state >= OMX_StateVendorStartUnused && state < OMX_StateMax)
3069 return "CustomVendorState";
3072 return "Unknown state";
3076 gst_omx_command_to_string (OMX_COMMANDTYPE cmd)
3079 case OMX_CommandStateSet:
3081 case OMX_CommandFlush:
3083 case OMX_CommandPortDisable:
3084 return "DisablePort";
3085 case OMX_CommandPortEnable:
3086 return "EnablePort";
3087 case OMX_CommandMarkBuffer:
3088 return "MarkBuffer";
3090 if (cmd >= OMX_CommandKhronosExtensions
3091 && cmd < OMX_CommandVendorStartUnused)
3092 return "KhronosExtensionCommand";
3093 if (cmd >= OMX_CommandVendorStartUnused && cmd < OMX_CommandMax)
3094 return "VendorExtensionCommand";
3097 return "Unknown command";
3100 struct BufferFlagString
3106 struct BufferFlagString buffer_flags_map[] = {
3107 {OMX_BUFFERFLAG_EOS, "eos"},
3108 {OMX_BUFFERFLAG_STARTTIME, "start-time"},
3109 {OMX_BUFFERFLAG_DECODEONLY, "decode-only"},
3110 {OMX_BUFFERFLAG_DATACORRUPT, "data-corrupt"},
3111 {OMX_BUFFERFLAG_ENDOFFRAME, "end-of-frame"},
3112 {OMX_BUFFERFLAG_SYNCFRAME, "sync-frame"},
3113 {OMX_BUFFERFLAG_EXTRADATA, "extra-data"},
3114 {OMX_BUFFERFLAG_CODECCONFIG, "codec-config"},
3115 /* Introduced in OMX 1.2.0 */
3116 #ifdef OMX_BUFFERFLAG_TIMESTAMPINVALID
3117 {OMX_BUFFERFLAG_TIMESTAMPINVALID, "timestamp-invalid"},
3119 #ifdef OMX_BUFFERFLAG_READONLY
3120 {OMX_BUFFERFLAG_READONLY, "read-only"},
3122 #ifdef OMX_BUFFERFLAG_ENDOFSUBFRAME
3123 {OMX_BUFFERFLAG_ENDOFSUBFRAME, "end-of-subframe"},
3125 #ifdef OMX_BUFFERFLAG_SKIPFRAME
3126 {OMX_BUFFERFLAG_SKIPFRAME, "skip-frame"},
3133 gst_omx_buffer_flags_to_string (guint32 flags)
3142 /* Keep a cache of the string representation of the flags so we don't allocate
3143 * and free strings for each buffer. In practice we should only have a handfull
3144 * of flags so the cache won't consume much memory. */
3145 if (!buffer_flags_str) {
3146 G_LOCK (buffer_flags_str);
3147 buffer_flags_str = g_hash_table_new_full (NULL, NULL, NULL, g_free);
3148 G_UNLOCK (buffer_flags_str);
3151 str = g_hash_table_lookup (buffer_flags_str, GUINT_TO_POINTER (flags));
3155 for (i = 0; buffer_flags_map[i].str != NULL; i++) {
3156 if ((flags & buffer_flags_map[i].flag) == 0)
3160 s = g_string_new (buffer_flags_map[i].str);
3162 g_string_append_printf (s, ", %s", buffer_flags_map[i].str);
3168 str = g_string_free (s, FALSE);
3170 G_LOCK (buffer_flags_str);
3171 /* Transfer ownership of str to hash table */
3172 g_hash_table_insert (buffer_flags_str, GUINT_TO_POINTER (flags),
3174 G_UNLOCK (buffer_flags_str);
3179 #if defined(USE_OMX_TARGET_RPI)
3180 #define DEFAULT_HACKS (GST_OMX_HACK_NO_COMPONENT_ROLE | GST_OMX_HACK_HEIGHT_MULTIPLE_16)
3182 #define DEFAULT_HACKS (0)
3186 gst_omx_parse_hacks (gchar ** hacks)
3188 guint64 hacks_flags = DEFAULT_HACKS;
3194 if (g_str_equal (*hacks,
3195 "event-port-settings-changed-ndata-parameter-swap"))
3197 GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_NDATA_PARAMETER_SWAP;
3198 else if (g_str_equal (*hacks, "event-port-settings-changed-port-0-to-1"))
3199 hacks_flags |= GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_PORT_0_TO_1;
3200 else if (g_str_equal (*hacks, "video-framerate-integer"))
3201 hacks_flags |= GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER;
3202 else if (g_str_equal (*hacks, "syncframe-flag-not-used"))
3203 hacks_flags |= GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED;
3204 else if (g_str_equal (*hacks, "no-component-reconfigure"))
3205 hacks_flags |= GST_OMX_HACK_NO_COMPONENT_RECONFIGURE;
3206 else if (g_str_equal (*hacks, "no-empty-eos-buffer"))
3207 hacks_flags |= GST_OMX_HACK_NO_EMPTY_EOS_BUFFER;
3208 else if (g_str_equal (*hacks, "drain-may-not-return"))
3209 hacks_flags |= GST_OMX_HACK_DRAIN_MAY_NOT_RETURN;
3210 else if (g_str_equal (*hacks, "no-component-role"))
3211 hacks_flags |= GST_OMX_HACK_NO_COMPONENT_ROLE;
3212 else if (g_str_equal (*hacks, "no-disable-outport"))
3213 hacks_flags |= GST_OMX_HACK_NO_DISABLE_OUTPORT;
3214 else if (g_str_equal (*hacks, "signals-premature-eos"))
3215 hacks_flags |= GST_OMX_HACK_SIGNALS_PREMATURE_EOS;
3216 else if (g_str_equal (*hacks, "height-multiple-16"))
3217 hacks_flags |= GST_OMX_HACK_HEIGHT_MULTIPLE_16;
3218 else if (g_str_equal (*hacks, "pass-profile-to-decoder"))
3219 hacks_flags |= GST_OMX_HACK_PASS_PROFILE_TO_DECODER;
3220 else if (g_str_equal (*hacks, "pass-color-format-to-decoder"))
3221 hacks_flags |= GST_OMX_HACK_PASS_COLOR_FORMAT_TO_DECODER;
3222 else if (g_str_equal (*hacks, "ensure-buffer-count-actual"))
3223 hacks_flags |= GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL;
3225 GST_WARNING ("Unknown hack: %s", *hacks);
3234 gst_omx_set_default_role (GstOMXClassData * class_data,
3235 const gchar * default_role)
3237 if (!class_data->component_role)
3238 class_data->component_role = default_role;
3242 gst_omx_buffer_set_omx_buf (GstBuffer * buffer, GstOMXBuffer * omx_buf)
3244 gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer),
3245 gst_omx_buffer_data_quark, omx_buf, NULL);
3249 gst_omx_buffer_get_omx_buf (GstBuffer * buffer)
3251 return gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer),
3252 gst_omx_buffer_data_quark);
3256 _class_init (gpointer g_class, gpointer data)
3258 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3259 GstOMXClassData *class_data = NULL;
3261 const gchar *element_name = data;
3263 gchar *core_name, *component_name, *component_role;
3264 gint in_port_index, out_port_index;
3265 gchar *template_caps;
3266 GstPadTemplate *templ;
3274 /* Find the GstOMXClassData for this class */
3275 for (i = 0; i < G_N_ELEMENTS (base_types); i++) {
3276 GType gtype = base_types[i].get_type ();
3278 if (G_TYPE_CHECK_CLASS_TYPE (g_class, gtype)) {
3279 class_data = (GstOMXClassData *)
3280 (((guint8 *) g_class) + base_types[i].offset);
3285 g_assert (class_data != NULL);
3287 config = gst_omx_get_configuration ();
3289 /* This will alwaxys succeed, see check in plugin_init */
3290 core_name = g_key_file_get_string (config, element_name, "core-name", NULL);
3291 g_assert (core_name != NULL);
3292 class_data->core_name = core_name;
3294 g_key_file_get_string (config, element_name, "component-name", NULL);
3295 g_assert (component_name != NULL);
3296 class_data->component_name = component_name;
3298 /* If this fails we simply don't set a role */
3299 if ((component_role =
3300 g_key_file_get_string (config, element_name, "component-role",
3302 GST_DEBUG ("Using component-role '%s' for element '%s'", component_role,
3304 class_data->component_role = component_role;
3308 /* Now set the inport/outport indizes and assume sane defaults */
3311 g_key_file_get_integer (config, element_name, "in-port-index", &err);
3313 GST_DEBUG ("No 'in-port-index' set for element '%s', auto-detecting: %s",
3314 element_name, err->message);
3318 class_data->in_port_index = in_port_index;
3322 g_key_file_get_integer (config, element_name, "out-port-index", &err);
3324 GST_DEBUG ("No 'out-port-index' set for element '%s', auto-detecting: %s",
3325 element_name, err->message);
3326 out_port_index = -1;
3329 class_data->out_port_index = out_port_index;
3331 /* Add pad templates */
3333 if (class_data->type != GST_OMX_COMPONENT_TYPE_SOURCE) {
3334 if (!(template_caps =
3335 g_key_file_get_string (config, element_name, "sink-template-caps",
3338 ("No sink template caps specified for element '%s', using default '%s'",
3339 element_name, class_data->default_sink_template_caps);
3340 caps = gst_caps_from_string (class_data->default_sink_template_caps);
3341 g_assert (caps != NULL);
3344 caps = gst_caps_from_string (template_caps);
3347 ("Could not parse sink template caps '%s' for element '%s', using default '%s'",
3348 template_caps, element_name,
3349 class_data->default_sink_template_caps);
3350 caps = gst_caps_from_string (class_data->default_sink_template_caps);
3351 g_assert (caps != NULL);
3354 templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
3355 g_free (template_caps);
3356 gst_element_class_add_pad_template (element_class, templ);
3357 gst_caps_unref (caps);
3361 if (class_data->type != GST_OMX_COMPONENT_TYPE_SINK) {
3362 if (!(template_caps =
3363 g_key_file_get_string (config, element_name, "src-template-caps",
3366 ("No src template caps specified for element '%s', using default '%s'",
3367 element_name, class_data->default_src_template_caps);
3368 caps = gst_caps_from_string (class_data->default_src_template_caps);
3369 g_assert (caps != NULL);
3372 caps = gst_caps_from_string (template_caps);
3375 ("Could not parse src template caps '%s' for element '%s', using default '%s'",
3376 template_caps, element_name, class_data->default_src_template_caps);
3377 caps = gst_caps_from_string (class_data->default_src_template_caps);
3378 g_assert (caps != NULL);
3381 templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
3382 g_free (template_caps);
3383 gst_element_class_add_pad_template (element_class, templ);
3384 gst_caps_unref (caps);
3388 g_key_file_get_string_list (config, element_name, "hacks", NULL,
3390 #ifndef GST_DISABLE_GST_DEBUG
3391 gchar **walk = hacks;
3394 GST_DEBUG ("Using hack: %s", *walk);
3399 class_data->hacks = gst_omx_parse_hacks (hacks);
3405 plugin_init (GstPlugin * plugin)
3408 gchar **config_dirs;
3410 gchar *env_config_dir;
3411 const gchar *user_config_dir;
3412 const gchar *const *system_config_dirs;
3415 static const gchar *config_name[] = { "gstomx.conf", NULL };
3416 static const gchar *env_config_name[] = { "GST_OMX_CONFIG_DIR", NULL };
3417 static const gchar *gst_omx_config_dir = GST_OMX_CONFIG_DIR;
3419 GST_DEBUG_CATEGORY_INIT (gstomx_debug, "omx", 0, "gst-omx");
3420 GST_DEBUG_CATEGORY_INIT (gst_omx_video_debug_category, "omxvideo", 0,
3422 GST_DEBUG_CATEGORY_INIT (OMX_PERFORMANCE, "OMX_PERFORMANCE", 0,
3423 "gst-omx performace");
3425 gst_omx_buffer_data_quark = g_quark_from_static_string ("GstOMXBufferData");
3427 /* Read configuration file gstomx.conf from the preferred
3428 * configuration directories */
3429 env_config_dir = g_strdup (g_getenv (*env_config_name));
3430 user_config_dir = g_get_user_config_dir ();
3431 system_config_dirs = g_get_system_config_dirs ();
3433 g_new (gchar *, g_strv_length ((gchar **) system_config_dirs) + 4);
3438 config_dirs[i++] = (gchar *) env_config_dir;
3439 config_dirs[i++] = (gchar *) user_config_dir;
3440 while (system_config_dirs[j])
3441 config_dirs[i++] = (gchar *) system_config_dirs[j++];
3442 config_dirs[i++] = (gchar *) gst_omx_config_dir;
3443 config_dirs[i++] = NULL;
3445 gst_plugin_add_dependency (plugin, env_config_name,
3446 (const gchar **) (config_dirs + (env_config_dir ? 1 : 0)), config_name,
3447 GST_PLUGIN_DEPENDENCY_FLAG_NONE);
3449 config = g_key_file_new ();
3450 if (!g_key_file_load_from_dirs (config, *config_name,
3451 (const gchar **) config_dirs, NULL, G_KEY_FILE_NONE, &err)) {
3454 paths = g_strjoinv (":", config_dirs);
3455 GST_ERROR ("Failed to load configuration file: %s (searched in: %s as per "
3456 "GST_OMX_CONFIG_DIR environment variable, the xdg user config "
3457 "directory (or XDG_CONFIG_HOME) and the system config directory "
3458 "(or XDG_CONFIG_DIRS)", err->message, paths);
3464 /* Initialize all types */
3465 for (i = 0; i < G_N_ELEMENTS (types); i++)
3468 elements = g_key_file_get_groups (config, &n_elements);
3469 for (i = 0; i < n_elements; i++) {
3470 GTypeQuery type_query;
3471 GTypeInfo type_info = { 0, };
3472 GType type, subtype;
3473 gchar *type_name, *core_name, *component_name;
3476 GST_DEBUG ("Registering element '%s'", elements[i]);
3480 g_key_file_get_string (config, elements[i], "type-name", &err))) {
3482 ("Unable to read 'type-name' configuration for element '%s': %s",
3483 elements[i], err->message);
3488 type = g_type_from_name (type_name);
3489 if (type == G_TYPE_INVALID) {
3490 GST_ERROR ("Invalid type name '%s' for element '%s'", type_name,
3495 if (!g_type_is_a (type, GST_TYPE_ELEMENT)) {
3496 GST_ERROR ("Type '%s' is no GstElement subtype for element '%s'",
3497 type_name, elements[i]);
3503 /* And now some sanity checking */
3506 g_key_file_get_string (config, elements[i], "core-name", &err))) {
3508 ("Unable to read 'core-name' configuration for element '%s': %s",
3509 elements[i], err->message);
3513 if (!g_file_test (core_name, G_FILE_TEST_IS_REGULAR)) {
3514 GST_ERROR ("Core '%s' does not exist for element '%s'", core_name,
3522 if (!(component_name =
3523 g_key_file_get_string (config, elements[i], "component-name",
3526 ("Unable to read 'component-name' configuration for element '%s': %s",
3527 elements[i], err->message);
3531 g_free (component_name);
3534 rank = g_key_file_get_integer (config, elements[i], "rank", &err);
3536 GST_ERROR ("No rank set for element '%s': %s", elements[i], err->message);
3541 /* And now register the type, all other configuration will
3542 * be handled by the type itself */
3543 g_type_query (type, &type_query);
3544 memset (&type_info, 0, sizeof (type_info));
3545 type_info.class_size = type_query.class_size;
3546 type_info.instance_size = type_query.instance_size;
3547 type_info.class_init = _class_init;
3548 type_info.class_data = g_strdup (elements[i]);
3549 type_name = g_strdup_printf ("%s-%s", g_type_name (type), elements[i]);
3550 if (g_type_from_name (type_name) != G_TYPE_INVALID) {
3551 GST_ERROR ("Type '%s' already exists for element '%s'", type_name,
3556 subtype = g_type_register_static (type, type_name, &type_info, 0);
3558 gst_element_register (plugin, elements[i], rank, subtype);
3560 g_strfreev (elements);
3563 g_free (env_config_dir);
3564 g_free (config_dirs);
3569 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
3572 "GStreamer OpenMAX Plug-ins",
3574 PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)