2 * Copyright (C) 2007-2009 Nokia Corporation.
3 * Copyright (C) 2008 NXP.
6 * Felipe Contreras <felipe.contreras@nokia.com>
7 * Frederik Vernelen <frederik.vernelen@tass.be>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation
12 * version 2.1 of the License.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "gstomx_base_sink.h"
27 #include "gstomx_interface.h"
29 #include <string.h> /* for memcpy */
33 ARG_NUM_INPUT_BUFFERS = GSTOMX_NUM_COMMON_PROP,
36 static gboolean share_input_buffer;
38 static inline gboolean omx_init (GstOmxBaseSink * self);
40 static void init_interfaces (GType type);
41 GSTOMX_BOILERPLATE_FULL (GstOmxBaseSink, gst_omx_base_sink, GstBaseSink,
42 GST_TYPE_BASE_SINK, init_interfaces);
45 setup_ports (GstOmxBaseSink * self)
47 /* Input port configuration. */
48 g_omx_port_setup (self->in_port);
49 gst_pad_set_element_private (self->sinkpad, self->in_port);
52 static GstStateChangeReturn
53 change_state (GstElement * element, GstStateChange transition)
55 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
58 self = GST_OMX_BASE_SINK (element);
60 GST_LOG_OBJECT (self, "begin");
62 GST_INFO_OBJECT (self, "changing state %s - %s",
63 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
64 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
67 case GST_STATE_CHANGE_NULL_TO_READY:
68 if (!self->initialized) {
70 return GST_PAD_LINK_REFUSED;
72 self->initialized = TRUE;
75 g_omx_core_prepare (self->gomx);
78 case GST_STATE_CHANGE_READY_TO_PAUSED:
79 g_omx_core_start (self->gomx);
82 case GST_STATE_CHANGE_PAUSED_TO_READY:
83 g_omx_port_finish (self->in_port);
90 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
92 if (ret == GST_STATE_CHANGE_FAILURE)
96 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
97 g_omx_port_pause (self->in_port);
100 case GST_STATE_CHANGE_PAUSED_TO_READY:
101 g_omx_core_stop (self->gomx);
104 case GST_STATE_CHANGE_READY_TO_NULL:
105 g_omx_core_unload (self->gomx);
113 GST_LOG_OBJECT (self, "end");
119 finalize (GObject * obj)
121 GstOmxBaseSink *self;
123 self = GST_OMX_BASE_SINK (obj);
125 g_omx_core_free (self->gomx);
127 G_OBJECT_CLASS (parent_class)->finalize (obj);
131 render (GstBaseSink * gst_base, GstBuffer * buf)
135 GstOmxBaseSink *self;
136 GstFlowReturn ret = GST_FLOW_OK;
138 self = GST_OMX_BASE_SINK (gst_base);
142 GST_LOG_OBJECT (self, "begin");
143 GST_LOG_OBJECT (self, "gst_buffer: size=%u", GST_BUFFER_SIZE (buf));
145 GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);
147 in_port = self->in_port;
149 if (G_LIKELY (in_port->enabled)) {
150 guint buffer_offset = 0;
152 while (G_LIKELY (buffer_offset < GST_BUFFER_SIZE (buf))) {
153 OMX_BUFFERHEADERTYPE *omx_buffer;
155 GST_LOG_OBJECT (self, "request_buffer");
156 omx_buffer = g_omx_port_request_buffer (in_port);
158 if (G_LIKELY (omx_buffer)) {
159 GST_DEBUG_OBJECT (self,
160 "omx_buffer: size=%lu, len=%lu, flags=%lu, offset=%lu, timestamp=%lld",
161 omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
162 omx_buffer->nOffset, omx_buffer->nTimeStamp);
164 if (omx_buffer->nOffset == 0 && share_input_buffer) {
167 old_buf = omx_buffer->pAppPrivate;
170 gst_buffer_unref (old_buf);
171 } else if (omx_buffer->pBuffer) {
172 g_free (omx_buffer->pBuffer);
176 /* We are going to use this. */
177 gst_buffer_ref (buf);
179 omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
180 omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
181 omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf);
182 omx_buffer->pAppPrivate = buf;
184 omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf) - buffer_offset,
185 omx_buffer->nAllocLen - omx_buffer->nOffset);
186 memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
187 GST_BUFFER_DATA (buf) + buffer_offset, omx_buffer->nFilledLen);
190 GST_LOG_OBJECT (self, "release_buffer");
191 g_omx_port_release_buffer (in_port, omx_buffer);
193 buffer_offset += omx_buffer->nFilledLen;
195 GST_WARNING_OBJECT (self, "null buffer");
196 ret = GST_FLOW_UNEXPECTED;
201 GST_WARNING_OBJECT (self, "done");
202 ret = GST_FLOW_UNEXPECTED;
205 GST_LOG_OBJECT (self, "end");
211 handle_event (GstBaseSink * gst_base, GstEvent * event)
213 GstOmxBaseSink *self;
217 self = GST_OMX_BASE_SINK (gst_base);
219 in_port = self->in_port;
221 GST_LOG_OBJECT (self, "begin");
223 GST_DEBUG_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
225 switch (GST_EVENT_TYPE (event)) {
227 /* Close the inpurt port. */
228 g_omx_core_set_done (gomx);
231 case GST_EVENT_FLUSH_START:
233 g_omx_port_pause (in_port);
235 /* flush all buffers */
236 OMX_SendCommand (gomx->omx_handle, OMX_CommandFlush, OMX_ALL, NULL);
239 case GST_EVENT_FLUSH_STOP:
240 g_sem_down (gomx->flush_sem);
242 g_omx_port_resume (in_port);
249 GST_LOG_OBJECT (self, "end");
255 set_property (GObject * obj,
256 guint prop_id, const GValue * value, GParamSpec * pspec)
258 GstOmxBaseSink *self;
260 self = GST_OMX_BASE_SINK (obj);
263 case ARG_NUM_INPUT_BUFFERS:
265 OMX_PARAM_PORTDEFINITIONTYPE param;
266 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
267 OMX_U32 nBufferCountActual;
269 if (G_UNLIKELY (!omx_handle)) {
270 GST_WARNING_OBJECT (self, "no component");
274 nBufferCountActual = g_value_get_uint (value);
276 G_OMX_INIT_PARAM (param);
278 param.nPortIndex = self->in_port->port_index;
279 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
281 if (nBufferCountActual < param.nBufferCountMin) {
282 GST_ERROR_OBJECT (self, "buffer count %lu is less than minimum %lu",
283 nBufferCountActual, param.nBufferCountMin);
287 param.nBufferCountActual = nBufferCountActual;
289 OMX_SetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
293 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
299 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
301 GstOmxBaseSink *self;
303 self = GST_OMX_BASE_SINK (obj);
305 if (gstomx_get_property_helper (self->gomx, prop_id, value))
309 case ARG_NUM_INPUT_BUFFERS:
311 OMX_PARAM_PORTDEFINITIONTYPE param;
312 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
314 if (G_UNLIKELY (!omx_handle)) {
315 GST_WARNING_OBJECT (self, "no component");
316 g_value_set_uint (value, 0);
320 G_OMX_INIT_PARAM (param);
322 param.nPortIndex = self->in_port->port_index;
323 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
325 g_value_set_uint (value, param.nBufferCountActual);
329 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
335 type_base_init (gpointer g_class)
340 type_class_init (gpointer g_class, gpointer class_data)
342 GObjectClass *gobject_class;
343 GstBaseSinkClass *gst_base_sink_class;
344 GstElementClass *gstelement_class;
346 gobject_class = G_OBJECT_CLASS (g_class);
347 gst_base_sink_class = GST_BASE_SINK_CLASS (g_class);
348 gstelement_class = GST_ELEMENT_CLASS (g_class);
350 gobject_class->finalize = finalize;
352 gstelement_class->change_state = change_state;
354 gst_base_sink_class->event = handle_event;
355 gst_base_sink_class->preroll = render;
356 gst_base_sink_class->render = render;
358 /* Properties stuff */
360 gobject_class->set_property = set_property;
361 gobject_class->get_property = get_property;
363 gstomx_install_property_helper (gobject_class);
365 g_object_class_install_property (gobject_class, ARG_NUM_INPUT_BUFFERS,
366 g_param_spec_uint ("input-buffers", "Input buffers",
367 "The number of OMX input buffers",
368 1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
373 activate_push (GstPad * pad, gboolean active)
375 gboolean result = TRUE;
376 GstOmxBaseSink *self;
378 self = GST_OMX_BASE_SINK (gst_pad_get_parent (pad));
381 GST_DEBUG_OBJECT (self, "activate");
383 /* we do not start the task yet if the pad is not connected */
384 if (gst_pad_is_linked (pad)) {
385 /** @todo link callback function also needed */
386 g_omx_port_resume (self->in_port);
389 GST_DEBUG_OBJECT (self, "deactivate");
391 /** @todo disable this until we properly reinitialize the buffers. */
393 /* flush all buffers */
394 OMX_SendCommand (self->gomx->omx_handle, OMX_CommandFlush, OMX_ALL, NULL);
398 g_omx_port_pause (self->in_port);
401 gst_object_unref (self);
404 result = self->base_activatepush (pad, active);
409 static inline gboolean
410 omx_init (GstOmxBaseSink * self)
412 if (self->gomx->omx_error)
420 static GstPadLinkReturn
421 pad_sink_link (GstPad * pad, GstPad * peer)
423 GstOmxBaseSink *self;
425 self = GST_OMX_BASE_SINK (GST_OBJECT_PARENT (pad));
427 GST_INFO_OBJECT (self, "link");
429 if (!self->initialized) {
430 if (!omx_init (self))
431 return GST_PAD_LINK_REFUSED;
432 self->initialized = TRUE;
435 return GST_PAD_LINK_OK;
439 type_instance_init (GTypeInstance * instance, gpointer g_class)
441 GstOmxBaseSink *self;
443 self = GST_OMX_BASE_SINK (instance);
445 GST_LOG_OBJECT (self, "begin");
447 self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class));
448 self->in_port = g_omx_core_new_port (self->gomx, 0);
452 self->sinkpad = sinkpad = GST_BASE_SINK_PAD (self);
453 self->base_activatepush = GST_PAD_ACTIVATEPUSHFUNC (sinkpad);
454 gst_pad_set_activatepush_function (sinkpad, activate_push);
455 gst_pad_set_link_function (sinkpad, pad_sink_link);
458 GST_LOG_OBJECT (self, "end");
462 omx_interface_init (GstImplementsInterfaceClass * klass)
467 interface_supported (GstImplementsInterface * iface, GType type)
469 g_assert (type == GST_TYPE_OMX);
474 interface_init (GstImplementsInterfaceClass * klass)
476 klass->supported = interface_supported;
480 init_interfaces (GType type)
482 GInterfaceInfo *iface_info;
483 GInterfaceInfo *omx_info;
485 iface_info = g_new0 (GInterfaceInfo, 1);
486 iface_info->interface_init = (GInterfaceInitFunc) interface_init;
488 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, iface_info);
491 omx_info = g_new0 (GInterfaceInfo, 1);
492 omx_info->interface_init = (GInterfaceInitFunc) omx_interface_init;
494 g_type_add_interface_static (type, GST_TYPE_OMX, omx_info);