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_src.h"
25 #include <string.h> /* for memcpy */
29 ARG_NUM_OUTPUT_BUFFERS = GSTOMX_NUM_COMMON_PROP,
32 GSTOMX_BOILERPLATE (GstOmxBaseSrc, gst_omx_base_src, GstBaseSrc,
36 setup_ports (GstOmxBaseSrc * self)
38 /* Input port configuration. */
39 g_omx_port_setup (self->out_port);
41 if (self->setup_ports) {
42 self->setup_ports (self);
47 start (GstBaseSrc * gst_base)
51 self = GST_OMX_BASE_SRC (gst_base);
53 GST_LOG_OBJECT (self, "begin");
55 if (self->gomx->omx_error)
56 return GST_STATE_CHANGE_FAILURE;
58 GST_LOG_OBJECT (self, "end");
64 stop (GstBaseSrc * gst_base)
68 self = GST_OMX_BASE_SRC (gst_base);
70 GST_LOG_OBJECT (self, "begin");
72 g_omx_core_stop (self->gomx);
73 g_omx_core_unload (self->gomx);
75 if (self->gomx->omx_error)
76 return GST_STATE_CHANGE_FAILURE;
78 GST_LOG_OBJECT (self, "end");
84 finalize (GObject * obj)
88 self = GST_OMX_BASE_SRC (obj);
90 g_omx_core_free (self->gomx);
92 G_OBJECT_CLASS (parent_class)->finalize (obj);
96 create (GstBaseSrc * gst_base,
97 guint64 offset, guint length, GstBuffer ** ret_buf)
102 GstFlowReturn ret = GST_FLOW_OK;
104 self = GST_OMX_BASE_SRC (gst_base);
108 GST_LOG_OBJECT (self, "begin");
110 GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);
112 if (gomx->omx_state == OMX_StateLoaded) {
113 GST_INFO_OBJECT (self, "omx: prepare");
116 g_omx_core_prepare (self->gomx);
119 out_port = self->out_port;
121 while (out_port->enabled) {
122 switch (gomx->omx_state) {
125 GST_INFO_OBJECT (self, "omx: play");
126 g_omx_core_start (gomx);
133 switch (gomx->omx_state) {
134 case OMX_StateExecuting:
138 GST_ERROR_OBJECT (self, "Whoa! very wrong");
143 OMX_BUFFERHEADERTYPE *omx_buffer;
145 GST_LOG_OBJECT (self, "request_buffer");
146 omx_buffer = g_omx_port_request_buffer (out_port);
149 GST_DEBUG_OBJECT (self, "omx_buffer: size=%lu, len=%lu, offset=%lu",
150 omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nOffset);
152 if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS) {
153 GST_INFO_OBJECT (self, "got eos");
154 g_omx_core_set_done (gomx);
158 if (omx_buffer->nFilledLen > 0) {
161 if (out_port->enabled) {
162 GstCaps *caps = NULL;
164 caps = gst_pad_get_negotiated_caps (gst_base->srcpad);
167 /** @todo We shouldn't be doing this. */
168 GST_WARNING_OBJECT (self, "somebody didn't do his work");
169 gomx->settings_changed_cb (gomx);
171 GST_LOG_OBJECT (self, "caps already fixed");
172 gst_caps_unref (caps);
176 buf = omx_buffer->pAppPrivate;
178 if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
179 GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
181 if (self->use_timestamps) {
182 GST_BUFFER_TIMESTAMP (buf) =
183 omx_buffer->nTimeStamp * (GST_SECOND / OMX_TICKS_PER_SECOND);
187 omx_buffer->pAppPrivate = NULL;
188 omx_buffer->pBuffer = NULL;
189 omx_buffer->nFilledLen = 0;
193 gst_buffer_unref (buf);
195 /* This is only meant for the first OpenMAX buffers,
196 * which need to be pre-allocated. */
197 /* Also for the very last one. */
198 gst_pad_alloc_buffer_and_set_caps (gst_base->srcpad,
199 GST_BUFFER_OFFSET_NONE,
200 omx_buffer->nFilledLen, GST_PAD_CAPS (gst_base->srcpad), &buf);
203 GST_WARNING_OBJECT (self, "couldn't zero-copy");
204 memcpy (GST_BUFFER_DATA (buf),
205 omx_buffer->pBuffer + omx_buffer->nOffset,
206 omx_buffer->nFilledLen);
208 if (self->use_timestamps) {
209 GST_BUFFER_TIMESTAMP (buf) =
210 omx_buffer->nTimeStamp * (GST_SECOND /
211 OMX_TICKS_PER_SECOND);
215 omx_buffer->nFilledLen = 0;
216 g_free (omx_buffer->pBuffer);
217 omx_buffer->pBuffer = NULL;
221 GST_ERROR_OBJECT (self, "whoa!");
225 if (!omx_buffer->pBuffer) {
227 GstFlowReturn result;
229 GST_LOG_OBJECT (self, "allocate buffer");
230 result = gst_pad_alloc_buffer_and_set_caps (gst_base->srcpad,
231 GST_BUFFER_OFFSET_NONE,
232 omx_buffer->nAllocLen,
233 GST_PAD_CAPS (gst_base->srcpad), &new_buf);
235 if (result == GST_FLOW_OK) {
236 gst_buffer_ref (new_buf);
237 omx_buffer->pAppPrivate = new_buf;
239 omx_buffer->pBuffer = GST_BUFFER_DATA (new_buf);
240 omx_buffer->nAllocLen = GST_BUFFER_SIZE (new_buf);
242 GST_WARNING_OBJECT (self, "could not allocate buffer");
243 omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen);
247 GST_LOG_OBJECT (self, "release_buffer");
248 g_omx_port_release_buffer (out_port, omx_buffer);
251 GST_WARNING_OBJECT (self, "empty buffer");
252 GST_LOG_OBJECT (self, "release_buffer");
253 g_omx_port_release_buffer (out_port, omx_buffer);
257 GST_WARNING_OBJECT (self, "null buffer");
258 /* ret = GST_FLOW_ERROR; */
264 if (!out_port->enabled) {
265 GST_WARNING_OBJECT (self, "done");
266 ret = GST_FLOW_UNEXPECTED;
269 GST_LOG_OBJECT (self, "end");
275 handle_event (GstBaseSrc * gst_base, GstEvent * event)
279 self = GST_OMX_BASE_SRC (gst_base);
281 GST_LOG_OBJECT (self, "begin");
283 GST_DEBUG_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
285 switch (GST_EVENT_TYPE (event)) {
287 /* Close the output port. */
288 g_omx_core_set_done (self->gomx);
291 case GST_EVENT_NEWSEGMENT:
298 GST_LOG_OBJECT (self, "end");
304 set_property (GObject * obj,
305 guint prop_id, const GValue * value, GParamSpec * pspec)
309 self = GST_OMX_BASE_SRC (obj);
312 case ARG_NUM_OUTPUT_BUFFERS:
314 OMX_PARAM_PORTDEFINITIONTYPE param;
315 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
316 OMX_U32 nBufferCountActual;
318 if (G_UNLIKELY (omx_handle)) {
319 GST_WARNING_OBJECT (self, "no component");
323 nBufferCountActual = g_value_get_uint (value);
325 G_OMX_INIT_PARAM (param);
327 param.nPortIndex = self->out_port->port_index;
328 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
330 if (nBufferCountActual < param.nBufferCountMin) {
331 GST_ERROR_OBJECT (self, "buffer count %lu is less than minimum %lu",
332 nBufferCountActual, param.nBufferCountMin);
336 param.nBufferCountActual = nBufferCountActual;
338 OMX_SetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
342 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
348 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
352 self = GST_OMX_BASE_SRC (obj);
354 if (gstomx_get_property_helper (self->gomx, prop_id, value))
358 case ARG_NUM_OUTPUT_BUFFERS:
360 OMX_PARAM_PORTDEFINITIONTYPE param;
361 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
363 if (G_UNLIKELY (!omx_handle)) {
364 GST_WARNING_OBJECT (self, "no component");
365 g_value_set_uint (value, 0);
369 G_OMX_INIT_PARAM (param);
371 param.nPortIndex = self->out_port->port_index;
372 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
374 g_value_set_uint (value, param.nBufferCountActual);
378 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
384 type_base_init (gpointer g_class)
389 type_class_init (gpointer g_class, gpointer class_data)
391 GObjectClass *gobject_class;
392 GstBaseSrcClass *gst_base_src_class;
394 gobject_class = G_OBJECT_CLASS (g_class);
395 gst_base_src_class = GST_BASE_SRC_CLASS (g_class);
397 gobject_class->finalize = finalize;
399 gst_base_src_class->start = start;
400 gst_base_src_class->stop = stop;
401 gst_base_src_class->event = handle_event;
402 gst_base_src_class->create = create;
404 /* Properties stuff */
406 gobject_class->set_property = set_property;
407 gobject_class->get_property = get_property;
409 gstomx_install_property_helper (gobject_class);
411 g_object_class_install_property (gobject_class, ARG_NUM_OUTPUT_BUFFERS,
412 g_param_spec_uint ("output-buffers", "Output buffers",
413 "The number of OMX output buffers",
414 1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
419 type_instance_init (GTypeInstance * instance, gpointer g_class)
423 self = GST_OMX_BASE_SRC (instance);
425 GST_LOG_OBJECT (self, "begin");
427 self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class));
428 self->out_port = g_omx_core_new_port (self->gomx, 1);
430 GST_LOG_OBJECT (self, "end");