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"
25 #include <string.h> /* for memcpy */
26 #include <unistd.h> /* for close */
28 /* MODIFICATION: for state-tuning */
29 static void output_loop (gpointer data);
31 /* MODIFICATION: for buffer management */
32 static GstBufferClass *gstomx_buffer_parent_class = NULL;
33 static void gst_omx_buffer_class_init(gpointer g_class, gpointer class_data);
34 static void gst_omx_buffer_finalize(GstOmxBuffer *buffer);
35 static GstOmxBuffer *gst_omx_buffer_new(GstOmxBaseFilter *self);
37 static void instance_init (GstElement * element);
38 static void instance_deinit (GstElement * element);
42 ARG_USE_TIMESTAMPS = GSTOMX_NUM_COMMON_PROP,
43 ARG_NUM_INPUT_BUFFERS,
44 ARG_NUM_OUTPUT_BUFFERS,
47 static void init_interfaces (GType type);
48 GSTOMX_BOILERPLATE_FULL (GstOmxBaseFilter, gst_omx_base_filter, GstElement,
49 GST_TYPE_ELEMENT, init_interfaces);
52 log_buffer (GstOmxBaseFilter * self, OMX_BUFFERHEADERTYPE * omx_buffer, const gchar *name)
54 GST_DEBUG_OBJECT (self, "%s: omx_buffer: "
60 name, omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
61 omx_buffer->nOffset, omx_buffer->nTimeStamp);
65 /* MODIFICATION: handle gstomxbuffer unref */
67 gst_omx_buffer_class_init(gpointer g_class, gpointer class_data)
69 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS(g_class);
70 gstomx_buffer_parent_class = g_type_class_peek_parent(g_class);
71 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)gst_omx_buffer_finalize;
75 gst_omx_buffer_get_type(void)
77 static GType _gst_gstomx_out_buffer_type;
79 if (G_UNLIKELY(_gst_gstomx_out_buffer_type == 0)) {
80 static const GTypeInfo gstomx_buffer_info = {
81 sizeof (GstBufferClass),
84 gst_omx_buffer_class_init,
87 sizeof (GstOmxBuffer),
92 _gst_gstomx_out_buffer_type = g_type_register_static(GST_TYPE_BUFFER,
94 &gstomx_buffer_info, 0);
96 return _gst_gstomx_out_buffer_type;
100 gst_omx_buffer_finalize(GstOmxBuffer *buffer)
102 GstOmxBaseFilter *gstomx = buffer->gstomx;
103 SCMN_IMGB *outbuf = NULL;
106 GST_LOG ("gst_buf: %p omx_buf: %p ts: %"GST_TIME_FORMAT, buffer, buffer->omx_buffer,
107 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
109 if (buffer->buffer_direction == GSTOMX_BUFFER_INPUT) {
110 /* for input buffer unref case in TZ. add input buf queue and free */
111 GST_LOG ("Unref IN TZ buf from other element. push input buf queue. (omx_buf: %p)", buffer->omx_buffer);
112 g_omx_port_push_buffer (gstomx->in_port, buffer->omx_buffer);
114 } else if (buffer->buffer_direction == GSTOMX_BUFFER_INPUT_AFTER_ETB) {
115 /* for just unref input buffer in TZ. */
116 GST_LOG ("Unref IN TZ buf in gst-openmax after ETB. just unref this. (omx_buf: %p)", buffer->omx_buffer);
118 } else if (buffer->buffer_direction == GSTOMX_BUFFER_OUTPUT) {
119 /* for output buffer case both normal and TZ. */
120 GST_LOG ("Unref OUT buf. (omx_buf: %p)", buffer->omx_buffer);
122 g_atomic_int_dec_and_test(&gstomx->num_live_buffers);
123 if (gstomx->buffer_cond) {
124 g_cond_signal(gstomx->buffer_cond);
126 GST_ERROR ("we got gst_omx_buffer_finalize. But buffer cond is already NULL!");
131 if (gstomx->gomx == NULL) {
132 /* FIXME: if we see this log, need to check state with render */
133 GST_ERROR ("we got gst_omx_buffer_finalize. But we already free this omx core!!!");
137 if (!(gstomx->gomx->omx_state == OMX_StateExecuting || gstomx->gomx->omx_state == OMX_StatePause)) {
138 /* FIXME: if we see this log, need to check state with render */
139 GST_ERROR ("we got gst_omx_buffer_finalize at wrong omx state (%d)!!!", gstomx->gomx->omx_state);
143 if (gstomx->out_port->flushing == TRUE) { /* to modify seek issue */
144 GST_WARNING ("we are in flushing. do not send to omx component. omx_buf: %p", buffer->omx_buffer);
145 g_omx_port_push_buffer (gstomx->out_port, buffer->omx_buffer);
149 /* MODIFICATION: DRC */
150 if((gstomx->out_port->core->reconfiguring == GOMX_RECONF_STATE_START ||
151 gstomx->out_port->core->reconfiguring == GOMX_RECONF_STATE_PENDING) &&
152 (gstomx->out_port->enabled == FALSE)) {
154 outbuf = (SCMN_IMGB*)(GST_BUFFER_MALLOCDATA(buffer));
156 GST_INFO ("we will finalize buffer but do not fillthisbuffer but just free during reconfiguration");
158 for(i = 0; i < gstomx->out_port->num_buffers; i ++) {
159 GstOmxSendCmdQueue *gomx_cmd = NULL;
161 if (outbuf->fd[0] == gstomx->out_port->scmn_out[i].fd[0]) {
162 if (gstomx->out_port->buffers[i] == NULL) {
163 GST_INFO ("buffers is NULL");
167 GST_INFO ("send OMX_FreeBuffer");
168 gomx_cmd = g_malloc(sizeof(GstOmxSendCmdQueue));
169 gomx_cmd->type = GSTOMX_COMMAND_FREE_BUFFER;
170 gomx_cmd->port = gstomx->out_port->port_index;
171 gomx_cmd->omx_buffer = buffer->omx_buffer;
172 async_queue_push (gstomx->gomx->cmd.cmd_queue, gomx_cmd);
174 if (gstomx->out_port->buffer_type == GOMX_BUFFER_GEM_VDEC_OUTPUT) {
175 GST_INFO ("tbm_slp_bo_unref: bo[%d] Y plane: %p", i, gstomx->out_port->bo[i].bo_y);
176 tbm_bo_unref(gstomx->out_port->bo[i].bo_y);
177 gstomx->out_port->bo[i].bo_y = NULL;
179 if (gstomx->gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS) {
180 GST_INFO ("tbm_slp_bo_unref: bo[%d] UV plane: %p", i, gstomx->out_port->bo[i].bo_uv);
181 tbm_bo_unref(gstomx->out_port->bo[i].bo_uv);
182 gstomx->out_port->bo[i].bo_uv = NULL;
192 log_buffer (gstomx, buffer->omx_buffer, "FillThisBuffer");
193 buffer->omx_buffer->nFilledLen = 0;
194 g_omx_port_release_buffer (gstomx->out_port, buffer->omx_buffer);
197 if (GST_BUFFER_MALLOCDATA(buffer)) {
198 g_free(GST_BUFFER_MALLOCDATA(buffer));
199 GST_BUFFER_MALLOCDATA(buffer) = NULL;
202 if (GST_MINI_OBJECT_CLASS (gstomx_buffer_parent_class)->finalize) {
203 GST_MINI_OBJECT_CLASS (gstomx_buffer_parent_class)->finalize (GST_MINI_OBJECT(buffer));
208 static GstOmxBuffer *
209 gst_omx_buffer_new(GstOmxBaseFilter *self)
211 GstOmxBuffer *ret = NULL;
213 ret = (GstOmxBuffer *)gst_mini_object_new(GST_TYPE_GSTOMX_BUFFER);
214 GST_LOG("creating buffer : %p", ret);
217 ret->buffer_direction = GSTOMX_BUFFER_DEFAULT;
222 send_flush_buffer_and_wait(GstOmxBaseFilter *self)
225 GstCaps *nego_caps = NULL;
227 if (self->gomx->output_log_count == 0 && self->gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS) {
228 GST_WARNING_OBJECT (self, "do not send FLUSH_BUFFER in this case. just wait for port reconfigure done"); /* only for tizenw */
232 nego_caps = gst_pad_get_negotiated_caps (self->srcpad);
234 GstStructure *structure = NULL;
236 gint nego_height = 0;
237 GstBuffer *flush_buffer = NULL;
239 structure = gst_caps_get_structure (nego_caps, 0);
240 gst_structure_get_int(structure, "width", &nego_width);
241 gst_structure_get_int(structure, "height", &nego_height);
243 flush_buffer = gst_buffer_new_and_alloc (nego_width * nego_height * 3 / 2);
246 GstFlowReturn ret = GST_FLOW_OK;
247 SCMN_IMGB *outbuf = NULL;
249 outbuf = (SCMN_IMGB*)(GST_BUFFER_MALLOCDATA(flush_buffer));
250 outbuf->buf_share_method = BUF_SHARE_METHOD_FLUSH_BUFFER; /* 3 */
252 outbuf->w[0] = nego_width;
253 outbuf->h[0] = nego_height;
254 outbuf->w[1] = nego_width;
255 outbuf->h[1] = nego_height / 2;
256 outbuf->s[0] = ALIGN(nego_width, 128);
257 outbuf->e[0] = ALIGN(nego_height, 32);
258 outbuf->s[1] = ALIGN(nego_width, 128);
259 outbuf->e[1] = ALIGN(nego_height / 2, 16);
263 gst_buffer_set_caps(flush_buffer, nego_caps);
265 GST_WARNING_OBJECT (self, "DRC: gst_pad_push FLUSH_BUFFER");
266 ret = gst_pad_push (self->srcpad, flush_buffer);
267 GST_WARNING_OBJECT (self, "DRC: gst_pad_push end. ret = %d (%s)", ret, gst_flow_get_name(ret));
269 GST_ERROR_OBJECT(self, "gst_buffer_new_and_alloc failed");
272 gst_caps_unref (nego_caps);
274 GST_ERROR_OBJECT (self, "gst_pad_get_negotiated_caps has NULL");
279 /* now we will wait OMX_CommandPortEnable complete event after sending flush buffer */
280 g_mutex_lock(self->gomx->drc_lock);
284 g_get_current_time(&abstimeout);
285 g_time_val_add(&abstimeout, _DRC_WAIT_TIMEOUT);
287 if (!g_cond_timed_wait(self->gomx->drc_cond, self->gomx->drc_lock, &abstimeout)) {
288 GST_ERROR_OBJECT (self, "DRC wait timeout [%d usec].Skip waiting", _DRC_WAIT_TIMEOUT);
290 GST_WARNING_OBJECT (self, "DRC done signal received.");
293 g_mutex_unlock(self->gomx->drc_lock);
298 /* Add_code_for_extended_color_format */
300 is_extended_color_format(GstOmxBaseFilter * self, GOmxPort * port)
302 if ((self->gomx->codec_type == GSTOMX_CODECTYPE_VIDEO_DEC && port->type == GOMX_PORT_INPUT) ||
303 (self->gomx->codec_type == GSTOMX_CODECTYPE_VIDEO_ENC && port->type == GOMX_PORT_OUTPUT)) {
304 /* do not need to check decoder input or encoder output color format. */
308 if (port->output_color_format == OMX_VIDEO_CodingUnused) {
309 OMX_PARAM_PORTDEFINITIONTYPE param;
310 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
312 if (G_UNLIKELY (!omx_handle)) {
313 GST_WARNING_OBJECT (self, "no component");
317 G_OMX_INIT_PARAM (param);
319 param.nPortIndex = port->port_index;
320 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
322 port->output_color_format = param.format.video.eColorFormat;
323 GST_INFO_OBJECT (self, "output_color_format is 0x%x from GetParameter", port->output_color_format);
326 switch ((guint)port->output_color_format) {
327 case OMX_EXT_COLOR_FormatNV12T_Phyaddr_Fd:
328 case OMX_EXT_COLOR_FormatNV12L_Phyaddr_Fd:
329 case OMX_COLOR_FormatYUV420SemiPlanar:
332 GST_ERROR_OBJECT (self, "can not find colorformat(0x%x) from GetParameter. this is non-zero copy. (port: %d)",
333 port->output_color_format, port->port_index);
339 setup_ports (GstOmxBaseFilter * self)
341 /* Input port configuration. */
342 g_omx_port_setup (self->in_port);
343 gst_pad_set_element_private (self->sinkpad, self->in_port);
345 /* Output port configuration. */
346 g_omx_port_setup (self->out_port);
347 gst_pad_set_element_private (self->srcpad, self->out_port);
349 /* @todo: read from config file: */
350 if (g_getenv ("OMX_ALLOCATE_ON")) {
351 GST_DEBUG_OBJECT (self, "OMX_ALLOCATE_ON");
352 self->in_port->omx_allocate = TRUE;
353 self->out_port->omx_allocate = TRUE;
354 self->in_port->shared_buffer = FALSE;
355 self->out_port->shared_buffer = FALSE;
356 } else if (g_getenv ("OMX_SHARE_HACK_ON")) {
357 GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_ON");
358 self->in_port->shared_buffer = TRUE;
359 self->out_port->shared_buffer = TRUE;
360 } else if (g_getenv ("OMX_SHARE_HACK_OFF")) {
361 GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_OFF");
362 self->in_port->shared_buffer = FALSE;
363 self->out_port->shared_buffer = FALSE;
364 /* MODIFICATION: Add extended_color_format */
365 } else if (self->gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS ||
366 self->gomx->component_vendor == GOMX_VENDOR_SLSI_SEC) {
367 /* MODIFICATION: always share input. enc input buffer unref after EBD. */
368 self->in_port->shared_buffer = TRUE;
369 self->out_port->shared_buffer = (is_extended_color_format(self, self->out_port))
373 GST_DEBUG_OBJECT (self, "default sharing and allocation");
376 GST_DEBUG_OBJECT (self, "omx_allocate: in: %d, out: %d",
377 self->in_port->omx_allocate, self->out_port->omx_allocate);
378 GST_DEBUG_OBJECT (self, "share_buffer: in: %d, out: %d",
379 self->in_port->shared_buffer, self->out_port->shared_buffer);
383 omx_change_state(GstOmxBaseFilter * self,GstOmxChangeState transition, GOmxPort *in_port, GstBuffer * buf)
386 GstFlowReturn ret = GST_FLOW_OK;
390 switch (transition) {
391 case GstOmx_LoadedToIdle:
393 g_mutex_lock (self->ready_lock);
395 GST_WARNING_OBJECT (self, "omx: prepare");
397 /** @todo this should probably go after doing preparations. */
398 if (self->omx_setup) {
399 self->omx_setup (self);
404 g_omx_core_prepare (self->gomx);
406 if (gomx->omx_state == OMX_StateIdle) {
408 gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
411 g_mutex_unlock (self->ready_lock);
413 if (gomx->omx_state != OMX_StateIdle)
418 case GstOmx_IdleToExecuting:
420 GST_WARNING_OBJECT (self, "omx: play");
421 g_omx_core_start (gomx);
423 if (gomx->omx_state != OMX_StateExecuting)
426 /* send buffer with codec data flag */
427 /** @todo move to util */
428 if (self->codec_data) {
429 if (self->is_divx_drm) {
430 /* we do not send codec data in divx drm case. because codec can not parse strd in divx drm. */
431 GST_INFO_OBJECT (self, "this is divx drm file. we do not send codec_data(strd) to omx component.");
433 OMX_BUFFERHEADERTYPE *omx_buffer;
435 GST_LOG_OBJECT (self, "request buffer (codec_data)");
436 omx_buffer = g_omx_port_request_buffer (in_port);
438 if (G_LIKELY (omx_buffer)) {
439 omx_buffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
441 omx_buffer->nFilledLen = GST_BUFFER_SIZE (self->codec_data);
442 memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
443 GST_BUFFER_DATA (self->codec_data), omx_buffer->nFilledLen);
445 GST_LOG_OBJECT (self, "release_buffer (codec_data)");
446 g_omx_port_release_buffer (in_port, omx_buffer);
459 GST_LOG_OBJECT (self, "end");
462 /* special conditions */
465 const gchar *error_msg = NULL;
467 if (gomx->omx_error) {
468 error_msg = "Error from OpenMAX component";
469 } else if (gomx->omx_state != OMX_StateExecuting &&
470 gomx->omx_state != OMX_StatePause) {
471 error_msg = "OpenMAX component in wrong state";
475 if (gomx->post_gst_element_error == FALSE) {
476 GST_ERROR_OBJECT (self, "post GST_ELEMENT_ERROR as %s", error_msg);
477 GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("%s", error_msg));
478 gomx->post_gst_element_error = TRUE;
479 ret = GST_FLOW_ERROR;
481 GST_ERROR_OBJECT (self, "GST_ELEMENT_ERROR is already posted. skip this (%s)", error_msg);
486 gst_buffer_unref (buf);
491 static GstStateChangeReturn
492 change_state (GstElement * element, GstStateChange transition)
494 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
495 GstOmxBaseFilter *self;
496 GstOmxBaseFilterClass *basefilter_class;
499 self = GST_OMX_BASE_FILTER (element);
501 basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
502 GST_LOG_OBJECT (self, "begin");
504 GST_WARNING_OBJECT (self, "changing state %s - %s",
505 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
506 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
508 switch (transition) {
509 case GST_STATE_CHANGE_NULL_TO_READY:
510 GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_NULL_TO_READY");
511 /*MODIFICATION : for transcode performance move instance init operation here*/
512 if (basefilter_class->instance_init && !core)
514 GST_WARNING_OBJECT (self, "current state is NULL_TO_READY but core is NULL. instance_init now.");
515 basefilter_class->instance_init(element);
519 self->gomx->input_log_count = 0;
520 self->gomx->output_log_count = 0;
521 core->omx_unrecover_err_cnt = 0;
522 core->post_gst_element_error = FALSE;
523 if (core->omx_state != OMX_StateLoaded) {
524 ret = GST_STATE_CHANGE_FAILURE;
528 if (self->adapter_size > 0) {
529 GST_LOG_OBJECT (self, "gst_adapter_new. size: %d", self->adapter_size);
530 self->adapter = gst_adapter_new();
531 if (self->adapter == NULL)
532 GST_ERROR_OBJECT (self, "Failed to create adapter!!");
536 case GST_STATE_CHANGE_READY_TO_PAUSED:
537 GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_READY_TO_PAUSED");
539 /* MODIFICATION: check live output buffer count */
541 g_atomic_int_set(&self->num_live_buffers, 0);
543 /* MODIFICATION: state tuning */
544 if (self->use_state_tuning) {
545 GST_WARNING_OBJECT (self, "use state-tuning feature");
546 /* to handle abnormal state change. */
547 if (self->gomx != self->in_port->core) {
548 GST_ERROR_OBJECT(self, "self->gomx != self->in_port->core. start new in_port");
549 self->in_port = g_omx_core_new_port (self->gomx, 0);
551 if (self->gomx != self->out_port->core) {
552 GST_ERROR_OBJECT(self, "self->gomx != self->out_port->core. start new out_port");
553 self->out_port = g_omx_core_new_port (self->gomx, 1);
556 if (core->omx_state != OMX_StateLoaded &&
557 core->omx_state != OMX_StateInvalid) {
558 GST_ERROR_OBJECT(self, "omx is already over OMX_StateIdle");
559 ret = GST_STATE_CHANGE_SUCCESS;
563 omx_change_state(self, GstOmx_LoadedToIdle, NULL, NULL);
565 if (core->omx_state != OMX_StateIdle) {
566 GST_ERROR_OBJECT(self, "fail to move from OMX state Loaded to Idle");
567 g_omx_port_finish(self->in_port);
568 g_omx_port_finish(self->out_port);
569 g_omx_cmd_queue_finish(core);
571 g_omx_core_stop(core);
572 g_omx_core_unload(core);
573 ret = GST_STATE_CHANGE_FAILURE;
579 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
580 GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_PLAYING");
587 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
589 if (ret == GST_STATE_CHANGE_FAILURE)
592 switch (transition) {
593 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
594 GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_PLAYING_TO_PAUSED");
595 self->gomx->input_log_count = 0;
596 self->gomx->output_log_count = 0;
599 case GST_STATE_CHANGE_PAUSED_TO_READY:
600 GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_READY");
601 self->gomx->reconfiguring = GOMX_RECONF_STATE_DEFAULT;
604 case GST_STATE_CHANGE_READY_TO_NULL:
605 GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_READY_TO_NULL");
607 /* MODIFICATION: state moved for ipp close */
608 g_mutex_lock (self->ready_lock);
610 GST_LOG_OBJECT (self, "port finish and unload omx core");
611 g_omx_port_finish (self->in_port);
612 g_omx_port_finish (self->out_port);
613 g_omx_cmd_queue_finish(core);
615 g_omx_core_stop (core);
617 /* MODIFICATION: check live output buffer count */
618 g_mutex_lock(self->buffer_lock);
619 GST_LOG_OBJECT (self, "num_live_buffers = %d", self->num_live_buffers);
620 while (self->num_live_buffers > 0) {
622 GST_ERROR_OBJECT (self, "Wait until all live buffers are released. (Live=%d)", self->num_live_buffers);
624 g_get_current_time(&abstimeout);
625 g_time_val_add(&abstimeout, _OUT_BUFFER_WAIT_TIMEOUT);
627 if (!g_cond_timed_wait(self->buffer_cond, self->buffer_lock, &abstimeout)) {
628 GST_ERROR("Buffer wait timeout[%d usec].(Live=%d) Skip waiting...",
629 _OUT_BUFFER_WAIT_TIMEOUT, self->num_live_buffers);
632 GST_WARNING_OBJECT (self, "Signal received. output buffer returned");
635 GST_LOG_OBJECT (self, "Waiting free buffer finished. (Live=%d)", self->num_live_buffers);
636 g_mutex_unlock(self->buffer_lock);
638 g_omx_core_unload (core);
641 g_mutex_unlock (self->ready_lock);
642 if (core->omx_state != OMX_StateLoaded &&
643 core->omx_state != OMX_StateInvalid) {
644 GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_FAILURE");
645 ret = GST_STATE_CHANGE_FAILURE;
650 gst_adapter_clear(self->adapter);
651 g_object_unref(self->adapter);
652 self->adapter = NULL;
655 self->gomx->input_log_count = 0;
656 self->gomx->output_log_count = 0;
657 core->omx_unrecover_err_cnt = 0;
658 core->post_gst_element_error = FALSE;
660 /*MODIFICATION : for transcode performance move instance finalize operation here*/
661 if (basefilter_class->instance_deinit)
663 basefilter_class->instance_deinit(element);
672 GST_WARNING_OBJECT (self, "change_state end");
678 instance_deinit (GstElement * element)
680 GstOmxBaseFilter *self;
682 self = GST_OMX_BASE_FILTER (element);
684 GST_WARNING_OBJECT (self, "begin");
686 gst_adapter_clear(self->adapter);
687 g_object_unref(self->adapter);
688 self->adapter = NULL;
691 if (self->codec_data) {
692 gst_buffer_unref (self->codec_data);
693 self->codec_data = NULL;
696 /* MODIFICATION : handling new segment event */
697 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
698 self->in_need_segment = FALSE;
699 self->out_need_segment = FALSE;
700 if (self->segment_queue) {
701 g_queue_foreach (self->segment_queue, (GFunc) gst_mini_object_unref, NULL);
702 g_queue_free (self->segment_queue);
703 self->segment_queue = NULL;
707 g_omx_port_clear(self->gomx);
708 g_omx_core_free (self->gomx);
711 GST_WARNING_OBJECT (self, "end");
715 finalize (GObject * obj)
717 GstOmxBaseFilter *self;
718 GstOmxBaseFilterClass *basefilter_class;
720 self = GST_OMX_BASE_FILTER (obj);
721 basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
723 GST_WARNING_OBJECT (self, "finalize enter");
725 if (basefilter_class->instance_deinit && self->gomx)
727 GST_WARNING_OBJECT (self, "instance_deinit");
728 basefilter_class->instance_deinit((GstElement *)obj);
731 /* MODIFICATION: check live output buffer count */
732 g_cond_free (self->buffer_cond);
733 self->buffer_cond = NULL;
734 g_mutex_free (self->buffer_lock);
736 g_mutex_free (self->ready_lock);
738 G_OBJECT_CLASS (parent_class)->finalize (obj);
739 GST_LOG_OBJECT(self, "finalize end");
743 set_property (GObject * obj,
744 guint prop_id, const GValue * value, GParamSpec * pspec)
746 GstOmxBaseFilter *self;
748 self = GST_OMX_BASE_FILTER (obj);
751 case ARG_USE_TIMESTAMPS:
752 self->use_timestamps = g_value_get_boolean (value);
754 case ARG_NUM_INPUT_BUFFERS:
755 case ARG_NUM_OUTPUT_BUFFERS:
757 OMX_PARAM_PORTDEFINITIONTYPE param;
758 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
759 OMX_U32 nBufferCountActual;
760 GOmxPort *port = (prop_id == ARG_NUM_INPUT_BUFFERS) ?
761 self->in_port : self->out_port;
763 if (G_UNLIKELY (!omx_handle)) {
764 GST_WARNING_OBJECT (self, "no component");
768 nBufferCountActual = g_value_get_uint (value);
770 G_OMX_INIT_PARAM (param);
772 param.nPortIndex = port->port_index;
773 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
775 if (nBufferCountActual < param.nBufferCountMin) {
776 GST_ERROR_OBJECT (self, "buffer count %lu is less than minimum %lu",
777 nBufferCountActual, param.nBufferCountMin);
781 param.nBufferCountActual = nBufferCountActual;
783 OMX_SetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
787 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
793 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
795 GstOmxBaseFilter *self;
797 self = GST_OMX_BASE_FILTER (obj);
799 if (gstomx_get_property_helper (self->gomx, prop_id, value))
803 case ARG_USE_TIMESTAMPS:
804 g_value_set_boolean (value, self->use_timestamps);
806 case ARG_NUM_INPUT_BUFFERS:
807 case ARG_NUM_OUTPUT_BUFFERS:
809 OMX_PARAM_PORTDEFINITIONTYPE param;
810 OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
811 GOmxPort *port = (prop_id == ARG_NUM_INPUT_BUFFERS) ?
812 self->in_port : self->out_port;
814 if (G_UNLIKELY (!omx_handle)) {
815 GST_WARNING_OBJECT (self, "no component");
816 g_value_set_uint (value, 0);
820 G_OMX_INIT_PARAM (param);
822 param.nPortIndex = port->port_index;
823 OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
825 g_value_set_uint (value, param.nBufferCountActual);
829 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
835 type_base_init (gpointer g_class)
840 type_class_init (gpointer g_class, gpointer class_data)
842 GObjectClass *gobject_class;
843 GstElementClass *gstelement_class;
844 GstOmxBaseFilterClass *basefilter_class;
846 gobject_class = G_OBJECT_CLASS (g_class);
847 gstelement_class = GST_ELEMENT_CLASS (g_class);
848 basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
850 gobject_class->finalize = finalize;
851 gstelement_class->change_state = change_state;
852 basefilter_class->instance_init = instance_init;
853 basefilter_class->instance_deinit = instance_deinit;
855 /* Properties stuff */
857 gobject_class->set_property = set_property;
858 gobject_class->get_property = get_property;
860 gstomx_install_property_helper (gobject_class);
862 g_object_class_install_property (gobject_class, ARG_USE_TIMESTAMPS,
863 g_param_spec_boolean ("use-timestamps", "Use timestamps",
864 "Whether or not to use timestamps",
865 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
867 g_object_class_install_property (gobject_class, ARG_NUM_INPUT_BUFFERS,
868 g_param_spec_uint ("input-buffers", "Input buffers",
869 "The number of OMX input buffers",
870 1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
871 g_object_class_install_property (gobject_class, ARG_NUM_OUTPUT_BUFFERS,
872 g_param_spec_uint ("output-buffers", "Output buffers",
873 "The number of OMX output buffers",
874 1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
879 static inline GstFlowReturn
880 push_buffer (GstOmxBaseFilter * self, GstBuffer * buf, OMX_BUFFERHEADERTYPE * omx_buffer)
882 GstFlowReturn ret = GST_FLOW_OK;
883 GstOmxBaseFilterClass *basefilter_class;
884 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
885 GstEvent *newsegment = NULL;
889 gint64 start, stop, pos;
891 if (G_UNLIKELY (self->out_need_segment)) {
892 newsegment = g_queue_pop_head (self->segment_queue);
894 gst_event_parse_new_segment_full(newsegment, &update, &rate, &arate, &format, &start, &stop, &pos);
895 if (GST_CLOCK_DIFF(GST_BUFFER_TIMESTAMP (buf), (GstClockTime)start) > 0) {
896 GST_DEBUG_OBJECT (self, "got new segment");
897 gst_pad_push_event (self->srcpad, GST_EVENT_CAST (newsegment));
898 self->out_need_segment = FALSE;
904 basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
905 /* process output gst buffer before gst_pad_push */
906 if (basefilter_class->process_output_buf) {
907 GstOmxReturn ret = GSTOMX_RETURN_OK;
908 ret = basefilter_class->process_output_buf(self, &buf, omx_buffer);
909 if (ret == GSTOMX_RETURN_SKIP) {
910 gst_buffer_unref (buf);
915 /* set average duration for memsink. need to check */
916 GST_BUFFER_DURATION(buf) = self->duration;
918 if (self->gomx->output_log_count < MAX_DEBUG_FRAME_CNT) {
919 GST_WARNING_OBJECT (self, "OUT_BUF[%02d]: gst_buf= %p omx_buf= %p ts= %" GST_TIME_FORMAT " size= %lu",
920 self->gomx->output_log_count, buf, omx_buffer, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf));
922 GST_LOG_OBJECT (self, "OUT_BUF: gst_buf= %p omx_buf= %p ts= %" GST_TIME_FORMAT " size= %lu",
923 buf, omx_buffer, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf));
926 /* avoid sending buffers which were already sent to the sink */
927 if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buf))) {
928 if (self->gomx->hls_streaming && GST_BUFFER_TIMESTAMP(buf) < self->gomx->previous_ts) {
929 GST_WARNING_OBJECT (self, "dropping the buffer with ts = %"GST_TIME_FORMAT" and previous_ts = %"GST_TIME_FORMAT,
930 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)), GST_TIME_ARGS(self->gomx->previous_ts));
931 gst_buffer_unref (buf);
935 self->gomx->previous_ts = GST_BUFFER_TIMESTAMP(buf);
939 ret = gst_pad_push (self->srcpad, buf);
941 if (self->gomx->output_log_count < MAX_DEBUG_FRAME_CNT) {
942 GST_WARNING_OBJECT (self, "gst_pad_push end [%02d]. ret = %d", self->gomx->output_log_count, ret);
943 self->gomx->output_log_count++;
945 GST_LOG_OBJECT (self, "gst_pad_push end. ret = %d", ret);
948 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
949 if (G_UNLIKELY (self->out_need_segment)) {
951 GST_DEBUG_OBJECT (self, "got new segment");
952 gst_pad_push_event (self->srcpad, GST_EVENT_CAST (newsegment));
953 self->out_need_segment = FALSE;
963 output_loop (gpointer data)
968 GstOmxBaseFilter *self;
969 GstFlowReturn ret = GST_FLOW_OK;
971 self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
974 GST_LOG_OBJECT (self, "begin");
976 /* do not bother if we have been setup to bail out */
977 if ((ret = g_atomic_int_get (&self->last_pad_push_return)) != GST_FLOW_OK)
981 g_error ("not ready");
985 out_port = self->out_port;
987 if (out_port->flushing == TRUE) {
988 GST_WARNING("port is on flushing. go to leave");
992 if (G_LIKELY (out_port->enabled)) {
993 OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
995 GST_LOG_OBJECT (self, "request buffer");
996 omx_buffer = g_omx_port_request_buffer (out_port);
998 GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);
1000 if (G_UNLIKELY (!omx_buffer)) {
1001 GST_WARNING_OBJECT (self, "null buffer: leaving");
1003 if (self->gomx->reconfiguring == GOMX_RECONF_STATE_START ||
1004 self->gomx->reconfiguring == GOMX_RECONF_STATE_PENDING) {
1005 GST_WARNING_OBJECT (self, "on port setting reconfigure");
1010 ret = GST_FLOW_WRONG_STATE;
1014 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
1015 /* MODIFICATION : handling new segment event */
1016 if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_STARTTIME)) {
1017 self->out_need_segment = TRUE;
1021 log_buffer (self, omx_buffer, "output_loop");
1023 if (G_LIKELY (omx_buffer->nFilledLen > 0)) {
1027 /** @todo remove this check */
1028 if (G_LIKELY (self->in_port->enabled)) {
1029 GstCaps *caps = NULL;
1031 caps = gst_pad_get_negotiated_caps (self->srcpad);
1034 /** @todo We shouldn't be doing this. */
1035 GST_WARNING_OBJECT (self, "faking settings changed notification");
1036 if (gomx->settings_changed_cb)
1037 gomx->settings_changed_cb (gomx);
1039 GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps);
1040 gst_caps_unref (caps);
1045 /* buf is always null when the output buffer pointer isn't shared. */
1046 buf = omx_buffer->pAppPrivate;
1048 /** @todo we need to move all the caps handling to one single
1049 * place, in the output loop probably. */
1051 /* [CONDITION 1] encoder OMX_BUFFERFLAG_CODECCONFIG */
1052 if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
1053 /* modification: to handle both byte-stream and packetized codec_data */
1054 GstOmxBaseFilterClass *basefilter_class;
1056 GST_WARNING_OBJECT (self, "OMX_BUFFERFLAG_CODECCONFIG flag was set from component. we will set codec_data to src caps.");
1057 basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
1058 if (basefilter_class->process_output_caps) {
1059 basefilter_class->process_output_caps(self, omx_buffer);
1062 /* [CONDITION 2] MODIFICATION: to handle output ST12 and SN12 HW addr (dec) */
1063 } else if (is_extended_color_format(self, self->out_port)) {
1064 GstOmxBuffer *gstomx_buf = NULL;
1065 GstCaps *caps = NULL, *new_caps = NULL;
1066 GstStructure *structure;
1067 gint width = 0, height = 0;
1068 SCMN_IMGB *outbuf = NULL;
1070 if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_DECODEONLY)) {
1071 GST_INFO_OBJECT (self, "Decodeonly flag was set from component");
1072 g_omx_port_release_buffer (out_port, omx_buffer);
1076 caps = gst_pad_get_negotiated_caps(self->srcpad);
1077 new_caps = gst_caps_make_writable(caps);
1078 structure = gst_caps_get_structure(new_caps, 0);
1080 gst_structure_get_int(structure, "width", &width);
1081 gst_structure_get_int(structure, "height", &height);
1084 if(self->out_port->core->component_vendor == GOMX_VENDOR_SLSI_EXYNOS)
1086 gint buffer_index = 0;
1088 if (omx_buffer->nAllocLen != sizeof(SCMN_IMGB) || omx_buffer->nFilledLen != sizeof(SCMN_IMGB)) {
1089 GST_ERROR_OBJECT (self, "invalid omx_buffer nAllocLen or nFilledLen. skip this buffer.");
1090 g_omx_port_release_buffer (out_port, omx_buffer);
1094 outbuf = (SCMN_IMGB*)(omx_buffer->pBuffer);
1096 for (buffer_index = 0; buffer_index < self->out_port->num_buffers; buffer_index++) {
1097 if(outbuf->fd[0] == self->out_port->scmn_out[buffer_index].fd[0]) {
1098 GST_LOG_OBJECT (self, "found the correct SCMN_IMGB");
1099 outbuf->bo[0] = self->out_port->bo[buffer_index].bo_y ;
1100 outbuf->bo[1] = self->out_port->bo[buffer_index].bo_uv ;
1101 outbuf->buf_share_method = BUF_SHARE_METHOD_TIZEN_BUFFER;
1104 } /* GOMX_VENDOR_SLSI_EXYNOS case */
1105 else if(self->out_port->core->component_vendor == GOMX_VENDOR_SLSI_SEC)
1107 if (omx_buffer->nAllocLen != sizeof(SCMN_IMGB) || omx_buffer->nFilledLen != sizeof(SCMN_IMGB)) {
1108 GST_ERROR_OBJECT (self, "invalid omx_buffer nAllocLen or nFilledLen. skip this buffer.");
1109 g_omx_port_release_buffer (out_port, omx_buffer);
1113 outbuf = (SCMN_IMGB*)(omx_buffer->pBuffer);
1114 } /* GOMX_VENDOR_SLSI_SEC case */
1117 GST_ERROR_OBJECT (self, "we can not support H/W color format (ST12, SN12) with this vendor (%d)", self->out_port->core->component_vendor);
1121 /* MODIFICATION : correct resolution. modify caps if caps and buffer width, height are different */
1122 if ((width != outbuf->w[0]) || (height != outbuf->h[0])) {
1123 GST_INFO_OBJECT (self, "resolution does not match, caps:%dx%d but received:%dx%d. so modify caps.", width, height, outbuf->w[0], outbuf->h[0]);
1124 width = outbuf->w[0];
1125 height = outbuf->h[0];
1126 gst_structure_set (structure, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
1129 if (G_LIKELY((width > 0) && (height > 0))) {
1130 /* MODIFICATION: handle gstomxbuffer unref */
1131 gstomx_buf = gst_omx_buffer_new(self);
1133 gstomx_buf->omx_buffer = omx_buffer;
1134 gstomx_buf->buffer_direction = GSTOMX_BUFFER_OUTPUT;
1135 buf =(GstBuffer *)gstomx_buf;
1137 GST_ERROR_OBJECT (self, "invalid buffer size");
1138 ret = GST_FLOW_UNEXPECTED;
1142 if (outbuf->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
1143 GST_LOG_OBJECT (self, "dec outbuf TIZEN_BUFFER: bo[0]:%p fd[0]:%d a[0]:%p a[1]:%p w[0]:%d h[0]:%d",
1144 outbuf->bo[0], outbuf->fd[0], outbuf->a[0], outbuf->a[1], outbuf->w[0], outbuf->h[0]);
1145 } else if (outbuf->buf_share_method == BUF_SHARE_METHOD_FD) {
1146 GST_LOG_OBJECT (self, "dec outbuf FD: fd[0]:%d a[0]:%p a[1]:%p w[0]:%d h[0]:%d",
1147 outbuf->fd[0], outbuf->a[0], outbuf->a[1], outbuf->w[0], outbuf->h[0]);
1148 } else if (outbuf->buf_share_method == BUF_SHARE_METHOD_PADDR) {
1149 GST_LOG_OBJECT (self, "dec output buf has H/W addr");
1152 GST_BUFFER_DATA(buf) = outbuf->a[0]; // we can not free this.
1153 outbuf->tz_enable = 0;
1155 GST_BUFFER_SIZE(buf) = width * height * 3 / 2;
1156 GST_LOG_OBJECT(self, "GST_BUFFER_DATA(buf)=%p, GST_BUFFER_SIZE(buf)=%d", GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
1157 GST_BUFFER_MALLOCDATA(buf) = g_malloc(width * height * 3 / 2);
1158 memcpy (GST_BUFFER_MALLOCDATA(buf), outbuf, sizeof(SCMN_IMGB));
1160 if (self->use_timestamps) {
1161 GST_BUFFER_TIMESTAMP (buf) =
1162 gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND,
1163 OMX_TICKS_PER_SECOND);
1165 gst_buffer_set_caps(buf, new_caps);
1166 gst_caps_unref (new_caps);
1168 /* MODIFICATION: check live output buffer count */
1169 g_atomic_int_inc(&self->num_live_buffers);
1171 ret = push_buffer (self, buf, omx_buffer);
1173 /* [CONDITION 4] Output buffer share mode on */
1174 } else if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
1175 GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
1176 if (self->use_timestamps) {
1177 GST_BUFFER_TIMESTAMP (buf) =
1178 gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND,
1179 OMX_TICKS_PER_SECOND);
1182 omx_buffer->pAppPrivate = NULL;
1183 omx_buffer->pBuffer = NULL;
1185 ret = push_buffer (self, buf, omx_buffer);
1188 /* [CONDITION 5] the First buffers in Output buffer share mode on */
1190 /* This is only meant for the first OpenMAX buffers,
1191 * which need to be pre-allocated. */
1192 /* Also for the very last one. */
1193 ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
1194 GST_BUFFER_OFFSET_NONE,
1195 omx_buffer->nFilledLen, GST_PAD_CAPS (self->srcpad), &buf);
1197 if (G_LIKELY (buf)) {
1198 memcpy (GST_BUFFER_DATA (buf),
1199 omx_buffer->pBuffer + omx_buffer->nOffset,
1200 omx_buffer->nFilledLen);
1201 if (self->use_timestamps) {
1202 GST_BUFFER_TIMESTAMP (buf) =
1203 gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND,
1204 OMX_TICKS_PER_SECOND);
1207 if (self->out_port->shared_buffer) {
1208 GST_WARNING_OBJECT (self, "couldn't zero-copy");
1209 /* If pAppPrivate is NULL, it means it was a dummy
1210 * allocation, free it. */
1211 if (!omx_buffer->pAppPrivate) {
1212 g_free (omx_buffer->pBuffer);
1213 omx_buffer->pBuffer = NULL;
1217 ret = push_buffer (self, buf, omx_buffer);
1219 GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %lu",
1220 omx_buffer->nFilledLen);
1224 GST_WARNING_OBJECT (self, "empty buffer");
1225 /* temporary fix for DivX when nFilledLen is zero sometimes */
1226 if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
1227 GST_WARNING_OBJECT (self, "EOS Case , so skip to release");
1229 GST_WARNING_OBJECT (self, "release_buffer for empty buffer case");
1230 omx_buffer->nFilledLen = 0;
1231 g_omx_port_release_buffer (out_port, omx_buffer);
1235 if (self->out_port->shared_buffer &&
1236 !omx_buffer->pBuffer && omx_buffer->nOffset == 0) {
1238 GstFlowReturn result;
1240 GST_LOG_OBJECT (self, "allocate buffer");
1241 result = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
1242 GST_BUFFER_OFFSET_NONE,
1243 omx_buffer->nAllocLen, GST_PAD_CAPS (self->srcpad), &buf);
1245 if (G_LIKELY (result == GST_FLOW_OK)) {
1246 omx_buffer->pAppPrivate = buf;
1248 omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
1249 omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
1251 GST_WARNING_OBJECT (self,
1252 "could not pad allocate buffer, using malloc");
1253 omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen);
1257 if (self->out_port->shared_buffer && !omx_buffer->pBuffer) {
1258 GST_ERROR_OBJECT (self, "no input buffer to share");
1261 if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
1262 GST_WARNING_OBJECT (self, "got eos");
1264 g_omx_port_push_buffer (out_port, omx_buffer);
1265 GST_WARNING ("in EOS case, push omx buffer (%p) to client output queue. OMX_CommandFlush will be called. port: %d", omx_buffer, out_port->type);
1267 gst_pad_push_event (self->srcpad, gst_event_new_eos ());
1268 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
1269 ret = GST_FLOW_UNEXPECTED;
1272 /* MODIFICATION: handle gstomxbuffer unref */
1273 if (is_extended_color_format(self, self->out_port) ||omx_buffer->nFilledLen == 0) {
1274 /* do not release in this case. we already release_buffer in gstbuffer_finalize */
1275 /* if nFilledLen ==0, we already release this buffer. */
1278 omx_buffer->nFilledLen = 0;
1279 GST_LOG_OBJECT (self, "release_buffer");
1280 g_omx_port_release_buffer (out_port, omx_buffer);
1284 /* out_port->enabled == FLASE */
1286 if (self->gomx->reconfiguring == GOMX_RECONF_STATE_START) {
1287 /* we will send BUF_SHARE_METHOD_FLUSH_BUFFER to videosink
1288 * to return back the previous decoder output buffer (fd) */
1289 send_flush_buffer_and_wait(self);
1297 self->last_pad_push_return = ret;
1299 if (gomx->omx_error != OMX_ErrorNone)
1300 ret = GST_FLOW_ERROR;
1302 if (ret != GST_FLOW_OK) {
1303 GST_INFO_OBJECT (self, "pause task, reason: %s", gst_flow_get_name (ret));
1304 gst_pad_pause_task (self->srcpad);
1307 GST_LOG_OBJECT (self, "end");
1309 gst_object_unref (self);
1312 static GstFlowReturn
1313 pad_chain (GstPad * pad, GstBuffer * buf)
1317 GstOmxBaseFilter *self;
1318 GstOmxBaseFilterClass *basefilter_class;
1319 GstFlowReturn ret = GST_FLOW_OK;
1320 GstBuffer *adapter_buf = NULL;
1322 self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
1326 if (self->gomx->input_log_count < MAX_DEBUG_FRAME_CNT) {
1327 GST_WARNING_OBJECT (self, "IN_BUF[%02d]: gst_buf= %p ts= %" GST_TIME_FORMAT " size= %lu state: %d",
1328 self->gomx->input_log_count, buf, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf), gomx->omx_state);
1329 self->gomx->input_log_count++;
1331 GST_LOG_OBJECT (self, "IN_BUF: gst_buf= %p ts= %" GST_TIME_FORMAT " size= %lu state: %d",
1332 buf, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf), gomx->omx_state);
1336 if (!self->use_state_tuning) {
1337 if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded))
1338 omx_change_state(self, GstOmx_LoadedToIdle, NULL, NULL);
1341 in_port = self->in_port;
1343 if (G_LIKELY (in_port->enabled)) {
1344 guint buffer_offset = 0;
1345 guint8 *src_data = NULL;
1347 GstClockTime src_timestamp = 0;
1348 GstClockTime src_duration = 0;
1350 if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle))
1351 omx_change_state(self, GstOmx_IdleToExecuting,in_port, buf);
1353 if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) {
1354 GST_ERROR_OBJECT (self, "Whoa! very wrong");
1357 if (is_extended_color_format(self, self->in_port)) {
1358 if (!GST_BUFFER_MALLOCDATA(buf)) {
1359 GST_WARNING_OBJECT (self, "null MALLOCDATA in hw color format. skip this.");
1364 basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
1365 /* process input gst buffer before OMX_EmptyThisBuffer */
1366 if (basefilter_class->process_input_buf)
1368 GstOmxReturn ret = GSTOMX_RETURN_OK;
1369 ret = basefilter_class->process_input_buf(self,&buf);
1370 if (ret == GSTOMX_RETURN_SKIP) {
1371 gst_buffer_unref(buf);
1376 if (self->adapter_size > 0) {
1377 if (!self->adapter) {
1378 GST_WARNING_OBJECT (self, "adapter is NULL. retry gst_adapter_new");
1379 self->adapter = gst_adapter_new();
1382 if (GST_BUFFER_IS_DISCONT(buf))
1384 GST_INFO_OBJECT (self, "got GST_BUFFER_IS_DISCONT.");
1385 gst_adapter_clear(self->adapter);
1388 gst_adapter_push(self->adapter, buf);
1390 src_size = gst_adapter_available(self->adapter);
1391 if (src_size < self->adapter_size) {
1392 GST_LOG_OBJECT (self, "Not enough data in adapter to feed to decoder.");
1396 if (src_size > self->adapter_size) {
1397 src_size = src_size - GST_BUFFER_SIZE(buf);
1398 GST_LOG_OBJECT (self, "take buffer from adapter. size=%d", src_size);
1401 src_timestamp = gst_adapter_prev_timestamp(self->adapter, NULL);
1402 adapter_buf = gst_adapter_take_buffer(self->adapter, src_size);
1403 src_data = GST_BUFFER_DATA(adapter_buf);
1404 src_duration = GST_BUFFER_TIMESTAMP (buf) - src_timestamp;
1406 src_data = GST_BUFFER_DATA (buf);
1407 src_size = GST_BUFFER_SIZE (buf);
1408 src_timestamp = GST_BUFFER_TIMESTAMP (buf);
1409 src_duration = GST_BUFFER_DURATION (buf);
1412 while (G_LIKELY (buffer_offset < src_size)) {
1413 OMX_BUFFERHEADERTYPE *omx_buffer;
1415 if (self->last_pad_push_return != GST_FLOW_OK ||
1416 !(gomx->omx_state == OMX_StateExecuting ||
1417 gomx->omx_state == OMX_StatePause)) {
1418 if (self->gomx->reconfiguring == GOMX_RECONF_STATE_START ||
1419 self->gomx->reconfiguring == GOMX_RECONF_STATE_PENDING) {
1420 GST_WARNING_OBJECT (self, "on port setting reconf");
1422 GST_WARNING_OBJECT (self, "go to out_flushing");
1427 if (self->gomx->input_log_count < MAX_DEBUG_FRAME_CNT) {
1428 GST_WARNING_OBJECT (self, "request buffer");
1429 omx_buffer = g_omx_port_request_buffer (in_port);
1430 GST_WARNING_OBJECT (self, "request buffer Done");
1432 GST_LOG_OBJECT (self, "request buffer");
1433 omx_buffer = g_omx_port_request_buffer (in_port);
1434 GST_LOG_OBJECT (self, "request buffer Done");
1437 GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);
1439 if (G_LIKELY (omx_buffer)) {
1440 log_buffer (self, omx_buffer, "pad_chain");
1442 /* MODIFICATION: to handle input SN12 and ST12 HW addr */
1443 if (is_extended_color_format(self, self->in_port)) {
1444 SCMN_IMGB *inbuf = NULL;
1446 if (!GST_BUFFER_MALLOCDATA(buf)) {
1447 GST_WARNING_OBJECT (self, "null MALLOCDATA in hw color format. skip this.");
1451 inbuf = (SCMN_IMGB*)(GST_BUFFER_MALLOCDATA(buf));
1453 /* make fd from bo to support BUF_SHARE_METHOD_TIZEN_BUFFER */
1454 if (inbuf != NULL && inbuf->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
1455 tbm_bo_handle handle_fd;
1457 handle_fd = tbm_bo_get_handle (inbuf->bo[0], TBM_DEVICE_MM);
1458 inbuf->fd[0] = handle_fd.u32;
1460 /* Exynos send Y & UV by using different bo plane */
1461 if(self->gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS || self->gomx->component_vendor == GOMX_VENDOR_SLSI_SEC)
1463 handle_fd = tbm_bo_get_handle (inbuf->bo[1], TBM_DEVICE_MM);
1464 inbuf->fd[1] = handle_fd.u32;
1465 memcpy(&self->eos_buffer, inbuf, sizeof(SCMN_IMGB));
1468 if (inbuf->fd[0] == 0)
1469 GST_ERROR_OBJECT (self, "input TIZEN_BUFFER with Wrong FD: bo[0]:%p fd[0]:%d a[0]:%p w[0]:%d h[0]:%d",
1470 inbuf->bo[0], inbuf->fd[0], inbuf->a[0], inbuf->w[0], inbuf->h[0]);
1472 GST_LOG_OBJECT (self, "input TIZEN_BUFFER: bo[0]:%p fd[0]:%d a[0]:%p w[0]:%d h[0]:%d",
1473 inbuf->bo[0], inbuf->fd[0], inbuf->a[0], inbuf->w[0], inbuf->h[0]);
1476 } else if (inbuf != NULL && inbuf->buf_share_method == BUF_SHARE_METHOD_FD) {
1477 GST_LOG_OBJECT (self, "input FD: fd[0]:%d a[0]:%p w[0]:%d h[0]:%d",
1478 inbuf->fd[0], inbuf->a[0], inbuf->w[0], inbuf->h[0]);
1480 if(self->gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS || self->gomx->component_vendor == GOMX_VENDOR_SLSI_SEC)
1481 memcpy(&self->eos_buffer, inbuf, sizeof(SCMN_IMGB));
1483 } else if (inbuf != NULL && inbuf->buf_share_method == BUF_SHARE_METHOD_PADDR) {
1484 GST_LOG_OBJECT (self, "input PADDR: p[0]:%d a[0]:%p w[0]:%d h[0]:%d",
1485 inbuf->p[0], inbuf->a[0], inbuf->w[0], inbuf->h[0], inbuf->buf_share_method);
1488 GST_ERROR_OBJECT (self, "encoder Input buffer has wrong buf_share_method");
1490 omx_buffer->pBuffer = GST_BUFFER_MALLOCDATA(buf);
1491 omx_buffer->nAllocLen = sizeof(SCMN_IMGB);
1492 omx_buffer->nFilledLen = sizeof(SCMN_IMGB);
1493 /* MODIFICATION: enc input buffer unref after EBD. */
1494 omx_buffer->pAppPrivate = (OMX_PTR)buf;
1495 } else if (omx_buffer->nOffset == 0 && self->in_port->shared_buffer) {
1496 /* MODIFICATION: move unref pAppPrivate code to EBD */
1497 omx_buffer->pBuffer = src_data;
1498 omx_buffer->nAllocLen = src_size; /* check this */
1499 omx_buffer->nFilledLen = src_size;
1500 omx_buffer->pAppPrivate = (self->adapter_size > 0) ? (OMX_PTR)adapter_buf : (OMX_PTR)buf;
1502 omx_buffer->nFilledLen = MIN (src_size - buffer_offset,
1503 omx_buffer->nAllocLen - omx_buffer->nOffset);
1505 memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
1506 src_data + buffer_offset, omx_buffer->nFilledLen);
1509 if (self->use_timestamps) {
1510 GstClockTime timestamp_offset = 0;
1512 if (buffer_offset && src_duration != GST_CLOCK_TIME_NONE) {
1513 timestamp_offset = gst_util_uint64_scale_int (buffer_offset,
1514 src_duration, src_size);
1517 /* MODIFICATION: to handle timestamps which are set to -1 in source element */
1518 if(src_timestamp + timestamp_offset >= G_MAXUINT64)
1519 omx_buffer->nTimeStamp = G_MAXUINT64;
1521 omx_buffer->nTimeStamp =
1522 gst_util_uint64_scale_int (src_timestamp +
1523 timestamp_offset, OMX_TICKS_PER_SECOND, GST_SECOND);
1526 /* MODIFICATION: hw addr */
1527 if (is_extended_color_format(self, self->in_port)) {
1528 buffer_offset = GST_BUFFER_SIZE (buf);
1530 buffer_offset += omx_buffer->nFilledLen;
1533 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
1534 /* MODIFICATION : handling new segment event */
1535 if (self->in_need_segment) {
1536 omx_buffer->nFlags |= OMX_BUFFERFLAG_STARTTIME;
1537 self->in_need_segment = FALSE;
1541 GST_LOG_OBJECT (self, "release_buffer");
1542 /* @todo untaint buffer */
1543 g_omx_port_release_buffer (in_port, omx_buffer);
1545 GST_WARNING_OBJECT (self, "null buffer");
1546 ret = GST_FLOW_WRONG_STATE;
1551 GST_WARNING_OBJECT (self, "done");
1552 ret = GST_FLOW_UNEXPECTED;
1555 if (!self->in_port->shared_buffer) {
1556 if (self->adapter_size > 0 && adapter_buf) {
1557 gst_buffer_unref (adapter_buf);
1560 gst_buffer_unref (buf);
1566 GST_LOG_OBJECT (self, "end");
1570 /* special conditions */
1573 const gchar *error_msg = NULL;
1575 ret = self->last_pad_push_return;
1576 GST_WARNING_OBJECT(self, "out_flushing: gst_pad_push return: %d (%s)", ret, gst_flow_get_name(ret));
1578 if (gomx->omx_error) {
1579 error_msg = "Error from OpenMAX component";
1580 } else if (gomx->omx_state != OMX_StateExecuting &&
1581 gomx->omx_state != OMX_StatePause) {
1582 error_msg = "OpenMAX component in wrong state";
1586 if (gomx->post_gst_element_error == FALSE) {
1587 GST_ERROR_OBJECT (self, "post GST_ELEMENT_ERROR as %s", error_msg);
1588 GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("%s", error_msg));
1589 gomx->post_gst_element_error = TRUE;
1590 ret = GST_FLOW_ERROR;
1592 GST_ERROR_OBJECT (self, "GST_ELEMENT_ERROR is already posted. skip this (%s)", error_msg);
1596 if (self->adapter_size > 0 && adapter_buf) {
1597 gst_buffer_unref (adapter_buf);
1600 gst_buffer_unref (buf);
1608 pad_event (GstPad * pad, GstEvent * event)
1610 GstOmxBaseFilter *self;
1613 gboolean ret = TRUE;
1615 self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
1617 in_port = self->in_port;
1619 GST_LOG_OBJECT (self, "begin");
1621 GST_INFO_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
1623 if (self->pad_event) {
1624 if (!self->pad_event(pad, event))
1628 switch (GST_EVENT_TYPE (event)) {
1630 /* if we are init'ed, and there is a running loop; then
1631 * if we get a buffer to inform it of EOS, let it handle the rest
1632 * in any other case, we send EOS */
1633 self->gomx->input_log_count = 0;
1634 self->gomx->output_log_count = 0;
1636 if (self->ready && self->last_pad_push_return == GST_FLOW_OK)
1638 /* send buffer with eos flag */
1639 /** @todo move to util */
1641 /* S.LSI case, encoder does not send eos bufer. */
1642 if (gomx->component_vendor == GOMX_VENDOR_SLSI_SEC || gomx->component_vendor == GOMX_VENDOR_SLSI_EXYNOS)
1644 OMX_BUFFERHEADERTYPE *omx_buffer;
1646 GST_LOG_OBJECT (self, "request buffer");
1647 omx_buffer = g_omx_port_request_buffer (in_port);
1649 if (G_LIKELY (omx_buffer))
1651 if (gomx->codec_type == GSTOMX_CODECTYPE_AUDIO_DEC)
1653 if (self->adapter_size > 0 && self->adapter) {
1655 GstBuffer *adapter_buf = NULL;
1657 src_len = gst_adapter_available(self->adapter);
1658 if (src_len > 0 && src_len < self->adapter_size) {
1659 omx_buffer->nTimeStamp = gst_util_uint64_scale_int(
1660 gst_adapter_prev_timestamp(self->adapter, NULL),
1661 OMX_TICKS_PER_SECOND, GST_SECOND);
1662 adapter_buf = gst_adapter_take_buffer(self->adapter, src_len);
1663 omx_buffer->pBuffer = GST_BUFFER_DATA(adapter_buf);
1664 omx_buffer->nAllocLen = src_len;
1665 omx_buffer->nFilledLen = src_len;
1666 omx_buffer->pAppPrivate = adapter_buf;
1668 gst_adapter_clear(self->adapter);
1671 else if (gomx->codec_type == GSTOMX_CODECTYPE_VIDEO_ENC)
1673 SCMN_IMGB* inbuf = NULL;
1674 omx_buffer->pBuffer = (OMX_U8*) g_malloc(sizeof(SCMN_IMGB));
1676 memcpy(omx_buffer->pBuffer, &self->eos_buffer, sizeof(SCMN_IMGB));
1677 inbuf = (SCMN_IMGB*)omx_buffer->pBuffer;
1679 GST_INFO_OBJECT (self, "EOS buffer: fd[0]:%d fd[1]:%d fd[2]:%d a[0]:%p a[1]:%p w[0]:%d h[0]:%d buf_share_method:%d",
1680 inbuf->fd[0], inbuf->fd[1], inbuf->fd[2], inbuf->a[0], inbuf->a[1], inbuf->w[0], inbuf->h[0], inbuf->buf_share_method);
1681 omx_buffer->nFilledLen = 0;
1682 omx_buffer->pAppPrivate = NULL;
1684 else if (gomx->codec_type == GSTOMX_CODECTYPE_VIDEO_DEC)
1686 omx_buffer->nFilledLen = 0;
1687 omx_buffer->pAppPrivate = NULL;
1689 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
1691 GST_WARNING_OBJECT (self, "release_buffer in EOS. omx_buf= %p size= %d", omx_buffer, omx_buffer->nFilledLen);
1692 /* foo_buffer_untaint (omx_buffer); */
1693 g_omx_port_release_buffer (in_port, omx_buffer);
1694 /* loop handles EOS, eat it here */
1695 gst_event_unref (event);
1702 GST_WARNING_OBJECT (self, "gst_pad_push_event : EOS");
1703 /* we tried, but it's up to us here */
1704 ret = gst_pad_push_event (self->srcpad, event);
1707 case GST_EVENT_FLUSH_START:
1708 self->gomx->input_log_count = 0;
1709 self->gomx->output_log_count = 0;
1710 if (gomx->omx_state == OMX_StatePause || gomx->omx_state == OMX_StateExecuting) {
1711 gst_pad_push_event (self->srcpad, event);
1712 self->last_pad_push_return = GST_FLOW_WRONG_STATE;
1714 g_omx_core_flush_start (gomx);
1716 gst_pad_pause_task (self->srcpad);
1718 GST_WARNING_OBJECT (self, "GST_EVENT_FLUSH_START");
1722 GST_ERROR_OBJECT (self, "flush start in wrong omx state");
1727 case GST_EVENT_FLUSH_STOP:
1728 if (gomx->omx_state == OMX_StatePause || gomx->omx_state == OMX_StateExecuting) {
1729 gst_pad_push_event (self->srcpad, event);
1730 self->last_pad_push_return = GST_FLOW_OK;
1731 self->gomx->previous_ts = 0;
1733 g_omx_core_flush_stop (gomx);
1735 if (self->adapter_size > 0 && self->adapter) {
1736 gst_adapter_clear(self->adapter);
1740 gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
1742 GST_WARNING_OBJECT (self, "GST_EVENT_FLUSH_STOP");
1745 GST_ERROR_OBJECT (self, "flush start in wrong omx state");
1750 case GST_EVENT_NEWSEGMENT:
1751 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
1752 /* MODIFICATION : handling new segment event */
1753 if (gomx->omx_state == OMX_StatePause || gomx->omx_state == OMX_StateExecuting) {
1754 g_queue_push_tail (self->segment_queue, event);
1755 self->in_need_segment = TRUE;
1757 ret = gst_pad_push_event (self->srcpad, event);
1760 GST_WARNING_OBJECT (self, "GST_EVENT_NEWSEGMENT");
1761 ret = gst_pad_push_event (self->srcpad, event);
1766 ret = gst_pad_push_event (self->srcpad, event);
1770 GST_LOG_OBJECT (self, "end");
1776 activate_push (GstPad * pad, gboolean active)
1778 gboolean result = TRUE;
1779 GstOmxBaseFilter *self;
1781 self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
1784 GST_DEBUG_OBJECT (self, "activate");
1785 /* task may carry on */
1786 g_atomic_int_set (&self->last_pad_push_return, GST_FLOW_OK);
1788 /* we do not start the task yet if the pad is not connected */
1789 if (gst_pad_is_linked (pad)) {
1791 /** @todo link callback function also needed */
1792 g_omx_port_resume (self->in_port);
1793 g_omx_port_resume (self->out_port);
1795 result = gst_pad_start_task (pad, output_loop, pad);
1799 GST_DEBUG_OBJECT (self, "deactivate");
1801 /* persuade task to bail out */
1802 g_atomic_int_set (&self->last_pad_push_return, GST_FLOW_WRONG_STATE);
1805 /** @todo disable this until we properly reinitialize the buffers. */
1807 /* flush all buffers */
1808 OMX_SendCommand (self->gomx->omx_handle, OMX_CommandFlush, OMX_ALL, NULL);
1812 g_omx_port_pause (self->in_port);
1813 g_omx_port_pause (self->out_port);
1816 /* make sure streaming finishes */
1817 result = gst_pad_stop_task (pad);
1820 gst_object_unref (self);
1826 instance_init (GstElement *element)
1828 GstOmxBaseFilter *self;
1830 self = GST_OMX_BASE_FILTER (element);
1832 GST_WARNING_OBJECT (self, "begin");
1834 self->use_timestamps = TRUE;
1835 self->use_state_tuning = FALSE;
1836 self->adapter_size = 0;
1837 self->adapter = NULL;
1838 self->is_divx_drm = FALSE;
1840 self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (GST_OMX_BASE_FILTER_GET_CLASS(element)));
1841 self->gomx->drc_cond = g_cond_new (); /* for DRC cond wait */
1842 self->gomx->drc_lock = g_mutex_new (); /* for DRC cond wait */
1844 self->in_port = g_omx_core_new_port (self->gomx, 0);
1845 self->out_port = g_omx_core_new_port (self->gomx, 1);
1846 self->gomx->codec_type = GSTOMX_CODECTYPE_DEFAULT;
1848 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
1849 /* MODIFICATION : handling new segment event */
1850 self->segment_queue = g_queue_new ();
1852 GST_LOG_OBJECT (self, "end");
1856 type_instance_init (GTypeInstance * instance, gpointer g_class)
1858 GstOmxBaseFilter *self;
1859 GstElementClass *element_class;
1861 element_class = GST_ELEMENT_CLASS (g_class);
1863 self = GST_OMX_BASE_FILTER (instance);
1865 GST_WARNING_OBJECT (self, "begin");
1867 self->use_timestamps = TRUE;
1868 self->use_state_tuning = FALSE;
1869 self->adapter_size = 0;
1870 self->adapter = NULL;
1871 self->is_divx_drm = FALSE;
1873 self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class));
1874 self->gomx->drc_cond = g_cond_new (); /* for DRC cond wait */
1875 self->gomx->drc_lock = g_mutex_new (); /* for DRC cond wait */
1877 self->in_port = g_omx_core_new_port (self->gomx, 0);
1878 self->out_port = g_omx_core_new_port (self->gomx, 1);
1879 self->gomx->codec_type = GSTOMX_CODECTYPE_DEFAULT;
1880 self->ready_lock = g_mutex_new ();
1881 /* MODIFICATION: check live output buffer count */
1882 self->buffer_lock = g_mutex_new ();
1883 self->buffer_cond = g_cond_new ();
1885 /* MODIFICATION: flags to avoid sending repeated frames to sink in HLS case */
1886 self->gomx->hls_streaming = FALSE;
1887 self->gomx->previous_ts = 0;
1890 gst_pad_new_from_template (gst_element_class_get_pad_template
1891 (element_class, "sink"), "sink");
1893 gst_pad_set_chain_function (self->sinkpad, pad_chain);
1894 gst_pad_set_event_function (self->sinkpad, pad_event);
1897 gst_pad_new_from_template (gst_element_class_get_pad_template
1898 (element_class, "src"), "src");
1900 gst_pad_set_activatepush_function (self->srcpad, activate_push);
1902 gst_pad_use_fixed_caps (self->srcpad);
1904 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1905 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1907 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
1908 /* MODIFICATION : handling new segment event */
1909 self->segment_queue = g_queue_new ();
1912 GST_LOG_OBJECT (self, "end");
1916 omx_interface_init (GstImplementsInterfaceClass * klass)
1921 interface_supported (GstImplementsInterface * iface, GType type)
1923 g_assert (type == GST_TYPE_OMX);
1928 interface_init (GstImplementsInterfaceClass * klass)
1930 klass->supported = interface_supported;
1934 init_interfaces (GType type)
1936 GInterfaceInfo *iface_info;
1937 GInterfaceInfo *omx_info;
1940 iface_info = g_new0 (GInterfaceInfo, 1);
1941 iface_info->interface_init = (GInterfaceInitFunc) interface_init;
1943 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, iface_info);
1944 g_free (iface_info);
1946 omx_info = g_new0 (GInterfaceInfo, 1);
1947 omx_info->interface_init = (GInterfaceInitFunc) omx_interface_init;
1949 g_type_add_interface_static (type, GST_TYPE_OMX, omx_info);