2 * Copyright (C) 2007-2009 Nokia Corporation.
4 * Author: Felipe Contreras <felipe.contreras@nokia.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "gstomx_base_filter.h"
24 #include "gstomx_interface.h"
26 #include <string.h> /* for memcpy */
29 static void output_loop (gpointer data);
33 ARG_USE_TIMESTAMPS = GSTOMX_NUM_COMMON_PROP,
34 ARG_NUM_INPUT_BUFFERS,
35 ARG_NUM_OUTPUT_BUFFERS,
36 ARG_USE_STATETUNING, /* STATE_TUNING */
39 static void init_interfaces (GType type);
40 GSTOMX_BOILERPLATE_FULL (GstOmxBaseFilter, gst_omx_base_filter, GstElement,
41 GST_TYPE_ELEMENT, init_interfaces);
44 log_buffer (GstOmxBaseFilter * self, OMX_BUFFERHEADERTYPE * omx_buffer)
46 GST_DEBUG_OBJECT (self, "omx_buffer: "
52 omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
53 omx_buffer->nOffset, omx_buffer->nTimeStamp);
56 /* Add_code_for_extended_color_format */
58 is_extended_color_format(GstOmxBaseFilter * self, GOmxPort * port)
60 OMX_PARAM_PORTDEFINITIONTYPE param;
61 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
63 if (G_UNLIKELY (!omx_handle)) {
64 GST_WARNING_OBJECT (self, "no component");
68 G_OMX_INIT_PARAM (param);
70 param.nPortIndex = port->port_index;
71 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
73 switch ((guint)param.format.video.eColorFormat) {
74 case OMX_EXT_COLOR_FormatNV12TPhysicalAddress:
75 case OMX_EXT_COLOR_FormatNV12LPhysicalAddress:
76 case OMX_EXT_COLOR_FormatNV12Tiled:
84 setup_ports (GstOmxBaseFilter * self)
86 /* Input port configuration. */
87 g_omx_port_setup (self->in_port);
88 gst_pad_set_element_private (self->sinkpad, self->in_port);
90 /* Output port configuration. */
91 g_omx_port_setup (self->out_port);
92 gst_pad_set_element_private (self->srcpad, self->out_port);
94 /* @todo: read from config file: */
95 if (g_getenv ("OMX_ALLOCATE_ON")) {
96 GST_DEBUG_OBJECT (self, "OMX_ALLOCATE_ON");
97 self->in_port->omx_allocate = TRUE;
98 self->out_port->omx_allocate = TRUE;
99 self->share_input_buffer = FALSE;
100 self->share_output_buffer = FALSE;
101 } else if (g_getenv ("OMX_SHARE_HACK_ON")) {
102 GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_ON");
103 self->share_input_buffer = TRUE;
104 self->share_output_buffer = TRUE;
105 } else if (g_getenv ("OMX_SHARE_HACK_OFF")) {
106 GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_OFF");
107 self->share_input_buffer = FALSE;
108 self->share_output_buffer = FALSE;
109 /* Add extended_color_format */
110 } else if (self->gomx->component_vendor == GOMX_VENDOR_SLSI) {
111 self->share_input_buffer = (is_extended_color_format(self, self->in_port))
113 self->share_output_buffer = (is_extended_color_format(self, self->out_port))
116 GST_DEBUG_OBJECT (self, "default sharing and allocation");
119 GST_DEBUG_OBJECT (self, "omx_allocate: in: %d, out: %d",
120 self->in_port->omx_allocate, self->out_port->omx_allocate);
121 GST_DEBUG_OBJECT (self, "share_buffer: in: %d, out: %d",
122 self->share_input_buffer, self->share_output_buffer);
125 static GstStateChangeReturn
126 change_state (GstElement * element, GstStateChange transition)
128 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
129 GstOmxBaseFilter *self;
132 self = GST_OMX_BASE_FILTER (element);
135 GST_LOG_OBJECT (self, "begin");
137 GST_INFO_OBJECT (self, "changing state %s - %s",
138 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
139 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
141 switch (transition) {
142 case GST_STATE_CHANGE_NULL_TO_READY:
143 if (core->omx_state != OMX_StateLoaded) {
144 ret = GST_STATE_CHANGE_FAILURE;
149 case GST_STATE_CHANGE_READY_TO_PAUSED:
151 if (self->use_state_tuning) {
152 GST_INFO_OBJECT (self, "use state-tuning feature");
153 g_mutex_lock (self->ready_lock);
155 self->sink_set_caps = (GstCaps *)gst_pad_peer_get_caps (self->sinkpad);
156 if (self->sink_set_caps == NULL) {
157 GST_ERROR_OBJECT (self, "Caps is NULL");
160 GST_INFO_OBJECT (self, "omx: prepare");
162 /** @todo this should probably go after doing preparations. */
163 if (self->omx_setup) {
164 self->omx_setup (self);
169 g_omx_core_prepare (self->gomx);
171 if (core->omx_state == OMX_StateIdle) {
173 gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
175 GST_ERROR_OBJECT(self, "fail to move from OMX state Loaded to Idle");
176 g_omx_port_finish(self->in_port);
177 g_omx_port_finish(self->out_port);
178 g_omx_core_stop(core);
179 g_omx_core_unload(core);
180 g_mutex_unlock(self->ready_lock);
181 ret = GST_STATE_CHANGE_FAILURE;
185 g_mutex_unlock (self->ready_lock);
193 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
195 if (ret == GST_STATE_CHANGE_FAILURE)
198 switch (transition) {
199 case GST_STATE_CHANGE_PAUSED_TO_READY:
200 g_mutex_lock (self->ready_lock);
203 g_omx_port_finish (self->in_port);
204 g_omx_port_finish (self->out_port);
206 g_omx_core_stop (core);
207 g_omx_core_unload (core);
210 g_mutex_unlock (self->ready_lock);
211 if (core->omx_state != OMX_StateLoaded &&
212 core->omx_state != OMX_StateInvalid) {
213 ret = GST_STATE_CHANGE_FAILURE;
223 GST_LOG_OBJECT (self, "end");
229 finalize (GObject * obj)
231 GstOmxBaseFilter *self;
233 self = GST_OMX_BASE_FILTER (obj);
235 if (self->codec_data) {
236 gst_buffer_unref (self->codec_data);
237 self->codec_data = NULL;
240 g_omx_core_free (self->gomx);
242 g_mutex_free (self->ready_lock);
244 G_OBJECT_CLASS (parent_class)->finalize (obj);
248 set_property (GObject * obj,
249 guint prop_id, const GValue * value, GParamSpec * pspec)
251 GstOmxBaseFilter *self;
253 self = GST_OMX_BASE_FILTER (obj);
256 case ARG_USE_TIMESTAMPS:
257 self->use_timestamps = g_value_get_boolean (value);
259 case ARG_NUM_INPUT_BUFFERS:
260 case ARG_NUM_OUTPUT_BUFFERS:
262 OMX_PARAM_PORTDEFINITIONTYPE param;
263 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
264 OMX_U32 nBufferCountActual;
265 GOmxPort *port = (prop_id == ARG_NUM_INPUT_BUFFERS) ?
266 self->in_port : self->out_port;
268 if (G_UNLIKELY (!omx_handle)) {
269 GST_WARNING_OBJECT (self, "no component");
273 nBufferCountActual = g_value_get_uint (value);
275 G_OMX_INIT_PARAM (param);
277 param.nPortIndex = port->port_index;
278 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
280 if (nBufferCountActual < param.nBufferCountMin) {
281 GST_ERROR_OBJECT (self, "buffer count %lu is less than minimum %lu",
282 nBufferCountActual, param.nBufferCountMin);
286 param.nBufferCountActual = nBufferCountActual;
288 OMX_SetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
292 case ARG_USE_STATETUNING:
293 self->use_state_tuning = g_value_get_boolean(value);
296 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
302 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
304 GstOmxBaseFilter *self;
306 self = GST_OMX_BASE_FILTER (obj);
308 if (gstomx_get_property_helper (self->gomx, prop_id, value))
312 case ARG_USE_TIMESTAMPS:
313 g_value_set_boolean (value, self->use_timestamps);
315 case ARG_NUM_INPUT_BUFFERS:
316 case ARG_NUM_OUTPUT_BUFFERS:
318 OMX_PARAM_PORTDEFINITIONTYPE param;
319 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
320 GOmxPort *port = (prop_id == ARG_NUM_INPUT_BUFFERS) ?
321 self->in_port : self->out_port;
323 if (G_UNLIKELY (!omx_handle)) {
324 GST_WARNING_OBJECT (self, "no component");
325 g_value_set_uint (value, 0);
329 G_OMX_INIT_PARAM (param);
331 param.nPortIndex = port->port_index;
332 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
334 g_value_set_uint (value, param.nBufferCountActual);
338 case ARG_USE_STATETUNING:
339 g_value_set_boolean(value, self->use_state_tuning);
342 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
348 type_base_init (gpointer g_class)
353 type_class_init (gpointer g_class, gpointer class_data)
355 GObjectClass *gobject_class;
356 GstElementClass *gstelement_class;
358 gobject_class = G_OBJECT_CLASS (g_class);
359 gstelement_class = GST_ELEMENT_CLASS (g_class);
361 gobject_class->finalize = finalize;
362 gstelement_class->change_state = change_state;
364 /* Properties stuff */
366 gobject_class->set_property = set_property;
367 gobject_class->get_property = get_property;
369 gstomx_install_property_helper (gobject_class);
371 g_object_class_install_property (gobject_class, ARG_USE_TIMESTAMPS,
372 g_param_spec_boolean ("use-timestamps", "Use timestamps",
373 "Whether or not to use timestamps",
374 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
376 g_object_class_install_property (gobject_class, ARG_NUM_INPUT_BUFFERS,
377 g_param_spec_uint ("input-buffers", "Input buffers",
378 "The number of OMX input buffers",
379 1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
380 g_object_class_install_property (gobject_class, ARG_NUM_OUTPUT_BUFFERS,
381 g_param_spec_uint ("output-buffers", "Output buffers",
382 "The number of OMX output buffers",
383 1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
386 g_object_class_install_property (gobject_class, ARG_USE_STATETUNING,
387 g_param_spec_boolean ("state-tuning", "start omx component in gst paused state",
388 "Whether or not to use state-tuning feature",
389 FALSE, G_PARAM_READWRITE));
393 static inline GstFlowReturn
394 push_buffer (GstOmxBaseFilter * self, GstBuffer * buf)
398 /** @todo check if tainted */
399 GST_LOG_OBJECT (self, "begin");
400 ret = gst_pad_push (self->srcpad, buf);
401 GST_LOG_OBJECT (self, "end");
407 output_loop (gpointer data)
412 GstOmxBaseFilter *self;
413 GstFlowReturn ret = GST_FLOW_OK;
416 self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
419 GST_LOG_OBJECT (self, "begin");
421 /* do not bother if we have been setup to bail out */
422 if ((ret = g_atomic_int_get (&self->last_pad_push_return)) != GST_FLOW_OK)
426 g_error ("not ready");
430 out_port = self->out_port;
432 if (G_LIKELY (out_port->enabled)) {
433 OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
435 GST_LOG_OBJECT (self, "request buffer");
436 omx_buffer = g_omx_port_request_buffer (out_port);
438 GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);
440 if (G_UNLIKELY (!omx_buffer)) {
441 GST_WARNING_OBJECT (self, "null buffer: leaving");
442 ret = GST_FLOW_WRONG_STATE;
446 log_buffer (self, omx_buffer);
448 if (G_LIKELY (omx_buffer->nFilledLen > 0)) {
452 /** @todo remove this check */
453 if (G_LIKELY (self->in_port->enabled)) {
454 GstCaps *caps = NULL;
456 caps = gst_pad_get_negotiated_caps (self->srcpad);
459 /** @todo We shouldn't be doing this. */
460 GST_WARNING_OBJECT (self, "faking settings changed notification");
461 if (gomx->settings_changed_cb)
462 gomx->settings_changed_cb (gomx);
464 GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps);
465 gst_caps_unref (caps);
470 /* buf is always null when the output buffer pointer isn't shared. */
471 buf = omx_buffer->pAppPrivate;
473 /** @todo we need to move all the caps handling to one single
474 * place, in the output loop probably. */
475 if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
476 GstCaps *caps = NULL;
477 GstStructure *structure;
478 GValue value = { 0, {{0}
482 caps = gst_pad_get_negotiated_caps (self->srcpad);
483 caps = gst_caps_make_writable (caps);
484 structure = gst_caps_get_structure (caps, 0);
486 g_value_init (&value, GST_TYPE_BUFFER);
487 buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
488 memcpy (GST_BUFFER_DATA (buf),
489 omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
490 gst_value_set_buffer (&value, buf);
491 gst_buffer_unref (buf);
492 gst_structure_set_value (structure, "codec_data", &value);
493 g_value_unset (&value);
495 gst_pad_set_caps (self->srcpad, caps);
497 } else if (is_extended_color_format(self, self->out_port)) {
498 GstCaps *caps = NULL;
499 GstStructure *structure;
500 gint width = 0, height = 0;
502 caps = gst_pad_get_negotiated_caps(self->srcpad);
503 structure = gst_caps_get_structure(caps, 0);
505 gst_structure_get_int(structure, "width", &width);
506 gst_structure_get_int(structure, "height", &height);
508 if (G_LIKELY((width > 0) && (height > 0))) {
509 buf = gst_buffer_new_and_alloc((width * height * 3) / 2);
511 GST_ERROR_OBJECT (self, "invalid buffer size");
512 ret = GST_FLOW_UNEXPECTED;
516 memcpy (GST_BUFFER_MALLOCDATA(buf), omx_buffer->pBuffer, omx_buffer->nFilledLen);
518 if (self->use_timestamps) {
519 GST_BUFFER_TIMESTAMP (buf) =
520 gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND,
521 OMX_TICKS_PER_SECOND);
523 gst_buffer_set_caps(buf, GST_PAD_CAPS(self->srcpad));
525 ret = push_buffer (self, buf);
526 } else if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
527 GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
528 if (self->use_timestamps) {
529 GST_BUFFER_TIMESTAMP (buf) =
530 gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND,
531 OMX_TICKS_PER_SECOND);
534 omx_buffer->pAppPrivate = NULL;
535 omx_buffer->pBuffer = NULL;
537 /* Set sync frame info while encoding */
538 if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
539 GST_BUFFER_FLAG_UNSET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
541 GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
544 ret = push_buffer (self, buf);
546 gst_buffer_unref (buf);
548 /* This is only meant for the first OpenMAX buffers,
549 * which need to be pre-allocated. */
550 /* Also for the very last one. */
551 ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
552 GST_BUFFER_OFFSET_NONE,
553 omx_buffer->nFilledLen, GST_PAD_CAPS (self->srcpad), &buf);
555 if (G_LIKELY (buf)) {
556 memcpy (GST_BUFFER_DATA (buf),
557 omx_buffer->pBuffer + omx_buffer->nOffset,
558 omx_buffer->nFilledLen);
559 if (self->use_timestamps) {
560 GST_BUFFER_TIMESTAMP (buf) =
561 gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND,
562 OMX_TICKS_PER_SECOND);
565 if (self->share_output_buffer) {
566 GST_WARNING_OBJECT (self, "couldn't zero-copy");
567 /* If pAppPrivate is NULL, it means it was a dummy
568 * allocation, free it. */
569 if (!omx_buffer->pAppPrivate) {
570 g_free (omx_buffer->pBuffer);
571 omx_buffer->pBuffer = NULL;
575 /* Set sync frame info while encoding */
576 if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
577 GST_BUFFER_FLAG_UNSET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
579 GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
582 ret = push_buffer (self, buf);
584 GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %lu",
585 omx_buffer->nFilledLen);
589 GST_WARNING_OBJECT (self, "empty buffer");
592 if (self->share_output_buffer &&
593 !omx_buffer->pBuffer && omx_buffer->nOffset == 0) {
595 GstFlowReturn result;
597 GST_LOG_OBJECT (self, "allocate buffer");
598 result = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
599 GST_BUFFER_OFFSET_NONE,
600 omx_buffer->nAllocLen, GST_PAD_CAPS (self->srcpad), &buf);
602 if (G_LIKELY (result == GST_FLOW_OK)) {
603 gst_buffer_ref (buf);
604 omx_buffer->pAppPrivate = buf;
606 omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
607 omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
609 GST_WARNING_OBJECT (self,
610 "could not pad allocate buffer, using malloc");
611 omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen);
615 if (self->share_output_buffer && !omx_buffer->pBuffer) {
616 GST_ERROR_OBJECT (self, "no input buffer to share");
619 if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
620 GST_DEBUG_OBJECT (self, "got eos");
621 gst_pad_push_event (self->srcpad, gst_event_new_eos ());
622 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
623 ret = GST_FLOW_UNEXPECTED;
626 omx_buffer->nFilledLen = 0;
627 GST_LOG_OBJECT (self, "release_buffer");
628 g_omx_port_release_buffer (out_port, omx_buffer);
633 self->last_pad_push_return = ret;
635 if (gomx->omx_error != OMX_ErrorNone)
636 ret = GST_FLOW_ERROR;
638 if (ret != GST_FLOW_OK) {
639 GST_INFO_OBJECT (self, "pause task, reason: %s", gst_flow_get_name (ret));
640 gst_pad_pause_task (self->srcpad);
643 GST_LOG_OBJECT (self, "end");
645 gst_object_unref (self);
649 pad_chain (GstPad * pad, GstBuffer * buf)
653 GstOmxBaseFilter *self;
654 GstFlowReturn ret = GST_FLOW_OK;
656 self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
660 GST_LOG_OBJECT (self, "begin");
661 GST_LOG_OBJECT (self, "gst_buffer: size=%u", GST_BUFFER_SIZE (buf));
663 GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);
666 if (!self->use_state_tuning) {
667 if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded)) {
668 g_mutex_lock (self->ready_lock);
670 GST_INFO_OBJECT (self, "omx: prepare");
672 /** @todo this should probably go after doing preparations. */
673 if (self->omx_setup) {
674 self->omx_setup (self);
679 g_omx_core_prepare (self->gomx);
681 if (gomx->omx_state == OMX_StateIdle) {
683 gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
686 g_mutex_unlock (self->ready_lock);
688 if (gomx->omx_state != OMX_StateIdle)
693 in_port = self->in_port;
695 if (G_LIKELY (in_port->enabled)) {
696 guint buffer_offset = 0;
698 if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle)) {
699 GST_INFO_OBJECT (self, "omx: play");
700 g_omx_core_start (gomx);
702 if (gomx->omx_state != OMX_StateExecuting)
705 /* send buffer with codec data flag */
706 /** @todo move to util */
707 if (self->codec_data) {
708 OMX_BUFFERHEADERTYPE *omx_buffer;
710 GST_LOG_OBJECT (self, "request buffer");
711 omx_buffer = g_omx_port_request_buffer (in_port);
713 if (G_LIKELY (omx_buffer)) {
714 omx_buffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; /* codec data flag */
716 omx_buffer->nFilledLen = GST_BUFFER_SIZE (self->codec_data);
717 memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
718 GST_BUFFER_DATA (self->codec_data), omx_buffer->nFilledLen);
720 GST_LOG_OBJECT (self, "release_buffer");
721 g_omx_port_release_buffer (in_port, omx_buffer);
726 if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) {
727 GST_ERROR_OBJECT (self, "Whoa! very wrong");
730 while (G_LIKELY (buffer_offset < GST_BUFFER_SIZE (buf))) {
731 OMX_BUFFERHEADERTYPE *omx_buffer;
733 if (self->last_pad_push_return != GST_FLOW_OK ||
734 !(gomx->omx_state == OMX_StateExecuting ||
735 gomx->omx_state == OMX_StatePause)) {
739 GST_LOG_OBJECT (self, "request buffer");
740 omx_buffer = g_omx_port_request_buffer (in_port);
742 GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);
744 if (G_LIKELY (omx_buffer)) {
745 log_buffer (self, omx_buffer);
747 if (is_extended_color_format(self, self->in_port)) {
748 if(!GST_BUFFER_MALLOCDATA(buf)) {
749 GST_WARNING_OBJECT (self, "null MALLOCDATA in hw color format. skip this.");
753 /* Copy p[0], p[1] of SCMN_IMGB to pAddrY, pAddrC of MFC_ENC_ADDR_INFO */
754 memcpy (omx_buffer->pBuffer,
755 GST_BUFFER_MALLOCDATA(buf)
756 + (sizeof (int) * 4 + sizeof (void*)) * 4, sizeof (void*));
757 memcpy (omx_buffer->pBuffer + sizeof (void*),
758 GST_BUFFER_MALLOCDATA(buf)
759 + (sizeof (int) * 4 + sizeof (void*)) * 4 + sizeof (void*),
761 omx_buffer->nAllocLen = sizeof (void*) * 2;
762 omx_buffer->nFilledLen = sizeof (void*) * 2;
763 } else if (omx_buffer->nOffset == 0 && self->share_input_buffer) {
766 old_buf = omx_buffer->pAppPrivate;
769 gst_buffer_unref (old_buf);
770 } else if (omx_buffer->pBuffer) {
771 g_free (omx_buffer->pBuffer);
775 omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
776 omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
777 omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf);
778 omx_buffer->pAppPrivate = buf;
780 omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf) - buffer_offset,
781 omx_buffer->nAllocLen - omx_buffer->nOffset);
782 memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
783 GST_BUFFER_DATA (buf) + buffer_offset, omx_buffer->nFilledLen);
786 if (self->use_timestamps) {
787 GstClockTime timestamp_offset = 0;
789 if (buffer_offset && GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) {
790 timestamp_offset = gst_util_uint64_scale_int (buffer_offset,
791 GST_BUFFER_DURATION (buf), GST_BUFFER_SIZE (buf));
794 omx_buffer->nTimeStamp =
795 gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf) +
796 timestamp_offset, OMX_TICKS_PER_SECOND, GST_SECOND);
799 if (is_extended_color_format(self, self->in_port)) {
800 buffer_offset = GST_BUFFER_SIZE (buf);
802 buffer_offset += omx_buffer->nFilledLen;
805 GST_LOG_OBJECT (self, "release_buffer");
806 /** @todo untaint buffer */
807 g_omx_port_release_buffer (in_port, omx_buffer);
809 GST_WARNING_OBJECT (self, "null buffer");
810 ret = GST_FLOW_WRONG_STATE;
815 GST_WARNING_OBJECT (self, "done");
816 ret = GST_FLOW_UNEXPECTED;
819 if (!self->share_input_buffer) {
820 gst_buffer_unref (buf);
825 GST_LOG_OBJECT (self, "end");
829 /* special conditions */
832 const gchar *error_msg = NULL;
834 if (gomx->omx_error) {
835 error_msg = "Error from OpenMAX component";
836 } else if (gomx->omx_state != OMX_StateExecuting &&
837 gomx->omx_state != OMX_StatePause) {
838 error_msg = "OpenMAX component in wrong state";
842 GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("%s", error_msg));
843 ret = GST_FLOW_ERROR;
846 gst_buffer_unref (buf);
853 pad_event (GstPad * pad, GstEvent * event)
855 GstOmxBaseFilter *self;
860 self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
862 in_port = self->in_port;
864 GST_LOG_OBJECT (self, "begin");
866 GST_INFO_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
868 switch (GST_EVENT_TYPE (event)) {
870 /* if we are init'ed, and there is a running loop; then
871 * if we get a buffer to inform it of EOS, let it handle the rest
872 * in any other case, we send EOS */
873 if (self->ready && self->last_pad_push_return == GST_FLOW_OK) {
874 /* send buffer with eos flag */
875 /** @todo move to util */
877 OMX_BUFFERHEADERTYPE *omx_buffer;
879 GST_LOG_OBJECT (self, "request buffer");
880 omx_buffer = g_omx_port_request_buffer (in_port);
882 if (G_LIKELY (omx_buffer)) {
883 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
885 GST_LOG_OBJECT (self, "release_buffer");
886 /* foo_buffer_untaint (omx_buffer); */
887 g_omx_port_release_buffer (in_port, omx_buffer);
888 /* loop handles EOS, eat it here */
889 gst_event_unref (event);
895 /* we tried, but it's up to us here */
896 ret = gst_pad_push_event (self->srcpad, event);
899 case GST_EVENT_FLUSH_START:
900 if((gomx->omx_state == OMX_StatePause)||(gomx->omx_state == OMX_StateExecuting)) {
901 gst_pad_push_event (self->srcpad, event);
902 self->last_pad_push_return = GST_FLOW_WRONG_STATE;
904 g_omx_core_flush_start (gomx);
906 gst_pad_pause_task (self->srcpad);
910 GST_WARNING_OBJECT (self, "flush start in wrong omx state");
915 case GST_EVENT_FLUSH_STOP:
916 if((gomx->omx_state == OMX_StatePause)||(gomx->omx_state == OMX_StateExecuting)) {
917 gst_pad_push_event (self->srcpad, event);
918 self->last_pad_push_return = GST_FLOW_OK;
920 g_omx_core_flush_stop (gomx);
923 gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
927 GST_WARNING_OBJECT (self, "flush start in wrong omx state");
932 case GST_EVENT_NEWSEGMENT:
933 ret = gst_pad_push_event (self->srcpad, event);
937 ret = gst_pad_push_event (self->srcpad, event);
941 GST_LOG_OBJECT (self, "end");
947 activate_push (GstPad * pad, gboolean active)
949 gboolean result = TRUE;
950 GstOmxBaseFilter *self;
952 self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
955 GST_DEBUG_OBJECT (self, "activate");
956 /* task may carry on */
957 g_atomic_int_set (&self->last_pad_push_return, GST_FLOW_OK);
959 /* we do not start the task yet if the pad is not connected */
960 if (gst_pad_is_linked (pad)) {
962 /** @todo link callback function also needed */
963 g_omx_port_resume (self->in_port);
964 g_omx_port_resume (self->out_port);
966 result = gst_pad_start_task (pad, output_loop, pad);
970 GST_DEBUG_OBJECT (self, "deactivate");
972 /* persuade task to bail out */
973 g_atomic_int_set (&self->last_pad_push_return, GST_FLOW_WRONG_STATE);
976 /** @todo disable this until we properly reinitialize the buffers. */
978 /* flush all buffers */
979 OMX_SendCommand (self->gomx->omx_handle, OMX_CommandFlush, OMX_ALL, NULL);
983 g_omx_port_pause (self->in_port);
984 g_omx_port_pause (self->out_port);
987 /* make sure streaming finishes */
988 result = gst_pad_stop_task (pad);
991 gst_object_unref (self);
997 type_instance_init (GTypeInstance * instance, gpointer g_class)
999 GstOmxBaseFilter *self;
1000 GstElementClass *element_class;
1002 element_class = GST_ELEMENT_CLASS (g_class);
1004 self = GST_OMX_BASE_FILTER (instance);
1006 GST_LOG_OBJECT (self, "begin");
1008 self->use_timestamps = TRUE;
1009 self->use_state_tuning = FALSE; /* STATE_TUNING */
1011 self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class));
1012 self->in_port = g_omx_core_new_port (self->gomx, 0);
1013 self->out_port = g_omx_core_new_port (self->gomx, 1);
1015 self->ready_lock = g_mutex_new ();
1018 gst_pad_new_from_template (gst_element_class_get_pad_template
1019 (element_class, "sink"), "sink");
1021 gst_pad_set_chain_function (self->sinkpad, pad_chain);
1022 gst_pad_set_event_function (self->sinkpad, pad_event);
1025 gst_pad_new_from_template (gst_element_class_get_pad_template
1026 (element_class, "src"), "src");
1028 gst_pad_set_activatepush_function (self->srcpad, activate_push);
1030 gst_pad_use_fixed_caps (self->srcpad);
1032 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1033 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1035 GST_LOG_OBJECT (self, "end");
1039 omx_interface_init (GstImplementsInterfaceClass * klass)
1044 interface_supported (GstImplementsInterface * iface, GType type)
1046 g_assert (type == GST_TYPE_OMX);
1051 interface_init (GstImplementsInterfaceClass * klass)
1053 klass->supported = interface_supported;
1057 init_interfaces (GType type)
1059 GInterfaceInfo *iface_info;
1060 GInterfaceInfo *omx_info;
1063 iface_info = g_new0 (GInterfaceInfo, 1);
1064 iface_info->interface_init = (GInterfaceInitFunc) interface_init;
1066 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, iface_info);
1067 g_free (iface_info);
1069 omx_info = g_new0 (GInterfaceInfo, 1);
1070 omx_info->interface_init = (GInterfaceInitFunc) omx_interface_init;
1072 g_type_add_interface_static (type, GST_TYPE_OMX, omx_info);