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 inline gboolean omx_init (GstOmxBaseSink * self);
38 static void init_interfaces (GType type);
39 GSTOMX_BOILERPLATE_FULL (GstOmxBaseSink, gst_omx_base_sink, GstBaseSink,
40 GST_TYPE_BASE_SINK, init_interfaces);
43 setup_ports (GstOmxBaseSink * self)
45 /* Input port configuration. */
46 g_omx_port_setup (self->in_port);
47 gst_pad_set_element_private (self->sinkpad, self->in_port);
50 static GstStateChangeReturn
51 change_state (GstElement * element, GstStateChange transition)
53 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
56 self = GST_OMX_BASE_SINK (element);
58 GST_LOG_OBJECT (self, "begin");
60 GST_INFO_OBJECT (self, "changing state %s - %s",
61 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
62 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
65 case GST_STATE_CHANGE_NULL_TO_READY:
66 if (!self->initialized) {
68 return GST_PAD_LINK_REFUSED;
70 self->initialized = TRUE;
73 g_omx_core_prepare (self->gomx);
76 case GST_STATE_CHANGE_READY_TO_PAUSED:
77 g_omx_core_start (self->gomx);
80 case GST_STATE_CHANGE_PAUSED_TO_READY:
81 g_omx_port_finish (self->in_port);
88 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
90 if (ret == GST_STATE_CHANGE_FAILURE)
94 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
95 g_omx_port_pause (self->in_port);
98 case GST_STATE_CHANGE_PAUSED_TO_READY:
99 g_omx_core_stop (self->gomx);
102 case GST_STATE_CHANGE_READY_TO_NULL:
103 g_omx_core_unload (self->gomx);
111 GST_LOG_OBJECT (self, "end");
117 finalize (GObject * obj)
119 GstOmxBaseSink *self;
121 self = GST_OMX_BASE_SINK (obj);
123 g_omx_core_free (self->gomx);
125 G_OBJECT_CLASS (parent_class)->finalize (obj);
129 render (GstBaseSink * gst_base, GstBuffer * buf)
133 GstOmxBaseSink *self;
134 GstFlowReturn ret = GST_FLOW_OK;
136 self = GST_OMX_BASE_SINK (gst_base);
140 GST_LOG_OBJECT (self, "begin");
141 GST_LOG_OBJECT (self, "gst_buffer: size=%u", GST_BUFFER_SIZE (buf));
143 GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);
145 in_port = self->in_port;
147 if (G_LIKELY (in_port->enabled)) {
148 guint buffer_offset = 0;
150 while (G_LIKELY (buffer_offset < GST_BUFFER_SIZE (buf))) {
151 OMX_BUFFERHEADERTYPE *omx_buffer;
153 GST_LOG_OBJECT (self, "request_buffer");
154 omx_buffer = g_omx_port_request_buffer (in_port);
156 if (G_LIKELY (omx_buffer)) {
157 GST_DEBUG_OBJECT (self,
158 "omx_buffer: size=%lu, len=%lu, flags=%lu, offset=%lu, timestamp=%lld",
159 omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
160 omx_buffer->nOffset, omx_buffer->nTimeStamp);
162 if (omx_buffer->nOffset == 0 && self->in_port->shared_buffer) {
165 old_buf = omx_buffer->pAppPrivate;
168 gst_buffer_unref (old_buf);
169 } else if (omx_buffer->pBuffer) {
170 g_free (omx_buffer->pBuffer);
171 omx_buffer->pBuffer = NULL;
175 /* We are going to use this. */
176 gst_buffer_ref (buf);
178 omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
179 omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
180 omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf);
181 omx_buffer->pAppPrivate = buf;
183 omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf) - buffer_offset,
184 omx_buffer->nAllocLen - omx_buffer->nOffset);
185 memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
186 GST_BUFFER_DATA (buf) + buffer_offset, omx_buffer->nFilledLen);
189 GST_LOG_OBJECT (self, "release_buffer");
190 g_omx_port_release_buffer (in_port, omx_buffer);
192 buffer_offset += omx_buffer->nFilledLen;
194 GST_WARNING_OBJECT (self, "null buffer");
195 ret = GST_FLOW_UNEXPECTED;
200 GST_WARNING_OBJECT (self, "done");
201 ret = GST_FLOW_UNEXPECTED;
204 GST_LOG_OBJECT (self, "end");
210 handle_event (GstBaseSink * gst_base, GstEvent * event)
212 GstOmxBaseSink *self;
216 self = GST_OMX_BASE_SINK (gst_base);
218 in_port = self->in_port;
220 GST_LOG_OBJECT (self, "begin");
222 GST_DEBUG_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
224 switch (GST_EVENT_TYPE (event)) {
226 /* Close the inpurt port. */
227 g_omx_core_set_done (gomx);
230 case GST_EVENT_FLUSH_START:
232 g_omx_port_pause (in_port);
234 /* flush all buffers */
235 OMX_SendCommand (gomx->omx_handle, OMX_CommandFlush, OMX_ALL, NULL);
238 case GST_EVENT_FLUSH_STOP:
239 g_sem_down (gomx->flush_sem);
241 g_omx_port_resume (in_port);
248 GST_LOG_OBJECT (self, "end");
254 set_property (GObject * obj,
255 guint prop_id, const GValue * value, GParamSpec * pspec)
257 GstOmxBaseSink *self;
259 self = GST_OMX_BASE_SINK (obj);
262 case ARG_NUM_INPUT_BUFFERS:
264 OMX_PARAM_PORTDEFINITIONTYPE param;
265 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
266 OMX_U32 nBufferCountActual;
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 = self->in_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 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
298 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
300 GstOmxBaseSink *self;
302 self = GST_OMX_BASE_SINK (obj);
304 if (gstomx_get_property_helper (self->gomx, prop_id, value))
308 case ARG_NUM_INPUT_BUFFERS:
310 OMX_PARAM_PORTDEFINITIONTYPE param;
311 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
313 if (G_UNLIKELY (!omx_handle)) {
314 GST_WARNING_OBJECT (self, "no component");
315 g_value_set_uint (value, 0);
319 G_OMX_INIT_PARAM (param);
321 param.nPortIndex = self->in_port->port_index;
322 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
324 g_value_set_uint (value, param.nBufferCountActual);
328 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
334 type_base_init (gpointer g_class)
339 type_class_init (gpointer g_class, gpointer class_data)
341 GObjectClass *gobject_class;
342 GstBaseSinkClass *gst_base_sink_class;
343 GstElementClass *gstelement_class;
345 gobject_class = G_OBJECT_CLASS (g_class);
346 gst_base_sink_class = GST_BASE_SINK_CLASS (g_class);
347 gstelement_class = GST_ELEMENT_CLASS (g_class);
349 gobject_class->finalize = finalize;
351 gstelement_class->change_state = change_state;
353 gst_base_sink_class->event = handle_event;
354 gst_base_sink_class->preroll = render;
355 gst_base_sink_class->render = render;
357 /* Properties stuff */
359 gobject_class->set_property = set_property;
360 gobject_class->get_property = get_property;
362 gstomx_install_property_helper (gobject_class);
364 g_object_class_install_property (gobject_class, ARG_NUM_INPUT_BUFFERS,
365 g_param_spec_uint ("input-buffers", "Input buffers",
366 "The number of OMX input buffers",
367 1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
372 activate_push (GstPad * pad, gboolean active)
374 gboolean result = TRUE;
375 GstOmxBaseSink *self;
377 self = GST_OMX_BASE_SINK (gst_pad_get_parent (pad));
380 GST_DEBUG_OBJECT (self, "activate");
382 /* we do not start the task yet if the pad is not connected */
383 if (gst_pad_is_linked (pad)) {
384 /** @todo link callback function also needed */
385 g_omx_port_resume (self->in_port);
388 GST_DEBUG_OBJECT (self, "deactivate");
390 /** @todo disable this until we properly reinitialize the buffers. */
392 /* flush all buffers */
393 OMX_SendCommand (self->gomx->omx_handle, OMX_CommandFlush, OMX_ALL, NULL);
397 g_omx_port_pause (self->in_port);
400 gst_object_unref (self);
403 result = self->base_activatepush (pad, active);
408 static inline gboolean
409 omx_init (GstOmxBaseSink * self)
411 if (self->gomx->omx_error)
419 static GstPadLinkReturn
420 pad_sink_link (GstPad * pad, GstPad * peer)
422 GstOmxBaseSink *self;
424 self = GST_OMX_BASE_SINK (GST_OBJECT_PARENT (pad));
426 GST_INFO_OBJECT (self, "link");
428 if (!self->initialized) {
429 if (!omx_init (self))
430 return GST_PAD_LINK_REFUSED;
431 self->initialized = TRUE;
434 return GST_PAD_LINK_OK;
438 type_instance_init (GTypeInstance * instance, gpointer g_class)
440 GstOmxBaseSink *self;
442 self = GST_OMX_BASE_SINK (instance);
444 GST_LOG_OBJECT (self, "begin");
446 self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class));
447 self->in_port = g_omx_core_new_port (self->gomx, 0);
451 self->sinkpad = sinkpad = GST_BASE_SINK_PAD (self);
452 self->base_activatepush = GST_PAD_ACTIVATEPUSHFUNC (sinkpad);
453 gst_pad_set_activatepush_function (sinkpad, activate_push);
454 gst_pad_set_link_function (sinkpad, pad_sink_link);
457 GST_LOG_OBJECT (self, "end");
461 omx_interface_init (GstImplementsInterfaceClass * klass)
466 interface_supported (GstImplementsInterface * iface, GType type)
468 g_assert (type == GST_TYPE_OMX);
473 interface_init (GstImplementsInterfaceClass * klass)
475 klass->supported = interface_supported;
479 init_interfaces (GType type)
481 GInterfaceInfo *iface_info;
482 GInterfaceInfo *omx_info;
484 iface_info = g_new0 (GInterfaceInfo, 1);
485 iface_info->interface_init = (GInterfaceInitFunc) interface_init;
487 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, iface_info);
490 omx_info = g_new0 (GInterfaceInfo, 1);
491 omx_info->interface_init = (GInterfaceInitFunc) omx_interface_init;
493 g_type_add_interface_static (type, GST_TYPE_OMX, omx_info);