enabling omx decoder
[platform/upstream/gstreamer.git] / omx / gstomxvideodec.c
1 /*
2  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
4  * Copyright (C) 2013, Collabora Ltd.
5  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation
10  * version 2.1 of the License.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gst/gst.h>
28
29 #if defined (USE_OMX_TARGET_RPI) && defined(__GNUC__)
30 #ifndef __VCCOREVER__
31 #define __VCCOREVER__ 0x04000000
32 #endif
33
34 #pragma GCC diagnostic push
35 #pragma GCC diagnostic ignored "-Wredundant-decls"
36 #pragma GCC optimize ("gnu89-inline")
37 #endif
38
39 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
40 #include <gst/gl/gl.h>
41 #include <gst/gl/egl/gsteglimagememory.h>
42 #endif
43
44 #if defined (USE_OMX_TARGET_RPI) && defined(__GNUC__)
45 #pragma GCC reset_options
46 #pragma GCC diagnostic pop
47 #endif
48
49 //#define CODEC_DEC_OUTPUT_DUMP
50 #include <stdio.h>
51 #include <string.h>
52
53 #include "gstomxbufferpool.h"
54 #include "gstomxvideo.h"
55 #include "gstomxvideodec.h"
56
57 GST_DEBUG_CATEGORY_STATIC (gst_omx_video_dec_debug_category);
58 #define GST_CAT_DEFAULT gst_omx_video_dec_debug_category
59
60 /* prototypes */
61 static void gst_omx_video_dec_finalize (GObject * object);
62
63 static GstStateChangeReturn
64 gst_omx_video_dec_change_state (GstElement * element,
65     GstStateChange transition);
66
67 static gboolean gst_omx_video_dec_open (GstVideoDecoder * decoder);
68 static gboolean gst_omx_video_dec_close (GstVideoDecoder * decoder);
69 static gboolean gst_omx_video_dec_start (GstVideoDecoder * decoder);
70 static gboolean gst_omx_video_dec_stop (GstVideoDecoder * decoder);
71 static gboolean gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
72     GstVideoCodecState * state);
73 static gboolean gst_omx_video_dec_flush (GstVideoDecoder * decoder);
74 static GstFlowReturn gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
75     GstVideoCodecFrame * frame);
76 static GstFlowReturn gst_omx_video_dec_finish (GstVideoDecoder * decoder);
77 static gboolean gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec,
78     GstQuery * query);
79
80 static GstFlowReturn gst_omx_video_dec_drain (GstOMXVideoDec * self);
81
82 static OMX_ERRORTYPE gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec *
83     self);
84 static OMX_ERRORTYPE gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec
85     * self);
86
87 enum
88 {
89   PROP_0
90 };
91
92 /* class initialization */
93
94 #define DEBUG_INIT \
95   GST_DEBUG_CATEGORY_INIT (gst_omx_video_dec_debug_category, "omxvideodec", 0, \
96       "debug category for gst-omx video decoder base class");
97
98
99 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoDec, gst_omx_video_dec,
100     GST_TYPE_VIDEO_DECODER, DEBUG_INIT);
101
102 static void
103 gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass)
104 {
105   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
106   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
107   GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
108
109   gobject_class->finalize = gst_omx_video_dec_finalize;
110
111   element_class->change_state =
112       GST_DEBUG_FUNCPTR (gst_omx_video_dec_change_state);
113
114   video_decoder_class->open = GST_DEBUG_FUNCPTR (gst_omx_video_dec_open);
115   video_decoder_class->close = GST_DEBUG_FUNCPTR (gst_omx_video_dec_close);
116   video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_dec_start);
117   video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_dec_stop);
118   video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_video_dec_flush);
119   video_decoder_class->set_format =
120       GST_DEBUG_FUNCPTR (gst_omx_video_dec_set_format);
121   video_decoder_class->handle_frame =
122       GST_DEBUG_FUNCPTR (gst_omx_video_dec_handle_frame);
123   video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_dec_finish);
124   video_decoder_class->decide_allocation =
125       GST_DEBUG_FUNCPTR (gst_omx_video_dec_decide_allocation);
126
127   klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER;
128   klass->cdata.default_src_template_caps =
129 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
130       GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
131       "RGBA") "; "
132 #endif
133       "video/x-raw, "
134       "width = " GST_VIDEO_SIZE_RANGE ", "
135       "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE;
136 }
137
138 static void
139 gst_omx_video_dec_init (GstOMXVideoDec * self)
140 {
141   gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
142   gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
143       (self), TRUE);
144   GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (self));
145
146   g_mutex_init (&self->drain_lock);
147   g_cond_init (&self->drain_cond);
148
149 #ifdef GST_TIZEN_MODIFICATION
150   self->hTBMBufMgr = NULL;
151   self->drm_fd = -1;
152 #endif
153 }
154
155 static gboolean
156 gst_omx_video_dec_open (GstVideoDecoder * decoder)
157 {
158   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
159   GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
160   gint in_port_index, out_port_index;
161
162   GST_DEBUG_OBJECT (self, "Opening decoder");
163
164   self->dec =
165       gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
166       klass->cdata.component_name, klass->cdata.component_role,
167       klass->cdata.hacks);
168   self->started = FALSE;
169
170   if (!self->dec)
171     return FALSE;
172
173   if (gst_omx_component_get_state (self->dec,
174           GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
175     return FALSE;
176
177   in_port_index = klass->cdata.in_port_index;
178   out_port_index = klass->cdata.out_port_index;
179
180   if (in_port_index == -1 || out_port_index == -1) {
181     OMX_PORT_PARAM_TYPE param;
182     OMX_ERRORTYPE err;
183
184     GST_OMX_INIT_STRUCT (&param);
185
186     err =
187         gst_omx_component_get_parameter (self->dec, OMX_IndexParamVideoInit,
188         &param);
189     if (err != OMX_ErrorNone) {
190       GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
191           gst_omx_error_to_string (err), err);
192       /* Fallback */
193       in_port_index = 0;
194       out_port_index = 1;
195     } else {
196       GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
197           (guint) param.nPorts, (guint) param.nStartPortNumber);
198       in_port_index = param.nStartPortNumber + 0;
199       out_port_index = param.nStartPortNumber + 1;
200     }
201   }
202   self->dec_in_port = gst_omx_component_add_port (self->dec, in_port_index);
203   self->dec_out_port = gst_omx_component_add_port (self->dec, out_port_index);
204
205   if (!self->dec_in_port || !self->dec_out_port)
206     return FALSE;
207
208 #ifdef GST_TIZEN_MODIFICATION
209
210    self->hTBMBufMgr = tbm_bufmgr_init(self->drm_fd);
211    if(self->hTBMBufMgr == NULL){
212     GST_ERROR_OBJECT (self, "TBM initialization failed.");
213     return FALSE;
214    }
215 #endif
216   GST_DEBUG_OBJECT (self, "Opened decoder");
217
218 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
219   GST_DEBUG_OBJECT (self, "Opening EGL renderer");
220   self->egl_render =
221       gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
222       "OMX.broadcom.egl_render", NULL, klass->cdata.hacks);
223
224   if (!self->egl_render)
225     return FALSE;
226
227   if (gst_omx_component_get_state (self->egl_render,
228           GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
229     return FALSE;
230
231   {
232     OMX_PORT_PARAM_TYPE param;
233     OMX_ERRORTYPE err;
234
235     GST_OMX_INIT_STRUCT (&param);
236
237     err =
238         gst_omx_component_get_parameter (self->egl_render,
239         OMX_IndexParamVideoInit, &param);
240     if (err != OMX_ErrorNone) {
241       GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
242           gst_omx_error_to_string (err), err);
243       /* Fallback */
244       in_port_index = 0;
245       out_port_index = 1;
246     } else {
247       GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u", param.nPorts,
248           param.nStartPortNumber);
249       in_port_index = param.nStartPortNumber + 0;
250       out_port_index = param.nStartPortNumber + 1;
251     }
252   }
253
254   self->egl_in_port =
255       gst_omx_component_add_port (self->egl_render, in_port_index);
256   self->egl_out_port =
257       gst_omx_component_add_port (self->egl_render, out_port_index);
258
259   if (!self->egl_in_port || !self->egl_out_port)
260     return FALSE;
261
262   GST_DEBUG_OBJECT (self, "Opened EGL renderer");
263 #endif
264
265   return TRUE;
266 }
267
268 static gboolean
269 gst_omx_video_dec_shutdown (GstOMXVideoDec * self)
270 {
271   OMX_STATETYPE state;
272
273   GST_DEBUG_OBJECT (self, "Shutting down decoder");
274
275 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
276   state = gst_omx_component_get_state (self->egl_render, 0);
277   if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
278     if (state > OMX_StateIdle) {
279       gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
280       gst_omx_component_set_state (self->dec, OMX_StateIdle);
281       gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
282       gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
283     }
284     gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
285     gst_omx_component_set_state (self->dec, OMX_StateLoaded);
286
287     gst_omx_port_deallocate_buffers (self->dec_in_port);
288     gst_omx_video_dec_deallocate_output_buffers (self);
289     gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
290     if (state > OMX_StateLoaded) {
291       gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
292       gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
293     }
294   }
295
296   /* Otherwise we didn't use EGL and just fall back to 
297    * shutting down the decoder */
298 #endif
299
300   state = gst_omx_component_get_state (self->dec, 0);
301   if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
302     if (state > OMX_StateIdle) {
303       gst_omx_component_set_state (self->dec, OMX_StateIdle);
304       gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
305     }
306     gst_omx_component_set_state (self->dec, OMX_StateLoaded);
307     gst_omx_port_deallocate_buffers (self->dec_in_port);
308     gst_omx_video_dec_deallocate_output_buffers (self);
309     if (state > OMX_StateLoaded)
310       gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
311   }
312
313 #ifdef GST_TIZEN_MODIFICATION
314    /* uninitialize tbm buffer manager */
315    if(self->hTBMBufMgr != NULL){
316     tbm_bufmgr_deinit(self->hTBMBufMgr);
317     self->hTBMBufMgr = NULL;
318    }
319
320    if(self->drm_fd != -1) {
321        GST_DEBUG_OBJECT (self, "close drm fd");
322        close(self->drm_fd);
323        self->drm_fd = -1;
324    }
325 #endif
326
327   return TRUE;
328 }
329
330 static gboolean
331 gst_omx_video_dec_close (GstVideoDecoder * decoder)
332 {
333   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
334
335   GST_DEBUG_OBJECT (self, "Closing decoder");
336
337   if (!gst_omx_video_dec_shutdown (self))
338     return FALSE;
339
340   self->dec_in_port = NULL;
341   self->dec_out_port = NULL;
342   if (self->dec)
343     gst_omx_component_free (self->dec);
344   self->dec = NULL;
345
346 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
347   self->egl_in_port = NULL;
348   self->egl_out_port = NULL;
349   if (self->egl_render)
350     gst_omx_component_free (self->egl_render);
351   self->egl_render = NULL;
352 #endif
353
354   self->started = FALSE;
355
356   GST_DEBUG_OBJECT (self, "Closed decoder");
357
358   return TRUE;
359 }
360
361 static void
362 gst_omx_video_dec_finalize (GObject * object)
363 {
364   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (object);
365
366   g_mutex_clear (&self->drain_lock);
367   g_cond_clear (&self->drain_cond);
368
369   G_OBJECT_CLASS (gst_omx_video_dec_parent_class)->finalize (object);
370 }
371
372 static GstStateChangeReturn
373 gst_omx_video_dec_change_state (GstElement * element, GstStateChange transition)
374 {
375   GstOMXVideoDec *self;
376   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
377
378   g_return_val_if_fail (GST_IS_OMX_VIDEO_DEC (element),
379       GST_STATE_CHANGE_FAILURE);
380   self = GST_OMX_VIDEO_DEC (element);
381
382   switch (transition) {
383     case GST_STATE_CHANGE_NULL_TO_READY:
384       break;
385     case GST_STATE_CHANGE_READY_TO_PAUSED:
386       self->downstream_flow_ret = GST_FLOW_OK;
387       self->draining = FALSE;
388       self->started = FALSE;
389       break;
390     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
391       break;
392     case GST_STATE_CHANGE_PAUSED_TO_READY:
393       if (self->dec_in_port)
394         gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
395       if (self->dec_out_port)
396         gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
397 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
398       if (self->egl_in_port)
399         gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
400       if (self->egl_out_port)
401         gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
402 #endif
403
404       g_mutex_lock (&self->drain_lock);
405       self->draining = FALSE;
406       g_cond_broadcast (&self->drain_cond);
407       g_mutex_unlock (&self->drain_lock);
408       break;
409     default:
410       break;
411   }
412
413   if (ret == GST_STATE_CHANGE_FAILURE)
414     return ret;
415
416   ret =
417       GST_ELEMENT_CLASS (gst_omx_video_dec_parent_class)->change_state
418       (element, transition);
419
420   if (ret == GST_STATE_CHANGE_FAILURE)
421     return ret;
422
423   switch (transition) {
424     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
425       break;
426     case GST_STATE_CHANGE_PAUSED_TO_READY:
427       self->downstream_flow_ret = GST_FLOW_FLUSHING;
428       self->started = FALSE;
429
430       if (!gst_omx_video_dec_shutdown (self))
431         ret = GST_STATE_CHANGE_FAILURE;
432       break;
433     case GST_STATE_CHANGE_READY_TO_NULL:
434       break;
435     default:
436       break;
437   }
438
439   return ret;
440 }
441
442 #ifdef CODEC_DEC_OUTPUT_DUMP /* for decoder output dump */
443 static inline void
444 decoder_output_dump(GstOMXVideoDec *self, MMVideoBuffer *outbuf)
445 {
446   char *temp = (char *)outbuf->data[0];
447   int i = 0;
448   char filename[100]={0};
449   FILE *fp = NULL;
450   int ret =0;
451
452   GST_ERROR_OBJECT (self, "codec dec output dump start. w = %d, h = %d", outbuf->width[0], outbuf->height[0]);
453
454   sprintf(filename, "/tmp/dec_output_dump_%d_%d.yuv", outbuf->stride_width[0], outbuf->height[0]);
455   fp = fopen(filename, "ab");
456
457   for (i = 0; i < outbuf->height[0]; i++) {
458     ret = fwrite(temp, outbuf->width[0], 1, fp);
459     temp += outbuf->stride_width[0];
460   }
461
462   temp = (char *)outbuf->data[1];
463
464   for(i = 0; i < outbuf->height[1]; i++) {
465    ret = fwrite(temp, outbuf->width[1], 1, fp);
466     temp += outbuf->stride_width[1];
467   }
468
469   GST_ERROR_OBJECT (self,"codec dec output dumped!! ret = %d", ret);
470   fclose(fp);
471 }
472 #endif
473
474 static gboolean
475 gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self,
476     GstOMXBuffer * inbuf, GstBuffer * outbuf)
477 {
478   GstVideoCodecState *state =
479       gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
480   GstVideoInfo *vinfo = &state->info;
481   OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->dec_out_port->port_def;
482   gboolean ret = FALSE;
483   GstVideoFrame frame;
484
485   if (vinfo->width != port_def->format.video.nFrameWidth ||
486       vinfo->height != port_def->format.video.nFrameHeight) {
487     GST_ERROR_OBJECT (self, "Resolution do not match: port=%ux%u vinfo=%dx%d",
488         (guint) port_def->format.video.nFrameWidth,
489         (guint) port_def->format.video.nFrameHeight,
490         vinfo->width, vinfo->height);
491     goto done;
492   }
493
494   /* Same strides and everything */
495 #if 0  //ENS:a
496   if (gst_buffer_get_size (outbuf) == inbuf->omx_buf->nFilledLen) {
497     GstMapInfo map = GST_MAP_INFO_INIT;
498
499     if (!gst_buffer_map (outbuf, &map, GST_MAP_WRITE)) {
500       GST_ERROR_OBJECT (self, "Failed to map output buffer");
501       goto done;
502     }
503
504     memcpy (map.data,
505         inbuf->omx_buf->pBuffer + inbuf->omx_buf->nOffset,
506         inbuf->omx_buf->nFilledLen);
507     gst_buffer_unmap (outbuf, &map);
508     ret = TRUE;
509     goto done;
510   }
511 #endif  //ENS:a
512
513   /* Different strides */
514   if (gst_video_frame_map (&frame, vinfo, outbuf, GST_MAP_WRITE)) {
515     const guint nstride = port_def->format.video.nStride;
516     const guint nslice = port_def->format.video.nSliceHeight;
517     guint src_stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };
518     guint src_size[GST_VIDEO_MAX_PLANES] = { nstride * nslice, 0, };
519     gint dst_width[GST_VIDEO_MAX_PLANES] = { 0, };
520     gint dst_height[GST_VIDEO_MAX_PLANES] =
521         { GST_VIDEO_INFO_HEIGHT (vinfo), 0, };
522     const guint8 *src;
523     guint p;
524
525     switch (GST_VIDEO_INFO_FORMAT (vinfo)) {
526       case GST_VIDEO_FORMAT_ABGR:
527       case GST_VIDEO_FORMAT_ARGB:
528         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo) * 4;
529         break;
530       case GST_VIDEO_FORMAT_RGB16:
531       case GST_VIDEO_FORMAT_BGR16:
532       case GST_VIDEO_FORMAT_YUY2:
533       case GST_VIDEO_FORMAT_UYVY:
534       case GST_VIDEO_FORMAT_YVYU:
535         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo) * 2;
536         break;
537       case GST_VIDEO_FORMAT_GRAY8:
538         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
539         break;
540       case GST_VIDEO_FORMAT_I420:
541         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
542         src_stride[1] = nstride / 2;
543         src_size[1] = (src_stride[1] * nslice) / 2;
544         dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo) / 2;
545         dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
546         src_stride[2] = nstride / 2;
547         src_size[2] = (src_stride[1] * nslice) / 2;
548         dst_width[2] = GST_VIDEO_INFO_WIDTH (vinfo) / 2;
549         dst_height[2] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
550         break;
551       case GST_VIDEO_FORMAT_NV12:
552         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
553         src_stride[1] = nstride;
554         src_size[1] = src_stride[1] * nslice / 2;
555         dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo);
556         dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
557         break;
558       case GST_VIDEO_FORMAT_NV16:
559         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
560         src_stride[1] = nstride;
561         src_size[1] = src_stride[1] * nslice;
562         dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo);
563         dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo);
564         break;
565       case GST_VIDEO_FORMAT_SN12:
566       case GST_VIDEO_FORMAT_ST12:{
567         GstMemory *mem_imgb = NULL;
568         void *imgb_data = NULL;
569 #ifdef GST_TIZEN_MODIFICATION
570         MMVideoBuffer *mm_vbuffer = NULL;
571         mm_vbuffer = (MMVideoBuffer*)(inbuf->omx_buf->pBuffer);
572         mm_vbuffer->type = MM_VIDEO_BUFFER_TYPE_TBM_BO;
573
574         if (mm_vbuffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
575           GST_LOG_OBJECT (self, "dec output buf: fd[0]:%d  fd[1]:%d fd[2]:%d  w[0]:%d h[0]:%d  buf_share_method:%d",
576                   mm_vbuffer->handle.dmabuf_fd[0], mm_vbuffer->handle.dmabuf_fd[1], mm_vbuffer->handle.dmabuf_fd[2],
577                   mm_vbuffer->width[0], mm_vbuffer->height[0], mm_vbuffer->type);
578         } else if (mm_vbuffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
579           GST_LOG_OBJECT (self, "dec output uses hw addr");
580         } else {
581           GST_WARNING_OBJECT (self, "dec output buf has TBM_BO buf_share_method");
582         }
583 #ifdef CODEC_DEC_OUTPUT_DUMP
584        decoder_output_dump(self, mm_vbuffer);
585 #endif
586 #endif
587         if (gst_buffer_n_memory(outbuf) < 2) {
588             imgb_data = g_malloc0(sizeof(*mm_vbuffer));
589             mem_imgb = gst_memory_new_wrapped(0, imgb_data, sizeof(*mm_vbuffer), 0, sizeof(*mm_vbuffer), imgb_data, g_free);
590             gst_buffer_append_memory(outbuf, mem_imgb);
591         } else {
592             GstMapInfo imgb_info = GST_MAP_INFO_INIT;
593             mem_imgb = gst_buffer_peek_memory(outbuf, 1);
594             gst_memory_map(mem_imgb, &imgb_info, GST_MAP_WRITE);
595             imgb_data = imgb_info.data;
596             gst_memory_unmap(mem_imgb, &imgb_info);
597         }
598 #ifdef GST_TIZEN_MODIFICATION
599         memcpy(imgb_data, mm_vbuffer, sizeof(MMVideoBuffer));
600 #endif
601         ret = TRUE;
602         break;
603     }
604
605       default:
606         g_assert_not_reached ();
607         break;
608     }
609
610     src = inbuf->omx_buf->pBuffer + inbuf->omx_buf->nOffset;
611     for (p = 0; p < GST_VIDEO_INFO_N_PLANES (vinfo); p++) {
612       const guint8 *data;
613       guint8 *dst;
614       guint h;
615
616       dst = GST_VIDEO_FRAME_PLANE_DATA (&frame, p);
617       data = src;
618       for (h = 0; h < dst_height[p]; h++) {
619         memcpy (dst, data, dst_width[p]);
620         dst += GST_VIDEO_INFO_PLANE_STRIDE (vinfo, p);
621         data += src_stride[p];
622       }
623       src += src_size[p];
624     }
625
626     gst_video_frame_unmap (&frame);
627     ret = TRUE;
628   } else {
629     GST_ERROR_OBJECT (self, "Can't map output buffer to frame");
630     goto done;
631   }
632
633 done:
634   if (ret) {
635     GST_BUFFER_PTS (outbuf) =
636         gst_util_uint64_scale (inbuf->omx_buf->nTimeStamp, GST_SECOND,
637         OMX_TICKS_PER_SECOND);
638     if (inbuf->omx_buf->nTickCount != 0)
639       GST_BUFFER_DURATION (outbuf) =
640           gst_util_uint64_scale (inbuf->omx_buf->nTickCount, GST_SECOND,
641           OMX_TICKS_PER_SECOND);
642   }
643
644   gst_video_codec_state_unref (state);
645
646   return ret;
647 }
648
649 static OMX_ERRORTYPE
650 gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
651 {
652   OMX_ERRORTYPE err = OMX_ErrorNone;
653   GstOMXPort *port;
654   GstBufferPool *pool = NULL;
655   GstStructure *config;
656   gboolean eglimage = FALSE, add_videometa = FALSE;
657   GstCaps *caps = NULL;
658   guint min = 0, max = 0;
659   GstVideoCodecState *state =
660       gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
661
662 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
663   port = self->eglimage ? self->egl_out_port : self->dec_out_port;
664 #else
665   port = self->dec_out_port;
666 #endif
667
668   pool = gst_video_decoder_get_buffer_pool (GST_VIDEO_DECODER (self));
669   if (pool) {
670     GstAllocator *allocator;
671
672     config = gst_buffer_pool_get_config (pool);
673     if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min, &max)) {
674       GST_ERROR_OBJECT (self, "Can't get buffer pool params");
675       gst_structure_free (config);
676       err = OMX_ErrorUndefined;
677       goto done;
678     }
679     if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) {
680       GST_ERROR_OBJECT (self, "Can't get buffer pool allocator");
681       gst_structure_free (config);
682       err = OMX_ErrorUndefined;
683       goto done;
684     }
685
686     /* Need at least 2 buffers for anything meaningful */
687     min = MAX (MAX (min, port->port_def.nBufferCountMin), 4);
688     if (max == 0) {
689       max = min;
690     } else if (max < port->port_def.nBufferCountMin || max < 2) {
691       /* Can't use pool because can't have enough buffers */
692       gst_caps_replace (&caps, NULL);
693     } else {
694       min = max;
695     }
696
697     add_videometa = gst_buffer_pool_config_has_option (config,
698         GST_BUFFER_POOL_OPTION_VIDEO_META);
699     gst_structure_free (config);
700
701 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
702     eglimage = self->eglimage && (allocator
703         && g_strcmp0 (allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0);
704 #else
705     /* TODO: Implement something that works for other targets too */
706     eglimage = FALSE;
707 #endif
708     caps = caps ? gst_caps_ref (caps) : NULL;
709
710     GST_DEBUG_OBJECT (self, "Trying to use pool %p with caps %" GST_PTR_FORMAT
711         " and memory type %s", pool, caps,
712         (allocator ? allocator->mem_type : "(null)"));
713   } else {
714     gst_caps_replace (&caps, NULL);
715     min = max = port->port_def.nBufferCountMin;
716     GST_DEBUG_OBJECT (self, "No pool available, not negotiated yet");
717   }
718
719 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
720   /* Will retry without EGLImage */
721   if (self->eglimage && !eglimage) {
722     GST_DEBUG_OBJECT (self,
723         "Wanted to use EGLImage but downstream doesn't support it");
724     err = OMX_ErrorUndefined;
725     goto done;
726   }
727 #endif
728
729   if (caps)
730     self->out_port_pool =
731         gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->dec, port);
732
733 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
734   if (eglimage) {
735     GList *buffers = NULL;
736     GList *images = NULL;
737     gint i;
738     GstBufferPoolAcquireParams params = { 0, };
739     EGLDisplay egl_display = EGL_NO_DISPLAY;
740
741     GST_DEBUG_OBJECT (self, "Trying to allocate %d EGLImages", min);
742
743     for (i = 0; i < min; i++) {
744       GstBuffer *buffer;
745       GstMemory *mem;
746
747       if (gst_buffer_pool_acquire_buffer (pool, &buffer, &params) != GST_FLOW_OK
748           || gst_buffer_n_memory (buffer) != 1
749           || !(mem = gst_buffer_peek_memory (buffer, 0))
750           || g_strcmp0 (mem->allocator->mem_type,
751               GST_EGL_IMAGE_MEMORY_TYPE) != 0) {
752         GST_INFO_OBJECT (self, "Failed to allocated %d-th EGLImage", i);
753         g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
754         g_list_free (images);
755         buffers = NULL;
756         images = NULL;
757         /* TODO: For non-RPi targets we want to use the normal memory code below */
758         /* Retry without EGLImage */
759         err = OMX_ErrorUndefined;
760         goto done;
761       }
762
763       buffers = g_list_append (buffers, buffer);
764       gst_egl_image_memory_set_orientation (mem,
765           GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_FLIP);
766       images = g_list_append (images, gst_egl_image_memory_get_image (mem));
767       if (egl_display == EGL_NO_DISPLAY)
768         egl_display = gst_egl_image_memory_get_display (mem);
769     }
770
771     GST_DEBUG_OBJECT (self, "Allocated %d EGLImages successfully", min);
772
773     /* Everything went fine? */
774     if (eglimage) {
775       GST_DEBUG_OBJECT (self, "Setting EGLDisplay");
776       self->egl_out_port->port_def.format.video.pNativeWindow = egl_display;
777       err =
778           gst_omx_port_update_port_definition (self->egl_out_port,
779           &self->egl_out_port->port_def);
780       if (err != OMX_ErrorNone) {
781         GST_INFO_OBJECT (self,
782             "Failed to set EGLDisplay on port: %s (0x%08x)",
783             gst_omx_error_to_string (err), err);
784         g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
785         g_list_free (images);
786         /* TODO: For non-RPi targets we want to use the normal memory code below */
787         /* Retry without EGLImage */
788         goto done;
789       } else {
790         GList *l;
791
792         if (min != port->port_def.nBufferCountActual) {
793           err = gst_omx_port_update_port_definition (port, NULL);
794           if (err == OMX_ErrorNone) {
795             port->port_def.nBufferCountActual = min;
796             err = gst_omx_port_update_port_definition (port, &port->port_def);
797           }
798
799           if (err != OMX_ErrorNone) {
800             GST_INFO_OBJECT (self,
801                 "Failed to configure %u output buffers: %s (0x%08x)", min,
802                 gst_omx_error_to_string (err), err);
803             g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
804             g_list_free (images);
805             /* TODO: For non-RPi targets we want to use the normal memory code below */
806             /* Retry without EGLImage */
807
808             goto done;
809           }
810         }
811
812         if (!gst_omx_port_is_enabled (port)) {
813           err = gst_omx_port_set_enabled (port, TRUE);
814           if (err != OMX_ErrorNone) {
815             GST_INFO_OBJECT (self,
816                 "Failed to enable port: %s (0x%08x)",
817                 gst_omx_error_to_string (err), err);
818             g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
819             g_list_free (images);
820             /* TODO: For non-RPi targets we want to use the normal memory code below */
821             /* Retry without EGLImage */
822             goto done;
823           }
824         }
825
826         err = gst_omx_port_use_eglimages (port, images);
827         g_list_free (images);
828
829         if (err != OMX_ErrorNone) {
830           GST_INFO_OBJECT (self,
831               "Failed to pass EGLImages to port: %s (0x%08x)",
832               gst_omx_error_to_string (err), err);
833           g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
834           /* TODO: For non-RPi targets we want to use the normal memory code below */
835           /* Retry without EGLImage */
836           goto done;
837         }
838
839         err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND);
840         if (err != OMX_ErrorNone) {
841           GST_INFO_OBJECT (self,
842               "Failed to wait until port is enabled: %s (0x%08x)",
843               gst_omx_error_to_string (err), err);
844           g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
845           /* TODO: For non-RPi targets we want to use the normal memory code below */
846           /* Retry without EGLImage */
847           goto done;
848         }
849
850         GST_DEBUG_OBJECT (self, "Populating internal buffer pool");
851         GST_OMX_BUFFER_POOL (self->out_port_pool)->other_pool =
852             GST_BUFFER_POOL (gst_object_ref (pool));
853         for (l = buffers; l; l = l->next) {
854           g_ptr_array_add (GST_OMX_BUFFER_POOL (self->out_port_pool)->buffers,
855               l->data);
856         }
857         g_list_free (buffers);
858         /* All good and done, set caps below */
859       }
860     }
861   }
862 #endif
863
864   /* If not using EGLImage or trying to use EGLImage failed */
865   if (!eglimage) {
866     gboolean was_enabled = TRUE;
867
868     if (min != port->port_def.nBufferCountActual) {
869       err = gst_omx_port_update_port_definition (port, NULL);
870       if (err == OMX_ErrorNone) {
871         port->port_def.nBufferCountActual = min;
872         err = gst_omx_port_update_port_definition (port, &port->port_def);
873       }
874
875       if (err != OMX_ErrorNone) {
876         GST_ERROR_OBJECT (self,
877             "Failed to configure %u output buffers: %s (0x%08x)", min,
878             gst_omx_error_to_string (err), err);
879         goto done;
880       }
881     }
882
883     if (!gst_omx_port_is_enabled (port)) {
884       err = gst_omx_port_set_enabled (port, TRUE);
885       if (err != OMX_ErrorNone) {
886         GST_INFO_OBJECT (self,
887             "Failed to enable port: %s (0x%08x)",
888             gst_omx_error_to_string (err), err);
889         goto done;
890       }
891       was_enabled = FALSE;
892     }
893 #ifdef GST_TIZEN_MODIFICATION
894     err = gst_omx_port_tbm_allocate_dec_buffers(port, self->hTBMBufMgr,
895       self->dec_in_port->port_def.format.video.eCompressionFormat);
896 #else
897     err = gst_omx_port_allocate_buffers (port);
898 #endif
899     if (err != OMX_ErrorNone && min > port->port_def.nBufferCountMin) {
900       GST_ERROR_OBJECT (self,
901           "Failed to allocate required number of buffers %d, trying less and copying",
902           min);
903       min = port->port_def.nBufferCountMin;
904
905       if (!was_enabled) {
906         err = gst_omx_port_set_enabled (port, FALSE);
907         if (err != OMX_ErrorNone) {
908           GST_INFO_OBJECT (self,
909               "Failed to disable port again: %s (0x%08x)",
910               gst_omx_error_to_string (err), err);
911           goto done;
912         }
913       }
914
915       if (min != port->port_def.nBufferCountActual) {
916         err = gst_omx_port_update_port_definition (port, NULL);
917         if (err == OMX_ErrorNone) {
918           port->port_def.nBufferCountActual = min;
919           err = gst_omx_port_update_port_definition (port, &port->port_def);
920         }
921
922         if (err != OMX_ErrorNone) {
923           GST_ERROR_OBJECT (self,
924               "Failed to configure %u output buffers: %s (0x%08x)", min,
925               gst_omx_error_to_string (err), err);
926           goto done;
927         }
928       }
929 #ifdef GST_TIZEN_MODIFICATION
930       err = gst_omx_port_tbm_allocate_dec_buffers(port, self->hTBMBufMgr,
931           self->dec_in_port->port_def.format.video.eCompressionFormat);
932 #else
933       err = gst_omx_port_allocate_buffers (port);
934 #endif
935       /* Can't provide buffers downstream in this case */
936       gst_caps_replace (&caps, NULL);
937     }
938
939     if (err != OMX_ErrorNone) {
940       GST_ERROR_OBJECT (self, "Failed to allocate %d buffers: %s (0x%08x)", min,
941           gst_omx_error_to_string (err), err);
942       goto done;
943     }
944
945     if (!was_enabled) {
946       err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND);
947       if (err != OMX_ErrorNone) {
948         GST_ERROR_OBJECT (self,
949             "Failed to wait until port is enabled: %s (0x%08x)",
950             gst_omx_error_to_string (err), err);
951         goto done;
952       }
953     }
954
955
956   }
957
958   err = OMX_ErrorNone;
959
960   if (caps) {
961     config = gst_buffer_pool_get_config (self->out_port_pool);
962
963     if (add_videometa)
964       gst_buffer_pool_config_add_option (config,
965           GST_BUFFER_POOL_OPTION_VIDEO_META);
966
967     gst_buffer_pool_config_set_params (config, caps,
968         self->dec_out_port->port_def.nBufferSize, min, max);
969
970     if (!gst_buffer_pool_set_config (self->out_port_pool, config)) {
971       GST_INFO_OBJECT (self, "Failed to set config on internal pool");
972       gst_object_unref (self->out_port_pool);
973       self->out_port_pool = NULL;
974       goto done;
975     }
976
977     GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = TRUE;
978     /* This now allocates all the buffers */
979     if (!gst_buffer_pool_set_active (self->out_port_pool, TRUE)) {
980       GST_INFO_OBJECT (self, "Failed to activate internal pool");
981       gst_object_unref (self->out_port_pool);
982       self->out_port_pool = NULL;
983     } else {
984       GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = FALSE;
985     }
986   } else if (self->out_port_pool) {
987     gst_object_unref (self->out_port_pool);
988     self->out_port_pool = NULL;
989   }
990
991 done:
992   if (!self->out_port_pool && err == OMX_ErrorNone)
993     GST_DEBUG_OBJECT (self,
994         "Not using our internal pool and copying buffers for downstream");
995
996   if (caps)
997     gst_caps_unref (caps);
998   if (pool)
999     gst_object_unref (pool);
1000   if (state)
1001     gst_video_codec_state_unref (state);
1002
1003   return err;
1004 }
1005
1006 static OMX_ERRORTYPE
1007 gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self)
1008 {
1009   OMX_ERRORTYPE err;
1010
1011   if (self->out_port_pool) {
1012     gst_buffer_pool_set_active (self->out_port_pool, FALSE);
1013 #if 0
1014     gst_buffer_pool_wait_released (self->out_port_pool);
1015 #endif
1016     GST_OMX_BUFFER_POOL (self->out_port_pool)->deactivated = TRUE;
1017     gst_object_unref (self->out_port_pool);
1018     self->out_port_pool = NULL;
1019   }
1020 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1021   err =
1022       gst_omx_port_deallocate_buffers (self->
1023       eglimage ? self->egl_out_port : self->dec_out_port);
1024 #else
1025   err = gst_omx_port_deallocate_buffers (self->dec_out_port);
1026 #endif
1027
1028   return err;
1029 }
1030
1031 static OMX_ERRORTYPE
1032 gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self)
1033 {
1034   GstOMXPort *port;
1035   OMX_ERRORTYPE err;
1036   GstVideoCodecState *state;
1037   OMX_PARAM_PORTDEFINITIONTYPE port_def;
1038   GstVideoFormat format;
1039
1040   /* At this point the decoder output port is disabled */
1041
1042 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1043   {
1044     OMX_STATETYPE egl_state;
1045
1046     if (self->eglimage) {
1047       /* Nothing to do here, we could however fall back to non-EGLImage in theory */
1048       port = self->egl_out_port;
1049       err = OMX_ErrorNone;
1050       goto enable_port;
1051     } else {
1052       /* Set up egl_render */
1053
1054       self->eglimage = TRUE;
1055
1056       gst_omx_port_get_port_definition (self->dec_out_port, &port_def);
1057       GST_VIDEO_DECODER_STREAM_LOCK (self);
1058       state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1059           GST_VIDEO_FORMAT_RGBA, port_def.format.video.nFrameWidth,
1060           port_def.format.video.nFrameHeight, self->input_state);
1061
1062       /* at this point state->caps is NULL */
1063       if (state->caps)
1064         gst_caps_unref (state->caps);
1065       state->caps = gst_video_info_to_caps (&state->info);
1066       gst_caps_set_features (state->caps, 0,
1067           gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, NULL));
1068
1069       /* try to negotiate with caps feature */
1070       if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1071
1072         GST_DEBUG_OBJECT (self,
1073             "Failed to negotiate with feature %s",
1074             GST_CAPS_FEATURE_MEMORY_EGL_IMAGE);
1075
1076         if (state->caps)
1077           gst_caps_replace (&state->caps, NULL);
1078
1079         /* fallback: try to use EGLImage even if it is not in the caps feature */
1080         if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1081           gst_video_codec_state_unref (state);
1082           GST_ERROR_OBJECT (self, "Failed to negotiate RGBA for EGLImage");
1083           GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1084           goto no_egl;
1085         }
1086       }
1087
1088       gst_video_codec_state_unref (state);
1089       GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1090
1091       /* Now link it all together */
1092
1093       err = gst_omx_port_set_enabled (self->egl_in_port, FALSE);
1094       if (err != OMX_ErrorNone)
1095         goto no_egl;
1096
1097       err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
1098       if (err != OMX_ErrorNone)
1099         goto no_egl;
1100
1101       err = gst_omx_port_set_enabled (self->egl_out_port, FALSE);
1102       if (err != OMX_ErrorNone)
1103         goto no_egl;
1104
1105       err = gst_omx_port_wait_enabled (self->egl_out_port, 1 * GST_SECOND);
1106       if (err != OMX_ErrorNone)
1107         goto no_egl;
1108
1109       {
1110 #define OMX_IndexParamBrcmVideoEGLRenderDiscardMode 0x7f0000db
1111         OMX_CONFIG_PORTBOOLEANTYPE discardMode;
1112         memset (&discardMode, 0, sizeof (discardMode));
1113         discardMode.nSize = sizeof (discardMode);
1114         discardMode.nPortIndex = 220;
1115         discardMode.nVersion.nVersion = OMX_VERSION;
1116         discardMode.bEnabled = OMX_FALSE;
1117         if (gst_omx_component_set_parameter (self->egl_render,
1118                 OMX_IndexParamBrcmVideoEGLRenderDiscardMode,
1119                 &discardMode) != OMX_ErrorNone)
1120           goto no_egl;
1121 #undef OMX_IndexParamBrcmVideoEGLRenderDiscardMode
1122       }
1123
1124       err = gst_omx_setup_tunnel (self->dec_out_port, self->egl_in_port);
1125       if (err != OMX_ErrorNone)
1126         goto no_egl;
1127
1128       err = gst_omx_port_set_enabled (self->egl_in_port, TRUE);
1129       if (err != OMX_ErrorNone)
1130         goto no_egl;
1131
1132       err = gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1133       if (err != OMX_ErrorNone)
1134         goto no_egl;
1135
1136       err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
1137       if (err != OMX_ErrorNone)
1138         goto no_egl;
1139
1140       if (gst_omx_component_get_state (self->egl_render,
1141               GST_CLOCK_TIME_NONE) != OMX_StateIdle)
1142         goto no_egl;
1143
1144       err = gst_omx_video_dec_allocate_output_buffers (self);
1145       if (err != OMX_ErrorNone)
1146         goto no_egl;
1147
1148       if (gst_omx_component_set_state (self->egl_render,
1149               OMX_StateExecuting) != OMX_ErrorNone)
1150         goto no_egl;
1151
1152       if (gst_omx_component_get_state (self->egl_render,
1153               GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
1154         goto no_egl;
1155
1156       err =
1157           gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
1158       if (err != OMX_ErrorNone)
1159         goto no_egl;
1160
1161       err =
1162           gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
1163       if (err != OMX_ErrorNone)
1164         goto no_egl;
1165
1166       err =
1167           gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
1168       if (err != OMX_ErrorNone)
1169         goto no_egl;
1170
1171       err = gst_omx_port_populate (self->egl_out_port);
1172       if (err != OMX_ErrorNone)
1173         goto no_egl;
1174
1175       err = gst_omx_port_set_enabled (self->dec_out_port, TRUE);
1176       if (err != OMX_ErrorNone)
1177         goto no_egl;
1178
1179       err = gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
1180       if (err != OMX_ErrorNone)
1181         goto no_egl;
1182
1183
1184       err = gst_omx_port_mark_reconfigured (self->dec_out_port);
1185       if (err != OMX_ErrorNone)
1186         goto no_egl;
1187
1188       err = gst_omx_port_mark_reconfigured (self->egl_out_port);
1189       if (err != OMX_ErrorNone)
1190         goto no_egl;
1191
1192       goto done;
1193     }
1194
1195   no_egl:
1196
1197     gst_omx_port_set_enabled (self->dec_out_port, FALSE);
1198     gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
1199     egl_state = gst_omx_component_get_state (self->egl_render, 0);
1200     if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
1201       if (egl_state > OMX_StateIdle) {
1202         gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1203         gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
1204       }
1205       gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
1206
1207       gst_omx_video_dec_deallocate_output_buffers (self);
1208       gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
1209
1210       if (egl_state > OMX_StateLoaded) {
1211         gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
1212       }
1213     }
1214
1215     /* After this egl_render should be deactivated
1216      * and the decoder's output port disabled */
1217     self->eglimage = FALSE;
1218   }
1219 #endif
1220   port = self->dec_out_port;
1221
1222   /* Update caps */
1223   GST_VIDEO_DECODER_STREAM_LOCK (self);
1224
1225   gst_omx_port_get_port_definition (port, &port_def);
1226   g_assert (port_def.format.video.eCompressionFormat == OMX_VIDEO_CodingUnused);
1227
1228   format =
1229       gst_omx_video_get_format_from_omx (port_def.format.video.eColorFormat);
1230
1231   if (format == GST_VIDEO_FORMAT_UNKNOWN) {
1232     GST_ERROR_OBJECT (self, "Unsupported color format: %d",
1233         port_def.format.video.eColorFormat);
1234     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1235     err = OMX_ErrorUndefined;
1236     goto done;
1237   }
1238
1239   GST_DEBUG_OBJECT (self,
1240       "Setting output state: format %s (%d), width %u, height %u",
1241       gst_video_format_to_string (format),
1242       port_def.format.video.eColorFormat,
1243       (guint) port_def.format.video.nFrameWidth,
1244       (guint) port_def.format.video.nFrameHeight);
1245
1246   state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1247       format, port_def.format.video.nFrameWidth,
1248       port_def.format.video.nFrameHeight, self->input_state);
1249
1250   if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1251     gst_video_codec_state_unref (state);
1252     GST_ERROR_OBJECT (self, "Failed to negotiate");
1253     err = OMX_ErrorUndefined;
1254     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1255     goto done;
1256   }
1257
1258   gst_video_codec_state_unref (state);
1259
1260   GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1261
1262 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1263 enable_port:
1264 #endif
1265   err = gst_omx_video_dec_allocate_output_buffers (self);
1266   if (err != OMX_ErrorNone)
1267     goto done;
1268
1269   err = gst_omx_port_populate (port);
1270   if (err != OMX_ErrorNone)
1271     goto done;
1272
1273   err = gst_omx_port_mark_reconfigured (port);
1274   if (err != OMX_ErrorNone)
1275     goto done;
1276
1277 done:
1278
1279   return err;
1280 }
1281
1282 static void
1283 gst_omx_video_dec_clean_older_frames (GstOMXVideoDec * self,
1284     GstOMXBuffer * buf, GList * frames)
1285 {
1286   GList *l;
1287   GstClockTime timestamp;
1288
1289   timestamp = gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
1290       OMX_TICKS_PER_SECOND);
1291
1292   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
1293     /* We could release all frames stored with pts < timestamp since the
1294      * decoder will likely output frames in display order */
1295     for (l = frames; l; l = l->next) {
1296       GstVideoCodecFrame *tmp = l->data;
1297
1298       if (tmp->pts < timestamp) {
1299         gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
1300         GST_LOG_OBJECT (self,
1301             "discarding ghost frame %p (#%d) PTS:%" GST_TIME_FORMAT " DTS:%"
1302             GST_TIME_FORMAT, tmp, tmp->system_frame_number,
1303             GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
1304       } else {
1305         gst_video_codec_frame_unref (tmp);
1306       }
1307     }
1308   } else {
1309     /* We will release all frames with invalid timestamp because we don't even
1310      * know if they will be output some day. */
1311     for (l = frames; l; l = l->next) {
1312       GstVideoCodecFrame *tmp = l->data;
1313
1314       if (!GST_CLOCK_TIME_IS_VALID (tmp->pts)) {
1315         gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
1316         GST_LOG_OBJECT (self,
1317             "discarding frame %p (#%d) with invalid PTS:%" GST_TIME_FORMAT
1318             " DTS:%" GST_TIME_FORMAT, tmp, tmp->system_frame_number,
1319             GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
1320       } else {
1321         gst_video_codec_frame_unref (tmp);
1322       }
1323     }
1324   }
1325
1326   g_list_free (frames);
1327 }
1328
1329 static GstBuffer *
1330 copy_frame (const GstVideoInfo * info, GstBuffer * outbuf)
1331 {
1332   GstVideoInfo out_info, tmp_info;
1333   GstBuffer *tmpbuf;
1334   GstVideoFrame out_frame, tmp_frame;
1335
1336   out_info = *info;
1337   tmp_info = *info;
1338
1339   tmpbuf = gst_buffer_new_and_alloc (out_info.size);
1340
1341   gst_video_frame_map (&out_frame, &out_info, outbuf, GST_MAP_READ);
1342   gst_video_frame_map (&tmp_frame, &tmp_info, tmpbuf, GST_MAP_WRITE);
1343   gst_video_frame_copy (&tmp_frame, &out_frame);
1344   gst_video_frame_unmap (&out_frame);
1345   gst_video_frame_unmap (&tmp_frame);
1346
1347   gst_buffer_unref (outbuf);
1348
1349   return tmpbuf;
1350 }
1351
1352 static void
1353 gst_omx_video_dec_loop (GstOMXVideoDec * self)
1354 {
1355   GstOMXPort *port;
1356   GstOMXBuffer *buf = NULL;
1357   GstVideoCodecFrame *frame;
1358   GstFlowReturn flow_ret = GST_FLOW_OK;
1359   GstOMXAcquireBufferReturn acq_return;
1360   GstClockTimeDiff deadline;
1361   OMX_ERRORTYPE err;
1362
1363 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1364   port = self->eglimage ? self->egl_out_port : self->dec_out_port;
1365 #else
1366   port = self->dec_out_port;
1367 #endif
1368
1369   acq_return = gst_omx_port_acquire_buffer (port, &buf);
1370   if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
1371     goto component_error;
1372   } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
1373     goto flushing;
1374   } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
1375     goto eos;
1376   }
1377
1378   if (!gst_pad_has_current_caps (GST_VIDEO_DECODER_SRC_PAD (self)) ||
1379       acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1380     GstVideoCodecState *state;
1381     OMX_PARAM_PORTDEFINITIONTYPE port_def;
1382     GstVideoFormat format;
1383
1384     GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
1385
1386     /* Reallocate all buffers */
1387     if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
1388         && gst_omx_port_is_enabled (port)) {
1389       err = gst_omx_port_set_enabled (port, FALSE);
1390       if (err != OMX_ErrorNone)
1391         goto reconfigure_error;
1392
1393       err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
1394       if (err != OMX_ErrorNone)
1395         goto reconfigure_error;
1396
1397       err = gst_omx_video_dec_deallocate_output_buffers (self);
1398       if (err != OMX_ErrorNone)
1399         goto reconfigure_error;
1400
1401       err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
1402       if (err != OMX_ErrorNone)
1403         goto reconfigure_error;
1404     }
1405
1406     if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1407       /* We have the possibility to reconfigure everything now */
1408       err = gst_omx_video_dec_reconfigure_output_port (self);
1409       if (err != OMX_ErrorNone)
1410         goto reconfigure_error;
1411     } else {
1412       /* Just update caps */
1413       GST_VIDEO_DECODER_STREAM_LOCK (self);
1414
1415       gst_omx_port_get_port_definition (port, &port_def);
1416       g_assert (port_def.format.video.eCompressionFormat ==
1417           OMX_VIDEO_CodingUnused);
1418
1419       format =
1420           gst_omx_video_get_format_from_omx (port_def.format.
1421           video.eColorFormat);
1422
1423       if (format == GST_VIDEO_FORMAT_UNKNOWN) {
1424         GST_ERROR_OBJECT (self, "Unsupported color format: %d",
1425             port_def.format.video.eColorFormat);
1426         if (buf)
1427           gst_omx_port_release_buffer (port, buf);
1428         GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1429         goto caps_failed;
1430       }
1431
1432       GST_DEBUG_OBJECT (self,
1433           "Setting output state: format %s (%d), width %u, height %u",
1434           gst_video_format_to_string (format),
1435           port_def.format.video.eColorFormat,
1436           (guint) port_def.format.video.nFrameWidth,
1437           (guint) port_def.format.video.nFrameHeight);
1438
1439       state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1440           format, port_def.format.video.nFrameWidth,
1441           port_def.format.video.nFrameHeight, self->input_state);
1442
1443       /* Take framerate and pixel-aspect-ratio from sinkpad caps */
1444
1445       if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1446         if (buf)
1447           gst_omx_port_release_buffer (port, buf);
1448         gst_video_codec_state_unref (state);
1449         goto caps_failed;
1450       }
1451
1452       gst_video_codec_state_unref (state);
1453
1454       GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1455     }
1456
1457     /* Now get a buffer */
1458     if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
1459       return;
1460     }
1461   }
1462
1463   g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
1464
1465   /* This prevents a deadlock between the srcpad stream
1466    * lock and the videocodec stream lock, if ::reset()
1467    * is called at the wrong time
1468    */
1469   if (gst_omx_port_is_flushing (port)) {
1470     GST_DEBUG_OBJECT (self, "Flushing");
1471     gst_omx_port_release_buffer (port, buf);
1472     goto flushing;
1473   }
1474
1475   GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %" G_GUINT64_FORMAT,
1476       (guint) buf->omx_buf->nFlags, (guint64) buf->omx_buf->nTimeStamp);
1477
1478   GST_VIDEO_DECODER_STREAM_LOCK (self);
1479   frame = gst_omx_video_find_nearest_frame (buf,
1480       gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
1481
1482   /* So we have a timestamped OMX buffer and get, or not, corresponding frame.
1483    * Assuming decoder output frames in display order, frames preceding this
1484    * frame could be discarded as they seems useless due to e.g interlaced
1485    * stream, corrupted input data...
1486    * In any cases, not likely to be seen again. so drop it before they pile up
1487    * and use all the memory. */
1488   gst_omx_video_dec_clean_older_frames (self, buf,
1489       gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
1490
1491   if (frame
1492       && (deadline = gst_video_decoder_get_max_decode_time
1493           (GST_VIDEO_DECODER (self), frame)) < 0) {
1494     GST_WARNING_OBJECT (self,
1495         "Frame is too late, dropping (deadline %" GST_TIME_FORMAT ")",
1496         GST_TIME_ARGS (-deadline));
1497     flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1498     frame = NULL;
1499   } else if (!frame && (buf->omx_buf->nFilledLen > 0 || buf->eglimage)) {
1500     GstBuffer *outbuf = NULL;
1501
1502     /* This sometimes happens at EOS or if the input is not properly framed,
1503      * let's handle it gracefully by allocating a new buffer for the current
1504      * caps and filling it
1505      */
1506
1507     GST_ERROR_OBJECT (self, "No corresponding frame found");
1508
1509     if (self->out_port_pool) {
1510       gint i, n;
1511       GstBufferPoolAcquireParams params = { 0, };
1512
1513       n = port->buffers->len;
1514       for (i = 0; i < n; i++) {
1515         GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
1516
1517         if (tmp == buf)
1518           break;
1519       }
1520       g_assert (i != n);
1521
1522       GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
1523       flow_ret =
1524           gst_buffer_pool_acquire_buffer (self->out_port_pool, &outbuf,
1525           &params);
1526       if (flow_ret != GST_FLOW_OK) {
1527         gst_omx_port_release_buffer (port, buf);
1528         goto invalid_buffer;
1529       }
1530
1531       if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy)
1532         outbuf =
1533             copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
1534             outbuf);
1535
1536       buf = NULL;
1537     } else {
1538       outbuf =
1539           gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self));
1540       if (!gst_omx_video_dec_fill_buffer (self, buf, outbuf)) {
1541         gst_buffer_unref (outbuf);
1542         gst_omx_port_release_buffer (port, buf);
1543         goto invalid_buffer;
1544       }
1545     }
1546
1547     flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), outbuf);
1548   } else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage) {
1549     if (self->out_port_pool) {
1550       gint i, n;
1551       GstBuffer *outbuf;
1552       GstBufferPoolAcquireParams params = { 0, };
1553
1554       n = port->buffers->len;
1555       for (i = 0; i < n; i++) {
1556         GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
1557
1558         if (tmp == buf)
1559           break;
1560       }
1561       g_assert (i != n);
1562
1563       GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
1564       flow_ret =
1565           gst_buffer_pool_acquire_buffer (self->out_port_pool,
1566           &frame->output_buffer, &params);
1567       if (flow_ret != GST_FLOW_OK) {
1568         flow_ret =
1569             gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1570         frame = NULL;
1571         gst_omx_port_release_buffer (port, buf);
1572         goto invalid_buffer;
1573       }
1574
1575       if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy){
1576         outbuf =
1577             copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
1578             outbuf);
1579       frame->output_buffer = outbuf;
1580
1581       flow_ret =
1582           gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1583       frame = NULL;
1584       buf = NULL;
1585       } else {
1586           if(!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) {
1587               gst_buffer_replace (&frame->output_buffer, NULL);
1588               flow_ret =
1589                   gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1590               frame = NULL;
1591               gst_omx_port_release_buffer (port, buf);
1592               goto invalid_buffer;
1593           }
1594           flow_ret =
1595               gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1596           frame = NULL;
1597           buf = NULL;
1598       }
1599     } else {
1600       if ((flow_ret =
1601               gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER
1602                   (self), frame)) == GST_FLOW_OK) {
1603         /* FIXME: This currently happens because of a race condition too.
1604          * We first need to reconfigure the output port and then the input
1605          * port if both need reconfiguration.
1606          */
1607         if (!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) {
1608           gst_buffer_replace (&frame->output_buffer, NULL);
1609           flow_ret =
1610               gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1611           frame = NULL;
1612           gst_omx_port_release_buffer (port, buf);
1613           goto invalid_buffer;
1614         }
1615         flow_ret =
1616             gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1617         frame = NULL;
1618       }
1619     }
1620   } else if (frame != NULL) {
1621     flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1622     frame = NULL;
1623   }
1624
1625   GST_DEBUG_OBJECT (self, "Read frame from component");
1626
1627   GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
1628
1629   if (buf) {
1630     err = gst_omx_port_release_buffer (port, buf);
1631     if (err != OMX_ErrorNone)
1632       goto release_error;
1633   }
1634
1635   self->downstream_flow_ret = flow_ret;
1636
1637   if (flow_ret != GST_FLOW_OK)
1638     goto flow_error;
1639
1640   GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1641
1642   return;
1643
1644 component_error:
1645   {
1646     GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1647         ("OpenMAX component in error state %s (0x%08x)",
1648             gst_omx_component_get_last_error_string (self->dec),
1649             gst_omx_component_get_last_error (self->dec)));
1650     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1651     gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1652     self->downstream_flow_ret = GST_FLOW_ERROR;
1653     self->started = FALSE;
1654     return;
1655   }
1656
1657 flushing:
1658   {
1659     GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1660     gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1661     self->downstream_flow_ret = GST_FLOW_FLUSHING;
1662     self->started = FALSE;
1663     return;
1664   }
1665
1666 eos:
1667   {
1668     g_mutex_lock (&self->drain_lock);
1669     if (self->draining) {
1670       GstQuery *query = gst_query_new_drain ();
1671
1672       /* Drain the pipeline to reclaim all memories back to the pool */
1673       if (!gst_pad_peer_query (GST_VIDEO_DECODER_SRC_PAD (self), query))
1674         GST_DEBUG_OBJECT (self, "drain query failed");
1675       gst_query_unref (query);
1676
1677       GST_DEBUG_OBJECT (self, "Drained");
1678       self->draining = FALSE;
1679       g_cond_broadcast (&self->drain_cond);
1680       flow_ret = GST_FLOW_OK;
1681       gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1682     } else {
1683       GST_DEBUG_OBJECT (self, "Component signalled EOS");
1684       flow_ret = GST_FLOW_EOS;
1685     }
1686     g_mutex_unlock (&self->drain_lock);
1687
1688     GST_VIDEO_DECODER_STREAM_LOCK (self);
1689     self->downstream_flow_ret = flow_ret;
1690
1691     /* Here we fallback and pause the task for the EOS case */
1692     if (flow_ret != GST_FLOW_OK)
1693       goto flow_error;
1694
1695     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1696
1697     return;
1698   }
1699
1700 flow_error:
1701   {
1702     if (flow_ret == GST_FLOW_EOS) {
1703       GST_DEBUG_OBJECT (self, "EOS");
1704
1705       gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self),
1706           gst_event_new_eos ());
1707       gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1708       self->started = FALSE;
1709     } else if (flow_ret < GST_FLOW_EOS) {
1710       GST_ELEMENT_ERROR (self, STREAM, FAILED,
1711           ("Internal data stream error."), ("stream stopped, reason %s",
1712               gst_flow_get_name (flow_ret)));
1713
1714       gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self),
1715           gst_event_new_eos ());
1716       gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1717       self->started = FALSE;
1718     } else if (flow_ret == GST_FLOW_FLUSHING) {
1719       GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1720       gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1721       self->started = FALSE;
1722     }
1723     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1724     return;
1725   }
1726
1727 reconfigure_error:
1728   {
1729     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1730         ("Unable to reconfigure output port"));
1731     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1732     gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1733     self->downstream_flow_ret = GST_FLOW_ERROR;
1734     self->started = FALSE;
1735     return;
1736   }
1737
1738 invalid_buffer:
1739   {
1740     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1741         ("Invalid sized input buffer"));
1742     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1743     gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1744     self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
1745     self->started = FALSE;
1746     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1747     return;
1748   }
1749
1750 caps_failed:
1751   {
1752     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
1753     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1754     gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1755     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1756     self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
1757     self->started = FALSE;
1758     return;
1759   }
1760 release_error:
1761   {
1762     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1763         ("Failed to relase output buffer to component: %s (0x%08x)",
1764             gst_omx_error_to_string (err), err));
1765     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1766     gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1767     self->downstream_flow_ret = GST_FLOW_ERROR;
1768     self->started = FALSE;
1769     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1770     return;
1771   }
1772 }
1773
1774 static gboolean
1775 gst_omx_video_dec_start (GstVideoDecoder * decoder)
1776 {
1777   GstOMXVideoDec *self;
1778
1779   self = GST_OMX_VIDEO_DEC (decoder);
1780
1781   self->last_upstream_ts = 0;
1782   self->downstream_flow_ret = GST_FLOW_OK;
1783
1784   return TRUE;
1785 }
1786
1787 static gboolean
1788 gst_omx_video_dec_stop (GstVideoDecoder * decoder)
1789 {
1790   GstOMXVideoDec *self;
1791
1792   self = GST_OMX_VIDEO_DEC (decoder);
1793
1794   GST_DEBUG_OBJECT (self, "Stopping decoder");
1795
1796   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
1797   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
1798
1799 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1800   gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
1801   gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
1802 #endif
1803
1804   gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
1805
1806   if (gst_omx_component_get_state (self->dec, 0) > OMX_StateIdle)
1807     gst_omx_component_set_state (self->dec, OMX_StateIdle);
1808 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1809   if (gst_omx_component_get_state (self->egl_render, 0) > OMX_StateIdle)
1810     gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1811 #endif
1812
1813   self->downstream_flow_ret = GST_FLOW_FLUSHING;
1814   self->started = FALSE;
1815
1816   g_mutex_lock (&self->drain_lock);
1817   self->draining = FALSE;
1818   g_cond_broadcast (&self->drain_cond);
1819   g_mutex_unlock (&self->drain_lock);
1820
1821   gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
1822 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1823   gst_omx_component_get_state (self->egl_render, 1 * GST_SECOND);
1824 #endif
1825
1826   gst_buffer_replace (&self->codec_data, NULL);
1827
1828   if (self->input_state)
1829     gst_video_codec_state_unref (self->input_state);
1830   self->input_state = NULL;
1831
1832   GST_DEBUG_OBJECT (self, "Stopped decoder");
1833
1834   return TRUE;
1835 }
1836
1837 static gboolean
1838 gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
1839 {
1840   OMX_VIDEO_PARAM_PORTFORMATTYPE param;
1841   OMX_ERRORTYPE err;
1842   GstCaps *comp_supported_caps;
1843   GList *negotiation_map = NULL, *l;
1844   GstCaps *templ_caps, *intersection;
1845   GstVideoFormat format;
1846   GstStructure *s;
1847   const gchar *format_str;
1848 #ifdef GST_TIZEN_MODIFICATION
1849   gchar *format_tmp;
1850   int i;
1851   EnableGemBuffersParams gemBuffers;
1852 #endif
1853
1854   GST_DEBUG_OBJECT (self, "Trying to negotiate a video format with downstream");
1855
1856   templ_caps = gst_pad_get_pad_template_caps (GST_VIDEO_DECODER_SRC_PAD (self));
1857   intersection =
1858       gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (self), templ_caps);
1859   gst_caps_unref (templ_caps);
1860
1861   GST_DEBUG_OBJECT (self, "Allowed downstream caps: %" GST_PTR_FORMAT,
1862       intersection);
1863
1864   negotiation_map =
1865       gst_omx_video_get_supported_colorformats (self->dec_out_port,
1866       self->input_state);
1867
1868   comp_supported_caps = gst_omx_video_get_caps_for_map (negotiation_map);
1869
1870   if (!gst_caps_is_empty (comp_supported_caps)) {
1871     GstCaps *tmp;
1872
1873     tmp = gst_caps_intersect (comp_supported_caps, intersection);
1874     gst_caps_unref (intersection);
1875     intersection = tmp;
1876   }
1877   gst_caps_unref (comp_supported_caps);
1878
1879   if (gst_caps_is_empty (intersection)) {
1880     gst_caps_unref (intersection);
1881     GST_ERROR_OBJECT (self, "Empty caps");
1882     g_list_free_full (negotiation_map,
1883         (GDestroyNotify) gst_omx_video_negotiation_map_free);
1884     return FALSE;
1885   }
1886
1887   for(i=0; i<gst_caps_get_size(intersection); i++)
1888   {
1889       s = gst_caps_get_structure (intersection, i);
1890       format_tmp = gst_structure_get_string (s, "format");
1891
1892       if(!strncmp(format_tmp, "S", 1)) {
1893           format_str = format_tmp;
1894           GST_DEBUG_OBJECT (self, "SEC format found");
1895           break;
1896       }
1897   }
1898
1899   if(!format_str) {
1900     intersection = gst_caps_truncate (intersection);
1901     intersection = gst_caps_fixate (intersection);
1902
1903     s = gst_caps_get_structure (intersection, 0);
1904     format_str = gst_structure_get_string (s, "format");
1905     GST_DEBUG_OBJECT (self, "first structure will be fixated");
1906   }
1907
1908   if (!format_str ||
1909       (format =
1910           gst_video_format_from_string (format_str)) ==
1911       GST_VIDEO_FORMAT_UNKNOWN) {
1912     GST_ERROR_OBJECT (self, "Invalid caps: %" GST_PTR_FORMAT, intersection);
1913     gst_caps_unref (intersection);
1914     g_list_free_full (negotiation_map,
1915         (GDestroyNotify) gst_omx_video_negotiation_map_free);
1916     return FALSE;
1917   }
1918
1919   GST_OMX_INIT_STRUCT (&param);
1920   param.nPortIndex = self->dec_out_port->index;
1921
1922   for (l = negotiation_map; l; l = l->next) {
1923     GstOMXVideoNegotiationMap *m = l->data;
1924
1925     if (m->format == format) {
1926       param.eColorFormat = m->type;
1927       break;
1928     }
1929   }
1930
1931   GST_DEBUG_OBJECT (self, "Negotiating color format %s (%d)", format_str,
1932       param.eColorFormat);
1933
1934   /* We must find something here */
1935   g_assert (l != NULL);
1936   g_list_free_full (negotiation_map,
1937       (GDestroyNotify) gst_omx_video_negotiation_map_free);
1938
1939   err =
1940       gst_omx_component_set_parameter (self->dec,
1941       OMX_IndexParamVideoPortFormat, &param);
1942   if (err != OMX_ErrorNone) {
1943     GST_ERROR_OBJECT (self, "Failed to set video port format: %s (0x%08x)",
1944         gst_omx_error_to_string (err), err);
1945   }
1946
1947   /* set plateform specific gem buffer settings. */
1948
1949     /* Set platform specific buffer settings. to avoid plane support error.. */
1950 #ifdef GST_TIZEN_MODIFICATION
1951     OMX_INIT_STRUCTURE(gemBuffers);
1952     gemBuffers.enable = OMX_TRUE;
1953     gemBuffers.nPortIndex = 1;
1954       err =
1955       gst_omx_component_set_parameter (self->dec,
1956       OMX_IndexParamEnablePlatformSpecificBuffers,&gemBuffers);
1957   if (err != OMX_ErrorNone) {
1958     GST_ERROR_OBJECT (self, "Failed to set video port format: %s (0x%08x)",
1959         gst_omx_error_to_string (err), err);
1960   }
1961 #endif
1962   gst_caps_unref (intersection);
1963   return (err == OMX_ErrorNone);
1964 }
1965
1966 static gboolean
1967 gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
1968     GstVideoCodecState * state)
1969 {
1970   GstOMXVideoDec *self;
1971   GstOMXVideoDecClass *klass;
1972   GstVideoInfo *info = &state->info;
1973   gboolean is_format_change = FALSE;
1974   gboolean needs_disable = FALSE;
1975   OMX_PARAM_PORTDEFINITIONTYPE port_def;
1976
1977   self = GST_OMX_VIDEO_DEC (decoder);
1978   klass = GST_OMX_VIDEO_DEC_GET_CLASS (decoder);
1979
1980   GST_DEBUG_OBJECT (self, "Setting new caps %" GST_PTR_FORMAT, state->caps);
1981
1982   gst_omx_port_get_port_definition (self->dec_in_port, &port_def);
1983
1984   /* Check if the caps change is a real format change or if only irrelevant
1985    * parts of the caps have changed or nothing at all.
1986    */
1987   is_format_change |= port_def.format.video.nFrameWidth != info->width;
1988   is_format_change |= port_def.format.video.nFrameHeight != info->height;
1989   is_format_change |= (port_def.format.video.xFramerate == 0
1990       && info->fps_n != 0)
1991       || (port_def.format.video.xFramerate !=
1992       (info->fps_n << 16) / (info->fps_d));
1993   is_format_change |= (self->codec_data != state->codec_data);
1994   if (klass->is_format_change)
1995     is_format_change |=
1996         klass->is_format_change (self, self->dec_in_port, state);
1997
1998   needs_disable =
1999       gst_omx_component_get_state (self->dec,
2000       GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
2001   /* If the component is not in Loaded state and a real format change happens
2002    * we have to disable the port and re-allocate all buffers. If no real
2003    * format change happened we can just exit here.
2004    */
2005   if (needs_disable && !is_format_change) {
2006     GST_DEBUG_OBJECT (self,
2007         "Already running and caps did not change the format");
2008     if (self->input_state)
2009       gst_video_codec_state_unref (self->input_state);
2010     self->input_state = gst_video_codec_state_ref (state);
2011     return TRUE;
2012   }
2013
2014   if (needs_disable && is_format_change) {
2015 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2016     GstOMXPort *out_port =
2017         self->eglimage ? self->egl_out_port : self->dec_out_port;
2018 #else
2019     GstOMXPort *out_port = self->dec_out_port;
2020 #endif
2021
2022     GST_DEBUG_OBJECT (self, "Need to disable and drain decoder");
2023
2024     gst_omx_video_dec_drain (self);
2025     gst_omx_video_dec_flush (decoder);
2026     gst_omx_port_set_flushing (out_port, 5 * GST_SECOND, TRUE);
2027
2028     if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
2029       GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2030       gst_omx_video_dec_stop (GST_VIDEO_DECODER (self));
2031       gst_omx_video_dec_close (GST_VIDEO_DECODER (self));
2032       GST_VIDEO_DECODER_STREAM_LOCK (self);
2033
2034       if (!gst_omx_video_dec_open (GST_VIDEO_DECODER (self)))
2035         return FALSE;
2036       needs_disable = FALSE;
2037     } else {
2038 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2039       if (self->eglimage) {
2040         gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
2041         gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
2042         gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
2043         gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
2044       }
2045 #endif
2046
2047       if (gst_omx_port_set_enabled (self->dec_in_port, FALSE) != OMX_ErrorNone)
2048         return FALSE;
2049       if (gst_omx_port_set_enabled (out_port, FALSE) != OMX_ErrorNone)
2050         return FALSE;
2051       if (gst_omx_port_wait_buffers_released (self->dec_in_port,
2052               5 * GST_SECOND) != OMX_ErrorNone)
2053         return FALSE;
2054       if (gst_omx_port_wait_buffers_released (out_port,
2055               1 * GST_SECOND) != OMX_ErrorNone)
2056         return FALSE;
2057       if (gst_omx_port_deallocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2058         return FALSE;
2059       if (gst_omx_video_dec_deallocate_output_buffers (self) != OMX_ErrorNone)
2060         return FALSE;
2061       if (gst_omx_port_wait_enabled (self->dec_in_port,
2062               1 * GST_SECOND) != OMX_ErrorNone)
2063         return FALSE;
2064       if (gst_omx_port_wait_enabled (out_port, 1 * GST_SECOND) != OMX_ErrorNone)
2065         return FALSE;
2066
2067 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2068       if (self->eglimage) {
2069         OMX_STATETYPE egl_state;
2070
2071         egl_state = gst_omx_component_get_state (self->egl_render, 0);
2072         if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
2073
2074           if (egl_state > OMX_StateIdle) {
2075             gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
2076             gst_omx_component_set_state (self->dec, OMX_StateIdle);
2077             egl_state = gst_omx_component_get_state (self->egl_render,
2078                 5 * GST_SECOND);
2079             gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
2080           }
2081           gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
2082           gst_omx_component_set_state (self->dec, OMX_StateLoaded);
2083
2084           gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
2085
2086           if (egl_state > OMX_StateLoaded) {
2087             gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
2088           }
2089
2090           gst_omx_component_set_state (self->dec, OMX_StateIdle);
2091
2092           gst_omx_component_set_state (self->dec, OMX_StateExecuting);
2093           gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2094         }
2095         self->eglimage = FALSE;
2096       }
2097 #endif
2098     }
2099     if (self->input_state)
2100       gst_video_codec_state_unref (self->input_state);
2101     self->input_state = NULL;
2102
2103     GST_DEBUG_OBJECT (self, "Decoder drained and disabled");
2104   }
2105
2106   port_def.format.video.nFrameWidth = info->width;
2107   port_def.format.video.nFrameHeight = info->height;
2108   if (info->fps_n == 0)
2109     port_def.format.video.xFramerate = 0;
2110   else
2111     port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d);
2112
2113   GST_DEBUG_OBJECT (self, "Setting inport port definition");
2114
2115   if (gst_omx_port_update_port_definition (self->dec_in_port,
2116           &port_def) != OMX_ErrorNone)
2117     return FALSE;
2118
2119   if (klass->set_format) {
2120     if (!klass->set_format (self, self->dec_in_port, state)) {
2121       GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
2122       return FALSE;
2123     }
2124   }
2125
2126   GST_DEBUG_OBJECT (self, "Updating outport port definition");
2127   if (gst_omx_port_update_port_definition (self->dec_out_port,
2128           NULL) != OMX_ErrorNone)
2129     return FALSE;
2130
2131   gst_buffer_replace (&self->codec_data, state->codec_data);
2132   self->input_state = gst_video_codec_state_ref (state);
2133
2134   GST_DEBUG_OBJECT (self, "Enabling component");
2135
2136   if (needs_disable) {
2137     if (gst_omx_port_set_enabled (self->dec_in_port, TRUE) != OMX_ErrorNone)
2138       return FALSE;
2139 #ifdef GST_TIZEN_MODIFICATION
2140     if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_in_port, self->hTBMBufMgr, 0) != OMX_ErrorNone)
2141      return FALSE;
2142 #else
2143     if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2144       return FALSE;
2145 #endif
2146
2147     if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2148       if (gst_omx_port_set_enabled (self->dec_out_port, TRUE) != OMX_ErrorNone)
2149         return FALSE;
2150       if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2151         return FALSE;
2152
2153       if (gst_omx_port_wait_enabled (self->dec_out_port,
2154               5 * GST_SECOND) != OMX_ErrorNone)
2155         return FALSE;
2156     }
2157
2158     if (gst_omx_port_wait_enabled (self->dec_in_port,
2159             5 * GST_SECOND) != OMX_ErrorNone)
2160       return FALSE;
2161     if (gst_omx_port_mark_reconfigured (self->dec_in_port) != OMX_ErrorNone)
2162       return FALSE;
2163   } else {
2164     if (!gst_omx_video_dec_negotiate (self))
2165       GST_LOG_OBJECT (self, "Negotiation failed, will get output format later");
2166
2167     if (!(klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2168 #ifndef GST_TIZEN_MODIFICATION
2169       /* Disable output port */
2170       if (gst_omx_port_set_enabled (self->dec_out_port, FALSE) != OMX_ErrorNone)
2171         return FALSE;
2172
2173       if (gst_omx_port_wait_enabled (self->dec_out_port,
2174               1 * GST_SECOND) != OMX_ErrorNone)
2175         return FALSE;
2176 #endif
2177       if (gst_omx_component_set_state (self->dec,
2178               OMX_StateIdle) != OMX_ErrorNone)
2179         return FALSE;
2180
2181       /* Need to allocate buffers to reach Idle state */
2182 #ifdef GST_TIZEN_MODIFICATION
2183       if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_in_port, self->hTBMBufMgr, 0) != OMX_ErrorNone)
2184           return FALSE;
2185       if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_out_port, self->hTBMBufMgr,
2186           self->dec_in_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone)
2187           return FALSE;
2188 #else
2189       if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2190         return FALSE;
2191       if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2192         return FALSE;
2193 #endif
2194     } else {
2195
2196       if (gst_omx_component_set_state (self->dec,
2197               OMX_StateIdle) != OMX_ErrorNone)
2198         return FALSE;
2199
2200       /* Need to allocate buffers to reach Idle state */
2201 #ifdef GST_TIZEN_MODIFICATION
2202       if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_in_port, self->hTBMBufMgr, 0) != OMX_ErrorNone)
2203           return FALSE;
2204       if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_out_port, self->hTBMBufMgr,
2205           self->dec_in_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone)
2206           return FALSE;
2207 #else
2208       if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2209         return FALSE;
2210       if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2211         return FALSE;
2212 #endif
2213   }
2214
2215     if (gst_omx_component_get_state (self->dec,
2216             GST_CLOCK_TIME_NONE) != OMX_StateIdle)
2217       return FALSE;
2218
2219     if (gst_omx_component_set_state (self->dec,
2220             OMX_StateExecuting) != OMX_ErrorNone)
2221       return FALSE;
2222
2223     if (gst_omx_component_get_state (self->dec,
2224             GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
2225       return FALSE;
2226   }
2227
2228   /* Unset flushing to allow ports to accept data again */
2229   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
2230   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
2231
2232   if (gst_omx_component_get_last_error (self->dec) != OMX_ErrorNone) {
2233     GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
2234         gst_omx_component_get_last_error_string (self->dec),
2235         gst_omx_component_get_last_error (self->dec));
2236     return FALSE;
2237   }
2238
2239   self->downstream_flow_ret = GST_FLOW_OK;
2240   return TRUE;
2241 }
2242
2243 static gboolean
2244 gst_omx_video_dec_flush (GstVideoDecoder * decoder)
2245 {
2246   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
2247   OMX_ERRORTYPE err = OMX_ErrorNone;
2248
2249   GST_DEBUG_OBJECT (self, "Flushing decoder");
2250
2251   if (gst_omx_component_get_state (self->dec, 0) == OMX_StateLoaded)
2252     return TRUE;
2253
2254   /* 0) Pause the components */
2255   if (gst_omx_component_get_state (self->dec, 0) == OMX_StateExecuting) {
2256     gst_omx_component_set_state (self->dec, OMX_StatePause);
2257     gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2258   }
2259 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2260   if (self->eglimage) {
2261     if (gst_omx_component_get_state (self->egl_render, 0) == OMX_StateExecuting) {
2262       gst_omx_component_set_state (self->egl_render, OMX_StatePause);
2263       gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
2264     }
2265   }
2266 #endif
2267
2268   /* 1) Wait until the srcpad loop is stopped,
2269    * unlock GST_VIDEO_DECODER_STREAM_LOCK to prevent deadlocks
2270    * caused by using this lock from inside the loop function */
2271   GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2272   gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
2273   GST_DEBUG_OBJECT (self, "Flushing -- task stopped");
2274   GST_VIDEO_DECODER_STREAM_LOCK (self);
2275
2276   /* 2) Flush the ports */
2277   GST_DEBUG_OBJECT (self, "flushing ports");
2278   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
2279   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
2280
2281 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2282   if (self->eglimage) {
2283     gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
2284     gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
2285   }
2286 #endif
2287
2288   /* 3) Resume components */
2289   gst_omx_component_set_state (self->dec, OMX_StateExecuting);
2290   gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2291 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2292   if (self->eglimage) {
2293     gst_omx_component_set_state (self->egl_render, OMX_StateExecuting);
2294     gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
2295   }
2296 #endif
2297
2298   /* 4) Unset flushing to allow ports to accept data again */
2299   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
2300   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
2301
2302 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2303   if (self->eglimage) {
2304     gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
2305     gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
2306     err = gst_omx_port_populate (self->egl_out_port);
2307     gst_omx_port_mark_reconfigured (self->egl_out_port);
2308   } else {
2309     err = gst_omx_port_populate (self->dec_out_port);
2310   }
2311 #else
2312   err = gst_omx_port_populate (self->dec_out_port);
2313 #endif
2314
2315   if (err != OMX_ErrorNone) {
2316     GST_WARNING_OBJECT (self, "Failed to populate output port: %s (0x%08x)",
2317         gst_omx_error_to_string (err), err);
2318   }
2319
2320   /* Reset our state */
2321   self->last_upstream_ts = 0;
2322   self->downstream_flow_ret = GST_FLOW_OK;
2323   self->started = FALSE;
2324   GST_DEBUG_OBJECT (self, "Flush finished");
2325
2326   return TRUE;
2327 }
2328
2329 static GstFlowReturn
2330 gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
2331     GstVideoCodecFrame * frame)
2332 {
2333   GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2334   GstOMXVideoDec *self;
2335   GstOMXVideoDecClass *klass;
2336   GstOMXPort *port;
2337   GstOMXBuffer *buf;
2338   GstBuffer *codec_data = NULL;
2339   guint offset = 0, size;
2340   GstClockTime timestamp, duration;
2341   OMX_ERRORTYPE err;
2342
2343   self = GST_OMX_VIDEO_DEC (decoder);
2344   klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
2345
2346   GST_DEBUG_OBJECT (self, "Handling frame");
2347
2348   if (!self->started) {
2349     if (!GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
2350       gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
2351       return GST_FLOW_OK;
2352     }
2353     GST_DEBUG_OBJECT (self, "Starting task");
2354     gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self),
2355         (GstTaskFunction) gst_omx_video_dec_loop, decoder, NULL);
2356   }
2357
2358   timestamp = frame->pts;
2359   duration = frame->duration;
2360
2361   if (self->downstream_flow_ret != GST_FLOW_OK) {
2362     gst_video_codec_frame_unref (frame);
2363     return self->downstream_flow_ret;
2364   }
2365
2366   if (klass->prepare_frame) {
2367     GstFlowReturn ret;
2368
2369     ret = klass->prepare_frame (self, frame);
2370     if (ret != GST_FLOW_OK) {
2371       GST_ERROR_OBJECT (self, "Preparing frame failed: %s",
2372           gst_flow_get_name (ret));
2373       gst_video_codec_frame_unref (frame);
2374       return ret;
2375     }
2376   }
2377
2378   port = self->dec_in_port;
2379
2380   size = gst_buffer_get_size (frame->input_buffer);
2381   while (offset < size) {
2382     /* Make sure to release the base class stream lock, otherwise
2383      * _loop() can't call _finish_frame() and we might block forever
2384      * because no input buffers are released */
2385     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2386     acq_ret = gst_omx_port_acquire_buffer (port, &buf);
2387
2388     if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
2389       GST_VIDEO_DECODER_STREAM_LOCK (self);
2390       goto component_error;
2391     } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
2392       GST_VIDEO_DECODER_STREAM_LOCK (self);
2393       goto flushing;
2394     } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
2395       /* Reallocate all buffers */
2396       err = gst_omx_port_set_enabled (port, FALSE);
2397       if (err != OMX_ErrorNone) {
2398         GST_VIDEO_DECODER_STREAM_LOCK (self);
2399         goto reconfigure_error;
2400       }
2401
2402       err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
2403       if (err != OMX_ErrorNone) {
2404         GST_VIDEO_DECODER_STREAM_LOCK (self);
2405         goto reconfigure_error;
2406       }
2407
2408       err = gst_omx_port_deallocate_buffers (port);
2409       if (err != OMX_ErrorNone) {
2410         GST_VIDEO_DECODER_STREAM_LOCK (self);
2411         goto reconfigure_error;
2412       }
2413
2414       err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
2415       if (err != OMX_ErrorNone) {
2416         GST_VIDEO_DECODER_STREAM_LOCK (self);
2417         goto reconfigure_error;
2418       }
2419
2420       err = gst_omx_port_set_enabled (port, TRUE);
2421       if (err != OMX_ErrorNone) {
2422         GST_VIDEO_DECODER_STREAM_LOCK (self);
2423         goto reconfigure_error;
2424       }
2425 #ifdef GST_TIZEN_MODIFICATION
2426       err = gst_omx_port_tbm_allocate_dec_buffers(port, self->hTBMBufMgr,
2427           self->dec_in_port->port_def.format.video.eCompressionFormat);
2428 #else
2429       err = gst_omx_port_allocate_buffers (port);
2430 #endif
2431       if (err != OMX_ErrorNone) {
2432         GST_VIDEO_DECODER_STREAM_LOCK (self);
2433         goto reconfigure_error;
2434       }
2435
2436       err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
2437       if (err != OMX_ErrorNone) {
2438         GST_VIDEO_DECODER_STREAM_LOCK (self);
2439         goto reconfigure_error;
2440       }
2441
2442       err = gst_omx_port_mark_reconfigured (port);
2443       if (err != OMX_ErrorNone) {
2444         GST_VIDEO_DECODER_STREAM_LOCK (self);
2445         goto reconfigure_error;
2446       }
2447
2448       /* Now get a new buffer and fill it */
2449       GST_VIDEO_DECODER_STREAM_LOCK (self);
2450       continue;
2451     }
2452     GST_VIDEO_DECODER_STREAM_LOCK (self);
2453
2454     g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
2455
2456     if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
2457       gst_omx_port_release_buffer (port, buf);
2458       goto full_buffer;
2459     }
2460
2461     if (self->downstream_flow_ret != GST_FLOW_OK) {
2462       gst_omx_port_release_buffer (port, buf);
2463       goto flow_error;
2464     }
2465
2466     if (self->codec_data) {
2467       GST_DEBUG_OBJECT (self, "Passing codec data to the component");
2468
2469       codec_data = self->codec_data;
2470
2471       if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <
2472           gst_buffer_get_size (codec_data)) {
2473         gst_omx_port_release_buffer (port, buf);
2474         goto too_large_codec_data;
2475       }
2476
2477       buf->omx_buf->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
2478       buf->omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
2479       buf->omx_buf->nFilledLen = gst_buffer_get_size (codec_data);;
2480
2481 #ifdef GST_TIZEN_MODIFICATION
2482       gst_buffer_extract (codec_data, 0,
2483           buf->mm_vbuffer->data[0] + buf->omx_buf->nOffset,
2484           buf->omx_buf->nFilledLen);
2485 #else
2486       gst_buffer_extract (codec_data, 0,
2487           buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
2488           buf->omx_buf->nFilledLen);
2489 #endif
2490
2491       if (GST_CLOCK_TIME_IS_VALID (timestamp))
2492         buf->omx_buf->nTimeStamp =
2493             gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND);
2494       else
2495         buf->omx_buf->nTimeStamp = 0;
2496       buf->omx_buf->nTickCount = 0;
2497
2498       self->started = TRUE;
2499       err = gst_omx_port_release_buffer (port, buf);
2500       gst_buffer_replace (&self->codec_data, NULL);
2501       if (err != OMX_ErrorNone)
2502         goto release_error;
2503       /* Acquire new buffer for the actual frame */
2504       continue;
2505     }
2506
2507     /* Now handle the frame */
2508     GST_DEBUG_OBJECT (self, "Passing frame offset %d to the component", offset);
2509
2510     /* Copy the buffer content in chunks of size as requested
2511      * by the port */
2512     buf->omx_buf->nFilledLen =
2513         MIN (size - offset, buf->omx_buf->nAllocLen - buf->omx_buf->nOffset);
2514     GST_DEBUG_OBJECT (self, "nFilledLen %d, %p", buf->omx_buf->nFilledLen, buf->omx_buf->pBuffer);
2515
2516 #ifdef GST_TIZEN_MODIFICATION
2517      gst_buffer_extract (frame->input_buffer, offset,
2518           buf->mm_vbuffer->data[0] + buf->omx_buf->nOffset,
2519           buf->omx_buf->nFilledLen);
2520 #else
2521     gst_buffer_extract (frame->input_buffer, offset,
2522         buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
2523         buf->omx_buf->nFilledLen);
2524 #endif
2525
2526     if (timestamp != GST_CLOCK_TIME_NONE) {
2527       buf->omx_buf->nTimeStamp =
2528           gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND);
2529       self->last_upstream_ts = timestamp;
2530     } else {
2531       buf->omx_buf->nTimeStamp = 0;
2532     }
2533
2534     if (duration != GST_CLOCK_TIME_NONE && offset == 0) {
2535       buf->omx_buf->nTickCount =
2536           gst_util_uint64_scale (duration, OMX_TICKS_PER_SECOND, GST_SECOND);
2537       self->last_upstream_ts += duration;
2538     } else {
2539       buf->omx_buf->nTickCount = 0;
2540     }
2541
2542     if (offset == 0 && GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame))
2543       buf->omx_buf->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
2544
2545     /* TODO: Set flags
2546      *   - OMX_BUFFERFLAG_DECODEONLY for buffers that are outside
2547      *     the segment
2548      */
2549
2550     offset += buf->omx_buf->nFilledLen;
2551
2552     if (offset == size)
2553       buf->omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
2554
2555     self->started = TRUE;
2556     err = gst_omx_port_release_buffer (port, buf);
2557     if (err != OMX_ErrorNone)
2558       goto release_error;
2559   }
2560
2561   gst_video_codec_frame_unref (frame);
2562
2563   GST_DEBUG_OBJECT (self, "Passed frame to component");
2564
2565   return self->downstream_flow_ret;
2566
2567 full_buffer:
2568   {
2569     gst_video_codec_frame_unref (frame);
2570     GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2571         ("Got OpenMAX buffer with no free space (%p, %u/%u)", buf,
2572             (guint) buf->omx_buf->nOffset, (guint) buf->omx_buf->nAllocLen));
2573     return GST_FLOW_ERROR;
2574   }
2575
2576 flow_error:
2577   {
2578     gst_video_codec_frame_unref (frame);
2579
2580     return self->downstream_flow_ret;
2581   }
2582
2583 too_large_codec_data:
2584   {
2585     gst_video_codec_frame_unref (frame);
2586     GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2587         ("codec_data larger than supported by OpenMAX port "
2588             "(%" G_GSIZE_FORMAT " > %u)", gst_buffer_get_size (codec_data),
2589             (guint) self->dec_in_port->port_def.nBufferSize));
2590     return GST_FLOW_ERROR;
2591   }
2592
2593 component_error:
2594   {
2595     gst_video_codec_frame_unref (frame);
2596     GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2597         ("OpenMAX component in error state %s (0x%08x)",
2598             gst_omx_component_get_last_error_string (self->dec),
2599             gst_omx_component_get_last_error (self->dec)));
2600     return GST_FLOW_ERROR;
2601   }
2602
2603 flushing:
2604   {
2605     gst_video_codec_frame_unref (frame);
2606     GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
2607     return GST_FLOW_FLUSHING;
2608   }
2609 reconfigure_error:
2610   {
2611     gst_video_codec_frame_unref (frame);
2612     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
2613         ("Unable to reconfigure input port"));
2614     return GST_FLOW_ERROR;
2615   }
2616 release_error:
2617   {
2618     gst_video_codec_frame_unref (frame);
2619     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
2620         ("Failed to relase input buffer to component: %s (0x%08x)",
2621             gst_omx_error_to_string (err), err));
2622     return GST_FLOW_ERROR;
2623   }
2624 }
2625
2626 static GstFlowReturn
2627 gst_omx_video_dec_finish (GstVideoDecoder * decoder)
2628 {
2629   GstOMXVideoDec *self;
2630
2631   self = GST_OMX_VIDEO_DEC (decoder);
2632
2633   return gst_omx_video_dec_drain (self);
2634 }
2635
2636 static GstFlowReturn
2637 gst_omx_video_dec_drain (GstOMXVideoDec * self)
2638 {
2639   GstOMXVideoDecClass *klass;
2640   GstOMXBuffer *buf;
2641   GstOMXAcquireBufferReturn acq_ret;
2642   OMX_ERRORTYPE err;
2643
2644   GST_DEBUG_OBJECT (self, "Draining component");
2645
2646   klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
2647
2648   if (!self->started) {
2649     GST_DEBUG_OBJECT (self, "Component not started yet");
2650     return GST_FLOW_OK;
2651   }
2652   self->started = FALSE;
2653
2654   if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
2655     GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
2656     return GST_FLOW_OK;
2657   }
2658
2659   /* Make sure to release the base class stream lock, otherwise
2660    * _loop() can't call _finish_frame() and we might block forever
2661    * because no input buffers are released */
2662   GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2663
2664   /* Send an EOS buffer to the component and let the base
2665    * class drop the EOS event. We will send it later when
2666    * the EOS buffer arrives on the output port. */
2667   acq_ret = gst_omx_port_acquire_buffer (self->dec_in_port, &buf);
2668   if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
2669     GST_VIDEO_DECODER_STREAM_LOCK (self);
2670     GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
2671         acq_ret);
2672     return GST_FLOW_ERROR;
2673   }
2674
2675   g_mutex_lock (&self->drain_lock);
2676   self->draining = TRUE;
2677   buf->omx_buf->nFilledLen = 0;
2678   buf->omx_buf->nTimeStamp =
2679       gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
2680       GST_SECOND);
2681   buf->omx_buf->nTickCount = 0;
2682   buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
2683   err = gst_omx_port_release_buffer (self->dec_in_port, buf);
2684   if (err != OMX_ErrorNone) {
2685     GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
2686         gst_omx_error_to_string (err), err);
2687     g_mutex_unlock (&self->drain_lock);
2688     GST_VIDEO_DECODER_STREAM_LOCK (self);
2689     return GST_FLOW_ERROR;
2690   }
2691
2692   GST_DEBUG_OBJECT (self, "Waiting until component is drained");
2693
2694   if (G_UNLIKELY (self->dec->hacks & GST_OMX_HACK_DRAIN_MAY_NOT_RETURN)) {
2695     gint64 wait_until = g_get_monotonic_time () + G_TIME_SPAN_SECOND / 2;
2696
2697     if (!g_cond_wait_until (&self->drain_cond, &self->drain_lock, wait_until))
2698       GST_WARNING_OBJECT (self, "Drain timed out");
2699     else
2700       GST_DEBUG_OBJECT (self, "Drained component");
2701
2702   } else {
2703     g_cond_wait (&self->drain_cond, &self->drain_lock);
2704     GST_DEBUG_OBJECT (self, "Drained component");
2705   }
2706
2707   g_mutex_unlock (&self->drain_lock);
2708   GST_VIDEO_DECODER_STREAM_LOCK (self);
2709
2710   self->started = FALSE;
2711
2712   return GST_FLOW_OK;
2713 }
2714
2715 static gboolean
2716 gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
2717 {
2718   GstBufferPool *pool;
2719   GstStructure *config;
2720
2721 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2722   {
2723     GstCaps *caps;
2724     gint i, n;
2725     GstVideoInfo info;
2726
2727     gst_query_parse_allocation (query, &caps, NULL);
2728     if (caps && gst_video_info_from_caps (&info, caps)
2729         && info.finfo->format == GST_VIDEO_FORMAT_RGBA) {
2730       gboolean found = FALSE;
2731       GstCapsFeatures *feature = gst_caps_get_features (caps, 0);
2732       /* Prefer an EGLImage allocator if available and we want to use it */
2733       n = gst_query_get_n_allocation_params (query);
2734       for (i = 0; i < n; i++) {
2735         GstAllocator *allocator;
2736         GstAllocationParams params;
2737
2738         gst_query_parse_nth_allocation_param (query, i, &allocator, &params);
2739         if (allocator) {
2740           if (g_strcmp0 (allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0) {
2741             found = TRUE;
2742             gst_query_set_nth_allocation_param (query, 0, allocator, &params);
2743             while (gst_query_get_n_allocation_params (query) > 1)
2744               gst_query_remove_nth_allocation_param (query, 1);
2745           }
2746
2747           gst_object_unref (allocator);
2748
2749           if (found)
2750             break;
2751         }
2752       }
2753
2754       /* if try to negotiate with caps feature memory:EGLImage
2755        * and if allocator is not of type memory EGLImage then fails */
2756       if (feature
2757           && gst_caps_features_contains (feature,
2758               GST_CAPS_FEATURE_MEMORY_EGL_IMAGE) && !found) {
2759         return FALSE;
2760       }
2761     }
2762   }
2763 #endif
2764
2765   if (!GST_VIDEO_DECODER_CLASS
2766       (gst_omx_video_dec_parent_class)->decide_allocation (bdec, query))
2767     return FALSE;
2768
2769   g_assert (gst_query_get_n_allocation_pools (query) > 0);
2770   gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
2771   g_assert (pool != NULL);
2772
2773   config = gst_buffer_pool_get_config (pool);
2774   if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
2775     gst_buffer_pool_config_add_option (config,
2776         GST_BUFFER_POOL_OPTION_VIDEO_META);
2777   }
2778   gst_buffer_pool_set_config (pool, config);
2779   gst_object_unref (pool);
2780
2781   return TRUE;
2782 }