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 EventHandler (OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_EVENTTYPE eEvent,
496 OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData)
498 GstOMXComponent *comp = (GstOMXComponent *) pAppData;
501 case OMX_EventCmdComplete:
503 OMX_COMMANDTYPE cmd = (OMX_COMMANDTYPE) nData1;
505 GST_DEBUG_OBJECT (comp->parent, "%s %s command complete (%d)",
506 comp->name, gst_omx_command_to_string (cmd), cmd);
509 case OMX_CommandStateSet:{
510 GstOMXMessage *msg = g_slice_new (GstOMXMessage);
512 msg->type = GST_OMX_MESSAGE_STATE_SET;
513 msg->content.state_set.state = nData2;
515 GST_DEBUG_OBJECT (comp->parent, "%s state change to %s finished",
517 gst_omx_state_to_string (msg->content.state_set.state));
519 gst_omx_component_send_message (comp, msg);
522 case OMX_CommandFlush:{
523 GstOMXMessage *msg = g_slice_new (GstOMXMessage);
525 msg->type = GST_OMX_MESSAGE_FLUSH;
526 msg->content.flush.port = nData2;
527 GST_DEBUG_OBJECT (comp->parent, "%s port %u flushed", comp->name,
528 (guint) msg->content.flush.port);
530 gst_omx_component_send_message (comp, msg);
533 case OMX_CommandPortEnable:
534 case OMX_CommandPortDisable:{
535 GstOMXMessage *msg = g_slice_new (GstOMXMessage);
537 msg->type = GST_OMX_MESSAGE_PORT_ENABLE;
538 msg->content.port_enable.port = nData2;
539 msg->content.port_enable.enable = (cmd == OMX_CommandPortEnable);
540 GST_DEBUG_OBJECT (comp->parent, "%s port %u %s", comp->name,
541 (guint) msg->content.port_enable.port,
542 (msg->content.port_enable.enable ? "enabled" : "disabled"));
544 gst_omx_component_send_message (comp, msg);
555 OMX_ERRORTYPE error_type = nData1;
557 /* Yes, this really happens... */
558 if (error_type == OMX_ErrorNone)
561 /* Always ignore PortUnpopulated error. This error is informational
562 * at best but it is useful for debugging some strange scenarios.
564 if (error_type == OMX_ErrorPortUnpopulated) {
565 GST_DEBUG_OBJECT (comp->parent, "%s got error: %s (0x%08x)",
566 comp->name, gst_omx_error_to_string (error_type), error_type);
570 msg = g_slice_new (GstOMXMessage);
572 msg->type = GST_OMX_MESSAGE_ERROR;
573 msg->content.error.error = error_type;
574 GST_ERROR_OBJECT (comp->parent, "%s got error: %s (0x%08x)", comp->name,
575 gst_omx_error_to_string (msg->content.error.error),
576 msg->content.error.error);
578 gst_omx_component_send_message (comp, msg);
581 case OMX_EventPortSettingsChanged:
583 GstOMXMessage *msg = g_slice_new (GstOMXMessage);
587 GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_NDATA_PARAMETER_SWAP)) {
596 GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_PORT_0_TO_1))
600 msg->type = GST_OMX_MESSAGE_PORT_SETTINGS_CHANGED;
601 msg->content.port_settings_changed.port = index;
602 GST_DEBUG_OBJECT (comp->parent, "%s settings changed (port index: %u)",
603 comp->name, (guint) msg->content.port_settings_changed.port);
605 gst_omx_component_send_message (comp, msg);
608 case OMX_EventBufferFlag:{
611 msg = g_slice_new (GstOMXMessage);
613 msg->type = GST_OMX_MESSAGE_BUFFER_FLAG;
614 msg->content.buffer_flag.port = nData1;
615 msg->content.buffer_flag.flags = nData2;
616 GST_DEBUG_OBJECT (comp->parent, "%s port %u got buffer flags 0x%08x (%s)",
617 comp->name, (guint) msg->content.buffer_flag.port,
618 (guint) msg->content.buffer_flag.flags,
619 gst_omx_buffer_flags_to_string (msg->content.buffer_flag.flags));
621 gst_omx_component_send_message (comp, msg);
624 case OMX_EventPortFormatDetected:
626 GST_DEBUG_OBJECT (comp->parent, "%s unknown event 0x%08x", comp->name,
631 return OMX_ErrorNone;
635 gst_omx_buffer_unmap (GstOMXBuffer * buffer)
637 g_return_if_fail (buffer != NULL);
639 if (buffer->input_frame_mapped) {
640 g_assert (!buffer->input_mem);
641 g_assert (!buffer->input_buffer);
642 g_assert (!buffer->input_buffer_mapped);
643 gst_video_frame_unmap (&buffer->input_frame);
644 buffer->input_frame_mapped = FALSE;
645 } else if (buffer->input_mem) {
646 g_assert (!buffer->input_buffer);
647 g_assert (!buffer->input_buffer_mapped);
648 gst_memory_unmap (buffer->input_mem, &buffer->map);
649 g_clear_pointer (&buffer->input_mem, gst_memory_unref);
650 } else if (buffer->input_buffer) {
651 if (buffer->input_buffer_mapped)
652 gst_buffer_unmap (buffer->input_buffer, &buffer->map);
653 buffer->input_buffer_mapped = FALSE;
654 g_clear_pointer (&buffer->input_buffer, gst_buffer_unref);
659 log_omx_performance (GstOMXComponent * comp, const gchar * event,
664 /* Don't bother creating useless structs if not needed */
665 if (gst_debug_category_get_threshold (OMX_PERFORMANCE) < GST_LEVEL_TRACE)
669 gchar *buf_str, *omx_buf_str, *pbuffer_str;
671 /* GST_PTR_FORMAT won't serialize G_TYPE_POINTER fields so stringify pointers */
672 buf_str = g_strdup_printf ("%p", buf);
673 omx_buf_str = g_strdup_printf ("%p", buf->omx_buf);
674 pbuffer_str = g_strdup_printf ("%p", buf->omx_buf->pBuffer);
677 s = gst_structure_new (event,
678 "GstOMXBuffer", G_TYPE_STRING, buf_str,
679 "OMX-buffer", G_TYPE_STRING, omx_buf_str,
680 "pBuffer", G_TYPE_STRING, pbuffer_str,
681 "TimeStamp", G_TYPE_UINT64, GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp),
682 "AllocLen", G_TYPE_UINT, buf->omx_buf->nAllocLen,
683 "FilledLen", G_TYPE_UINT, buf->omx_buf->nFilledLen,
684 "flags", G_TYPE_UINT, buf->omx_buf->nFlags,
685 "flags-str", G_TYPE_STRING, gst_omx_buffer_flags_to_string (buf->omx_buf->nFlags),
690 g_free (omx_buf_str);
691 g_free (pbuffer_str);
693 s = gst_structure_new_empty (event);
696 GST_CAT_TRACE_OBJECT (OMX_PERFORMANCE, comp->parent, "%" GST_PTR_FORMAT, s);
698 gst_structure_free (s);
702 EmptyBufferDone (OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
703 OMX_BUFFERHEADERTYPE * pBuffer)
706 GstOMXComponent *comp;
709 buf = pBuffer->pAppPrivate;
711 GST_ERROR ("Have unknown or deallocated buffer %p", pBuffer);
712 return OMX_ErrorNone;
715 g_assert (buf->omx_buf == pBuffer);
717 if (buf->port->tunneled) {
718 GST_ERROR ("EmptyBufferDone on tunneled port");
719 return OMX_ErrorBadParameter;
722 comp = buf->port->comp;
724 msg = g_slice_new (GstOMXMessage);
725 msg->type = GST_OMX_MESSAGE_BUFFER_DONE;
726 msg->content.buffer_done.component = hComponent;
727 msg->content.buffer_done.app_data = pAppData;
728 msg->content.buffer_done.buffer = pBuffer;
729 msg->content.buffer_done.empty = OMX_TRUE;
731 log_omx_performance (comp, "EmptyBufferDone", buf);
732 GST_LOG_OBJECT (comp->parent, "%s port %u emptied buffer %p (%p)",
733 comp->name, buf->port->index, buf, buf->omx_buf->pBuffer);
735 gst_omx_component_send_message (comp, msg);
737 return OMX_ErrorNone;
741 FillBufferDone (OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
742 OMX_BUFFERHEADERTYPE * pBuffer)
745 GstOMXComponent *comp;
748 buf = pBuffer->pAppPrivate;
750 GST_ERROR ("Have unknown or deallocated buffer %p", pBuffer);
751 return OMX_ErrorNone;
754 g_assert (buf->omx_buf == pBuffer);
756 if (buf->port->tunneled) {
757 GST_ERROR ("FillBufferDone on tunneled port");
758 return OMX_ErrorBadParameter;
761 comp = buf->port->comp;
763 msg = g_slice_new (GstOMXMessage);
764 msg->type = GST_OMX_MESSAGE_BUFFER_DONE;
765 msg->content.buffer_done.component = hComponent;
766 msg->content.buffer_done.app_data = pAppData;
767 msg->content.buffer_done.buffer = pBuffer;
768 msg->content.buffer_done.empty = OMX_FALSE;
770 log_omx_performance (comp, "FillBufferDone", buf);
771 GST_LOG_OBJECT (comp->parent, "%s port %u filled buffer %p (%p)", comp->name,
772 buf->port->index, buf, buf->omx_buf->pBuffer);
774 gst_omx_component_send_message (comp, msg);
776 return OMX_ErrorNone;
779 static OMX_CALLBACKTYPE callbacks =
780 { EventHandler, EmptyBufferDone, FillBufferDone };
782 GST_DEFINE_MINI_OBJECT_TYPE (GstOMXComponent, gst_omx_component);
784 static void gst_omx_component_free (GstOMXComponent * comp);
786 /* NOTE: Uses comp->lock and comp->messages_lock */
788 gst_omx_component_new (GstObject * parent, const gchar * core_name,
789 const gchar * component_name, const gchar * component_role, guint64 hacks)
793 GstOMXComponent *comp;
796 core = gst_omx_core_acquire (core_name);
800 comp = g_slice_new0 (GstOMXComponent);
803 gst_mini_object_init (GST_MINI_OBJECT_CAST (comp), 0,
804 gst_omx_component_get_type (), NULL, NULL,
805 (GstMiniObjectFreeFunction) gst_omx_component_free);
807 if ((dot = g_strrstr (component_name, ".")))
808 comp->name = g_strdup (dot + 1);
810 comp->name = g_strdup (component_name);
813 core->get_handle (&comp->handle, (OMX_STRING) component_name, comp,
815 if (err != OMX_ErrorNone) {
816 GST_ERROR_OBJECT (parent,
817 "Failed to get component handle '%s' from core '%s': 0x%08x",
818 component_name, core_name, err);
819 gst_omx_core_release (core);
821 g_slice_free (GstOMXComponent, comp);
824 GST_DEBUG_OBJECT (parent,
825 "Successfully got component handle %p (%s) from core '%s'", comp->handle,
826 component_name, core_name);
827 comp->parent = gst_object_ref (parent);
830 comp->ports = g_ptr_array_new ();
831 comp->n_in_ports = 0;
832 comp->n_out_ports = 0;
834 g_mutex_init (&comp->lock);
835 g_mutex_init (&comp->messages_lock);
836 g_cond_init (&comp->messages_cond);
838 g_queue_init (&comp->messages);
839 comp->pending_state = OMX_StateInvalid;
840 comp->last_error = OMX_ErrorNone;
842 /* Set component role if any */
843 if (component_role && !(hacks & GST_OMX_HACK_NO_COMPONENT_ROLE)) {
844 OMX_PARAM_COMPONENTROLETYPE param;
846 GST_OMX_INIT_STRUCT (¶m);
848 g_strlcpy ((gchar *) param.cRole, component_role, sizeof (param.cRole));
850 gst_omx_component_set_parameter (comp,
851 OMX_IndexParamStandardComponentRole, ¶m);
853 DEBUG_IF_OK (comp->parent, err,
854 "Setting component role to '%s': %s (0x%08x)", component_role,
855 gst_omx_error_to_string (err), err);
857 /* If setting the role failed this component is unusable */
858 if (err != OMX_ErrorNone) {
859 gst_omx_component_free (comp);
864 OMX_GetState (comp->handle, &comp->state);
866 g_mutex_lock (&comp->lock);
867 gst_omx_component_handle_messages (comp);
868 g_mutex_unlock (&comp->lock);
873 /* NOTE: Uses comp->messages_lock */
875 gst_omx_component_free (GstOMXComponent * comp)
879 g_return_if_fail (comp != NULL);
881 GST_INFO_OBJECT (comp->parent, "Unloading component %p %s", comp, comp->name);
884 n = comp->ports->len;
885 for (i = 0; i < n; i++) {
886 GstOMXPort *port = g_ptr_array_index (comp->ports, i);
888 gst_omx_port_deallocate_buffers (port);
889 g_assert (port->buffers == NULL);
890 g_assert (g_queue_get_length (&port->pending_buffers) == 0);
892 g_slice_free (GstOMXPort, port);
894 g_ptr_array_unref (comp->ports);
898 comp->core->free_handle (comp->handle);
899 gst_omx_core_release (comp->core);
901 gst_omx_component_flush_messages (comp);
903 g_cond_clear (&comp->messages_cond);
904 g_mutex_clear (&comp->messages_lock);
905 g_mutex_clear (&comp->lock);
907 gst_object_unref (comp->parent);
912 g_slice_free (GstOMXComponent, comp);
916 gst_omx_component_ref (GstOMXComponent * comp)
918 g_return_val_if_fail (comp, NULL);
920 gst_mini_object_ref (GST_MINI_OBJECT_CAST (comp));
925 gst_omx_component_unref (GstOMXComponent * comp)
927 g_return_if_fail (comp);
929 gst_mini_object_unref (GST_MINI_OBJECT_CAST (comp));
932 /* NOTE: Uses comp->lock and comp->messages_lock */
934 gst_omx_component_set_state (GstOMXComponent * comp, OMX_STATETYPE state)
936 OMX_STATETYPE old_state;
937 OMX_ERRORTYPE err = OMX_ErrorNone;
939 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
941 g_mutex_lock (&comp->lock);
943 gst_omx_component_handle_messages (comp);
945 old_state = comp->state;
946 GST_INFO_OBJECT (comp->parent, "Setting %s state from %s to %s", comp->name,
947 gst_omx_state_to_string (old_state), gst_omx_state_to_string (state));
949 if ((err = comp->last_error) != OMX_ErrorNone && state > old_state) {
950 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
951 comp->name, gst_omx_error_to_string (err), err);
955 if (old_state == state || comp->pending_state == state) {
956 GST_DEBUG_OBJECT (comp->parent, "Component %s already in state %s",
957 comp->name, gst_omx_state_to_string (state));
961 comp->pending_state = state;
963 /* Reset some things */
964 if ((old_state == OMX_StateExecuting || old_state == OMX_StatePause)
965 && state < old_state) {
966 g_list_free (comp->pending_reconfigure_outports);
967 comp->pending_reconfigure_outports = NULL;
968 /* Notify all inports that are still waiting */
969 gst_omx_component_send_message (comp, NULL);
972 err = OMX_SendCommand (comp->handle, OMX_CommandStateSet, state, NULL);
973 /* No need to check if anything has changed here */
977 gst_omx_component_handle_messages (comp);
979 if (err != OMX_ErrorNone && comp->last_error == OMX_ErrorNone) {
980 GST_ERROR_OBJECT (comp->parent,
981 "Last operation returned an error. Setting last_error manually.");
982 comp->last_error = err;
985 g_mutex_unlock (&comp->lock);
987 if (err != OMX_ErrorNone) {
988 GST_ERROR_OBJECT (comp->parent,
989 "Error setting %s state from %s to %s: %s (0x%08x)", comp->name,
990 gst_omx_state_to_string (old_state), gst_omx_state_to_string (state),
991 gst_omx_error_to_string (err), err);
996 /* NOTE: Uses comp->lock and comp->messages_lock */
998 gst_omx_component_get_state (GstOMXComponent * comp, GstClockTime timeout)
1001 gboolean signalled = TRUE;
1003 g_return_val_if_fail (comp != NULL, OMX_StateInvalid);
1005 GST_DEBUG_OBJECT (comp->parent, "Getting state of %s", comp->name);
1007 g_mutex_lock (&comp->lock);
1009 gst_omx_component_handle_messages (comp);
1011 if (comp->last_error != OMX_ErrorNone) {
1012 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
1013 comp->name, gst_omx_error_to_string (comp->last_error),
1015 ret = OMX_StateInvalid;
1020 if (comp->pending_state == OMX_StateInvalid)
1023 while (signalled && comp->last_error == OMX_ErrorNone
1024 && comp->pending_state != OMX_StateInvalid) {
1026 signalled = gst_omx_component_wait_message (comp, timeout);
1028 gst_omx_component_handle_messages (comp);
1032 if (comp->last_error != OMX_ErrorNone) {
1033 GST_ERROR_OBJECT (comp->parent,
1034 "%s got error while waiting for state change: %s (0x%08x)",
1035 comp->name, gst_omx_error_to_string (comp->last_error),
1037 ret = OMX_StateInvalid;
1038 } else if (comp->pending_state == OMX_StateInvalid) {
1039 /* State change finished and everything's fine */
1042 ret = OMX_StateInvalid;
1043 g_assert_not_reached ();
1046 ret = OMX_StateInvalid;
1047 GST_WARNING_OBJECT (comp->parent, "%s timeout while waiting for state "
1048 "change", comp->name);
1052 g_mutex_unlock (&comp->lock);
1054 GST_DEBUG_OBJECT (comp->parent, "%s returning state %s", comp->name,
1055 gst_omx_state_to_string (ret));
1061 gst_omx_component_add_port (GstOMXComponent * comp, guint32 index)
1065 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1068 g_return_val_if_fail (comp != NULL, NULL);
1070 /* Check if this port exists already */
1071 n = comp->ports->len;
1072 for (i = 0; i < n; i++) {
1073 port = g_ptr_array_index (comp->ports, i);
1074 g_return_val_if_fail (port->index != index, NULL);
1077 GST_DEBUG_OBJECT (comp->parent, "%s adding port %u", comp->name, index);
1079 GST_OMX_INIT_STRUCT (&port_def);
1080 port_def.nPortIndex = index;
1082 err = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1084 if (err != OMX_ErrorNone) {
1085 GST_ERROR_OBJECT (comp->parent, "%s failed to add port %u: %s (0x%08x)",
1086 comp->name, index, gst_omx_error_to_string (err), err);
1090 port = g_slice_new0 (GstOMXPort);
1092 port->index = index;
1094 port->tunneled = FALSE;
1096 port->port_def = port_def;
1098 g_queue_init (&port->pending_buffers);
1099 port->flushing = TRUE;
1100 port->flushed = FALSE;
1101 port->enabled_pending = FALSE;
1102 port->disabled_pending = FALSE;
1104 port->using_pool = FALSE;
1106 if (port->port_def.eDir == OMX_DirInput)
1109 comp->n_out_ports++;
1111 g_ptr_array_add (comp->ports, port);
1117 gst_omx_component_get_port (GstOMXComponent * comp, guint32 index)
1121 n = comp->ports->len;
1122 for (i = 0; i < n; i++) {
1123 GstOMXPort *tmp = g_ptr_array_index (comp->ports, i);
1125 if (tmp->index == index)
1131 /* NOTE: Uses comp->lock and comp->messages_lock */
1133 gst_omx_component_get_last_error (GstOMXComponent * comp)
1137 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1139 g_mutex_lock (&comp->lock);
1140 gst_omx_component_handle_messages (comp);
1141 err = comp->last_error;
1142 g_mutex_unlock (&comp->lock);
1144 GST_DEBUG_OBJECT (comp->parent, "Returning last %s error: %s (0x%08x)",
1145 comp->name, gst_omx_error_to_string (err), err);
1151 gst_omx_component_get_last_error_string (GstOMXComponent * comp)
1153 g_return_val_if_fail (comp != NULL, NULL);
1155 return gst_omx_error_to_string (gst_omx_component_get_last_error (comp));
1158 /* comp->lock must be unlocked while calling this */
1160 gst_omx_component_get_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1165 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1166 g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1168 GST_DEBUG_OBJECT (comp->parent, "Getting %s parameter at index 0x%08x",
1170 err = OMX_GetParameter (comp->handle, index, param);
1171 DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1172 "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1177 /* comp->lock must be unlocked while calling this */
1179 gst_omx_component_set_parameter (GstOMXComponent * comp, OMX_INDEXTYPE index,
1184 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1185 g_return_val_if_fail (param != NULL, OMX_ErrorUndefined);
1187 GST_DEBUG_OBJECT (comp->parent, "Setting %s parameter at index 0x%08x",
1189 err = OMX_SetParameter (comp->handle, index, param);
1190 DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1191 "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1196 /* comp->lock must be unlocked while calling this */
1198 gst_omx_component_get_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1203 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1204 g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1206 GST_DEBUG_OBJECT (comp->parent, "Getting %s configuration at index 0x%08x",
1208 err = OMX_GetConfig (comp->handle, index, config);
1209 DEBUG_IF_OK (comp->parent, err, "Got %s parameter at index 0x%08x: %s "
1210 "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1215 /* comp->lock must be unlocked while calling this */
1217 gst_omx_component_set_config (GstOMXComponent * comp, OMX_INDEXTYPE index,
1222 g_return_val_if_fail (comp != NULL, OMX_ErrorUndefined);
1223 g_return_val_if_fail (config != NULL, OMX_ErrorUndefined);
1225 GST_DEBUG_OBJECT (comp->parent, "Setting %s configuration at index 0x%08x",
1227 err = OMX_SetConfig (comp->handle, index, config);
1228 DEBUG_IF_OK (comp->parent, err, "Set %s parameter at index 0x%08x: %s "
1229 "(0x%08x)", comp->name, index, gst_omx_error_to_string (err), err);
1235 gst_omx_setup_tunnel (GstOMXPort * port1, GstOMXPort * port2)
1237 GstOMXComponent *comp1;
1238 GstOMXComponent *comp2;
1241 g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
1242 g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
1243 OMX_ErrorUndefined);
1244 comp1 = port1->comp;
1246 g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
1247 g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
1248 OMX_ErrorUndefined);
1249 comp2 = port2->comp;
1251 g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
1253 g_mutex_lock (&comp1->lock);
1254 g_mutex_lock (&comp2->lock);
1255 GST_DEBUG_OBJECT (comp1->parent,
1256 "Setup tunnel between %s port %u and %s port %u",
1257 comp1->name, port1->index, comp2->name, port2->index);
1259 err = comp1->core->setup_tunnel (comp1->handle, port1->index, comp2->handle,
1262 if (err == OMX_ErrorNone) {
1263 port1->tunneled = TRUE;
1264 port2->tunneled = TRUE;
1267 DEBUG_IF_OK (comp1->parent, err,
1268 "Setup tunnel between %s port %u and %s port %u: %s (0x%08x)",
1269 comp1->name, port1->index,
1270 comp2->name, port2->index, gst_omx_error_to_string (err), err);
1272 g_mutex_unlock (&comp2->lock);
1273 g_mutex_unlock (&comp1->lock);
1279 gst_omx_close_tunnel (GstOMXPort * port1, GstOMXPort * port2)
1281 GstOMXComponent *comp1;
1282 GstOMXComponent *comp2;
1285 g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
1286 g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
1287 OMX_ErrorUndefined);
1288 comp1 = port1->comp;
1290 g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
1291 g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
1292 OMX_ErrorUndefined);
1293 comp2 = port2->comp;
1295 g_return_val_if_fail (comp1->core == comp2->core, OMX_ErrorUndefined);
1296 g_return_val_if_fail (port1->tunneled && port2->tunneled, OMX_ErrorUndefined);
1298 g_mutex_lock (&comp1->lock);
1299 g_mutex_lock (&comp2->lock);
1300 GST_DEBUG_OBJECT (comp1->parent,
1301 "Closing tunnel between %s port %u and %s port %u",
1302 comp1->name, port1->index, comp2->name, port2->index);
1304 err = comp1->core->setup_tunnel (comp1->handle, port1->index, 0, 0);
1305 if (err != OMX_ErrorNone) {
1306 GST_ERROR_OBJECT (comp1->parent,
1307 "Failed to close tunnel on output side %s (0x%08x)",
1308 gst_omx_error_to_string (err), err);
1310 err = comp2->core->setup_tunnel (0, 0, comp2->handle, port2->index);
1311 if (err != OMX_ErrorNone) {
1312 GST_ERROR_OBJECT (comp2->parent,
1313 "Failed to close tunnel on input side %s (0x%08x)",
1314 gst_omx_error_to_string (err), err);
1317 port1->tunneled = FALSE;
1318 port2->tunneled = FALSE;
1320 GST_DEBUG_OBJECT (comp1->parent,
1321 "Closed tunnel between %s port %u and %s port %u",
1322 comp1->name, port1->index, comp2->name, port2->index);
1324 g_mutex_unlock (&comp2->lock);
1325 g_mutex_unlock (&comp1->lock);
1331 gst_omx_port_get_port_definition (GstOMXPort * port,
1332 OMX_PARAM_PORTDEFINITIONTYPE * port_def)
1334 GstOMXComponent *comp;
1337 g_return_val_if_fail (port != NULL, OMX_ErrorBadParameter);
1341 GST_OMX_INIT_STRUCT (port_def);
1342 port_def->nPortIndex = port->index;
1344 err = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1351 gst_omx_port_update_port_definition (GstOMXPort * port,
1352 OMX_PARAM_PORTDEFINITIONTYPE * port_def)
1354 OMX_ERRORTYPE err_get, err_set = OMX_ErrorNone;
1355 GstOMXComponent *comp;
1357 g_return_val_if_fail (port != NULL, FALSE);
1363 gst_omx_component_set_parameter (comp, OMX_IndexParamPortDefinition,
1365 err_get = gst_omx_component_get_parameter (comp, OMX_IndexParamPortDefinition,
1368 DEBUG_IF_OK (comp->parent, err_set,
1369 "Updated %s port %u definition: %s (0x%08x)", comp->name, port->index,
1370 gst_omx_error_to_string (err_set), err_set);
1372 if (err_set != OMX_ErrorNone)
1378 /* NOTE: Uses comp->lock and comp->messages_lock */
1379 GstOMXAcquireBufferReturn
1380 gst_omx_port_acquire_buffer (GstOMXPort * port, GstOMXBuffer ** buf,
1383 GstOMXAcquireBufferReturn ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
1384 GstOMXComponent *comp;
1386 GstOMXBuffer *_buf = NULL;
1387 gint64 timeout = GST_CLOCK_TIME_NONE;
1389 g_return_val_if_fail (port != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
1390 g_return_val_if_fail (!port->tunneled, GST_OMX_ACQUIRE_BUFFER_ERROR);
1391 g_return_val_if_fail (buf != NULL, GST_OMX_ACQUIRE_BUFFER_ERROR);
1397 g_mutex_lock (&comp->lock);
1398 GST_DEBUG_OBJECT (comp->parent, "Acquiring %s buffer from port %u",
1399 comp->name, port->index);
1402 gst_omx_component_handle_messages (comp);
1404 /* If we are in the case where we waited for a buffer after EOS,
1405 * make sure we don't do that again */
1409 /* Check if the component is in an error state */
1410 if ((err = comp->last_error) != OMX_ErrorNone) {
1411 GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s",
1412 comp->name, gst_omx_error_to_string (err));
1413 ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
1417 /* Check if the port is flushing */
1418 if (port->flushing) {
1419 GST_DEBUG_OBJECT (comp->parent, "Component %s port %d is flushing",
1420 comp->name, port->index);
1421 ret = GST_OMX_ACQUIRE_BUFFER_FLUSHING;
1425 /* If this is an input port and at least one of the output ports
1426 * needs to be reconfigured, we wait until all output ports are
1427 * reconfigured. Afterwards this port is reconfigured if required
1428 * or buffers are returned to be filled as usual.
1430 if (port->port_def.eDir == OMX_DirInput) {
1431 if (comp->pending_reconfigure_outports) {
1432 gst_omx_component_handle_messages (comp);
1433 while (comp->pending_reconfigure_outports &&
1434 (err = comp->last_error) == OMX_ErrorNone && !port->flushing) {
1435 GST_DEBUG_OBJECT (comp->parent,
1436 "Waiting for %s output ports to reconfigure", comp->name);
1437 gst_omx_component_wait_message (comp, GST_CLOCK_TIME_NONE);
1438 gst_omx_component_handle_messages (comp);
1443 /* Only if this port needs to be reconfigured too notify
1444 * the caller about it */
1445 if (port->settings_cookie != port->configured_settings_cookie) {
1446 GST_DEBUG_OBJECT (comp->parent,
1447 "Component %s port %d needs reconfiguring", comp->name, port->index);
1448 ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
1453 /* If we have an output port that needs to be reconfigured
1454 * and it still has buffers pending for the old configuration
1455 * we first return them.
1456 * NOTE: If buffers for this configuration arrive later
1457 * we have to drop them... */
1458 if (port->port_def.eDir == OMX_DirOutput &&
1459 port->settings_cookie != port->configured_settings_cookie) {
1460 if (!g_queue_is_empty (&port->pending_buffers)) {
1461 GST_DEBUG_OBJECT (comp->parent,
1462 "%s output port %u needs reconfiguration but has buffers pending",
1463 comp->name, port->index);
1464 _buf = g_queue_pop_head (&port->pending_buffers);
1466 ret = GST_OMX_ACQUIRE_BUFFER_OK;
1470 GST_DEBUG_OBJECT (comp->parent, "Component %s port %d needs reconfiguring",
1471 comp->name, port->index);
1472 ret = GST_OMX_ACQUIRE_BUFFER_RECONFIGURE;
1476 if (port->port_def.eDir == OMX_DirOutput && port->eos) {
1477 if (!g_queue_is_empty (&port->pending_buffers)) {
1478 GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but has "
1479 "buffers pending", comp->name, port->index);
1480 _buf = g_queue_pop_head (&port->pending_buffers);
1482 ret = GST_OMX_ACQUIRE_BUFFER_OK;
1486 if (comp->hacks & GST_OMX_HACK_SIGNALS_PREMATURE_EOS && timeout != -2) {
1487 timeout = 33 * GST_MSECOND;
1489 GST_DEBUG_OBJECT (comp->parent, "%s output port %u is EOS but waiting "
1490 "in case it spits out more buffers", comp->name, port->index);
1492 GST_DEBUG_OBJECT (comp->parent, "Component %s port %d signalled EOS",
1493 comp->name, port->index);
1494 ret = GST_OMX_ACQUIRE_BUFFER_EOS;
1501 * At this point we have no error or flushing/eos port
1502 * and a properly configured port.
1506 /* If the queue is empty we wait until a buffer
1507 * arrives, an error happens, the port is flushing
1508 * or the port needs to be reconfigured.
1510 if (g_queue_is_empty (&port->pending_buffers)) {
1511 GST_DEBUG_OBJECT (comp->parent, "Queue of %s port %u is empty",
1512 comp->name, port->index);
1514 if (wait == GST_OMX_WAIT) {
1515 gst_omx_component_wait_message (comp,
1516 timeout == -2 ? GST_CLOCK_TIME_NONE : timeout);
1518 /* And now check everything again and maybe get a buffer */
1521 ret = GST_OMX_ACQUIRE_BUFFER_NO_AVAILABLE;
1526 GST_DEBUG_OBJECT (comp->parent, "%s port %u has pending buffers",
1527 comp->name, port->index);
1528 _buf = g_queue_pop_head (&port->pending_buffers);
1529 ret = GST_OMX_ACQUIRE_BUFFER_OK;
1532 g_mutex_unlock (&comp->lock);
1535 g_assert (_buf == _buf->omx_buf->pAppPrivate);
1539 GST_DEBUG_OBJECT (comp->parent, "Acquired buffer %p (%p) from %s port %u: %d",
1540 _buf, (_buf ? _buf->omx_buf->pBuffer : NULL), comp->name, port->index,
1546 /* NOTE: Uses comp->lock and comp->messages_lock */
1548 gst_omx_port_release_buffer (GstOMXPort * port, GstOMXBuffer * buf)
1550 GstOMXComponent *comp;
1551 OMX_ERRORTYPE err = OMX_ErrorNone;
1553 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
1554 g_return_val_if_fail (!port->tunneled, OMX_ErrorUndefined);
1555 g_return_val_if_fail (buf != NULL, OMX_ErrorUndefined);
1556 g_return_val_if_fail (buf->port == port, OMX_ErrorUndefined);
1560 g_mutex_lock (&comp->lock);
1562 GST_DEBUG_OBJECT (comp->parent, "Releasing buffer %p (%p) to %s port %u",
1563 buf, buf->omx_buf->pBuffer, comp->name, port->index);
1565 gst_omx_component_handle_messages (comp);
1567 if (port->port_def.eDir == OMX_DirOutput) {
1568 /* Reset all flags, some implementations don't
1569 * reset them themselves and the flags are not
1570 * valid anymore after the buffer was consumed
1572 gst_omx_buffer_reset (buf);
1575 if ((err = comp->last_error) != OMX_ErrorNone) {
1576 GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
1577 "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
1578 g_queue_push_tail (&port->pending_buffers, buf);
1579 gst_omx_component_send_message (comp, NULL);
1583 if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
1584 GST_DEBUG_OBJECT (comp->parent,
1585 "%s port %u is flushing or disabled, not releasing " "buffer",
1586 comp->name, port->index);
1587 g_queue_push_tail (&port->pending_buffers, buf);
1588 gst_omx_component_send_message (comp, NULL);
1592 g_assert (buf == buf->omx_buf->pAppPrivate);
1594 /* FIXME: What if the settings cookies don't match? */
1598 if (port->port_def.eDir == OMX_DirInput) {
1599 log_omx_performance (comp, "EmptyThisBuffer", buf);
1600 err = OMX_EmptyThisBuffer (comp->handle, buf->omx_buf);
1602 log_omx_performance (comp, "FillThisBuffer", buf);
1603 err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
1605 DEBUG_IF_OK (comp->parent, err, "Released buffer %p to %s port %u: %s "
1606 "(0x%08x)", buf, comp->name, port->index, gst_omx_error_to_string (err),
1610 gst_omx_component_handle_messages (comp);
1611 g_mutex_unlock (&comp->lock);
1616 /* NOTE: Must be called while holding comp->lock */
1618 should_wait_until_flushed (GstOMXPort * port)
1621 /* Flush command hasn't been completed yet by OMX */
1624 if (port->buffers) {
1627 /* Wait for all the buffers used by OMX to be released */
1628 for (i = 0; i < port->buffers->len; i++) {
1629 GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
1639 /* NOTE: Uses comp->lock and comp->messages_lock */
1641 gst_omx_port_set_flushing (GstOMXPort * port, GstClockTime timeout,
1644 GstOMXComponent *comp;
1645 OMX_ERRORTYPE err = OMX_ErrorNone;
1647 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
1651 g_mutex_lock (&comp->lock);
1653 GST_DEBUG_OBJECT (comp->parent, "Setting %s port %d to %sflushing",
1654 comp->name, port->index, (flush ? "" : "not "));
1656 gst_omx_component_handle_messages (comp);
1658 if (! !flush == ! !port->flushing) {
1659 GST_DEBUG_OBJECT (comp->parent, "%s port %u was %sflushing already",
1660 comp->name, port->index, (flush ? "" : "not "));
1664 if ((err = comp->last_error) != OMX_ErrorNone) {
1665 GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s "
1666 "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
1670 port->flushing = flush;
1673 OMX_ERRORTYPE last_error;
1675 gst_omx_component_send_message (comp, NULL);
1677 /* Now flush the port */
1678 port->flushed = FALSE;
1680 err = OMX_SendCommand (comp->handle, OMX_CommandFlush, port->index, NULL);
1682 if (err != OMX_ErrorNone) {
1683 GST_ERROR_OBJECT (comp->parent,
1684 "Error sending flush command to %s port %u: %s (0x%08x)", comp->name,
1685 port->index, gst_omx_error_to_string (err), err);
1689 if ((err = comp->last_error) != OMX_ErrorNone) {
1690 GST_ERROR_OBJECT (comp->parent,
1691 "Component %s is in error state: %s (0x%08x)", comp->name,
1692 gst_omx_error_to_string (err), err);
1696 if (! !port->flushing != ! !flush) {
1697 GST_ERROR_OBJECT (comp->parent, "%s: another flush happened in the "
1698 " meantime", comp->name);
1703 if (should_wait_until_flushed (port))
1704 err = OMX_ErrorTimeout;
1708 /* Retry until timeout or until an error happend or
1709 * until all buffers were released by the component and
1710 * the flush command completed */
1712 last_error = OMX_ErrorNone;
1713 gst_omx_component_handle_messages (comp);
1714 while (should_wait_until_flushed (port)) {
1715 signalled = gst_omx_component_wait_message (comp, timeout);
1717 gst_omx_component_handle_messages (comp);
1719 last_error = comp->last_error;
1721 if (!signalled || last_error != OMX_ErrorNone)
1722 /* Something gone wrong or we timed out */
1725 port->flushed = FALSE;
1727 GST_DEBUG_OBJECT (comp->parent, "%s port %d flushed", comp->name,
1729 if (last_error != OMX_ErrorNone) {
1730 GST_ERROR_OBJECT (comp->parent,
1731 "Got error while flushing %s port %u: %s (0x%08x)", comp->name,
1732 port->index, gst_omx_error_to_string (last_error), last_error);
1735 } else if (!signalled) {
1736 GST_ERROR_OBJECT (comp->parent, "Timeout while flushing %s port %u",
1737 comp->name, port->index);
1738 err = OMX_ErrorTimeout;
1743 /* Reset EOS flag */
1747 gst_omx_port_update_port_definition (port, NULL);
1749 DEBUG_IF_OK (comp->parent, err, "Set %s port %u to %sflushing: %s (0x%08x)",
1750 comp->name, port->index, (flush ? "" : "not "),
1751 gst_omx_error_to_string (err), err);
1752 gst_omx_component_handle_messages (comp);
1753 g_mutex_unlock (&comp->lock);
1758 /* NOTE: Uses comp->lock and comp->messages_lock */
1760 gst_omx_port_is_flushing (GstOMXPort * port)
1762 GstOMXComponent *comp;
1765 g_return_val_if_fail (port != NULL, FALSE);
1769 g_mutex_lock (&comp->lock);
1770 gst_omx_component_handle_messages (port->comp);
1771 flushing = port->flushing;
1772 g_mutex_unlock (&comp->lock);
1774 GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing: %d", comp->name,
1775 port->index, flushing);
1780 static OMX_ERRORTYPE gst_omx_port_deallocate_buffers_unlocked (GstOMXPort *
1783 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
1784 static OMX_ERRORTYPE
1785 gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port,
1786 const GList * buffers, const GList * images, guint n)
1788 GstOMXComponent *comp;
1789 OMX_ERRORTYPE err = OMX_ErrorNone;
1793 g_assert (!port->buffers || port->buffers->len == 0);
1795 g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
1799 gst_omx_component_handle_messages (port->comp);
1800 if ((err = comp->last_error) != OMX_ErrorNone) {
1801 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
1802 comp->name, gst_omx_error_to_string (err), err);
1806 /* Update the port definition to check if we need more
1807 * buffers after the port configuration was done and to
1808 * update the buffer size
1810 gst_omx_port_update_port_definition (port, NULL);
1812 g_return_val_if_fail (n != -1 || (!buffers
1813 && !images), OMX_ErrorBadParameter);
1816 n = port->port_def.nBufferCountActual;
1818 g_return_val_if_fail (n == port->port_def.nBufferCountActual,
1819 OMX_ErrorBadParameter);
1821 GST_INFO_OBJECT (comp->parent,
1822 "Allocating %d buffers of size %" G_GSIZE_FORMAT " for %s port %u", n,
1823 (size_t) port->port_def.nBufferSize, comp->name, (guint) port->index);
1826 port->buffers = g_ptr_array_sized_new (n);
1828 l = (buffers ? buffers : images);
1829 for (i = 0; i < n; i++) {
1832 buf = g_slice_new0 (GstOMXBuffer);
1835 buf->settings_cookie = port->settings_cookie;
1836 g_ptr_array_add (port->buffers, buf);
1840 OMX_UseBuffer (comp->handle, &buf->omx_buf, port->index, buf,
1841 port->port_def.nBufferSize, l->data);
1842 buf->eglimage = FALSE;
1843 } else if (images) {
1845 OMX_UseEGLImage (comp->handle, &buf->omx_buf, port->index, buf,
1847 buf->eglimage = TRUE;
1850 OMX_AllocateBuffer (comp->handle, &buf->omx_buf, port->index, buf,
1851 port->port_def.nBufferSize);
1852 buf->eglimage = FALSE;
1855 /* Let the caller decide to print an error when OMX_UseBuffer or
1856 * OMX_UseEGLImage fail. Indeed it can be part of a trial path. So
1857 * it is not necessary to warn the user if the fallback path succeeds.
1859 if (err != OMX_ErrorNone) {
1860 GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, (buffers
1861 || images) ? GST_LEVEL_INFO : GST_LEVEL_ERROR, comp->parent,
1862 "Failed to allocate buffer for %s port %u: %s (0x%08x)", comp->name,
1863 port->index, gst_omx_error_to_string (err), err);
1864 gst_omx_port_deallocate_buffers_unlocked (port);
1868 GST_DEBUG_OBJECT (comp->parent, "%s: allocated buffer %p (%p)",
1869 comp->name, buf, buf->omx_buf->pBuffer);
1871 g_assert (buf->omx_buf->pAppPrivate == buf);
1873 /* In the beginning all buffers are not owned by the component */
1874 g_queue_push_tail (&port->pending_buffers, buf);
1875 if (buffers || images)
1879 gst_omx_component_handle_messages (comp);
1882 gst_omx_port_update_port_definition (port, NULL);
1884 INFO_IF_OK (comp->parent, err, "Allocated buffers for %s port %u: %s "
1885 "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
1890 /* NOTE: Uses comp->lock and comp->messages_lock */
1892 gst_omx_port_allocate_buffers (GstOMXPort * port)
1896 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
1898 g_mutex_lock (&port->comp->lock);
1899 err = gst_omx_port_allocate_buffers_unlocked (port, NULL, NULL, -1);
1900 port->allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
1901 g_mutex_unlock (&port->comp->lock);
1906 /* NOTE: Uses comp->lock and comp->messages_lock */
1908 gst_omx_port_use_buffers (GstOMXPort * port, const GList * buffers)
1913 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
1915 g_mutex_lock (&port->comp->lock);
1916 n = g_list_length ((GList *) buffers);
1917 err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
1918 port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER;
1919 g_mutex_unlock (&port->comp->lock);
1925 gst_omx_is_dynamic_allocation_supported (void)
1927 /* The Zynqultrascaleplus stack implements OMX 1.1.0 but supports the dynamic
1928 * allocation mode from 1.2.0 as an extension. */
1929 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
1933 #if OMX_VERSION_MINOR == 2
1940 /* OMX 1.2.0 introduced a dynamic allocation mode where only buffer headers are
1941 * being allocated during component's initialization. The actual buffers are
1942 * allocated upstream and passed to OMX by setting the pBuffer dynamically
1943 * for each input buffer.
1945 * This function takes care of allocating the buffer headers. Element should
1946 * then use one of the gst_omx_buffer_map_*() method to update buffer's pBuffer
1947 * pointers for each incoming buffer.
1949 * NOTE: Uses comp->lock and comp->messages_lock */
1951 gst_omx_port_use_dynamic_buffers (GstOMXPort * port)
1954 GList *buffers = NULL;
1957 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
1959 n = port->port_def.nBufferCountActual;
1960 for (i = 0; i < port->port_def.nBufferCountActual; i++)
1961 /* Pass NULL to UseBuffer() as the buffer is dynamic and so its payload
1962 * will be set each time before being passed to OMX. */
1963 buffers = g_list_prepend (buffers, GUINT_TO_POINTER (NULL));
1965 g_mutex_lock (&port->comp->lock);
1966 err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
1967 port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
1968 g_mutex_unlock (&port->comp->lock);
1970 g_list_free (buffers);
1975 /* gst_omx_buffer_map_* methods are used in dynamic buffer mode to map
1976 * a frame/memory/buffer and update @buffer so its pBuffer points to the
1977 * mapped data. It also ensures that the input will stay alive until
1978 * gst_omx_buffer_unmap() is called.
1979 * This is used in OMX 1.2.0 dynamic allocation mode so an OMX component can
1980 * safely process @buffer's content without having to copy it.
1981 * The input will be automatically unmapped when @buffer is released by OMX.
1984 gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input,
1985 GstVideoInfo * info)
1987 g_return_val_if_fail (buffer != NULL, FALSE);
1988 g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
1989 g_return_val_if_fail (!buffer->input_mem, FALSE);
1990 g_return_val_if_fail (!buffer->input_buffer, FALSE);
1991 g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
1993 if (!gst_video_frame_map (&buffer->input_frame, info, input, GST_MAP_READ))
1996 buffer->input_frame_mapped = TRUE;
1997 buffer->omx_buf->pBuffer =
1998 GST_VIDEO_FRAME_PLANE_DATA (&buffer->input_frame, 0);
1999 buffer->omx_buf->nAllocLen = gst_buffer_get_size (input);
2000 buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2006 gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
2008 g_return_val_if_fail (buffer != NULL, FALSE);
2009 g_return_val_if_fail (mem != NULL, FALSE);
2010 g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2011 g_return_val_if_fail (!buffer->input_mem, FALSE);
2012 g_return_val_if_fail (!buffer->input_buffer, FALSE);
2013 g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2015 if (!gst_memory_map (mem, &buffer->map, GST_MAP_READ))
2018 buffer->input_mem = gst_memory_ref (mem);
2019 buffer->omx_buf->pBuffer = buffer->map.data;
2020 buffer->omx_buf->nAllocLen = buffer->map.size;
2021 buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2027 gst_omx_buffer_import_fd (GstOMXBuffer * buffer, GstBuffer * input)
2032 g_return_val_if_fail (buffer != NULL, FALSE);
2033 g_return_val_if_fail (input != NULL, FALSE);
2034 g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2035 g_return_val_if_fail (!buffer->input_mem, FALSE);
2036 g_return_val_if_fail (!buffer->input_buffer, FALSE);
2037 g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2039 mem = gst_buffer_peek_memory (input, 0);
2040 g_return_val_if_fail (gst_is_dmabuf_memory (mem), FALSE);
2042 fd = gst_dmabuf_memory_get_fd (mem);
2044 buffer->input_buffer = gst_buffer_ref (input);
2045 buffer->omx_buf->pBuffer = GUINT_TO_POINTER (fd);
2046 buffer->omx_buf->nAllocLen = gst_memory_get_sizes (mem, NULL, NULL);
2047 buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2053 gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
2055 g_return_val_if_fail (buffer != NULL, FALSE);
2056 g_return_val_if_fail (input != NULL, FALSE);
2057 g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
2058 g_return_val_if_fail (!buffer->input_mem, FALSE);
2059 g_return_val_if_fail (!buffer->input_buffer, FALSE);
2060 g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
2062 if (!gst_buffer_map (input, &buffer->map, GST_MAP_READ))
2065 buffer->input_buffer_mapped = TRUE;
2066 buffer->input_buffer = gst_buffer_ref (input);
2067 buffer->omx_buf->pBuffer = buffer->map.data;
2068 buffer->omx_buf->nAllocLen = buffer->map.size;
2069 buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
2074 /* NOTE: Uses comp->lock and comp->messages_lock */
2076 gst_omx_port_use_eglimages (GstOMXPort * port, const GList * images)
2081 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2083 g_mutex_lock (&port->comp->lock);
2084 n = g_list_length ((GList *) images);
2085 err = gst_omx_port_allocate_buffers_unlocked (port, NULL, images, n);
2086 g_mutex_unlock (&port->comp->lock);
2091 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2092 static OMX_ERRORTYPE
2093 gst_omx_port_deallocate_buffers_unlocked (GstOMXPort * port)
2095 GstOMXComponent *comp;
2096 OMX_ERRORTYPE err = OMX_ErrorNone;
2099 g_return_val_if_fail (!port->tunneled, OMX_ErrorBadParameter);
2103 GST_INFO_OBJECT (comp->parent, "Deallocating buffers of %s port %u",
2104 comp->name, port->index);
2106 gst_omx_component_handle_messages (port->comp);
2108 if (!port->buffers) {
2109 GST_DEBUG_OBJECT (comp->parent, "No buffers allocated for %s port %u",
2110 comp->name, port->index);
2114 if ((err = comp->last_error) != OMX_ErrorNone) {
2115 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2116 comp->name, gst_omx_error_to_string (err), err);
2117 /* We still try to deallocate all buffers */
2120 /* We only allow deallocation of buffers after they
2121 * were all released from the port, either by flushing
2122 * the port or by disabling it.
2124 n = port->buffers->len;
2125 for (i = 0; i < n; i++) {
2126 GstOMXBuffer *buf = g_ptr_array_index (port->buffers, i);
2127 OMX_ERRORTYPE tmp = OMX_ErrorNone;
2130 GST_ERROR_OBJECT (comp->parent, "Trying to free used buffer %p of %s "
2131 "port %u", buf, comp->name, port->index);
2134 /* omx_buf can be NULL if allocation failed earlier
2135 * and we're just shutting down
2137 * errors do not cause exiting this loop because we want
2138 * to deallocate as much as possible.
2141 g_assert (buf == buf->omx_buf->pAppPrivate);
2142 buf->omx_buf->pAppPrivate = NULL;
2143 GST_DEBUG_OBJECT (comp->parent, "%s: deallocating buffer %p (%p)",
2144 comp->name, buf, buf->omx_buf->pBuffer);
2146 tmp = OMX_FreeBuffer (comp->handle, port->index, buf->omx_buf);
2148 if (tmp != OMX_ErrorNone) {
2149 GST_ERROR_OBJECT (comp->parent,
2150 "Failed to deallocate buffer %d of %s port %u: %s (0x%08x)", i,
2151 comp->name, port->index, gst_omx_error_to_string (tmp), tmp);
2152 if (err == OMX_ErrorNone)
2156 g_slice_free (GstOMXBuffer, buf);
2158 g_queue_clear (&port->pending_buffers);
2159 g_ptr_array_unref (port->buffers);
2160 port->buffers = NULL;
2162 gst_omx_component_handle_messages (comp);
2165 gst_omx_port_update_port_definition (port, NULL);
2167 DEBUG_IF_OK (comp->parent, err, "Deallocated buffers of %s port %u: %s "
2168 "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2173 /* NOTE: Uses comp->lock and comp->messages_lock */
2175 gst_omx_port_deallocate_buffers (GstOMXPort * port)
2179 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2181 g_mutex_lock (&port->comp->lock);
2182 err = gst_omx_port_deallocate_buffers_unlocked (port);
2183 g_mutex_unlock (&port->comp->lock);
2188 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2189 static OMX_ERRORTYPE
2190 gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled)
2192 GstOMXComponent *comp;
2193 OMX_ERRORTYPE err = OMX_ErrorNone;
2197 gst_omx_component_handle_messages (comp);
2199 if ((err = comp->last_error) != OMX_ErrorNone) {
2200 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2201 comp->name, gst_omx_error_to_string (err), err);
2205 if (port->enabled_pending || port->disabled_pending) {
2206 GST_ERROR_OBJECT (comp->parent, "%s port %d enabled/disabled pending "
2207 "already", comp->name, port->index);
2208 #if OMX_VERSION_MINOR == 2
2209 err = OMX_ErrorBadParameter;
2211 err = OMX_ErrorInvalidState;
2216 GST_INFO_OBJECT (comp->parent, "Setting %s port %u to %s", comp->name,
2217 port->index, (enabled ? "enabled" : "disabled"));
2219 /* Check if the port is already enabled/disabled first */
2220 gst_omx_port_update_port_definition (port, NULL);
2221 if (! !port->port_def.bEnabled == ! !enabled)
2225 port->enabled_pending = TRUE;
2227 port->disabled_pending = TRUE;
2231 OMX_SendCommand (comp->handle, OMX_CommandPortEnable, port->index,
2235 OMX_SendCommand (comp->handle, OMX_CommandPortDisable,
2238 if (err != OMX_ErrorNone) {
2239 GST_ERROR_OBJECT (comp->parent,
2240 "Failed to send enable/disable command to %s port %u: %s (0x%08x)",
2241 comp->name, port->index, gst_omx_error_to_string (err), err);
2245 if ((err = comp->last_error) != OMX_ErrorNone) {
2246 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2247 comp->name, gst_omx_error_to_string (err), err);
2252 gst_omx_component_handle_messages (comp);
2254 gst_omx_port_update_port_definition (port, NULL);
2256 INFO_IF_OK (comp->parent, err, "Set %s port %u to %s%s: %s (0x%08x)",
2257 comp->name, port->index, (err == OMX_ErrorNone ? "" : "not "),
2258 (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
2263 static OMX_ERRORTYPE
2264 gst_omx_port_wait_buffers_released_unlocked (GstOMXPort * port,
2265 GstClockTime timeout)
2267 GstOMXComponent *comp;
2268 OMX_ERRORTYPE err = OMX_ErrorNone;
2269 OMX_ERRORTYPE last_error;
2274 gst_omx_component_handle_messages (comp);
2276 if ((err = comp->last_error) != OMX_ErrorNone) {
2277 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2278 comp->name, gst_omx_error_to_string (err), err);
2282 GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to release all "
2283 "buffers", comp->name, port->index);
2286 if (!port->flushed || (port->buffers
2287 && port->buffers->len >
2288 g_queue_get_length (&port->pending_buffers)))
2289 err = OMX_ErrorTimeout;
2293 /* Wait until all buffers are released by the port */
2295 last_error = OMX_ErrorNone;
2296 gst_omx_component_handle_messages (comp);
2297 while (signalled && last_error == OMX_ErrorNone && (port->buffers
2298 && port->buffers->len >
2299 g_queue_get_length (&port->pending_buffers))) {
2300 signalled = gst_omx_component_wait_message (comp, timeout);
2302 gst_omx_component_handle_messages (comp);
2303 last_error = comp->last_error;
2306 if (last_error != OMX_ErrorNone) {
2308 GST_ERROR_OBJECT (comp->parent,
2309 "Got error while waiting for %s port %u to release all buffers: %s "
2310 "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err),
2313 } else if (!signalled) {
2314 GST_ERROR_OBJECT (comp->parent, "Timeout waiting for %s port %u to "
2315 "release all buffers", comp->name, port->index);
2316 err = OMX_ErrorTimeout;
2321 gst_omx_component_handle_messages (comp);
2323 gst_omx_port_update_port_definition (port, NULL);
2325 DEBUG_IF_OK (comp->parent, err,
2326 "Waited for %s port %u to release all buffers: %s (0x%08x)", comp->name,
2327 port->index, gst_omx_error_to_string (err), err);
2332 /* NOTE: Uses comp->lock and comp->messages_lock */
2334 gst_omx_port_wait_buffers_released (GstOMXPort * port, GstClockTime timeout)
2338 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2340 g_mutex_lock (&port->comp->lock);
2341 err = gst_omx_port_wait_buffers_released_unlocked (port, timeout);
2342 g_mutex_unlock (&port->comp->lock);
2347 /* NOTE: Uses comp->lock and comp->messages_lock */
2349 gst_omx_port_set_enabled (GstOMXPort * port, gboolean enabled)
2353 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2355 g_mutex_lock (&port->comp->lock);
2356 err = gst_omx_port_set_enabled_unlocked (port, enabled);
2357 g_mutex_unlock (&port->comp->lock);
2362 static OMX_ERRORTYPE
2363 gst_omx_port_populate_unlocked (GstOMXPort * port)
2365 GstOMXComponent *comp;
2366 OMX_ERRORTYPE err = OMX_ErrorNone;
2369 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2373 GST_DEBUG_OBJECT (comp->parent, "Populating %s port %d", comp->name,
2376 gst_omx_component_handle_messages (comp);
2378 if (port->flushing || port->disabled_pending || !port->port_def.bEnabled) {
2379 GST_DEBUG_OBJECT (comp->parent, "%s port %u is flushing or disabled",
2380 comp->name, port->index);
2381 err = OMX_ErrorIncorrectStateOperation;
2385 if ((err = comp->last_error) != OMX_ErrorNone) {
2386 GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s"
2387 "(0x%08x)", comp->name, gst_omx_error_to_string (err), err);
2391 if (port->port_def.eDir == OMX_DirOutput && port->buffers && !port->tunneled) {
2392 /* Enqueue all buffers for the component to fill */
2393 while ((buf = g_queue_pop_head (&port->pending_buffers))) {
2394 g_assert (!buf->used);
2396 /* Reset all flags, some implementations don't
2397 * reset them themselves and the flags are not
2398 * valid anymore after the buffer was consumed.
2399 * Also reset nFilledLen as FillThisBuffer() expects an empty buffer.
2401 gst_omx_buffer_reset (buf);
2403 log_omx_performance (comp, "FillThisBuffer", buf);
2404 err = OMX_FillThisBuffer (comp->handle, buf->omx_buf);
2406 if (err != OMX_ErrorNone) {
2407 GST_ERROR_OBJECT (comp->parent,
2408 "Failed to pass buffer %p (%p) to %s port %u: %s (0x%08x)", buf,
2409 buf->omx_buf->pBuffer, comp->name, port->index,
2410 gst_omx_error_to_string (err), err);
2413 GST_DEBUG_OBJECT (comp->parent, "Passed buffer %p (%p) to component %s",
2414 buf, buf->omx_buf->pBuffer, comp->name);
2419 gst_omx_port_update_port_definition (port, NULL);
2421 DEBUG_IF_OK (comp->parent, err, "Populated %s port %u: %s (0x%08x)",
2422 comp->name, port->index, gst_omx_error_to_string (err), err);
2423 gst_omx_component_handle_messages (comp);
2428 /* NOTE: Uses comp->lock and comp->messages_lock */
2430 gst_omx_port_populate (GstOMXPort * port)
2434 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2436 g_mutex_lock (&port->comp->lock);
2437 err = gst_omx_port_populate_unlocked (port);
2438 g_mutex_unlock (&port->comp->lock);
2443 /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */
2444 static OMX_ERRORTYPE
2445 gst_omx_port_wait_enabled_unlocked (GstOMXPort * port, GstClockTime timeout)
2447 GstOMXComponent *comp;
2448 OMX_ERRORTYPE err = OMX_ErrorNone;
2450 OMX_ERRORTYPE last_error;
2455 /* Check the current port status */
2456 gst_omx_port_update_port_definition (port, NULL);
2458 if (port->enabled_pending)
2460 else if (port->disabled_pending)
2463 enabled = port->port_def.bEnabled;
2465 gst_omx_component_handle_messages (comp);
2467 if ((err = comp->last_error) != OMX_ErrorNone) {
2468 GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)",
2469 comp->name, gst_omx_error_to_string (err), err);
2473 GST_INFO_OBJECT (comp->parent, "Waiting for %s port %u to be %s",
2474 comp->name, port->index, (enabled ? "enabled" : "disabled"));
2477 if (port->enabled_pending || port->disabled_pending)
2478 err = OMX_ErrorTimeout;
2482 /* And now wait until the enable/disable command is finished */
2484 last_error = OMX_ErrorNone;
2485 gst_omx_port_update_port_definition (port, NULL);
2486 gst_omx_component_handle_messages (comp);
2487 while (signalled && last_error == OMX_ErrorNone &&
2488 (! !port->port_def.bEnabled != ! !enabled || port->enabled_pending
2489 || port->disabled_pending)) {
2490 signalled = gst_omx_component_wait_message (comp, timeout);
2492 gst_omx_component_handle_messages (comp);
2493 last_error = comp->last_error;
2494 gst_omx_port_update_port_definition (port, NULL);
2496 port->enabled_pending = FALSE;
2497 port->disabled_pending = FALSE;
2500 GST_ERROR_OBJECT (comp->parent,
2501 "Timeout waiting for %s port %u to be %s", comp->name, port->index,
2502 (enabled ? "enabled" : "disabled"));
2503 err = OMX_ErrorTimeout;
2505 } else if (last_error != OMX_ErrorNone) {
2506 GST_ERROR_OBJECT (comp->parent,
2507 "Got error while waiting for %s port %u to be %s: %s (0x%08x)",
2508 comp->name, port->index, (enabled ? "enabled" : "disabled"),
2509 gst_omx_error_to_string (err), err);
2513 /* Reset EOS flag */
2518 gst_omx_component_handle_messages (comp);
2521 gst_omx_port_update_port_definition (port, NULL);
2523 GST_INFO_OBJECT (comp->parent, "%s port %u is %s%s: %s (0x%08x)", comp->name,
2524 port->index, (err == OMX_ErrorNone ? "" : "not "),
2525 (enabled ? "enabled" : "disabled"), gst_omx_error_to_string (err), err);
2530 /* NOTE: Uses comp->lock and comp->messages_lock */
2532 gst_omx_port_wait_enabled (GstOMXPort * port, GstClockTime timeout)
2536 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2538 g_mutex_lock (&port->comp->lock);
2539 err = gst_omx_port_wait_enabled_unlocked (port, timeout);
2540 g_mutex_unlock (&port->comp->lock);
2546 gst_omx_port_is_enabled (GstOMXPort * port)
2550 g_return_val_if_fail (port != NULL, FALSE);
2552 gst_omx_port_update_port_definition (port, NULL);
2553 enabled = ! !port->port_def.bEnabled;
2555 GST_DEBUG_OBJECT (port->comp->parent, "%s port %u is enabled: %d",
2556 port->comp->name, port->index, enabled);
2561 /* NOTE: Uses comp->lock and comp->messages_lock */
2563 gst_omx_port_mark_reconfigured (GstOMXPort * port)
2565 GstOMXComponent *comp;
2566 OMX_ERRORTYPE err = OMX_ErrorNone;
2568 g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
2572 g_mutex_lock (&comp->lock);
2573 GST_INFO_OBJECT (comp->parent, "Marking %s port %u is reconfigured",
2574 comp->name, port->index);
2576 gst_omx_component_handle_messages (comp);
2578 if ((err = comp->last_error) != OMX_ErrorNone)
2581 port->configured_settings_cookie = port->settings_cookie;
2583 if (port->port_def.eDir == OMX_DirOutput) {
2586 for (l = comp->pending_reconfigure_outports; l; l = l->next) {
2587 if (l->data == (gpointer) port) {
2588 comp->pending_reconfigure_outports =
2589 g_list_delete_link (comp->pending_reconfigure_outports, l);
2593 if (!comp->pending_reconfigure_outports)
2594 gst_omx_component_send_message (comp, NULL);
2598 gst_omx_port_update_port_definition (port, NULL);
2600 INFO_IF_OK (comp->parent, err, "Marked %s port %u as reconfigured: %s "
2601 "(0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err);
2603 g_mutex_unlock (&comp->lock);
2608 /* The OMX specs states that the nBufferCountActual of a port has to default
2609 * to its nBufferCountMin. If we don't change nBufferCountActual we purely rely
2610 * on this default. But in some cases, OMX may change nBufferCountMin before we
2611 * allocate buffers. Like for example when configuring the input ports with the
2612 * actual format, it may decrease the number of minimal buffers required.
2613 * This method checks this and update nBufferCountActual if needed so we'll use
2614 * less buffers than the worst case in such scenarios.
2617 gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port, guint extra)
2619 OMX_PARAM_PORTDEFINITIONTYPE port_def;
2622 gst_omx_port_get_port_definition (port, &port_def);
2624 nb = port_def.nBufferCountMin + extra;
2625 if (port_def.nBufferCountActual != nb) {
2626 port_def.nBufferCountActual = nb;
2628 GST_DEBUG_OBJECT (port->comp->parent,
2629 "set port %d nBufferCountActual to %d", (guint) port->index, nb);
2631 if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
2639 gst_omx_port_update_buffer_count_actual (GstOMXPort * port, guint nb)
2641 OMX_PARAM_PORTDEFINITIONTYPE port_def;
2643 gst_omx_port_get_port_definition (port, &port_def);
2645 if (nb < port_def.nBufferCountMin) {
2646 GST_DEBUG_OBJECT (port->comp->parent,
2647 "Requested to use %d buffers on port %d but it's minimum is %d", nb,
2648 (guint) port->index, (guint) port_def.nBufferCountMin);
2650 nb = port_def.nBufferCountMin;
2653 if (port_def.nBufferCountActual != nb) {
2654 port_def.nBufferCountActual = nb;
2656 GST_DEBUG_OBJECT (port->comp->parent,
2657 "set port %d nBufferCountActual to %d", (guint) port->index, nb);
2659 if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
2667 gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf)
2669 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2670 OMX_ALG_PORT_PARAM_BUFFER_MODE buffer_mode;
2673 GST_OMX_INIT_STRUCT (&buffer_mode);
2674 buffer_mode.nPortIndex = port->index;
2677 buffer_mode.eMode = OMX_ALG_BUF_DMA;
2679 buffer_mode.eMode = OMX_ALG_BUF_NORMAL;
2682 gst_omx_component_set_parameter (port->comp,
2683 (OMX_INDEXTYPE) OMX_ALG_IndexPortParamBufferMode, &buffer_mode);
2684 if (err != OMX_ErrorNone) {
2685 GST_WARNING_OBJECT (port->comp->parent,
2686 "Failed to set port %d in %sdmabuf mode: %s (0x%08x)",
2687 port->index, dmabuf ? "" : "non-", gst_omx_error_to_string (err), err);
2693 /* dmabuf not supported for this platform */
2698 typedef GType (*GGetTypeFunction) (void);
2700 static const GGetTypeFunction types[] = {
2701 gst_omx_analog_audio_sink_get_type, gst_omx_hdmi_audio_sink_get_type,
2702 gst_omx_mpeg2_video_dec_get_type, gst_omx_mpeg4_video_dec_get_type,
2703 gst_omx_h264_dec_get_type, gst_omx_h263_dec_get_type,
2704 gst_omx_wmv_dec_get_type, gst_omx_mpeg4_video_enc_get_type,
2705 gst_omx_h264_enc_get_type, gst_omx_h263_enc_get_type,
2706 gst_omx_aac_enc_get_type, gst_omx_mjpeg_dec_get_type,
2707 gst_omx_aac_dec_get_type, gst_omx_mp3_dec_get_type,
2708 gst_omx_aac_dec_get_type, gst_omx_mp3_enc_get_type,
2709 gst_omx_amr_dec_get_type
2711 , gst_omx_vp8_dec_get_type
2714 , gst_omx_theora_dec_get_type
2717 , gst_omx_h265_enc_get_type, gst_omx_h265_dec_get_type
2723 GType (*get_type) (void);
2727 static const struct TypeOffest base_types[] = {
2728 {gst_omx_audio_sink_get_type, G_STRUCT_OFFSET (GstOMXAudioSinkClass, cdata)},
2729 {gst_omx_video_dec_get_type, G_STRUCT_OFFSET (GstOMXVideoDecClass, cdata)},
2730 {gst_omx_video_enc_get_type, G_STRUCT_OFFSET (GstOMXVideoEncClass, cdata)},
2731 {gst_omx_audio_dec_get_type, G_STRUCT_OFFSET (GstOMXAudioDecClass, cdata)},
2732 {gst_omx_audio_enc_get_type, G_STRUCT_OFFSET (GstOMXAudioEncClass, cdata)},
2735 static GKeyFile *config = NULL;
2737 gst_omx_get_configuration (void)
2743 gst_omx_error_to_string (OMX_ERRORTYPE err)
2745 guint err_u = (guint) err;
2750 case OMX_ErrorInsufficientResources:
2751 return "Insufficient resources";
2752 case OMX_ErrorUndefined:
2754 case OMX_ErrorInvalidComponentName:
2755 return "Invalid component name";
2756 case OMX_ErrorComponentNotFound:
2757 return "Component not found";
2758 case OMX_ErrorBadParameter:
2759 return "Bad parameter";
2760 case OMX_ErrorNotImplemented:
2761 return "Not implemented";
2762 case OMX_ErrorUnderflow:
2764 case OMX_ErrorOverflow:
2766 case OMX_ErrorHardware:
2768 case OMX_ErrorStreamCorrupt:
2769 return "Stream corrupt";
2770 case OMX_ErrorPortsNotCompatible:
2771 return "Ports not compatible";
2772 case OMX_ErrorResourcesLost:
2773 return "Resources lost";
2774 case OMX_ErrorNoMore:
2776 case OMX_ErrorVersionMismatch:
2777 return "Version mismatch";
2778 case OMX_ErrorNotReady:
2780 case OMX_ErrorTimeout:
2782 case OMX_ErrorSameState:
2783 return "Same state";
2784 case OMX_ErrorResourcesPreempted:
2785 return "Resources preempted";
2786 case OMX_ErrorIncorrectStateTransition:
2787 return "Incorrect state transition";
2788 case OMX_ErrorIncorrectStateOperation:
2789 return "Incorrect state operation";
2790 case OMX_ErrorUnsupportedSetting:
2791 return "Unsupported setting";
2792 case OMX_ErrorUnsupportedIndex:
2793 return "Unsupported index";
2794 case OMX_ErrorBadPortIndex:
2795 return "Bad port index";
2796 case OMX_ErrorPortUnpopulated:
2797 return "Port unpopulated";
2798 case OMX_ErrorComponentSuspended:
2799 return "Component suspended";
2800 case OMX_ErrorDynamicResourcesUnavailable:
2801 return "Dynamic resources unavailable";
2802 case OMX_ErrorMbErrorsInFrame:
2803 return "Macroblock errors in frame";
2804 case OMX_ErrorFormatNotDetected:
2805 return "Format not detected";
2806 case OMX_ErrorSeperateTablesUsed:
2807 return "Separate tables used";
2808 case OMX_ErrorTunnelingUnsupported:
2809 return "Tunneling unsupported";
2810 #if OMX_VERSION_MINOR == 1
2811 case OMX_ErrorInvalidComponent:
2812 return "Invalid component";
2813 case OMX_ErrorInvalidState:
2814 return "Invalid state";
2815 case OMX_ErrorPortUnresponsiveDuringAllocation:
2816 return "Port unresponsive during allocation";
2817 case OMX_ErrorPortUnresponsiveDuringDeallocation:
2818 return "Port unresponsive during deallocation";
2819 case OMX_ErrorPortUnresponsiveDuringStop:
2820 return "Port unresponsive during stop";
2821 case OMX_ErrorContentPipeOpenFailed:
2822 return "Content pipe open failed";
2823 case OMX_ErrorContentPipeCreationFailed:
2824 return "Content pipe creation failed";
2827 if (err_u >= (guint) OMX_ErrorKhronosExtensions
2828 && err_u < (guint) OMX_ErrorVendorStartUnused) {
2829 return "Khronos extension error";
2830 } else if (err_u >= (guint) OMX_ErrorVendorStartUnused
2831 && err_u < (guint) OMX_ErrorMax) {
2832 return "Vendor specific error";
2834 return "Unknown error";
2840 gst_omx_state_to_string (OMX_STATETYPE state)
2843 case OMX_StateInvalid:
2845 case OMX_StateLoaded:
2849 case OMX_StateExecuting:
2851 case OMX_StatePause:
2853 case OMX_StateWaitForResources:
2854 return "WaitForResources";
2856 if (state >= OMX_StateKhronosExtensions
2857 && state < OMX_StateVendorStartUnused)
2858 return "KhronosExtensionState";
2859 else if (state >= OMX_StateVendorStartUnused && state < OMX_StateMax)
2860 return "CustomVendorState";
2863 return "Unknown state";
2867 gst_omx_command_to_string (OMX_COMMANDTYPE cmd)
2870 case OMX_CommandStateSet:
2872 case OMX_CommandFlush:
2874 case OMX_CommandPortDisable:
2875 return "DisablePort";
2876 case OMX_CommandPortEnable:
2877 return "EnablePort";
2878 case OMX_CommandMarkBuffer:
2879 return "MarkBuffer";
2881 if (cmd >= OMX_CommandKhronosExtensions
2882 && cmd < OMX_CommandVendorStartUnused)
2883 return "KhronosExtensionCommand";
2884 if (cmd >= OMX_CommandVendorStartUnused && cmd < OMX_CommandMax)
2885 return "VendorExtensionCommand";
2888 return "Unknown command";
2891 struct BufferFlagString
2897 struct BufferFlagString buffer_flags_map[] = {
2898 {OMX_BUFFERFLAG_EOS, "eos"},
2899 {OMX_BUFFERFLAG_STARTTIME, "start-time"},
2900 {OMX_BUFFERFLAG_DECODEONLY, "decode-only"},
2901 {OMX_BUFFERFLAG_DATACORRUPT, "data-corrupt"},
2902 {OMX_BUFFERFLAG_ENDOFFRAME, "end-of-frame"},
2903 {OMX_BUFFERFLAG_SYNCFRAME, "sync-frame"},
2904 {OMX_BUFFERFLAG_EXTRADATA, "extra-data"},
2905 {OMX_BUFFERFLAG_CODECCONFIG, "codec-config"},
2906 /* Introduced in OMX 1.2.0 */
2907 #ifdef OMX_BUFFERFLAG_TIMESTAMPINVALID
2908 {OMX_BUFFERFLAG_TIMESTAMPINVALID, "timestamp-invalid"},
2910 #ifdef OMX_BUFFERFLAG_READONLY
2911 {OMX_BUFFERFLAG_READONLY, "read-only"},
2913 #ifdef OMX_BUFFERFLAG_ENDOFSUBFRAME
2914 {OMX_BUFFERFLAG_ENDOFSUBFRAME, "end-of-subframe"},
2916 #ifdef OMX_BUFFERFLAG_SKIPFRAME
2917 {OMX_BUFFERFLAG_SKIPFRAME, "skip-frame"},
2924 gst_omx_buffer_flags_to_string (guint32 flags)
2933 /* Keep a cache of the string representation of the flags so we don't allocate
2934 * and free strings for each buffer. In practice we should only have a handfull
2935 * of flags so the cache won't consume much memory. */
2936 if (!buffer_flags_str) {
2937 G_LOCK (buffer_flags_str);
2938 buffer_flags_str = g_hash_table_new_full (NULL, NULL, NULL, g_free);
2939 G_UNLOCK (buffer_flags_str);
2942 str = g_hash_table_lookup (buffer_flags_str, GUINT_TO_POINTER (flags));
2946 for (i = 0; buffer_flags_map[i].str != NULL; i++) {
2947 if ((flags & buffer_flags_map[i].flag) == 0)
2951 s = g_string_new (buffer_flags_map[i].str);
2953 g_string_append_printf (s, ", %s", buffer_flags_map[i].str);
2959 str = g_string_free (s, FALSE);
2961 G_LOCK (buffer_flags_str);
2962 /* Transfer ownership of str to hash table */
2963 g_hash_table_insert (buffer_flags_str, GUINT_TO_POINTER (flags),
2965 G_UNLOCK (buffer_flags_str);
2970 #if defined(USE_OMX_TARGET_RPI)
2971 #define DEFAULT_HACKS (GST_OMX_HACK_NO_COMPONENT_ROLE | GST_OMX_HACK_HEIGHT_MULTIPLE_16)
2973 #define DEFAULT_HACKS (0)
2977 gst_omx_parse_hacks (gchar ** hacks)
2979 guint64 hacks_flags = DEFAULT_HACKS;
2985 if (g_str_equal (*hacks,
2986 "event-port-settings-changed-ndata-parameter-swap"))
2988 GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_NDATA_PARAMETER_SWAP;
2989 else if (g_str_equal (*hacks, "event-port-settings-changed-port-0-to-1"))
2990 hacks_flags |= GST_OMX_HACK_EVENT_PORT_SETTINGS_CHANGED_PORT_0_TO_1;
2991 else if (g_str_equal (*hacks, "video-framerate-integer"))
2992 hacks_flags |= GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER;
2993 else if (g_str_equal (*hacks, "syncframe-flag-not-used"))
2994 hacks_flags |= GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED;
2995 else if (g_str_equal (*hacks, "no-component-reconfigure"))
2996 hacks_flags |= GST_OMX_HACK_NO_COMPONENT_RECONFIGURE;
2997 else if (g_str_equal (*hacks, "no-empty-eos-buffer"))
2998 hacks_flags |= GST_OMX_HACK_NO_EMPTY_EOS_BUFFER;
2999 else if (g_str_equal (*hacks, "drain-may-not-return"))
3000 hacks_flags |= GST_OMX_HACK_DRAIN_MAY_NOT_RETURN;
3001 else if (g_str_equal (*hacks, "no-component-role"))
3002 hacks_flags |= GST_OMX_HACK_NO_COMPONENT_ROLE;
3003 else if (g_str_equal (*hacks, "no-disable-outport"))
3004 hacks_flags |= GST_OMX_HACK_NO_DISABLE_OUTPORT;
3005 else if (g_str_equal (*hacks, "signals-premature-eos"))
3006 hacks_flags |= GST_OMX_HACK_SIGNALS_PREMATURE_EOS;
3007 else if (g_str_equal (*hacks, "height-multiple-16"))
3008 hacks_flags |= GST_OMX_HACK_HEIGHT_MULTIPLE_16;
3009 else if (g_str_equal (*hacks, "pass-profile-to-decoder"))
3010 hacks_flags |= GST_OMX_HACK_PASS_PROFILE_TO_DECODER;
3011 else if (g_str_equal (*hacks, "pass-color-format-to-decoder"))
3012 hacks_flags |= GST_OMX_HACK_PASS_COLOR_FORMAT_TO_DECODER;
3013 else if (g_str_equal (*hacks, "ensure-buffer-count-actual"))
3014 hacks_flags |= GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL;
3016 GST_WARNING ("Unknown hack: %s", *hacks);
3025 gst_omx_set_default_role (GstOMXClassData * class_data,
3026 const gchar * default_role)
3028 if (!class_data->component_role)
3029 class_data->component_role = default_role;
3033 gst_omx_buffer_set_omx_buf (GstBuffer * buffer, GstOMXBuffer * omx_buf)
3035 gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer),
3036 gst_omx_buffer_data_quark, omx_buf, NULL);
3040 gst_omx_buffer_get_omx_buf (GstBuffer * buffer)
3042 return gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer),
3043 gst_omx_buffer_data_quark);
3047 _class_init (gpointer g_class, gpointer data)
3049 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3050 GstOMXClassData *class_data = NULL;
3052 const gchar *element_name = data;
3054 gchar *core_name, *component_name, *component_role;
3055 gint in_port_index, out_port_index;
3056 gchar *template_caps;
3057 GstPadTemplate *templ;
3065 /* Find the GstOMXClassData for this class */
3066 for (i = 0; i < G_N_ELEMENTS (base_types); i++) {
3067 GType gtype = base_types[i].get_type ();
3069 if (G_TYPE_CHECK_CLASS_TYPE (g_class, gtype)) {
3070 class_data = (GstOMXClassData *)
3071 (((guint8 *) g_class) + base_types[i].offset);
3076 g_assert (class_data != NULL);
3078 config = gst_omx_get_configuration ();
3080 /* This will alwaxys succeed, see check in plugin_init */
3081 core_name = g_key_file_get_string (config, element_name, "core-name", NULL);
3082 g_assert (core_name != NULL);
3083 class_data->core_name = core_name;
3085 g_key_file_get_string (config, element_name, "component-name", NULL);
3086 g_assert (component_name != NULL);
3087 class_data->component_name = component_name;
3089 /* If this fails we simply don't set a role */
3090 if ((component_role =
3091 g_key_file_get_string (config, element_name, "component-role",
3093 GST_DEBUG ("Using component-role '%s' for element '%s'", component_role,
3095 class_data->component_role = component_role;
3099 /* Now set the inport/outport indizes and assume sane defaults */
3102 g_key_file_get_integer (config, element_name, "in-port-index", &err);
3104 GST_DEBUG ("No 'in-port-index' set for element '%s', auto-detecting: %s",
3105 element_name, err->message);
3109 class_data->in_port_index = in_port_index;
3113 g_key_file_get_integer (config, element_name, "out-port-index", &err);
3115 GST_DEBUG ("No 'out-port-index' set for element '%s', auto-detecting: %s",
3116 element_name, err->message);
3117 out_port_index = -1;
3120 class_data->out_port_index = out_port_index;
3122 /* Add pad templates */
3124 if (class_data->type != GST_OMX_COMPONENT_TYPE_SOURCE) {
3125 if (!(template_caps =
3126 g_key_file_get_string (config, element_name, "sink-template-caps",
3129 ("No sink template caps specified for element '%s', using default '%s'",
3130 element_name, class_data->default_sink_template_caps);
3131 caps = gst_caps_from_string (class_data->default_sink_template_caps);
3132 g_assert (caps != NULL);
3135 caps = gst_caps_from_string (template_caps);
3138 ("Could not parse sink template caps '%s' for element '%s', using default '%s'",
3139 template_caps, element_name,
3140 class_data->default_sink_template_caps);
3141 caps = gst_caps_from_string (class_data->default_sink_template_caps);
3142 g_assert (caps != NULL);
3145 templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
3146 g_free (template_caps);
3147 gst_element_class_add_pad_template (element_class, templ);
3148 gst_caps_unref (caps);
3152 if (class_data->type != GST_OMX_COMPONENT_TYPE_SINK) {
3153 if (!(template_caps =
3154 g_key_file_get_string (config, element_name, "src-template-caps",
3157 ("No src template caps specified for element '%s', using default '%s'",
3158 element_name, class_data->default_src_template_caps);
3159 caps = gst_caps_from_string (class_data->default_src_template_caps);
3160 g_assert (caps != NULL);
3163 caps = gst_caps_from_string (template_caps);
3166 ("Could not parse src template caps '%s' for element '%s', using default '%s'",
3167 template_caps, element_name, class_data->default_src_template_caps);
3168 caps = gst_caps_from_string (class_data->default_src_template_caps);
3169 g_assert (caps != NULL);
3172 templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
3173 g_free (template_caps);
3174 gst_element_class_add_pad_template (element_class, templ);
3175 gst_caps_unref (caps);
3179 g_key_file_get_string_list (config, element_name, "hacks", NULL,
3181 #ifndef GST_DISABLE_GST_DEBUG
3182 gchar **walk = hacks;
3185 GST_DEBUG ("Using hack: %s", *walk);
3190 class_data->hacks = gst_omx_parse_hacks (hacks);
3196 plugin_init (GstPlugin * plugin)
3199 gchar **config_dirs;
3201 gchar *env_config_dir;
3202 const gchar *user_config_dir;
3203 const gchar *const *system_config_dirs;
3206 static const gchar *config_name[] = { "gstomx.conf", NULL };
3207 static const gchar *env_config_name[] = { "GST_OMX_CONFIG_DIR", NULL };
3208 static const gchar *gst_omx_config_dir = GST_OMX_CONFIG_DIR;
3210 GST_DEBUG_CATEGORY_INIT (gstomx_debug, "omx", 0, "gst-omx");
3211 GST_DEBUG_CATEGORY_INIT (gst_omx_video_debug_category, "omxvideo", 0,
3213 GST_DEBUG_CATEGORY_INIT (OMX_PERFORMANCE, "OMX_PERFORMANCE", 0,
3214 "gst-omx performace");
3216 gst_omx_buffer_data_quark = g_quark_from_static_string ("GstOMXBufferData");
3218 /* Read configuration file gstomx.conf from the preferred
3219 * configuration directories */
3220 env_config_dir = g_strdup (g_getenv (*env_config_name));
3221 user_config_dir = g_get_user_config_dir ();
3222 system_config_dirs = g_get_system_config_dirs ();
3224 g_new (gchar *, g_strv_length ((gchar **) system_config_dirs) + 4);
3229 config_dirs[i++] = (gchar *) env_config_dir;
3230 config_dirs[i++] = (gchar *) user_config_dir;
3231 while (system_config_dirs[j])
3232 config_dirs[i++] = (gchar *) system_config_dirs[j++];
3233 config_dirs[i++] = (gchar *) gst_omx_config_dir;
3234 config_dirs[i++] = NULL;
3236 gst_plugin_add_dependency (plugin, env_config_name,
3237 (const gchar **) (config_dirs + (env_config_dir ? 1 : 0)), config_name,
3238 GST_PLUGIN_DEPENDENCY_FLAG_NONE);
3240 config = g_key_file_new ();
3241 if (!g_key_file_load_from_dirs (config, *config_name,
3242 (const gchar **) config_dirs, NULL, G_KEY_FILE_NONE, &err)) {
3245 paths = g_strjoinv (":", config_dirs);
3246 GST_ERROR ("Failed to load configuration file: %s (searched in: %s as per "
3247 "GST_OMX_CONFIG_DIR environment variable, the xdg user config "
3248 "directory (or XDG_CONFIG_HOME) and the system config directory "
3249 "(or XDG_CONFIG_DIRS)", err->message, paths);
3255 /* Initialize all types */
3256 for (i = 0; i < G_N_ELEMENTS (types); i++)
3259 elements = g_key_file_get_groups (config, &n_elements);
3260 for (i = 0; i < n_elements; i++) {
3261 GTypeQuery type_query;
3262 GTypeInfo type_info = { 0, };
3263 GType type, subtype;
3264 gchar *type_name, *core_name, *component_name;
3267 GST_DEBUG ("Registering element '%s'", elements[i]);
3271 g_key_file_get_string (config, elements[i], "type-name", &err))) {
3273 ("Unable to read 'type-name' configuration for element '%s': %s",
3274 elements[i], err->message);
3279 type = g_type_from_name (type_name);
3280 if (type == G_TYPE_INVALID) {
3281 GST_ERROR ("Invalid type name '%s' for element '%s'", type_name,
3286 if (!g_type_is_a (type, GST_TYPE_ELEMENT)) {
3287 GST_ERROR ("Type '%s' is no GstElement subtype for element '%s'",
3288 type_name, elements[i]);
3294 /* And now some sanity checking */
3297 g_key_file_get_string (config, elements[i], "core-name", &err))) {
3299 ("Unable to read 'core-name' configuration for element '%s': %s",
3300 elements[i], err->message);
3304 if (!g_file_test (core_name, G_FILE_TEST_IS_REGULAR)) {
3305 GST_ERROR ("Core '%s' does not exist for element '%s'", core_name,
3313 if (!(component_name =
3314 g_key_file_get_string (config, elements[i], "component-name",
3317 ("Unable to read 'component-name' configuration for element '%s': %s",
3318 elements[i], err->message);
3322 g_free (component_name);
3325 rank = g_key_file_get_integer (config, elements[i], "rank", &err);
3327 GST_ERROR ("No rank set for element '%s': %s", elements[i], err->message);
3332 /* And now register the type, all other configuration will
3333 * be handled by the type itself */
3334 g_type_query (type, &type_query);
3335 memset (&type_info, 0, sizeof (type_info));
3336 type_info.class_size = type_query.class_size;
3337 type_info.instance_size = type_query.instance_size;
3338 type_info.class_init = _class_init;
3339 type_info.class_data = g_strdup (elements[i]);
3340 type_name = g_strdup_printf ("%s-%s", g_type_name (type), elements[i]);
3341 if (g_type_from_name (type_name) != G_TYPE_INVALID) {
3342 GST_ERROR ("Type '%s' already exists for element '%s'", type_name,
3347 subtype = g_type_register_static (type, type_name, &type_info, 0);
3349 gst_element_register (plugin, elements[i], rank, subtype);
3351 g_strfreev (elements);
3354 g_free (env_config_dir);
3355 g_free (config_dirs);
3360 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
3363 "GStreamer OpenMAX Plug-ins",
3365 PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)