Initialize Tizen 2.3
[framework/multimedia/gst-openmax.git] / wearable / omx / gstomx_base_filter.c
1 /*
2  * Copyright (C) 2007-2009 Nokia Corporation.
3  *
4  * Author: Felipe Contreras <felipe.contreras@nokia.com>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "gstomx_base_filter.h"
23 #include "gstomx.h"
24 #include "gstomx_interface.h"
25 #include <string.h> /* for memcpy */
26 #include <unistd.h> /* for close */
27
28 /* MODIFICATION: for state-tuning */
29 static void output_loop (gpointer data);
30
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);
36
37 static void instance_init (GstElement * element);
38 static void instance_deinit (GstElement * element);
39
40 enum
41 {
42   ARG_USE_TIMESTAMPS = GSTOMX_NUM_COMMON_PROP,
43   ARG_NUM_INPUT_BUFFERS,
44   ARG_NUM_OUTPUT_BUFFERS,
45 };
46
47 static void init_interfaces (GType type);
48 GSTOMX_BOILERPLATE_FULL (GstOmxBaseFilter, gst_omx_base_filter, GstElement,
49     GST_TYPE_ELEMENT, init_interfaces);
50
51 static inline void
52 log_buffer (GstOmxBaseFilter * self, OMX_BUFFERHEADERTYPE * omx_buffer, const gchar *name)
53 {
54   GST_DEBUG_OBJECT (self, "%s: omx_buffer: "
55       "nAllocLen=%lu, "
56       "nFilledLen=%lu, "
57       "flags=%lu, "
58       "offset=%lu, "
59       "timestamp=%lld",
60       name, omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
61       omx_buffer->nOffset, omx_buffer->nTimeStamp);
62 }
63
64
65 /* MODIFICATION: handle gstomxbuffer unref */
66 static void
67 gst_omx_buffer_class_init(gpointer g_class, gpointer class_data)
68 {
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;
72 }
73
74 static GType
75 gst_omx_buffer_get_type(void)
76 {
77   static GType _gst_gstomx_out_buffer_type;
78
79   if (G_UNLIKELY(_gst_gstomx_out_buffer_type == 0)) {
80     static const GTypeInfo gstomx_buffer_info = {
81       sizeof (GstBufferClass),
82       NULL,
83       NULL,
84       gst_omx_buffer_class_init,
85       NULL,
86       NULL,
87       sizeof (GstOmxBuffer),
88       0,
89       NULL,
90       NULL
91     };
92     _gst_gstomx_out_buffer_type = g_type_register_static(GST_TYPE_BUFFER,
93                                                         "GstOmxBuffer",
94                                                         &gstomx_buffer_info, 0);
95   }
96   return _gst_gstomx_out_buffer_type;
97 }
98
99 static void
100 gst_omx_buffer_finalize(GstOmxBuffer *buffer)
101 {
102   GstOmxBaseFilter *gstomx = buffer->gstomx;
103   SCMN_IMGB *outbuf = NULL;
104   int i = 0;
105
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)));
108
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);
113     goto exit;
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);
117     goto exit;
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);
121
122     g_atomic_int_dec_and_test(&gstomx->num_live_buffers);
123     if (gstomx->buffer_cond) {
124       g_cond_signal(gstomx->buffer_cond);
125     } else {
126       GST_ERROR ("we got gst_omx_buffer_finalize. But buffer cond is already NULL!");
127     }
128   }
129
130
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!!!");
134     goto exit;
135   }
136
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);
140     goto exit;
141   }
142
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);
146     goto exit;
147   }
148
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)) {
153
154     outbuf = (SCMN_IMGB*)(GST_BUFFER_MALLOCDATA(buffer));
155
156     GST_INFO ("we will finalize buffer but do not fillthisbuffer but just free during reconfiguration");
157
158     for(i = 0; i < gstomx->out_port->num_buffers; i ++) {
159       GstOmxSendCmdQueue *gomx_cmd = NULL;
160
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");
164           goto exit;
165         }
166
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);
173
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;
178
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;
183         }
184       }
185
186       break;
187       }
188     }
189   goto exit;
190   }
191
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);
195
196 exit:
197   if (GST_BUFFER_MALLOCDATA(buffer)) {
198     g_free(GST_BUFFER_MALLOCDATA(buffer));
199     GST_BUFFER_MALLOCDATA(buffer) = NULL;
200   }
201
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));
204   }
205   return;
206 }
207
208 static GstOmxBuffer *
209 gst_omx_buffer_new(GstOmxBaseFilter *self)
210 {
211   GstOmxBuffer *ret = NULL;
212
213   ret = (GstOmxBuffer *)gst_mini_object_new(GST_TYPE_GSTOMX_BUFFER);
214   GST_LOG("creating buffer : %p", ret);
215
216   ret->gstomx = self;
217   ret->buffer_direction = GSTOMX_BUFFER_DEFAULT;
218   return ret;
219 }
220
221 static void
222 send_flush_buffer_and_wait(GstOmxBaseFilter *self)
223 {
224
225   GstCaps *nego_caps = NULL;
226
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 */
229     goto leave_and_wait;
230   }
231
232   nego_caps = gst_pad_get_negotiated_caps (self->srcpad);
233   if (nego_caps) {
234     GstStructure *structure = NULL;
235     gint nego_width = 0;
236     gint nego_height = 0;
237     GstBuffer *flush_buffer = NULL;
238
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);
242
243     flush_buffer = gst_buffer_new_and_alloc (nego_width * nego_height * 3 / 2);
244
245     if (flush_buffer) {
246       GstFlowReturn ret = GST_FLOW_OK;
247       SCMN_IMGB *outbuf = NULL;
248
249       outbuf = (SCMN_IMGB*)(GST_BUFFER_MALLOCDATA(flush_buffer));
250       outbuf->buf_share_method = BUF_SHARE_METHOD_FLUSH_BUFFER; /* 3 */
251
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);
260       outbuf->a[0] = NULL;
261       outbuf->a[1] = NULL;
262
263       gst_buffer_set_caps(flush_buffer, nego_caps);
264
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));
268     } else {
269       GST_ERROR_OBJECT(self, "gst_buffer_new_and_alloc failed");
270     }
271
272     gst_caps_unref (nego_caps);
273   } else {
274     GST_ERROR_OBJECT (self, "gst_pad_get_negotiated_caps has NULL");
275   }
276
277 leave_and_wait:
278
279   /* now we will wait OMX_CommandPortEnable complete event after sending flush buffer */
280   g_mutex_lock(self->gomx->drc_lock);
281   {
282     GTimeVal abstimeout;
283
284     g_get_current_time(&abstimeout);
285     g_time_val_add(&abstimeout, _DRC_WAIT_TIMEOUT);
286
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);
289     } else {
290       GST_WARNING_OBJECT (self, "DRC done signal received.");
291     }
292   }
293   g_mutex_unlock(self->gomx->drc_lock);
294
295   return;
296 }
297
298 /* Add_code_for_extended_color_format */
299 static gboolean
300 is_extended_color_format(GstOmxBaseFilter * self, GOmxPort * port)
301 {
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. */
305     return FALSE;
306   }
307
308   if (port->output_color_format == OMX_VIDEO_CodingUnused) {
309     OMX_PARAM_PORTDEFINITIONTYPE param;
310     OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
311
312     if (G_UNLIKELY (!omx_handle)) {
313       GST_WARNING_OBJECT (self, "no component");
314       return FALSE;
315     }
316
317     G_OMX_INIT_PARAM (param);
318
319     param.nPortIndex = port->port_index;
320     OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, &param);
321
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);
324   }
325
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:
330       return TRUE;
331     default:
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);
334       return FALSE;
335   }
336 }
337
338 static void
339 setup_ports (GstOmxBaseFilter * self)
340 {
341   /* Input port configuration. */
342   g_omx_port_setup (self->in_port);
343   gst_pad_set_element_private (self->sinkpad, self->in_port);
344
345   /* Output port configuration. */
346   g_omx_port_setup (self->out_port);
347   gst_pad_set_element_private (self->srcpad, self->out_port);
348
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))
370         ? FALSE : TRUE;
371
372   } else {
373     GST_DEBUG_OBJECT (self, "default sharing and allocation");
374   }
375
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);
380 }
381
382 static GstFlowReturn
383 omx_change_state(GstOmxBaseFilter * self,GstOmxChangeState transition, GOmxPort *in_port, GstBuffer * buf)
384 {
385   GOmxCore *gomx;
386   GstFlowReturn ret = GST_FLOW_OK;
387
388   gomx = self->gomx;
389
390   switch (transition) {
391   case GstOmx_LoadedToIdle:
392     {
393       g_mutex_lock (self->ready_lock);
394
395       GST_WARNING_OBJECT (self, "omx: prepare");
396
397       /** @todo this should probably go after doing preparations. */
398       if (self->omx_setup) {
399         self->omx_setup (self);
400       }
401
402       setup_ports (self);
403
404       g_omx_core_prepare (self->gomx);
405
406       if (gomx->omx_state == OMX_StateIdle) {
407         self->ready = TRUE;
408         gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
409       }
410
411       g_mutex_unlock (self->ready_lock);
412
413       if (gomx->omx_state != OMX_StateIdle)
414         goto out_flushing;
415     }
416     break;
417
418   case GstOmx_IdleToExecuting:
419     {
420       GST_WARNING_OBJECT (self, "omx: play");
421       g_omx_core_start (gomx);
422
423       if (gomx->omx_state != OMX_StateExecuting)
424         goto out_flushing;
425
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.");
432         }  else {
433           OMX_BUFFERHEADERTYPE *omx_buffer;
434
435           GST_LOG_OBJECT (self, "request buffer (codec_data)");
436           omx_buffer = g_omx_port_request_buffer (in_port);
437
438           if (G_LIKELY (omx_buffer)) {
439             omx_buffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
440
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);
444
445             GST_LOG_OBJECT (self, "release_buffer (codec_data)");
446             g_omx_port_release_buffer (in_port, omx_buffer);
447           }
448         }
449       }
450     }
451     break;
452
453   default:
454     break;
455   }
456
457 leave:
458
459   GST_LOG_OBJECT (self, "end");
460   return ret;
461
462   /* special conditions */
463 out_flushing:
464   {
465     const gchar *error_msg = NULL;
466
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";
472     }
473
474     if (error_msg) {
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;
480       } else {
481         GST_ERROR_OBJECT (self, "GST_ELEMENT_ERROR is already posted. skip this (%s)", error_msg);
482       }
483     }
484
485     if (buf)
486       gst_buffer_unref (buf);
487     goto leave;
488   }
489 }
490
491 static GstStateChangeReturn
492 change_state (GstElement * element, GstStateChange transition)
493 {
494   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
495   GstOmxBaseFilter *self;
496   GstOmxBaseFilterClass *basefilter_class;
497   GOmxCore *core;
498
499   self = GST_OMX_BASE_FILTER (element);
500   core = self->gomx;
501   basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
502   GST_LOG_OBJECT (self, "begin");
503
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)));
507
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)
513       {
514         GST_WARNING_OBJECT (self, "current state is NULL_TO_READY but core is NULL. instance_init now.");
515         basefilter_class->instance_init(element);
516       }
517
518       core = self->gomx;
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;
525         goto leave;
526       }
527
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!!");
533       }
534       break;
535
536     case GST_STATE_CHANGE_READY_TO_PAUSED:
537       GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_READY_TO_PAUSED");
538
539       /* MODIFICATION: check live output buffer count */
540
541       g_atomic_int_set(&self->num_live_buffers, 0);
542
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);
550         }
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);
554         }
555
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;
560           goto leave;
561         }
562
563         omx_change_state(self, GstOmx_LoadedToIdle, NULL, NULL);
564
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);
570
571           g_omx_core_stop(core);
572           g_omx_core_unload(core);
573           ret = GST_STATE_CHANGE_FAILURE;
574           goto leave;
575         }
576       }
577       break;
578
579     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
580       GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_PLAYING");
581       break;
582
583     default:
584       break;
585   }
586
587   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
588
589   if (ret == GST_STATE_CHANGE_FAILURE)
590     goto leave;
591
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;
597       break;
598
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;
602       break;
603
604     case GST_STATE_CHANGE_READY_TO_NULL:
605       GST_WARNING_OBJECT (self, "GST_STATE_CHANGE_READY_TO_NULL");
606
607       /* MODIFICATION: state moved for ipp close */
608       g_mutex_lock (self->ready_lock);
609       if (self->ready) {
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);
614
615         g_omx_core_stop (core);
616
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) {
621           GTimeVal abstimeout;
622           GST_ERROR_OBJECT (self, "Wait until all live buffers are released. (Live=%d)", self->num_live_buffers);
623
624           g_get_current_time(&abstimeout);
625           g_time_val_add(&abstimeout, _OUT_BUFFER_WAIT_TIMEOUT);
626
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);
630             break;
631           } else {
632             GST_WARNING_OBJECT (self, "Signal received. output buffer returned");
633           }
634         }
635         GST_LOG_OBJECT (self, "Waiting free buffer finished. (Live=%d)", self->num_live_buffers);
636         g_mutex_unlock(self->buffer_lock);
637
638         g_omx_core_unload (core);
639         self->ready = FALSE;
640       }
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;
646         goto leave;
647       }
648
649       if (self->adapter) {
650         gst_adapter_clear(self->adapter);
651         g_object_unref(self->adapter);
652         self->adapter = NULL;
653       }
654
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;
659
660       /*MODIFICATION : for transcode performance move instance finalize operation here*/
661       if (basefilter_class->instance_deinit)
662       {
663         basefilter_class->instance_deinit(element);
664       }
665       break;
666
667     default:
668       break;
669   }
670
671 leave:
672   GST_WARNING_OBJECT (self, "change_state end");
673
674   return ret;
675 }
676
677 static void
678 instance_deinit (GstElement * element)
679 {
680   GstOmxBaseFilter *self;
681
682   self = GST_OMX_BASE_FILTER (element);
683
684   GST_WARNING_OBJECT (self, "begin");
685   if (self->adapter) {
686     gst_adapter_clear(self->adapter);
687     g_object_unref(self->adapter);
688     self->adapter = NULL;
689   }
690
691   if (self->codec_data) {
692     gst_buffer_unref (self->codec_data);
693     self->codec_data = NULL;
694   }
695
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;
704   }
705 #endif
706
707   g_omx_port_clear(self->gomx);
708   g_omx_core_free (self->gomx);
709   self->gomx = NULL;
710
711   GST_WARNING_OBJECT (self, "end");
712 }
713
714 static void
715 finalize (GObject * obj)
716 {
717   GstOmxBaseFilter *self;
718   GstOmxBaseFilterClass *basefilter_class;
719
720   self = GST_OMX_BASE_FILTER (obj);
721   basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
722
723   GST_WARNING_OBJECT (self, "finalize enter");
724
725   if (basefilter_class->instance_deinit && self->gomx)
726   {
727     GST_WARNING_OBJECT (self, "instance_deinit");
728     basefilter_class->instance_deinit((GstElement *)obj);
729   }
730
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);
735
736   g_mutex_free (self->ready_lock);
737
738   G_OBJECT_CLASS (parent_class)->finalize (obj);
739   GST_LOG_OBJECT(self, "finalize end");
740 }
741
742 static void
743 set_property (GObject * obj,
744     guint prop_id, const GValue * value, GParamSpec * pspec)
745 {
746   GstOmxBaseFilter *self;
747
748   self = GST_OMX_BASE_FILTER (obj);
749
750   switch (prop_id) {
751     case ARG_USE_TIMESTAMPS:
752       self->use_timestamps = g_value_get_boolean (value);
753       break;
754     case ARG_NUM_INPUT_BUFFERS:
755     case ARG_NUM_OUTPUT_BUFFERS:
756     {
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;
762
763       if (G_UNLIKELY (!omx_handle)) {
764         GST_WARNING_OBJECT (self, "no component");
765         break;
766       }
767
768       nBufferCountActual = g_value_get_uint (value);
769
770       G_OMX_INIT_PARAM (param);
771
772       param.nPortIndex = port->port_index;
773       OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, &param);
774
775       if (nBufferCountActual < param.nBufferCountMin) {
776         GST_ERROR_OBJECT (self, "buffer count %lu is less than minimum %lu",
777             nBufferCountActual, param.nBufferCountMin);
778         return;
779       }
780
781       param.nBufferCountActual = nBufferCountActual;
782
783       OMX_SetParameter (omx_handle, OMX_IndexParamPortDefinition, &param);
784     }
785       break;
786     default:
787       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
788       break;
789   }
790 }
791
792 static void
793 get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
794 {
795   GstOmxBaseFilter *self;
796
797   self = GST_OMX_BASE_FILTER (obj);
798
799   if (gstomx_get_property_helper (self->gomx, prop_id, value))
800     return;
801
802   switch (prop_id) {
803     case ARG_USE_TIMESTAMPS:
804       g_value_set_boolean (value, self->use_timestamps);
805       break;
806     case ARG_NUM_INPUT_BUFFERS:
807     case ARG_NUM_OUTPUT_BUFFERS:
808     {
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;
813
814       if (G_UNLIKELY (!omx_handle)) {
815         GST_WARNING_OBJECT (self, "no component");
816         g_value_set_uint (value, 0);
817         break;
818       }
819
820       G_OMX_INIT_PARAM (param);
821
822       param.nPortIndex = port->port_index;
823       OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, &param);
824
825       g_value_set_uint (value, param.nBufferCountActual);
826     }
827       break;
828     default:
829       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
830       break;
831   }
832 }
833
834 static void
835 type_base_init (gpointer g_class)
836 {
837 }
838
839 static void
840 type_class_init (gpointer g_class, gpointer class_data)
841 {
842   GObjectClass *gobject_class;
843   GstElementClass *gstelement_class;
844   GstOmxBaseFilterClass *basefilter_class;
845
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);
849
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;
854
855   /* Properties stuff */
856   {
857     gobject_class->set_property = set_property;
858     gobject_class->get_property = get_property;
859
860     gstomx_install_property_helper (gobject_class);
861
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));
866
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));
875
876   }
877 }
878
879 static inline GstFlowReturn
880 push_buffer (GstOmxBaseFilter * self, GstBuffer * buf, OMX_BUFFERHEADERTYPE * omx_buffer)
881 {
882   GstFlowReturn ret = GST_FLOW_OK;
883   GstOmxBaseFilterClass *basefilter_class;
884 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
885   GstEvent *newsegment = NULL;
886   GstFormat format;
887   gboolean update;
888   gdouble rate, arate;
889   gint64 start, stop, pos;
890
891   if (G_UNLIKELY (self->out_need_segment)) {
892     newsegment = g_queue_pop_head (self->segment_queue);
893     if (newsegment) {
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;
899       }
900     }
901   }
902 #endif
903
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);
911       goto leave;
912     }
913   }
914
915   /* set average duration for memsink. need to check */
916   GST_BUFFER_DURATION(buf) = self->duration;
917
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));
921   } else {
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));
924   }
925
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);
932       ret = GST_FLOW_OK;
933       goto leave;
934     } else {
935       self->gomx->previous_ts = GST_BUFFER_TIMESTAMP(buf);
936     }
937   }
938
939   ret = gst_pad_push (self->srcpad, buf);
940
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++;
944   } else {
945     GST_LOG_OBJECT (self, "gst_pad_push end. ret = %d", ret);
946   }
947
948 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
949   if (G_UNLIKELY (self->out_need_segment)) {
950     if (newsegment) {
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;
954     }
955   }
956 #endif
957
958 leave:
959   return ret;
960 }
961
962 static void
963 output_loop (gpointer data)
964 {
965   GstPad *pad;
966   GOmxCore *gomx;
967   GOmxPort *out_port;
968   GstOmxBaseFilter *self;
969   GstFlowReturn ret = GST_FLOW_OK;
970   pad = data;
971   self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
972   gomx = self->gomx;
973
974   GST_LOG_OBJECT (self, "begin");
975
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)
978     goto leave;
979
980   if (!self->ready) {
981     g_error ("not ready");
982     return;
983   }
984
985   out_port = self->out_port;
986
987   if (out_port->flushing == TRUE) {
988     GST_WARNING("port is on flushing. go to leave");
989     goto leave;
990   }
991
992   if (G_LIKELY (out_port->enabled)) {
993     OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
994
995     GST_LOG_OBJECT (self, "request buffer");
996     omx_buffer = g_omx_port_request_buffer (out_port);
997
998     GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);
999
1000     if (G_UNLIKELY (!omx_buffer)) {
1001       GST_WARNING_OBJECT (self, "null buffer: leaving");
1002
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");
1006         ret = GST_FLOW_OK;
1007         goto leave;
1008       }
1009
1010       ret = GST_FLOW_WRONG_STATE;
1011       goto leave;
1012     }
1013
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;
1018     }
1019 #endif
1020
1021     log_buffer (self, omx_buffer, "output_loop");
1022
1023     if (G_LIKELY (omx_buffer->nFilledLen > 0)) {
1024       GstBuffer *buf;
1025
1026 #if 1
1027             /** @todo remove this check */
1028       if (G_LIKELY (self->in_port->enabled)) {
1029         GstCaps *caps = NULL;
1030
1031         caps = gst_pad_get_negotiated_caps (self->srcpad);
1032
1033         if (!caps) {
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);
1038         } else {
1039           GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps);
1040           gst_caps_unref (caps);
1041         }
1042       }
1043 #endif
1044
1045       /* buf is always null when the output buffer pointer isn't shared. */
1046       buf = omx_buffer->pAppPrivate;
1047
1048             /** @todo we need to move all the caps handling to one single
1049              * place, in the output loop probably. */
1050
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;
1055
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);
1060         }
1061
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;
1069
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);
1073           goto leave;
1074         }
1075
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);
1079
1080         gst_structure_get_int(structure, "width", &width);
1081         gst_structure_get_int(structure, "height", &height);
1082
1083
1084         if(self->out_port->core->component_vendor == GOMX_VENDOR_SLSI_EXYNOS)
1085         {
1086           gint buffer_index = 0;
1087
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);
1091             goto leave;
1092           }
1093
1094           outbuf = (SCMN_IMGB*)(omx_buffer->pBuffer);
1095
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;
1102             }
1103           }
1104         } /* GOMX_VENDOR_SLSI_EXYNOS case */
1105         else if(self->out_port->core->component_vendor == GOMX_VENDOR_SLSI_SEC)
1106         {
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);
1110             goto leave;
1111           }
1112
1113           outbuf = (SCMN_IMGB*)(omx_buffer->pBuffer);
1114         } /* GOMX_VENDOR_SLSI_SEC case */
1115         else
1116         {
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);
1118           goto leave;
1119         }
1120
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);
1127         }
1128
1129         if (G_LIKELY((width > 0) && (height > 0))) {
1130           /* MODIFICATION: handle gstomxbuffer unref */
1131           gstomx_buf = gst_omx_buffer_new(self);
1132
1133           gstomx_buf->omx_buffer = omx_buffer;
1134           gstomx_buf->buffer_direction = GSTOMX_BUFFER_OUTPUT;
1135           buf =(GstBuffer *)gstomx_buf;
1136         } else {
1137           GST_ERROR_OBJECT (self, "invalid buffer size");
1138           ret = GST_FLOW_UNEXPECTED;
1139           goto leave;
1140         }
1141
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");
1150         }
1151
1152         GST_BUFFER_DATA(buf) = outbuf->a[0]; // we can not free this.
1153         outbuf->tz_enable = 0;
1154
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));
1159
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);
1164         }
1165         gst_buffer_set_caps(buf, new_caps);
1166         gst_caps_unref (new_caps);
1167
1168         /* MODIFICATION: check live output buffer count */
1169         g_atomic_int_inc(&self->num_live_buffers);
1170
1171         ret = push_buffer (self, buf, omx_buffer);
1172
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);
1180         }
1181
1182         omx_buffer->pAppPrivate = NULL;
1183         omx_buffer->pBuffer = NULL;
1184
1185         ret = push_buffer (self, buf, omx_buffer);
1186
1187       } else {
1188 /* [CONDITION 5] the First buffers in Output buffer share mode on */
1189
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);
1196
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);
1205           }
1206
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;
1214             }
1215           }
1216
1217           ret = push_buffer (self, buf, omx_buffer);
1218         } else {
1219           GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %lu",
1220               omx_buffer->nFilledLen);
1221         }
1222       }
1223     } else {
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");
1228       } else {
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);
1232       }
1233     }
1234
1235     if (self->out_port->shared_buffer &&
1236         !omx_buffer->pBuffer && omx_buffer->nOffset == 0) {
1237       GstBuffer *buf;
1238       GstFlowReturn result;
1239
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);
1244
1245       if (G_LIKELY (result == GST_FLOW_OK)) {
1246         omx_buffer->pAppPrivate = buf;
1247
1248         omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
1249         omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
1250       } else {
1251         GST_WARNING_OBJECT (self,
1252             "could not pad allocate buffer, using malloc");
1253         omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen);
1254       }
1255     }
1256
1257     if (self->out_port->shared_buffer && !omx_buffer->pBuffer) {
1258       GST_ERROR_OBJECT (self, "no input buffer to share");
1259     }
1260
1261     if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
1262       GST_WARNING_OBJECT (self, "got eos");
1263
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);
1266
1267       gst_pad_push_event (self->srcpad, gst_event_new_eos ());
1268       omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
1269       ret = GST_FLOW_UNEXPECTED;
1270     }
1271
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. */
1276       goto leave;
1277     } else {
1278       omx_buffer->nFilledLen = 0;
1279       GST_LOG_OBJECT (self, "release_buffer");
1280       g_omx_port_release_buffer (out_port, omx_buffer);
1281     }
1282
1283   } else {
1284      /* out_port->enabled == FLASE */
1285
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);
1290
1291       ret = GST_FLOW_OK;
1292     }
1293   }
1294
1295 leave:
1296
1297   self->last_pad_push_return = ret;
1298
1299   if (gomx->omx_error != OMX_ErrorNone)
1300     ret = GST_FLOW_ERROR;
1301
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);
1305   }
1306
1307   GST_LOG_OBJECT (self, "end");
1308
1309   gst_object_unref (self);
1310 }
1311
1312 static GstFlowReturn
1313 pad_chain (GstPad * pad, GstBuffer * buf)
1314 {
1315   GOmxCore *gomx;
1316   GOmxPort *in_port;
1317   GstOmxBaseFilter *self;
1318   GstOmxBaseFilterClass *basefilter_class;
1319   GstFlowReturn ret = GST_FLOW_OK;
1320   GstBuffer *adapter_buf = NULL;
1321
1322   self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
1323
1324   gomx = self->gomx;
1325
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++;
1330   } else {
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);
1333   }
1334
1335   /* STATE_TUNING */
1336   if (!self->use_state_tuning) {
1337     if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded))
1338       omx_change_state(self, GstOmx_LoadedToIdle, NULL, NULL);
1339   }
1340
1341   in_port = self->in_port;
1342
1343   if (G_LIKELY (in_port->enabled)) {
1344     guint buffer_offset = 0;
1345     guint8 *src_data = NULL;
1346     guint src_size = 0;
1347     GstClockTime src_timestamp = 0;
1348     GstClockTime src_duration = 0;
1349
1350     if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle))
1351       omx_change_state(self, GstOmx_IdleToExecuting,in_port, buf);
1352
1353     if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) {
1354       GST_ERROR_OBJECT (self, "Whoa! very wrong");
1355     }
1356
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.");
1360         goto out_flushing;
1361       }
1362     }
1363
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)
1367     {
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);
1372         goto leave;
1373       }
1374     }
1375
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();
1380       }
1381
1382       if (GST_BUFFER_IS_DISCONT(buf))
1383       {
1384         GST_INFO_OBJECT (self, "got GST_BUFFER_IS_DISCONT.");
1385         gst_adapter_clear(self->adapter);
1386       }
1387
1388       gst_adapter_push(self->adapter, buf);
1389
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.");
1393         goto leave;
1394       }
1395
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);
1399       }
1400
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;
1405     } else {
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);
1410     }
1411
1412     while (G_LIKELY (buffer_offset < src_size)) {
1413       OMX_BUFFERHEADERTYPE *omx_buffer;
1414
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");
1421                 } else {
1422                     GST_WARNING_OBJECT (self, "go to out_flushing");
1423                   goto out_flushing;
1424                 }
1425       }
1426
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");
1431       } else{
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");
1435       }
1436
1437       GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);
1438
1439       if (G_LIKELY (omx_buffer)) {
1440         log_buffer (self, omx_buffer, "pad_chain");
1441
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;
1445
1446           if (!GST_BUFFER_MALLOCDATA(buf)) {
1447               GST_WARNING_OBJECT (self, "null MALLOCDATA in hw color format. skip this.");
1448               goto out_flushing;
1449           }
1450
1451           inbuf = (SCMN_IMGB*)(GST_BUFFER_MALLOCDATA(buf));
1452
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;
1456
1457             handle_fd = tbm_bo_get_handle (inbuf->bo[0], TBM_DEVICE_MM);
1458             inbuf->fd[0] = handle_fd.u32;
1459
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)
1462             {
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));
1466             }
1467
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]);
1471             else
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]);
1474
1475
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]);
1479
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));
1482
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);
1486
1487           } else {
1488             GST_ERROR_OBJECT (self, "encoder Input buffer has wrong buf_share_method");
1489           }
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;
1501         } else {
1502           omx_buffer->nFilledLen = MIN (src_size - buffer_offset,
1503               omx_buffer->nAllocLen - omx_buffer->nOffset);
1504
1505             memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
1506               src_data + buffer_offset, omx_buffer->nFilledLen);
1507         }
1508
1509         if (self->use_timestamps) {
1510           GstClockTime timestamp_offset = 0;
1511
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);
1515           }
1516
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;
1520           else
1521             omx_buffer->nTimeStamp =
1522               gst_util_uint64_scale_int (src_timestamp +
1523               timestamp_offset, OMX_TICKS_PER_SECOND, GST_SECOND);
1524         }
1525
1526         /* MODIFICATION: hw addr */
1527         if (is_extended_color_format(self, self->in_port)) {
1528           buffer_offset = GST_BUFFER_SIZE (buf);
1529         } else {
1530           buffer_offset += omx_buffer->nFilledLen;
1531         }
1532
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;
1538         }
1539 #endif
1540
1541         GST_LOG_OBJECT (self, "release_buffer");
1542         /* @todo untaint buffer */
1543         g_omx_port_release_buffer (in_port, omx_buffer);
1544       } else {
1545         GST_WARNING_OBJECT (self, "null buffer");
1546         ret = GST_FLOW_WRONG_STATE;
1547         goto out_flushing;
1548       }
1549     }
1550   } else {
1551     GST_WARNING_OBJECT (self, "done");
1552     ret = GST_FLOW_UNEXPECTED;
1553   }
1554
1555   if (!self->in_port->shared_buffer) {
1556     if (self->adapter_size > 0 && adapter_buf) {
1557       gst_buffer_unref (adapter_buf);
1558       adapter_buf = NULL;
1559     } else {
1560       gst_buffer_unref (buf);
1561     }
1562   }
1563
1564 leave:
1565
1566   GST_LOG_OBJECT (self, "end");
1567
1568   return ret;
1569
1570   /* special conditions */
1571 out_flushing:
1572   {
1573     const gchar *error_msg = NULL;
1574
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));
1577
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";
1583     }
1584
1585     if (error_msg) {
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;
1591       } else {
1592         GST_ERROR_OBJECT (self, "GST_ELEMENT_ERROR is already posted. skip this (%s)", error_msg);
1593       }
1594     }
1595
1596     if (self->adapter_size > 0 && adapter_buf) {
1597       gst_buffer_unref (adapter_buf);
1598       adapter_buf = NULL;
1599     } else {
1600       gst_buffer_unref (buf);
1601     }
1602
1603     goto leave;
1604   }
1605 }
1606
1607 static gboolean
1608 pad_event (GstPad * pad, GstEvent * event)
1609 {
1610   GstOmxBaseFilter *self;
1611   GOmxCore *gomx;
1612   GOmxPort *in_port;
1613   gboolean ret = TRUE;
1614
1615   self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
1616   gomx = self->gomx;
1617   in_port = self->in_port;
1618
1619   GST_LOG_OBJECT (self, "begin");
1620
1621   GST_INFO_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
1622
1623   if (self->pad_event) {
1624     if (!self->pad_event(pad, event))
1625       return TRUE;
1626   }
1627
1628   switch (GST_EVENT_TYPE (event)) {
1629     case GST_EVENT_EOS:
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;
1635
1636       if (self->ready && self->last_pad_push_return == GST_FLOW_OK)
1637       {
1638         /* send buffer with eos flag */
1639                 /** @todo move to util */
1640                      
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)
1643         {
1644           OMX_BUFFERHEADERTYPE *omx_buffer;
1645
1646           GST_LOG_OBJECT (self, "request buffer");
1647           omx_buffer = g_omx_port_request_buffer (in_port);
1648
1649           if (G_LIKELY (omx_buffer))
1650           {
1651             if (gomx->codec_type == GSTOMX_CODECTYPE_AUDIO_DEC)
1652             {
1653               if (self->adapter_size > 0 && self->adapter) {
1654                 guint src_len = 0;
1655                 GstBuffer *adapter_buf = NULL;
1656
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;
1667                 }
1668                 gst_adapter_clear(self->adapter);
1669               }
1670             }
1671             else if (gomx->codec_type == GSTOMX_CODECTYPE_VIDEO_ENC)
1672             {
1673               SCMN_IMGB* inbuf = NULL;
1674               omx_buffer->pBuffer = (OMX_U8*) g_malloc(sizeof(SCMN_IMGB));
1675
1676               memcpy(omx_buffer->pBuffer, &self->eos_buffer, sizeof(SCMN_IMGB));
1677               inbuf = (SCMN_IMGB*)omx_buffer->pBuffer;
1678
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;
1683             }
1684             else if (gomx->codec_type == GSTOMX_CODECTYPE_VIDEO_DEC)
1685             {
1686               omx_buffer->nFilledLen = 0;
1687               omx_buffer->pAppPrivate = NULL;
1688             }
1689             omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
1690
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);
1696             break;
1697           }
1698
1699         }
1700       }
1701
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);
1705       break;
1706
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;
1713
1714         g_omx_core_flush_start (gomx);
1715
1716         gst_pad_pause_task (self->srcpad);
1717
1718         GST_WARNING_OBJECT (self, "GST_EVENT_FLUSH_START");
1719
1720         ret = TRUE;
1721       } else {
1722         GST_ERROR_OBJECT (self, "flush start in wrong omx state");
1723         ret = FALSE;
1724       }
1725       break;
1726
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;
1732
1733         g_omx_core_flush_stop (gomx);
1734
1735         if (self->adapter_size > 0 && self->adapter) {
1736           gst_adapter_clear(self->adapter);
1737         }
1738
1739         if (self->ready)
1740           gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
1741
1742         GST_WARNING_OBJECT (self, "GST_EVENT_FLUSH_STOP");
1743         ret = TRUE;
1744       } else {
1745         GST_ERROR_OBJECT (self, "flush start in wrong omx state");
1746         ret = FALSE;
1747       }
1748       break;
1749
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;
1756       } else {
1757         ret = gst_pad_push_event (self->srcpad, event);
1758       }
1759 #else
1760       GST_WARNING_OBJECT (self, "GST_EVENT_NEWSEGMENT");
1761       ret = gst_pad_push_event (self->srcpad, event);
1762 #endif
1763       break;
1764
1765     default:
1766       ret = gst_pad_push_event (self->srcpad, event);
1767       break;
1768   }
1769
1770   GST_LOG_OBJECT (self, "end");
1771
1772   return ret;
1773 }
1774
1775 static gboolean
1776 activate_push (GstPad * pad, gboolean active)
1777 {
1778   gboolean result = TRUE;
1779   GstOmxBaseFilter *self;
1780
1781   self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
1782
1783   if (active) {
1784     GST_DEBUG_OBJECT (self, "activate");
1785     /* task may carry on */
1786     g_atomic_int_set (&self->last_pad_push_return, GST_FLOW_OK);
1787
1788     /* we do not start the task yet if the pad is not connected */
1789     if (gst_pad_is_linked (pad)) {
1790       if (self->ready) {
1791                 /** @todo link callback function also needed */
1792         g_omx_port_resume (self->in_port);
1793         g_omx_port_resume (self->out_port);
1794
1795         result = gst_pad_start_task (pad, output_loop, pad);
1796       }
1797     }
1798   } else {
1799     GST_DEBUG_OBJECT (self, "deactivate");
1800
1801     /* persuade task to bail out */
1802     g_atomic_int_set (&self->last_pad_push_return, GST_FLOW_WRONG_STATE);
1803
1804     if (self->ready) {
1805             /** @todo disable this until we properly reinitialize the buffers. */
1806 #if 0
1807       /* flush all buffers */
1808       OMX_SendCommand (self->gomx->omx_handle, OMX_CommandFlush, OMX_ALL, NULL);
1809 #endif
1810
1811       /* unlock loops */
1812       g_omx_port_pause (self->in_port);
1813       g_omx_port_pause (self->out_port);
1814     }
1815
1816     /* make sure streaming finishes */
1817     result = gst_pad_stop_task (pad);
1818   }
1819
1820   gst_object_unref (self);
1821
1822   return result;
1823 }
1824
1825 static void
1826 instance_init (GstElement *element)
1827 {
1828   GstOmxBaseFilter *self;
1829
1830   self = GST_OMX_BASE_FILTER (element);
1831
1832   GST_WARNING_OBJECT (self, "begin");
1833
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;
1839
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 */
1843
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;
1847
1848 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
1849   /* MODIFICATION : handling new segment event */
1850   self->segment_queue = g_queue_new ();
1851 #endif
1852   GST_LOG_OBJECT (self, "end");
1853 }
1854
1855 static void
1856 type_instance_init (GTypeInstance * instance, gpointer g_class)
1857 {
1858   GstOmxBaseFilter *self;
1859   GstElementClass *element_class;
1860
1861   element_class = GST_ELEMENT_CLASS (g_class);
1862
1863   self = GST_OMX_BASE_FILTER (instance);
1864
1865   GST_WARNING_OBJECT (self, "begin");
1866
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;
1872
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 */
1876
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 ();
1884
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;
1888
1889   self->sinkpad =
1890       gst_pad_new_from_template (gst_element_class_get_pad_template
1891       (element_class, "sink"), "sink");
1892
1893   gst_pad_set_chain_function (self->sinkpad, pad_chain);
1894   gst_pad_set_event_function (self->sinkpad, pad_event);
1895
1896   self->srcpad =
1897       gst_pad_new_from_template (gst_element_class_get_pad_template
1898       (element_class, "src"), "src");
1899
1900   gst_pad_set_activatepush_function (self->srcpad, activate_push);
1901
1902   gst_pad_use_fixed_caps (self->srcpad);
1903
1904   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1905   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1906
1907 #ifdef GSTOMX_HANDLE_NEW_SEGMENT
1908     /* MODIFICATION : handling new segment event */
1909     self->segment_queue = g_queue_new ();
1910 #endif
1911
1912   GST_LOG_OBJECT (self, "end");
1913 }
1914
1915 static void
1916 omx_interface_init (GstImplementsInterfaceClass * klass)
1917 {
1918 }
1919
1920 static gboolean
1921 interface_supported (GstImplementsInterface * iface, GType type)
1922 {
1923   g_assert (type == GST_TYPE_OMX);
1924   return TRUE;
1925 }
1926
1927 static void
1928 interface_init (GstImplementsInterfaceClass * klass)
1929 {
1930   klass->supported = interface_supported;
1931 }
1932
1933 static void
1934 init_interfaces (GType type)
1935 {
1936   GInterfaceInfo *iface_info;
1937   GInterfaceInfo *omx_info;
1938
1939
1940   iface_info = g_new0 (GInterfaceInfo, 1);
1941   iface_info->interface_init = (GInterfaceInitFunc) interface_init;
1942
1943   g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, iface_info);
1944   g_free (iface_info);
1945
1946   omx_info = g_new0 (GInterfaceInfo, 1);
1947   omx_info->interface_init = (GInterfaceInitFunc) omx_interface_init;
1948
1949   g_type_add_interface_static (type, GST_TYPE_OMX, omx_info);
1950   g_free (omx_info);
1951 }