omxvideoenc: drain encoder on ALLOCATION and DRAIN queries
[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 #include <gst/allocators/gstdmabuf.h>
29
30 #if defined (USE_OMX_TARGET_RPI) && defined(__GNUC__)
31 #ifndef __VCCOREVER__
32 #define __VCCOREVER__ 0x04000000
33 #endif
34
35 #pragma GCC diagnostic push
36 #pragma GCC diagnostic ignored "-Wredundant-decls"
37 #pragma GCC optimize ("gnu89-inline")
38 #endif
39
40 #if defined (HAVE_GST_GL)
41 #include <gst/gl/egl/gstglmemoryegl.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 #include <string.h>
50
51 #include "gstomxbufferpool.h"
52 #include "gstomxvideo.h"
53 #include "gstomxvideodec.h"
54
55 GST_DEBUG_CATEGORY_STATIC (gst_omx_video_dec_debug_category);
56 #define GST_CAT_DEFAULT gst_omx_video_dec_debug_category
57
58 /* prototypes */
59 static void gst_omx_video_dec_finalize (GObject * object);
60
61 static GstStateChangeReturn
62 gst_omx_video_dec_change_state (GstElement * element,
63     GstStateChange transition);
64
65 static gboolean gst_omx_video_dec_open (GstVideoDecoder * decoder);
66 static gboolean gst_omx_video_dec_close (GstVideoDecoder * decoder);
67 static gboolean gst_omx_video_dec_start (GstVideoDecoder * decoder);
68 static gboolean gst_omx_video_dec_stop (GstVideoDecoder * decoder);
69 static gboolean gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
70     GstVideoCodecState * state);
71 static gboolean gst_omx_video_dec_flush (GstVideoDecoder * decoder);
72 static GstFlowReturn gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
73     GstVideoCodecFrame * frame);
74 static GstFlowReturn gst_omx_video_dec_finish (GstVideoDecoder * decoder);
75 static gboolean gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec,
76     GstQuery * query);
77 static gboolean gst_omx_video_dec_propose_allocation (GstVideoDecoder * bdec,
78     GstQuery * query);
79
80 static GstFlowReturn gst_omx_video_dec_drain (GstVideoDecoder * decoder);
81
82 static OMX_ERRORTYPE gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec *
83     self);
84 static gboolean gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec
85     * self);
86
87 enum
88 {
89   PROP_0,
90   PROP_INTERNAL_ENTROPY_BUFFERS,
91 };
92
93 #define GST_OMX_VIDEO_DEC_INTERNAL_ENTROPY_BUFFERS_DEFAULT (5)
94
95 /* class initialization */
96
97 #define DEBUG_INIT \
98   GST_DEBUG_CATEGORY_INIT (gst_omx_video_dec_debug_category, "omxvideodec", 0, \
99       "debug category for gst-omx video decoder base class");
100
101
102 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoDec, gst_omx_video_dec,
103     GST_TYPE_VIDEO_DECODER, DEBUG_INIT);
104
105 static void
106 gst_omx_video_dec_set_property (GObject * object, guint prop_id,
107     const GValue * value, GParamSpec * pspec)
108 {
109 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
110   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (object);
111 #endif
112
113   switch (prop_id) {
114 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
115     case PROP_INTERNAL_ENTROPY_BUFFERS:
116       self->internal_entropy_buffers = g_value_get_uint (value);
117       break;
118 #endif
119     default:
120       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
121       break;
122   }
123 }
124
125 static void
126 gst_omx_video_dec_get_property (GObject * object, guint prop_id,
127     GValue * value, GParamSpec * pspec)
128 {
129 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
130   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (object);
131 #endif
132
133   switch (prop_id) {
134 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
135     case PROP_INTERNAL_ENTROPY_BUFFERS:
136       g_value_set_uint (value, self->internal_entropy_buffers);
137       break;
138 #endif
139     default:
140       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
141       break;
142   }
143 }
144
145 static void
146 gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass)
147 {
148   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
149   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
150   GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
151
152   gobject_class->finalize = gst_omx_video_dec_finalize;
153   gobject_class->set_property = gst_omx_video_dec_set_property;
154   gobject_class->get_property = gst_omx_video_dec_get_property;
155
156 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
157   g_object_class_install_property (gobject_class, PROP_INTERNAL_ENTROPY_BUFFERS,
158       g_param_spec_uint ("internal-entropy-buffers", "Internal entropy buffers",
159           "Number of internal buffers used by the decoder to smooth out entropy decoding performance. "
160           "Increasing it may improve the frame rate when decoding high bitrate streams. "
161           "Decreasing it reduces the memory footprint",
162           2, 16, GST_OMX_VIDEO_DEC_INTERNAL_ENTROPY_BUFFERS_DEFAULT,
163           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
164           GST_PARAM_MUTABLE_READY));
165 #endif
166
167   element_class->change_state =
168       GST_DEBUG_FUNCPTR (gst_omx_video_dec_change_state);
169
170   video_decoder_class->open = GST_DEBUG_FUNCPTR (gst_omx_video_dec_open);
171   video_decoder_class->close = GST_DEBUG_FUNCPTR (gst_omx_video_dec_close);
172   video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_dec_start);
173   video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_dec_stop);
174   video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_video_dec_flush);
175   video_decoder_class->set_format =
176       GST_DEBUG_FUNCPTR (gst_omx_video_dec_set_format);
177   video_decoder_class->handle_frame =
178       GST_DEBUG_FUNCPTR (gst_omx_video_dec_handle_frame);
179   video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_dec_finish);
180   video_decoder_class->drain = GST_DEBUG_FUNCPTR (gst_omx_video_dec_drain);
181   video_decoder_class->decide_allocation =
182       GST_DEBUG_FUNCPTR (gst_omx_video_dec_decide_allocation);
183   video_decoder_class->propose_allocation =
184       GST_DEBUG_FUNCPTR (gst_omx_video_dec_propose_allocation);
185
186   klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER;
187   klass->cdata.default_src_template_caps =
188 #if defined (HAVE_GST_GL)
189       GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
190       "RGBA") "; "
191 #endif
192       GST_VIDEO_CAPS_MAKE (GST_OMX_VIDEO_SUPPORTED_FORMATS);
193 }
194
195 static void
196 gst_omx_video_dec_init (GstOMXVideoDec * self)
197 {
198   self->dmabuf = FALSE;
199
200 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
201   self->internal_entropy_buffers =
202       GST_OMX_VIDEO_DEC_INTERNAL_ENTROPY_BUFFERS_DEFAULT;
203 #endif
204
205   gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
206   gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
207       (self), TRUE);
208   GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (self));
209
210   g_mutex_init (&self->drain_lock);
211   g_cond_init (&self->drain_cond);
212 }
213
214 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
215
216 #define CHECK_ERR(setting) \
217   if (err == OMX_ErrorUnsupportedIndex || err == OMX_ErrorUnsupportedSetting) { \
218     GST_WARNING_OBJECT (self, \
219         "Setting " setting " parameters not supported by the component"); \
220   } else if (err != OMX_ErrorNone) { \
221     GST_ERROR_OBJECT (self, \
222         "Failed to set " setting " parameters: %s (0x%08x)", \
223         gst_omx_error_to_string (err), err); \
224     return FALSE; \
225   }
226
227 static gboolean
228 set_zynqultrascaleplus_props (GstOMXVideoDec * self)
229 {
230   OMX_ERRORTYPE err;
231
232   {
233     OMX_ALG_VIDEO_PARAM_INTERNAL_ENTROPY_BUFFERS entropy_buffers;
234
235     GST_OMX_INIT_STRUCT (&entropy_buffers);
236     entropy_buffers.nPortIndex = self->dec_in_port->index;
237     entropy_buffers.nNumInternalEntropyBuffers = self->internal_entropy_buffers;
238
239     GST_DEBUG_OBJECT (self, "setting number of internal entropy buffers to %d",
240         self->internal_entropy_buffers);
241
242     err =
243         gst_omx_component_set_parameter (self->dec,
244         (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoInternalEntropyBuffers,
245         &entropy_buffers);
246     CHECK_ERR ("internal entropy buffers");
247   }
248
249   return TRUE;
250 }
251 #endif
252
253 static gboolean
254 gst_omx_video_dec_open (GstVideoDecoder * decoder)
255 {
256   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
257   GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
258   gint in_port_index, out_port_index;
259
260   GST_DEBUG_OBJECT (self, "Opening decoder");
261
262   self->dec =
263       gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
264       klass->cdata.component_name, klass->cdata.component_role,
265       klass->cdata.hacks);
266   self->started = FALSE;
267
268   if (!self->dec)
269     return FALSE;
270
271   if (gst_omx_component_get_state (self->dec,
272           GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
273     return FALSE;
274
275   in_port_index = klass->cdata.in_port_index;
276   out_port_index = klass->cdata.out_port_index;
277
278   if (in_port_index == -1 || out_port_index == -1) {
279     OMX_PORT_PARAM_TYPE param;
280     OMX_ERRORTYPE err;
281
282     GST_OMX_INIT_STRUCT (&param);
283
284     err =
285         gst_omx_component_get_parameter (self->dec, OMX_IndexParamVideoInit,
286         &param);
287     if (err != OMX_ErrorNone) {
288       GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
289           gst_omx_error_to_string (err), err);
290       /* Fallback */
291       in_port_index = 0;
292       out_port_index = 1;
293     } else {
294       GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
295           (guint) param.nPorts, (guint) param.nStartPortNumber);
296       in_port_index = param.nStartPortNumber + 0;
297       out_port_index = param.nStartPortNumber + 1;
298     }
299   }
300   self->dec_in_port = gst_omx_component_add_port (self->dec, in_port_index);
301   self->dec_out_port = gst_omx_component_add_port (self->dec, out_port_index);
302
303 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
304   GST_DEBUG_OBJECT (self, "Configure decoder output to export dmabuf");
305   self->dmabuf = gst_omx_port_set_dmabuf (self->dec_out_port, TRUE);
306 #endif
307
308   if (!self->dec_in_port || !self->dec_out_port)
309     return FALSE;
310
311   GST_DEBUG_OBJECT (self, "Opened decoder");
312
313 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
314   GST_DEBUG_OBJECT (self, "Opening EGL renderer");
315   self->egl_render =
316       gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
317       "OMX.broadcom.egl_render", NULL, klass->cdata.hacks);
318
319   if (!self->egl_render)
320     return FALSE;
321
322   if (gst_omx_component_get_state (self->egl_render,
323           GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
324     return FALSE;
325
326   {
327     OMX_PORT_PARAM_TYPE param;
328     OMX_ERRORTYPE err;
329
330     GST_OMX_INIT_STRUCT (&param);
331
332     err =
333         gst_omx_component_get_parameter (self->egl_render,
334         OMX_IndexParamVideoInit, &param);
335     if (err != OMX_ErrorNone) {
336       GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
337           gst_omx_error_to_string (err), err);
338       /* Fallback */
339       in_port_index = 0;
340       out_port_index = 1;
341     } else {
342       GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u", param.nPorts,
343           param.nStartPortNumber);
344       in_port_index = param.nStartPortNumber + 0;
345       out_port_index = param.nStartPortNumber + 1;
346     }
347   }
348
349   self->egl_in_port =
350       gst_omx_component_add_port (self->egl_render, in_port_index);
351   self->egl_out_port =
352       gst_omx_component_add_port (self->egl_render, out_port_index);
353
354   if (!self->egl_in_port || !self->egl_out_port)
355     return FALSE;
356
357   GST_DEBUG_OBJECT (self, "Opened EGL renderer");
358 #endif
359
360 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
361   if (!set_zynqultrascaleplus_props (self))
362     return FALSE;
363 #endif
364
365   return TRUE;
366 }
367
368 static gboolean
369 gst_omx_video_dec_shutdown (GstOMXVideoDec * self)
370 {
371   OMX_STATETYPE state;
372
373   GST_DEBUG_OBJECT (self, "Shutting down decoder");
374
375 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
376   state = gst_omx_component_get_state (self->egl_render, 0);
377   if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
378     if (state > OMX_StateIdle) {
379       gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
380       gst_omx_component_set_state (self->dec, OMX_StateIdle);
381       gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
382       gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
383     }
384     gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
385     gst_omx_component_set_state (self->dec, OMX_StateLoaded);
386
387     gst_omx_port_deallocate_buffers (self->dec_in_port);
388     gst_omx_video_dec_deallocate_output_buffers (self);
389     gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
390     if (state > OMX_StateLoaded) {
391       gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
392       gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
393     }
394   }
395
396   /* Otherwise we didn't use EGL and just fall back to 
397    * shutting down the decoder */
398 #endif
399
400   state = gst_omx_component_get_state (self->dec, 0);
401   if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
402     if (state > OMX_StateIdle) {
403       gst_omx_component_set_state (self->dec, OMX_StateIdle);
404       gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
405     }
406     gst_omx_component_set_state (self->dec, OMX_StateLoaded);
407     gst_omx_port_deallocate_buffers (self->dec_in_port);
408     gst_omx_video_dec_deallocate_output_buffers (self);
409     if (state > OMX_StateLoaded) {
410       if (self->dec_out_port->buffers)
411         /* Don't wait for the state transition if the pool still has outstanding
412          * buffers as it will timeout anyway */
413         GST_WARNING_OBJECT (self,
414             "Output buffers haven't been freed; still owned downstream?");
415       else
416         gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
417     }
418   }
419
420   return TRUE;
421 }
422
423 static gboolean
424 gst_omx_video_dec_close (GstVideoDecoder * decoder)
425 {
426   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
427
428   GST_DEBUG_OBJECT (self, "Closing decoder");
429
430   if (!gst_omx_video_dec_shutdown (self))
431     return FALSE;
432
433   self->dec_in_port = NULL;
434   self->dec_out_port = NULL;
435   if (self->dec)
436     gst_omx_component_unref (self->dec);
437   self->dec = NULL;
438
439 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
440   self->egl_in_port = NULL;
441   self->egl_out_port = NULL;
442   if (self->egl_render)
443     gst_omx_component_unref (self->egl_render);
444   self->egl_render = NULL;
445 #endif
446
447   self->started = FALSE;
448
449   GST_DEBUG_OBJECT (self, "Closed decoder");
450
451   return TRUE;
452 }
453
454 static void
455 gst_omx_video_dec_finalize (GObject * object)
456 {
457   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (object);
458
459   g_mutex_clear (&self->drain_lock);
460   g_cond_clear (&self->drain_cond);
461
462   G_OBJECT_CLASS (gst_omx_video_dec_parent_class)->finalize (object);
463 }
464
465 static GstStateChangeReturn
466 gst_omx_video_dec_change_state (GstElement * element, GstStateChange transition)
467 {
468   GstOMXVideoDec *self;
469   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
470
471   g_return_val_if_fail (GST_IS_OMX_VIDEO_DEC (element),
472       GST_STATE_CHANGE_FAILURE);
473   self = GST_OMX_VIDEO_DEC (element);
474
475   switch (transition) {
476     case GST_STATE_CHANGE_NULL_TO_READY:
477       break;
478     case GST_STATE_CHANGE_READY_TO_PAUSED:
479       self->downstream_flow_ret = GST_FLOW_OK;
480       self->draining = FALSE;
481       self->started = FALSE;
482       self->use_buffers = FALSE;
483       break;
484     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
485       break;
486     case GST_STATE_CHANGE_PAUSED_TO_READY:
487       if (self->dec_in_port)
488         gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
489       if (self->dec_out_port)
490         gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
491 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
492       if (self->egl_in_port)
493         gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
494       if (self->egl_out_port)
495         gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
496 #endif
497
498       g_mutex_lock (&self->drain_lock);
499       self->draining = FALSE;
500       g_cond_broadcast (&self->drain_cond);
501       g_mutex_unlock (&self->drain_lock);
502       break;
503     default:
504       break;
505   }
506
507   ret =
508       GST_ELEMENT_CLASS (gst_omx_video_dec_parent_class)->change_state
509       (element, transition);
510
511   if (ret == GST_STATE_CHANGE_FAILURE)
512     return ret;
513
514   switch (transition) {
515     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
516       break;
517     case GST_STATE_CHANGE_PAUSED_TO_READY:
518       self->downstream_flow_ret = GST_FLOW_FLUSHING;
519       self->started = FALSE;
520       break;
521     case GST_STATE_CHANGE_READY_TO_NULL:
522       break;
523     default:
524       break;
525   }
526
527   return ret;
528 }
529
530 static gboolean
531 gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self,
532     GstOMXBuffer * inbuf, GstBuffer * outbuf)
533 {
534   GstVideoCodecState *state =
535       gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
536   GstVideoInfo *vinfo = &state->info;
537   OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->dec_out_port->port_def;
538   gboolean ret = FALSE;
539   GstVideoFrame frame;
540
541   if (vinfo->width != port_def->format.video.nFrameWidth ||
542       vinfo->height != port_def->format.video.nFrameHeight) {
543     GST_ERROR_OBJECT (self, "Resolution do not match: port=%ux%u vinfo=%dx%d",
544         (guint) port_def->format.video.nFrameWidth,
545         (guint) port_def->format.video.nFrameHeight,
546         vinfo->width, vinfo->height);
547     goto done;
548   }
549
550   /* Same strides and everything */
551   if (gst_buffer_get_size (outbuf) == inbuf->omx_buf->nFilledLen) {
552     GstMapInfo map = GST_MAP_INFO_INIT;
553
554     if (!gst_buffer_map (outbuf, &map, GST_MAP_WRITE)) {
555       GST_ERROR_OBJECT (self, "Failed to map output buffer");
556       goto done;
557     }
558
559     memcpy (map.data,
560         inbuf->omx_buf->pBuffer + inbuf->omx_buf->nOffset,
561         inbuf->omx_buf->nFilledLen);
562     gst_buffer_unmap (outbuf, &map);
563     ret = TRUE;
564     goto done;
565   }
566
567   /* Different strides */
568   if (gst_video_frame_map (&frame, vinfo, outbuf, GST_MAP_WRITE)) {
569     const guint nstride = port_def->format.video.nStride;
570     const guint nslice = port_def->format.video.nSliceHeight;
571     guint src_stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };
572     guint src_size[GST_VIDEO_MAX_PLANES] = { nstride * nslice, 0, };
573     gint dst_width[GST_VIDEO_MAX_PLANES] = { 0, };
574     gint dst_height[GST_VIDEO_MAX_PLANES] =
575         { GST_VIDEO_INFO_HEIGHT (vinfo), 0, };
576     const guint8 *src;
577     guint p;
578
579     switch (GST_VIDEO_INFO_FORMAT (vinfo)) {
580       case GST_VIDEO_FORMAT_ABGR:
581       case GST_VIDEO_FORMAT_ARGB:
582         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo) * 4;
583         break;
584       case GST_VIDEO_FORMAT_RGB16:
585       case GST_VIDEO_FORMAT_BGR16:
586       case GST_VIDEO_FORMAT_YUY2:
587       case GST_VIDEO_FORMAT_UYVY:
588       case GST_VIDEO_FORMAT_YVYU:
589         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo) * 2;
590         break;
591       case GST_VIDEO_FORMAT_GRAY8:
592         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
593         break;
594       case GST_VIDEO_FORMAT_I420:
595         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
596         src_stride[1] = nstride / 2;
597         src_size[1] = (src_stride[1] * nslice) / 2;
598         dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo) / 2;
599         dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
600         src_stride[2] = nstride / 2;
601         src_size[2] = (src_stride[1] * nslice) / 2;
602         dst_width[2] = GST_VIDEO_INFO_WIDTH (vinfo) / 2;
603         dst_height[2] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
604         break;
605       case GST_VIDEO_FORMAT_NV12:
606         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
607         src_stride[1] = nstride;
608         src_size[1] = src_stride[1] * nslice / 2;
609         dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo);
610         dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
611         break;
612       case GST_VIDEO_FORMAT_NV16:
613         dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
614         src_stride[1] = nstride;
615         src_size[1] = src_stride[1] * nslice;
616         dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo);
617         dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo);
618         break;
619       case GST_VIDEO_FORMAT_NV12_10LE32:
620         /* Need ((width + 2) / 3) 32-bits words */
621         dst_width[0] = (GST_VIDEO_INFO_WIDTH (vinfo) + 2) / 3 * 4;
622         dst_width[1] = dst_width[0];
623         src_stride[1] = nstride;
624         src_size[1] = src_stride[1] * nslice / 2;
625         dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
626         break;
627       case GST_VIDEO_FORMAT_NV16_10LE32:
628         /* Need ((width + 2) / 3) 32-bits words */
629         dst_width[0] = (GST_VIDEO_INFO_WIDTH (vinfo) + 2) / 3 * 4;
630         dst_width[1] = dst_width[0];
631         src_stride[1] = nstride;
632         src_size[1] = src_stride[1] * nslice;
633         dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo);
634         break;
635       default:
636         g_assert_not_reached ();
637         break;
638     }
639
640     src = inbuf->omx_buf->pBuffer + inbuf->omx_buf->nOffset;
641     for (p = 0; p < GST_VIDEO_INFO_N_PLANES (vinfo); p++) {
642       const guint8 *data;
643       guint8 *dst;
644       guint h;
645
646       dst = GST_VIDEO_FRAME_PLANE_DATA (&frame, p);
647       data = src;
648       for (h = 0; h < dst_height[p]; h++) {
649         memcpy (dst, data, dst_width[p]);
650         dst += GST_VIDEO_FRAME_PLANE_STRIDE (&frame, p);
651         data += src_stride[p];
652       }
653       src += src_size[p];
654     }
655
656     gst_video_frame_unmap (&frame);
657     ret = TRUE;
658   } else {
659     GST_ERROR_OBJECT (self, "Can't map output buffer to frame");
660     goto done;
661   }
662
663 done:
664   if (ret) {
665     GST_BUFFER_PTS (outbuf) =
666         gst_util_uint64_scale (GST_OMX_GET_TICKS (inbuf->omx_buf->nTimeStamp),
667         GST_SECOND, OMX_TICKS_PER_SECOND);
668     if (inbuf->omx_buf->nTickCount != 0)
669       GST_BUFFER_DURATION (outbuf) =
670           gst_util_uint64_scale (inbuf->omx_buf->nTickCount, GST_SECOND,
671           OMX_TICKS_PER_SECOND);
672   }
673
674   gst_video_codec_state_unref (state);
675
676   return ret;
677 }
678
679 static GstBuffer *
680 gst_omx_try_importing_buffer (GstOMXVideoDec * self, GstBufferPool * pool,
681     GstOMXPort * port, GstVideoInfo * v_info, guint i, GstVideoFrame ** frame)
682 {
683   GstBufferPoolAcquireParams params = { 0, };
684   GstBuffer *buffer = NULL;
685   GstMemory *mem;
686   GstMapFlags flags = GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF;
687   gboolean is_mapped = FALSE;
688
689   *frame = NULL;
690
691   if (gst_buffer_pool_acquire_buffer (pool, &buffer, &params) != GST_FLOW_OK) {
692     GST_INFO_OBJECT (self, "Failed to acquire %d-th buffer", i);
693     return NULL;
694   }
695
696   if (gst_buffer_n_memory (buffer) != 1) {
697     GST_INFO_OBJECT (self, "%d-th buffer has more than one memory (%d)", i,
698         gst_buffer_n_memory (buffer));
699     goto out;
700   }
701
702   mem = gst_buffer_peek_memory (buffer, 0);
703   if (!mem) {
704     GST_INFO_OBJECT (self, "Failed to acquire memory of %d-th buffer", i);
705     goto out;
706   }
707
708   if (self->dmabuf && !gst_is_dmabuf_memory (mem)) {
709     GST_INFO_OBJECT (self,
710         "%d-th buffer doesn't contain dmabuf while the decoder is in dmabuf mode",
711         i);
712     goto out;
713   }
714
715   *frame = g_slice_new0 (GstVideoFrame);
716
717   is_mapped = gst_video_frame_map (*frame, v_info, buffer, flags);
718   if (!is_mapped) {
719     GST_INFO_OBJECT (self, "Failed to map %d-th buffer", i);
720     goto out;
721   }
722
723   if (GST_VIDEO_FRAME_SIZE (*frame) < port->port_def.nBufferSize) {
724     GST_INFO_OBJECT (self,
725         "Frame size of %d-th buffer (%" G_GSIZE_FORMAT
726         ") is too small for port buffer size (%d)", i,
727         GST_VIDEO_FRAME_SIZE (*frame), (guint32) port->port_def.nBufferSize);
728     goto out;
729   }
730
731   return buffer;
732
733 out:
734   if (*frame) {
735     if (is_mapped)
736       gst_video_frame_unmap (*frame);
737     g_slice_free (GstVideoFrame, *frame);
738     *frame = NULL;
739   }
740   gst_buffer_unref (buffer);
741   return NULL;
742 }
743
744 static OMX_ERRORTYPE
745 gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
746 {
747   OMX_ERRORTYPE err = OMX_ErrorNone;
748   GstOMXPort *port;
749   GstBufferPool *pool;
750   GstStructure *config;
751   gboolean eglimage = FALSE, add_videometa = FALSE;
752   GstCaps *caps = NULL;
753   guint min = 0, max = 0;
754   GstVideoCodecState *state =
755       gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
756
757 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
758   port = self->eglimage ? self->egl_out_port : self->dec_out_port;
759 #else
760   port = self->dec_out_port;
761 #endif
762
763   pool = gst_video_decoder_get_buffer_pool (GST_VIDEO_DECODER (self));
764   if (pool) {
765     GstAllocator *allocator;
766
767     config = gst_buffer_pool_get_config (pool);
768     if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min, &max)) {
769       GST_ERROR_OBJECT (self, "Can't get buffer pool params");
770       gst_structure_free (config);
771       err = OMX_ErrorUndefined;
772       goto done;
773     }
774     if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) {
775       GST_ERROR_OBJECT (self, "Can't get buffer pool allocator");
776       gst_structure_free (config);
777       err = OMX_ErrorUndefined;
778       goto done;
779     }
780
781     /* Need at least 4 buffers for anything meaningful */
782     min = MAX (min + port->port_def.nBufferCountMin, 4);
783     if (max == 0) {
784       max = min;
785     } else if (max < min) {
786       /* Can't use pool because can't have enough buffers */
787       GST_DEBUG_OBJECT (self,
788           "pool can only provide %d buffers but %d are required", max, min);
789       caps = NULL;
790     } else {
791       min = max;
792     }
793
794     add_videometa = gst_buffer_pool_config_has_option (config,
795         GST_BUFFER_POOL_OPTION_VIDEO_META);
796     gst_structure_free (config);
797
798 #if defined (HAVE_GST_GL)
799     eglimage = self->eglimage
800         && (allocator && GST_IS_GL_MEMORY_EGL_ALLOCATOR (allocator));
801 #else
802     eglimage = FALSE;
803 #endif
804     caps = caps ? gst_caps_ref (caps) : NULL;
805
806     GST_DEBUG_OBJECT (self, "Trying to use pool %p with caps %" GST_PTR_FORMAT
807         " and memory type %s", pool, caps,
808         (allocator ? allocator->mem_type : "(null)"));
809   } else {
810     gst_caps_replace (&caps, NULL);
811     min = max = port->port_def.nBufferCountMin;
812     GST_DEBUG_OBJECT (self, "No pool available, not negotiated yet");
813   }
814
815 #if defined (HAVE_GST_GL)
816   /* Will retry without EGLImage */
817   if (self->eglimage && !eglimage) {
818     GST_DEBUG_OBJECT (self,
819         "Wanted to use EGLImage but downstream doesn't support it");
820     err = OMX_ErrorUndefined;
821     goto done;
822   }
823 #endif
824
825   if (caps)
826     self->out_port_pool =
827         gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->dec, port,
828         self->dmabuf ? GST_OMX_BUFFER_MODE_DMABUF :
829         GST_OMX_BUFFER_MODE_SYSTEM_MEMORY);
830
831 #if defined (HAVE_GST_GL)
832   if (eglimage) {
833     GList *buffers = NULL;
834     GList *images = NULL;
835     gint i;
836     GstBufferPoolAcquireParams params = { 0, };
837     gpointer egl_display = 0;
838
839     GST_DEBUG_OBJECT (self, "Trying to allocate %d EGLImages", min);
840
841     for (i = 0; i < min; i++) {
842       GstBuffer *buffer = NULL;
843       GstMemory *mem;
844       GstGLMemoryEGL *gl_mem;
845
846       if (gst_buffer_pool_acquire_buffer (pool, &buffer, &params) != GST_FLOW_OK
847           || gst_buffer_n_memory (buffer) != 1
848           || !(mem = gst_buffer_peek_memory (buffer, 0))
849           || !GST_IS_GL_MEMORY_EGL_ALLOCATOR (mem->allocator)) {
850         GST_INFO_OBJECT (self, "Failed to allocated %d-th EGLImage", i);
851         gst_buffer_replace (&buffer, NULL);
852         g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
853         g_list_free (images);
854         buffers = NULL;
855         images = NULL;
856         err = OMX_ErrorUndefined;
857         goto done;
858       }
859       gl_mem = (GstGLMemoryEGL *) mem;
860       buffers = g_list_append (buffers, buffer);
861       images = g_list_append (images, gst_gl_memory_egl_get_image (gl_mem));
862       if (!egl_display)
863         egl_display = gst_gl_memory_egl_get_display (gl_mem);
864     }
865
866     GST_DEBUG_OBJECT (self, "Allocated %d EGLImages successfully", min);
867
868     /* Everything went fine? */
869     if (eglimage) {
870       GST_DEBUG_OBJECT (self, "Setting EGLDisplay");
871       port->port_def.format.video.pNativeWindow = egl_display;
872       err = gst_omx_port_update_port_definition (port, &port->port_def);
873       if (err != OMX_ErrorNone) {
874         GST_INFO_OBJECT (self,
875             "Failed to set EGLDisplay on port: %s (0x%08x)",
876             gst_omx_error_to_string (err), err);
877         g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
878         g_list_free (images);
879         goto done;
880       } else {
881         GList *l;
882
883         if (min != port->port_def.nBufferCountActual) {
884           err = gst_omx_port_update_port_definition (port, NULL);
885           if (err == OMX_ErrorNone) {
886             port->port_def.nBufferCountActual = min;
887             err = gst_omx_port_update_port_definition (port, &port->port_def);
888           }
889
890           if (err != OMX_ErrorNone) {
891             GST_INFO_OBJECT (self,
892                 "Failed to configure %u output buffers: %s (0x%08x)", min,
893                 gst_omx_error_to_string (err), err);
894             g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
895             g_list_free (images);
896             goto done;
897           }
898 #if OMX_VERSION_MINOR == 2
899           /* In OMX-IL 1.2.0, the nBufferCountActual change is propagated to the
900            * the input port upon call to the SetParameter on out port above. This
901            * propagation triggers a SettingsChanged event. It is up to the client
902            * to decide if this event should lead to reconfigure the port. Here
903            * this is clearly informal so lets just acknowledge the event to avoid
904            * input port reconfiguration. Note that the SettingsChanged event will
905            * be sent in-context of the SetParameter call above. So the event is
906            * garantie to be proceeded in the handle_message call below. */
907           err = gst_omx_port_mark_reconfigured (self->dec_in_port);
908
909           if (err != OMX_ErrorNone) {
910             GST_ERROR_OBJECT (self,
911                 "Failed to acknowledge port settings changed: %s (0x%08x)",
912                 gst_omx_error_to_string (err), err);
913             g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
914             g_list_free (images);
915             goto done;
916           }
917 #endif
918         }
919
920         if (!gst_omx_port_is_enabled (port)) {
921           err = gst_omx_port_set_enabled (port, TRUE);
922           if (err != OMX_ErrorNone) {
923             GST_INFO_OBJECT (self,
924                 "Failed to enable port: %s (0x%08x)",
925                 gst_omx_error_to_string (err), err);
926             g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
927             g_list_free (images);
928             goto done;
929           }
930         }
931
932         err = gst_omx_port_use_eglimages (port, images);
933         g_list_free (images);
934
935         if (err != OMX_ErrorNone) {
936           GST_INFO_OBJECT (self,
937               "Failed to pass EGLImages to port: %s (0x%08x)",
938               gst_omx_error_to_string (err), err);
939           g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
940           goto done;
941         }
942
943         err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND);
944         if (err != OMX_ErrorNone) {
945           GST_INFO_OBJECT (self,
946               "Failed to wait until port is enabled: %s (0x%08x)",
947               gst_omx_error_to_string (err), err);
948           g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
949           goto done;
950         }
951
952         GST_DEBUG_OBJECT (self, "Populating internal buffer pool");
953         GST_OMX_BUFFER_POOL (self->out_port_pool)->other_pool =
954             GST_BUFFER_POOL (gst_object_ref (pool));
955         for (l = buffers; l; l = l->next) {
956           g_ptr_array_add (GST_OMX_BUFFER_POOL (self->out_port_pool)->buffers,
957               l->data);
958         }
959         g_list_free (buffers);
960         /* All good and done, set caps below */
961       }
962     }
963   }
964 #endif /* defined (HAVE_GST_GL) */
965
966   /* If not using EGLImage or trying to use EGLImage failed */
967   if (!eglimage) {
968     gboolean was_enabled = TRUE;
969     GList *buffers = NULL;
970     GList *l = NULL;
971
972     if (min != port->port_def.nBufferCountActual) {
973       err = gst_omx_port_update_port_definition (port, NULL);
974       if (err == OMX_ErrorNone) {
975         port->port_def.nBufferCountActual = min;
976         err = gst_omx_port_update_port_definition (port, &port->port_def);
977       }
978
979       if (err != OMX_ErrorNone) {
980         GST_ERROR_OBJECT (self,
981             "Failed to configure %u output buffers: %s (0x%08x)", min,
982             gst_omx_error_to_string (err), err);
983         goto done;
984       }
985 #if OMX_VERSION_MINOR == 2
986       /* In OMX-IL 1.2.0, the nBufferCountActual change is propagated to the
987        * the input port upon call to the SetParameter on out port above. This
988        * propagation triggers a SettingsChanged event. It is up to the client
989        * to decide if this event should lead to reconfigure the port. Here
990        * this is clearly informal so lets just acknowledge the event to avoid
991        * input port reconfiguration. Note that the SettingsChanged event will
992        * be sent in-context of the SetParameter call above. So the event is
993        * garantie to be proceeded in the handle_message call below. */
994       err = gst_omx_port_mark_reconfigured (self->dec_in_port);
995
996       if (err != OMX_ErrorNone) {
997         GST_ERROR_OBJECT (self,
998             "Failed to acknowledge port settings changed: %s (0x%08x)",
999             gst_omx_error_to_string (err), err);
1000         goto done;
1001       }
1002 #endif
1003     }
1004
1005     if (!gst_omx_port_is_enabled (port)) {
1006       err = gst_omx_port_set_enabled (port, TRUE);
1007       if (err != OMX_ErrorNone) {
1008         GST_INFO_OBJECT (self,
1009             "Failed to enable port: %s (0x%08x)",
1010             gst_omx_error_to_string (err), err);
1011         goto done;
1012       }
1013       was_enabled = FALSE;
1014     }
1015
1016     if (!caps)
1017       self->use_buffers = FALSE;
1018
1019     if (self->use_buffers) {
1020       GList *images = NULL;
1021       GList *frames = NULL;
1022       GstVideoInfo v_info;
1023       gint i;
1024
1025       if (!gst_video_info_from_caps (&v_info, caps)) {
1026         GST_INFO_OBJECT (self,
1027             "Failed to get video info from caps %" GST_PTR_FORMAT, caps);
1028         err = OMX_ErrorUndefined;
1029         self->use_buffers = FALSE;
1030       }
1031
1032       GST_DEBUG_OBJECT (self, "Trying to use %d buffers", min);
1033
1034       for (i = 0; i < min && self->use_buffers; i++) {
1035         GstBuffer *buffer = NULL;
1036         GstVideoFrame *frame = NULL;
1037
1038         buffer =
1039             gst_omx_try_importing_buffer (self, pool, port, &v_info, i, &frame);
1040         if (!buffer) {
1041           /* buffer does not match minimal requirement to try OMX_UseBuffer */
1042           GST_DEBUG_OBJECT (self, "Failed to import %d-th buffer", i);
1043           g_list_free (images);
1044           g_list_free_full (frames, (GDestroyNotify) gst_video_frame_unmap);
1045           g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
1046           buffers = NULL;
1047           images = NULL;
1048           err = OMX_ErrorUndefined;
1049           self->use_buffers = FALSE;
1050           break;
1051         } else {
1052           /* if downstream pool is 1 n_mem then always try to use buffers
1053            * and retry without using them if it fails */
1054           GstMemory *mem;
1055
1056           buffers = g_list_append (buffers, buffer);
1057           frames = g_list_append (frames, frame);
1058
1059           mem = gst_buffer_peek_memory (buffer, 0);
1060           if (self->dmabuf && gst_is_dmabuf_memory (mem))
1061             /* Use the imported fd rather than mapped address in dmabuf mode */
1062             images =
1063                 g_list_append (images,
1064                 GUINT_TO_POINTER (gst_dmabuf_memory_get_fd (mem)));
1065           else
1066             images =
1067                 g_list_append (images, GST_VIDEO_FRAME_PLANE_DATA (frame, 0));
1068         }
1069       }
1070
1071       /* buffers match minimal requirements then
1072        * now try to actually use them */
1073       if (images) {
1074         err = gst_omx_port_use_buffers (port, images);
1075         g_list_free (images);
1076         g_list_free_full (frames, (GDestroyNotify) gst_video_frame_unmap);
1077
1078         if (err == OMX_ErrorNone) {
1079           GST_DEBUG_OBJECT (self, "Using %d buffers", min);
1080         } else {
1081           GST_INFO_OBJECT (self,
1082               "Failed to OMX_UseBuffer on port: %s (0x%08x)",
1083               gst_omx_error_to_string (err), err);
1084           g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
1085           self->use_buffers = FALSE;
1086         }
1087       }
1088     }
1089
1090     if (!self->use_buffers)
1091       err = gst_omx_port_allocate_buffers (port);
1092
1093     if (err != OMX_ErrorNone && min > port->port_def.nBufferCountMin) {
1094       GST_ERROR_OBJECT (self,
1095           "Failed to allocate required number of buffers %d, trying less and copying",
1096           min);
1097       min = port->port_def.nBufferCountMin;
1098
1099       if (!was_enabled) {
1100         err = gst_omx_port_set_enabled (port, FALSE);
1101         if (err != OMX_ErrorNone) {
1102           GST_INFO_OBJECT (self,
1103               "Failed to disable port again: %s (0x%08x)",
1104               gst_omx_error_to_string (err), err);
1105           goto done;
1106         }
1107       }
1108
1109       if (min != port->port_def.nBufferCountActual) {
1110         err = gst_omx_port_update_port_definition (port, NULL);
1111         if (err == OMX_ErrorNone) {
1112           port->port_def.nBufferCountActual = min;
1113           err = gst_omx_port_update_port_definition (port, &port->port_def);
1114         }
1115
1116         if (err != OMX_ErrorNone) {
1117           GST_ERROR_OBJECT (self,
1118               "Failed to configure %u output buffers: %s (0x%08x)", min,
1119               gst_omx_error_to_string (err), err);
1120           goto done;
1121         }
1122       }
1123
1124       err = gst_omx_port_allocate_buffers (port);
1125
1126       /* Can't provide buffers downstream in this case */
1127       gst_caps_replace (&caps, NULL);
1128     }
1129
1130     if (err != OMX_ErrorNone) {
1131       GST_ERROR_OBJECT (self, "Failed to allocate %d buffers: %s (0x%08x)", min,
1132           gst_omx_error_to_string (err), err);
1133       goto done;
1134     }
1135
1136     if (!was_enabled) {
1137       err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND);
1138       if (err != OMX_ErrorNone) {
1139         GST_ERROR_OBJECT (self,
1140             "Failed to wait until port is enabled: %s (0x%08x)",
1141             gst_omx_error_to_string (err), err);
1142         goto done;
1143       }
1144     }
1145
1146     if (self->use_buffers) {
1147       GST_DEBUG_OBJECT (self, "Populating internal buffer pool");
1148       GST_OMX_BUFFER_POOL (self->out_port_pool)->other_pool =
1149           GST_BUFFER_POOL (gst_object_ref (pool));
1150       for (l = buffers; l; l = l->next) {
1151         g_ptr_array_add (GST_OMX_BUFFER_POOL (self->out_port_pool)->buffers,
1152             l->data);
1153       }
1154       g_list_free (buffers);
1155     }
1156
1157   }
1158
1159   err = OMX_ErrorNone;
1160
1161   if (caps) {
1162     config = gst_buffer_pool_get_config (self->out_port_pool);
1163
1164     if (add_videometa)
1165       gst_buffer_pool_config_add_option (config,
1166           GST_BUFFER_POOL_OPTION_VIDEO_META);
1167
1168     gst_buffer_pool_config_set_params (config, caps,
1169         self->dec_out_port->port_def.nBufferSize, min, max);
1170
1171     if (!gst_buffer_pool_set_config (self->out_port_pool, config)) {
1172       GST_INFO_OBJECT (self, "Failed to set config on internal pool");
1173       gst_object_unref (self->out_port_pool);
1174       self->out_port_pool = NULL;
1175       goto done;
1176     }
1177
1178     /* This now allocates all the buffers */
1179     if (!gst_buffer_pool_set_active (self->out_port_pool, TRUE)) {
1180       GST_INFO_OBJECT (self, "Failed to activate internal pool");
1181       gst_object_unref (self->out_port_pool);
1182       self->out_port_pool = NULL;
1183     } else if (!self->use_buffers) {
1184       gst_buffer_pool_set_active (pool, FALSE);
1185     }
1186   } else if (self->out_port_pool) {
1187     gst_object_unref (self->out_port_pool);
1188     self->out_port_pool = NULL;
1189   }
1190
1191 done:
1192   if (!self->out_port_pool && err == OMX_ErrorNone)
1193     GST_DEBUG_OBJECT (self,
1194         "Not using our internal pool and copying buffers for downstream");
1195
1196   if (caps)
1197     gst_caps_unref (caps);
1198   if (pool)
1199     gst_object_unref (pool);
1200   if (state)
1201     gst_video_codec_state_unref (state);
1202
1203   return err;
1204 }
1205
1206 static gboolean
1207 gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self)
1208 {
1209   if (self->out_port_pool) {
1210     /* Pool will free buffers when stopping */
1211     gst_buffer_pool_set_active (self->out_port_pool, FALSE);
1212 #if 0
1213     gst_buffer_pool_wait_released (self->out_port_pool);
1214 #endif
1215     GST_OMX_BUFFER_POOL (self->out_port_pool)->deactivated = TRUE;
1216     gst_object_unref (self->out_port_pool);
1217     self->out_port_pool = NULL;
1218   } else {
1219     OMX_ERRORTYPE err;
1220
1221 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1222     err =
1223         gst_omx_port_deallocate_buffers (self->eglimage ? self->
1224         egl_out_port : self->dec_out_port);
1225 #else
1226     err = gst_omx_port_deallocate_buffers (self->dec_out_port);
1227 #endif
1228
1229     return err == OMX_ErrorNone;
1230   }
1231
1232   return TRUE;
1233 }
1234
1235 static OMX_ERRORTYPE
1236 gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self)
1237 {
1238   GstOMXPort *port;
1239   OMX_ERRORTYPE err;
1240   GstVideoCodecState *state;
1241   OMX_PARAM_PORTDEFINITIONTYPE port_def;
1242   GstVideoFormat format;
1243
1244   /* At this point the decoder output port is disabled */
1245
1246 #if defined (HAVE_GST_GL)
1247   {
1248 #if defined (USE_OMX_TARGET_RPI)
1249     OMX_STATETYPE egl_state;
1250 #endif
1251
1252     if (self->eglimage) {
1253       /* Nothing to do here, we could however fall back to non-EGLImage in theory */
1254 #if defined (USE_OMX_TARGET_RPI)
1255       port = self->egl_out_port;
1256 #else
1257       port = self->dec_out_port;
1258 #endif
1259       err = OMX_ErrorNone;
1260       goto enable_port;
1261     } else {
1262       /* Set up egl_render */
1263
1264       self->eglimage = TRUE;
1265
1266       gst_omx_port_get_port_definition (self->dec_out_port, &port_def);
1267       GST_VIDEO_DECODER_STREAM_LOCK (self);
1268       state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1269           GST_VIDEO_FORMAT_RGBA, port_def.format.video.nFrameWidth,
1270           port_def.format.video.nFrameHeight, self->input_state);
1271
1272       /* at this point state->caps is NULL */
1273       if (state->caps)
1274         gst_caps_unref (state->caps);
1275       state->caps = gst_video_info_to_caps (&state->info);
1276       gst_caps_set_features (state->caps, 0,
1277           gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, NULL));
1278
1279       /* try to negotiate with caps feature */
1280       if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1281
1282         GST_DEBUG_OBJECT (self,
1283             "Failed to negotiate with feature %s",
1284             GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
1285
1286         if (state->caps)
1287           gst_caps_replace (&state->caps, NULL);
1288
1289 #if defined (USE_OMX_TARGET_RPI)
1290         /* fallback: try to use EGLImage even if it is not in the caps feature */
1291         if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1292           gst_video_codec_state_unref (state);
1293           GST_DEBUG_OBJECT (self, "Failed to negotiate RGBA for EGLImage");
1294           GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1295           goto no_egl;
1296         }
1297 #else
1298         gst_video_codec_state_unref (state);
1299         GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1300         goto no_egl;
1301 #endif
1302       }
1303
1304       gst_video_codec_state_unref (state);
1305       GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1306
1307 #if defined (USE_OMX_TARGET_RPI)
1308       /* Now link it all together */
1309
1310       err = gst_omx_port_set_enabled (self->egl_in_port, FALSE);
1311       if (err != OMX_ErrorNone)
1312         goto no_egl;
1313
1314       err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
1315       if (err != OMX_ErrorNone)
1316         goto no_egl;
1317
1318       err = gst_omx_port_set_enabled (self->egl_out_port, FALSE);
1319       if (err != OMX_ErrorNone)
1320         goto no_egl;
1321
1322       err = gst_omx_port_wait_enabled (self->egl_out_port, 1 * GST_SECOND);
1323       if (err != OMX_ErrorNone)
1324         goto no_egl;
1325
1326       {
1327 #define OMX_IndexParamBrcmVideoEGLRenderDiscardMode 0x7f0000db
1328         OMX_CONFIG_PORTBOOLEANTYPE discardMode;
1329         memset (&discardMode, 0, sizeof (discardMode));
1330         discardMode.nSize = sizeof (discardMode);
1331         discardMode.nPortIndex = 220;
1332         discardMode.nVersion.nVersion = OMX_VERSION;
1333         discardMode.bEnabled = OMX_FALSE;
1334         if (gst_omx_component_set_parameter (self->egl_render,
1335                 OMX_IndexParamBrcmVideoEGLRenderDiscardMode,
1336                 &discardMode) != OMX_ErrorNone)
1337           goto no_egl;
1338 #undef OMX_IndexParamBrcmVideoEGLRenderDiscardMode
1339       }
1340
1341       err = gst_omx_setup_tunnel (self->dec_out_port, self->egl_in_port);
1342       if (err != OMX_ErrorNone)
1343         goto no_egl;
1344
1345       err = gst_omx_port_set_enabled (self->egl_in_port, TRUE);
1346       if (err != OMX_ErrorNone)
1347         goto no_egl;
1348
1349       err = gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1350       if (err != OMX_ErrorNone)
1351         goto no_egl;
1352
1353       err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
1354       if (err != OMX_ErrorNone)
1355         goto no_egl;
1356
1357       if (gst_omx_component_get_state (self->egl_render,
1358               GST_CLOCK_TIME_NONE) != OMX_StateIdle)
1359         goto no_egl;
1360
1361       err = gst_omx_video_dec_allocate_output_buffers (self);
1362       if (err != OMX_ErrorNone)
1363         goto no_egl;
1364
1365       if (gst_omx_component_set_state (self->egl_render,
1366               OMX_StateExecuting) != OMX_ErrorNone)
1367         goto no_egl;
1368
1369       if (gst_omx_component_get_state (self->egl_render,
1370               GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
1371         goto no_egl;
1372
1373       err =
1374           gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
1375       if (err != OMX_ErrorNone)
1376         goto no_egl;
1377
1378       err =
1379           gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
1380       if (err != OMX_ErrorNone)
1381         goto no_egl;
1382
1383       err =
1384           gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
1385       if (err != OMX_ErrorNone)
1386         goto no_egl;
1387
1388       err = gst_omx_port_populate (self->egl_out_port);
1389       if (err != OMX_ErrorNone)
1390         goto no_egl;
1391
1392       err = gst_omx_port_set_enabled (self->dec_out_port, TRUE);
1393       if (err != OMX_ErrorNone)
1394         goto no_egl;
1395
1396       err = gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
1397       if (err != OMX_ErrorNone)
1398         goto no_egl;
1399
1400
1401       err = gst_omx_port_mark_reconfigured (self->dec_out_port);
1402       if (err != OMX_ErrorNone)
1403         goto no_egl;
1404
1405       err = gst_omx_port_mark_reconfigured (self->egl_out_port);
1406       if (err != OMX_ErrorNone)
1407         goto no_egl;
1408
1409       goto done;
1410 #else
1411       port = self->dec_out_port;
1412       err = OMX_ErrorNone;
1413       goto enable_port;
1414 #endif /* defined (USE_OMX_TARGET_RPI) */
1415     }
1416
1417   no_egl:
1418
1419 #if defined (USE_OMX_TARGET_RPI)
1420     gst_omx_port_set_enabled (self->dec_out_port, FALSE);
1421     gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
1422     egl_state = gst_omx_component_get_state (self->egl_render, 0);
1423     if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
1424       if (egl_state > OMX_StateIdle) {
1425         gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1426         gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
1427       }
1428       gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
1429
1430       gst_omx_video_dec_deallocate_output_buffers (self);
1431       gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
1432
1433       if (egl_state > OMX_StateLoaded) {
1434         gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
1435       }
1436     }
1437 #endif
1438
1439     /* After this egl_render should be deactivated
1440      * and the decoder's output port disabled */
1441     self->eglimage = FALSE;
1442   }
1443 #endif /* defined (HAVE_GST_GL) */
1444
1445   port = self->dec_out_port;
1446
1447   /* Update caps */
1448   GST_VIDEO_DECODER_STREAM_LOCK (self);
1449
1450   gst_omx_port_get_port_definition (port, &port_def);
1451   g_assert (port_def.format.video.eCompressionFormat == OMX_VIDEO_CodingUnused);
1452
1453   format =
1454       gst_omx_video_get_format_from_omx (port_def.format.video.eColorFormat);
1455
1456   if (format == GST_VIDEO_FORMAT_UNKNOWN) {
1457     GST_ERROR_OBJECT (self, "Unsupported color format: %d",
1458         port_def.format.video.eColorFormat);
1459     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1460     err = OMX_ErrorUndefined;
1461     goto done;
1462   }
1463
1464   GST_DEBUG_OBJECT (self,
1465       "Setting output state: format %s (%d), width %u, height %u",
1466       gst_video_format_to_string (format),
1467       port_def.format.video.eColorFormat,
1468       (guint) port_def.format.video.nFrameWidth,
1469       (guint) port_def.format.video.nFrameHeight);
1470
1471   state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1472       format, port_def.format.video.nFrameWidth,
1473       port_def.format.video.nFrameHeight, self->input_state);
1474
1475   if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1476     gst_video_codec_state_unref (state);
1477     GST_ERROR_OBJECT (self, "Failed to negotiate");
1478     err = OMX_ErrorUndefined;
1479     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1480     goto done;
1481   }
1482
1483   gst_video_codec_state_unref (state);
1484
1485   GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1486
1487 #if defined (HAVE_GST_GL)
1488 enable_port:
1489 #endif
1490
1491   err = gst_omx_video_dec_allocate_output_buffers (self);
1492   if (err != OMX_ErrorNone) {
1493 #if defined (HAVE_GST_GL)
1494     /* TODO: works on desktop but need to try on RPI. */
1495 #if !defined (USE_OMX_TARGET_RPI)
1496     if (self->eglimage) {
1497       GST_INFO_OBJECT (self, "Fallback to non eglimage");
1498       goto no_egl;
1499     }
1500 #endif
1501 #endif
1502     goto done;
1503   }
1504
1505   err = gst_omx_port_populate (port);
1506   if (err != OMX_ErrorNone)
1507     goto done;
1508
1509   err = gst_omx_port_mark_reconfigured (port);
1510   if (err != OMX_ErrorNone)
1511     goto done;
1512
1513 done:
1514
1515   return err;
1516 }
1517
1518 static void
1519 gst_omx_video_dec_clean_older_frames (GstOMXVideoDec * self,
1520     GstOMXBuffer * buf, GList * frames)
1521 {
1522   GList *l;
1523   GstClockTime timestamp;
1524
1525   timestamp =
1526       gst_util_uint64_scale (GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp),
1527       GST_SECOND, OMX_TICKS_PER_SECOND);
1528
1529   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
1530     /* We could release all frames stored with pts < timestamp since the
1531      * decoder will likely output frames in display order */
1532     for (l = frames; l; l = l->next) {
1533       GstVideoCodecFrame *tmp = l->data;
1534
1535       if (tmp->pts < timestamp) {
1536         GST_LOG_OBJECT (self,
1537             "discarding ghost frame %p (#%d) PTS:%" GST_TIME_FORMAT " DTS:%"
1538             GST_TIME_FORMAT, tmp, tmp->system_frame_number,
1539             GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
1540         gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
1541       } else {
1542         gst_video_codec_frame_unref (tmp);
1543       }
1544     }
1545   } else {
1546     /* We will release all frames with invalid timestamp because we don't even
1547      * know if they will be output some day. */
1548     for (l = frames; l; l = l->next) {
1549       GstVideoCodecFrame *tmp = l->data;
1550
1551       if (!GST_CLOCK_TIME_IS_VALID (tmp->pts)) {
1552         GST_LOG_OBJECT (self,
1553             "discarding frame %p (#%d) with invalid PTS:%" GST_TIME_FORMAT
1554             " DTS:%" GST_TIME_FORMAT, tmp, tmp->system_frame_number,
1555             GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
1556         gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
1557       } else {
1558         gst_video_codec_frame_unref (tmp);
1559       }
1560     }
1561   }
1562
1563   g_list_free (frames);
1564 }
1565
1566 static GstBuffer *
1567 copy_frame (const GstVideoInfo * info, GstBuffer * outbuf)
1568 {
1569   GstVideoInfo out_info, tmp_info;
1570   GstBuffer *tmpbuf;
1571   GstVideoFrame out_frame, tmp_frame;
1572
1573   out_info = *info;
1574   tmp_info = *info;
1575
1576   tmpbuf = gst_buffer_new_and_alloc (out_info.size);
1577
1578   gst_video_frame_map (&out_frame, &out_info, outbuf, GST_MAP_READ);
1579   gst_video_frame_map (&tmp_frame, &tmp_info, tmpbuf, GST_MAP_WRITE);
1580   gst_video_frame_copy (&tmp_frame, &out_frame);
1581   gst_video_frame_unmap (&out_frame);
1582   gst_video_frame_unmap (&tmp_frame);
1583
1584   gst_buffer_unref (outbuf);
1585
1586   return tmpbuf;
1587 }
1588
1589 static void
1590 gst_omx_video_dec_pause_loop (GstOMXVideoDec * self, GstFlowReturn flow_ret)
1591 {
1592   g_mutex_lock (&self->drain_lock);
1593   if (self->draining) {
1594     self->draining = FALSE;
1595     g_cond_broadcast (&self->drain_cond);
1596   }
1597   gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1598   self->downstream_flow_ret = flow_ret;
1599   self->started = FALSE;
1600   g_mutex_unlock (&self->drain_lock);
1601 }
1602
1603 static void
1604 gst_omx_video_dec_loop (GstOMXVideoDec * self)
1605 {
1606   GstOMXPort *port;
1607   GstOMXBuffer *buf = NULL;
1608   GstVideoCodecFrame *frame;
1609   GstFlowReturn flow_ret = GST_FLOW_OK;
1610   GstOMXAcquireBufferReturn acq_return;
1611   OMX_ERRORTYPE err;
1612
1613 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1614   port = self->eglimage ? self->egl_out_port : self->dec_out_port;
1615 #else
1616   port = self->dec_out_port;
1617 #endif
1618
1619   acq_return = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
1620   if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
1621     goto component_error;
1622   } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
1623     goto flushing;
1624   } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
1625     goto eos;
1626   }
1627
1628   if (!gst_pad_has_current_caps (GST_VIDEO_DECODER_SRC_PAD (self)) ||
1629       acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1630     GstVideoCodecState *state;
1631     OMX_PARAM_PORTDEFINITIONTYPE port_def;
1632     GstVideoFormat format;
1633
1634     GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
1635
1636     /* Reallocate all buffers */
1637     if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
1638         && gst_omx_port_is_enabled (port)) {
1639       err = gst_omx_port_set_enabled (port, FALSE);
1640       if (err != OMX_ErrorNone)
1641         goto reconfigure_error;
1642
1643       err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
1644       if (err != OMX_ErrorNone)
1645         goto reconfigure_error;
1646
1647       if (!gst_omx_video_dec_deallocate_output_buffers (self))
1648         goto reconfigure_error;
1649
1650       err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
1651       if (err != OMX_ErrorNone)
1652         goto reconfigure_error;
1653     }
1654
1655     if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1656       /* We have the possibility to reconfigure everything now */
1657       err = gst_omx_video_dec_reconfigure_output_port (self);
1658       if (err != OMX_ErrorNone)
1659         goto reconfigure_error;
1660     } else {
1661       /* Just update caps */
1662       GST_VIDEO_DECODER_STREAM_LOCK (self);
1663
1664       gst_omx_port_get_port_definition (port, &port_def);
1665       g_assert (port_def.format.video.eCompressionFormat ==
1666           OMX_VIDEO_CodingUnused);
1667
1668       format =
1669           gst_omx_video_get_format_from_omx (port_def.format.video.
1670           eColorFormat);
1671
1672       if (format == GST_VIDEO_FORMAT_UNKNOWN) {
1673         GST_ERROR_OBJECT (self, "Unsupported color format: %d",
1674             port_def.format.video.eColorFormat);
1675         if (buf)
1676           gst_omx_port_release_buffer (port, buf);
1677         GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1678         goto caps_failed;
1679       }
1680
1681       GST_DEBUG_OBJECT (self,
1682           "Setting output state: format %s (%d), width %u, height %u",
1683           gst_video_format_to_string (format),
1684           port_def.format.video.eColorFormat,
1685           (guint) port_def.format.video.nFrameWidth,
1686           (guint) port_def.format.video.nFrameHeight);
1687
1688       state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1689           format, port_def.format.video.nFrameWidth,
1690           port_def.format.video.nFrameHeight, self->input_state);
1691
1692       /* Take framerate and pixel-aspect-ratio from sinkpad caps */
1693
1694       if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1695         if (buf)
1696           gst_omx_port_release_buffer (port, buf);
1697         gst_video_codec_state_unref (state);
1698         goto caps_failed;
1699       }
1700
1701       gst_video_codec_state_unref (state);
1702
1703       GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1704     }
1705
1706     /* Now get a buffer */
1707     if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
1708       return;
1709     }
1710   }
1711
1712   g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
1713
1714   /* This prevents a deadlock between the srcpad stream
1715    * lock and the videocodec stream lock, if ::reset()
1716    * is called at the wrong time
1717    */
1718   if (gst_omx_port_is_flushing (port)) {
1719     GST_DEBUG_OBJECT (self, "Flushing");
1720     gst_omx_port_release_buffer (port, buf);
1721     goto flushing;
1722   }
1723
1724   GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x (%s) %" G_GUINT64_FORMAT,
1725       (guint) buf->omx_buf->nFlags,
1726       gst_omx_buffer_flags_to_string (buf->omx_buf->nFlags),
1727       (guint64) GST_OMX_GET_TICKS (buf->omx_buf->nTimeStamp));
1728
1729   frame = gst_omx_video_find_nearest_frame (GST_ELEMENT_CAST (self), buf,
1730       gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
1731
1732   /* So we have a timestamped OMX buffer and get, or not, corresponding frame.
1733    * Assuming decoder output frames in display order, frames preceding this
1734    * frame could be discarded as they seems useless due to e.g interlaced
1735    * stream, corrupted input data...
1736    * In any cases, not likely to be seen again. so drop it before they pile up
1737    * and use all the memory. */
1738   gst_omx_video_dec_clean_older_frames (self, buf,
1739       gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
1740
1741   if (!frame && (buf->omx_buf->nFilledLen > 0 || buf->eglimage)) {
1742     GstBuffer *outbuf = NULL;
1743
1744     /* This sometimes happens at EOS or if the input is not properly framed,
1745      * let's handle it gracefully by allocating a new buffer for the current
1746      * caps and filling it
1747      */
1748
1749     GST_ERROR_OBJECT (self, "No corresponding frame found");
1750
1751     if (self->out_port_pool) {
1752       gint i, n;
1753       GstBufferPoolAcquireParams params = { 0, };
1754
1755       n = port->buffers->len;
1756       for (i = 0; i < n; i++) {
1757         GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
1758
1759         if (tmp == buf)
1760           break;
1761       }
1762       g_assert (i != n);
1763
1764       GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
1765       flow_ret =
1766           gst_buffer_pool_acquire_buffer (self->out_port_pool, &outbuf,
1767           &params);
1768       if (flow_ret != GST_FLOW_OK) {
1769         gst_omx_port_release_buffer (port, buf);
1770         goto invalid_buffer;
1771       }
1772
1773       if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy)
1774         outbuf =
1775             copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
1776             outbuf);
1777
1778       buf = NULL;
1779     } else {
1780       outbuf =
1781           gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self));
1782       if (!gst_omx_video_dec_fill_buffer (self, buf, outbuf)) {
1783         gst_buffer_unref (outbuf);
1784         gst_omx_port_release_buffer (port, buf);
1785         goto invalid_buffer;
1786       }
1787     }
1788
1789     flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), outbuf);
1790   } else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage) {
1791     if (self->out_port_pool) {
1792       gint i, n;
1793       GstBuffer *outbuf;
1794       GstBufferPoolAcquireParams params = { 0, };
1795
1796       n = port->buffers->len;
1797       for (i = 0; i < n; i++) {
1798         GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
1799
1800         if (tmp == buf)
1801           break;
1802       }
1803       g_assert (i != n);
1804
1805       GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
1806       flow_ret =
1807           gst_buffer_pool_acquire_buffer (self->out_port_pool,
1808           &outbuf, &params);
1809       if (flow_ret != GST_FLOW_OK) {
1810         flow_ret =
1811             gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1812         frame = NULL;
1813         gst_omx_port_release_buffer (port, buf);
1814         goto invalid_buffer;
1815       }
1816
1817       if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy)
1818         outbuf =
1819             copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
1820             outbuf);
1821
1822       frame->output_buffer = outbuf;
1823
1824       flow_ret =
1825           gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1826       frame = NULL;
1827       buf = NULL;
1828     } else {
1829       if ((flow_ret =
1830               gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER
1831                   (self), frame)) == GST_FLOW_OK) {
1832         /* FIXME: This currently happens because of a race condition too.
1833          * We first need to reconfigure the output port and then the input
1834          * port if both need reconfiguration.
1835          */
1836         if (!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) {
1837           gst_buffer_replace (&frame->output_buffer, NULL);
1838           flow_ret =
1839               gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1840           frame = NULL;
1841           gst_omx_port_release_buffer (port, buf);
1842           goto invalid_buffer;
1843         }
1844         flow_ret =
1845             gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1846         frame = NULL;
1847       }
1848     }
1849   } else if (frame != NULL) {
1850     /* Just ignore empty buffers, don't drop a frame for that */
1851     flow_ret = GST_FLOW_OK;
1852     gst_video_codec_frame_unref (frame);
1853     frame = NULL;
1854   }
1855
1856   GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
1857
1858   if (buf) {
1859     err = gst_omx_port_release_buffer (port, buf);
1860     if (err != OMX_ErrorNone)
1861       goto release_error;
1862   }
1863
1864   GST_VIDEO_DECODER_STREAM_LOCK (self);
1865   self->downstream_flow_ret = flow_ret;
1866   GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1867
1868   if (flow_ret != GST_FLOW_OK)
1869     goto flow_error;
1870
1871   return;
1872
1873 component_error:
1874   {
1875     GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1876         ("OpenMAX component in error state %s (0x%08x)",
1877             gst_omx_component_get_last_error_string (self->dec),
1878             gst_omx_component_get_last_error (self->dec)));
1879     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1880     gst_omx_video_dec_pause_loop (self, GST_FLOW_ERROR);
1881     return;
1882   }
1883
1884 flushing:
1885   {
1886     GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1887     gst_omx_video_dec_pause_loop (self, GST_FLOW_FLUSHING);
1888     return;
1889   }
1890
1891 eos:
1892   {
1893     g_mutex_lock (&self->drain_lock);
1894     if (self->draining) {
1895       GstQuery *query = gst_query_new_drain ();
1896
1897       /* Drain the pipeline to reclaim all memories back to the pool */
1898       if (!gst_pad_peer_query (GST_VIDEO_DECODER_SRC_PAD (self), query))
1899         GST_DEBUG_OBJECT (self, "drain query failed");
1900       gst_query_unref (query);
1901
1902       GST_DEBUG_OBJECT (self, "Drained");
1903       self->draining = FALSE;
1904       g_cond_broadcast (&self->drain_cond);
1905       flow_ret = GST_FLOW_OK;
1906       gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1907     } else {
1908       GST_DEBUG_OBJECT (self, "Component signalled EOS");
1909       flow_ret = GST_FLOW_EOS;
1910     }
1911     g_mutex_unlock (&self->drain_lock);
1912
1913     GST_VIDEO_DECODER_STREAM_LOCK (self);
1914     self->downstream_flow_ret = flow_ret;
1915     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1916
1917     /* Here we fallback and pause the task for the EOS case */
1918     if (flow_ret != GST_FLOW_OK)
1919       goto flow_error;
1920
1921     return;
1922   }
1923
1924 flow_error:
1925   {
1926     if (flow_ret == GST_FLOW_EOS) {
1927       GST_DEBUG_OBJECT (self, "EOS");
1928
1929       gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self),
1930           gst_event_new_eos ());
1931     } else if (flow_ret < GST_FLOW_EOS) {
1932       GST_ELEMENT_ERROR (self, STREAM, FAILED,
1933           ("Internal data stream error."), ("stream stopped, reason %s",
1934               gst_flow_get_name (flow_ret)));
1935
1936       gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self),
1937           gst_event_new_eos ());
1938     } else if (flow_ret == GST_FLOW_FLUSHING) {
1939       GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1940     }
1941     gst_omx_video_dec_pause_loop (self, flow_ret);
1942     return;
1943   }
1944
1945 reconfigure_error:
1946   {
1947     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1948         ("Unable to reconfigure output port"));
1949     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1950     gst_omx_video_dec_pause_loop (self, GST_FLOW_ERROR);
1951     return;
1952   }
1953
1954 invalid_buffer:
1955   {
1956     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1957         ("Invalid sized input buffer"));
1958     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1959     gst_omx_video_dec_pause_loop (self, GST_FLOW_NOT_NEGOTIATED);
1960     return;
1961   }
1962
1963 caps_failed:
1964   {
1965     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
1966     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1967     gst_omx_video_dec_pause_loop (self, GST_FLOW_NOT_NEGOTIATED);
1968     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1969     return;
1970   }
1971 release_error:
1972   {
1973     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1974         ("Failed to relase output buffer to component: %s (0x%08x)",
1975             gst_omx_error_to_string (err), err));
1976     gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1977     gst_omx_video_dec_pause_loop (self, GST_FLOW_ERROR);
1978     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1979     return;
1980   }
1981 }
1982
1983 static gboolean
1984 gst_omx_video_dec_start (GstVideoDecoder * decoder)
1985 {
1986   GstOMXVideoDec *self;
1987
1988   self = GST_OMX_VIDEO_DEC (decoder);
1989
1990   self->last_upstream_ts = 0;
1991   self->downstream_flow_ret = GST_FLOW_OK;
1992   self->use_buffers = FALSE;
1993
1994   return TRUE;
1995 }
1996
1997 static gboolean
1998 gst_omx_video_dec_stop (GstVideoDecoder * decoder)
1999 {
2000   GstOMXVideoDec *self;
2001
2002   self = GST_OMX_VIDEO_DEC (decoder);
2003
2004   GST_DEBUG_OBJECT (self, "Stopping decoder");
2005
2006   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
2007   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
2008
2009 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2010   gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
2011   gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
2012 #endif
2013
2014   gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
2015
2016   if (gst_omx_component_get_state (self->dec, 0) > OMX_StateIdle)
2017     gst_omx_component_set_state (self->dec, OMX_StateIdle);
2018 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2019   if (gst_omx_component_get_state (self->egl_render, 0) > OMX_StateIdle)
2020     gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
2021 #endif
2022
2023   self->downstream_flow_ret = GST_FLOW_FLUSHING;
2024   self->started = FALSE;
2025
2026   g_mutex_lock (&self->drain_lock);
2027   self->draining = FALSE;
2028   g_cond_broadcast (&self->drain_cond);
2029   g_mutex_unlock (&self->drain_lock);
2030
2031   gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
2032 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2033   gst_omx_component_get_state (self->egl_render, 1 * GST_SECOND);
2034 #endif
2035
2036   gst_buffer_replace (&self->codec_data, NULL);
2037
2038   if (self->input_state)
2039     gst_video_codec_state_unref (self->input_state);
2040   self->input_state = NULL;
2041
2042   GST_DEBUG_OBJECT (self, "Stopped decoder");
2043
2044   return TRUE;
2045 }
2046
2047 static gboolean
2048 gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
2049 {
2050   OMX_VIDEO_PARAM_PORTFORMATTYPE param;
2051   OMX_ERRORTYPE err;
2052   GstCaps *comp_supported_caps;
2053   GList *negotiation_map = NULL, *l;
2054   GstCaps *templ_caps, *intersection;
2055   GstVideoFormat format;
2056   GstStructure *s;
2057   const gchar *format_str;
2058
2059   GST_DEBUG_OBJECT (self, "Trying to negotiate a video format with downstream");
2060
2061   templ_caps = gst_pad_get_pad_template_caps (GST_VIDEO_DECODER_SRC_PAD (self));
2062   intersection =
2063       gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (self), templ_caps);
2064   gst_caps_unref (templ_caps);
2065
2066   GST_DEBUG_OBJECT (self, "Allowed downstream caps: %" GST_PTR_FORMAT,
2067       intersection);
2068
2069   negotiation_map =
2070       gst_omx_video_get_supported_colorformats (self->dec_out_port,
2071       self->input_state);
2072
2073   comp_supported_caps = gst_omx_video_get_caps_for_map (negotiation_map);
2074
2075   GST_DEBUG_OBJECT (self, "Decoder supported caps: %" GST_PTR_FORMAT,
2076       comp_supported_caps);
2077
2078   if (!gst_caps_is_empty (comp_supported_caps)) {
2079     GstCaps *tmp;
2080
2081     tmp = gst_caps_intersect (comp_supported_caps, intersection);
2082     gst_caps_unref (intersection);
2083     intersection = tmp;
2084   }
2085   gst_caps_unref (comp_supported_caps);
2086
2087   if (gst_caps_is_empty (intersection)) {
2088     gst_caps_unref (intersection);
2089     GST_ERROR_OBJECT (self, "Empty caps");
2090     g_list_free_full (negotiation_map,
2091         (GDestroyNotify) gst_omx_video_negotiation_map_free);
2092     return FALSE;
2093   }
2094
2095   intersection = gst_caps_truncate (intersection);
2096   intersection = gst_caps_fixate (intersection);
2097
2098   s = gst_caps_get_structure (intersection, 0);
2099   format_str = gst_structure_get_string (s, "format");
2100   if (!format_str ||
2101       (format =
2102           gst_video_format_from_string (format_str)) ==
2103       GST_VIDEO_FORMAT_UNKNOWN) {
2104     GST_ERROR_OBJECT (self, "Invalid caps: %" GST_PTR_FORMAT, intersection);
2105     gst_caps_unref (intersection);
2106     g_list_free_full (negotiation_map,
2107         (GDestroyNotify) gst_omx_video_negotiation_map_free);
2108     return FALSE;
2109   }
2110
2111   GST_OMX_INIT_STRUCT (&param);
2112   param.nPortIndex = self->dec_out_port->index;
2113
2114   err = gst_omx_component_get_parameter (self->dec,
2115       OMX_IndexParamVideoPortFormat, &param);
2116   if (err != OMX_ErrorNone) {
2117     GST_ERROR_OBJECT (self, "Failed to get video port format: %s (0x%08x)",
2118         gst_omx_error_to_string (err), err);
2119     return FALSE;
2120   }
2121
2122   for (l = negotiation_map; l; l = l->next) {
2123     GstOMXVideoNegotiationMap *m = l->data;
2124
2125     if (m->format == format) {
2126       param.eColorFormat = m->type;
2127       break;
2128     }
2129   }
2130
2131   GST_DEBUG_OBJECT (self, "Negotiating color format %s (%d)", format_str,
2132       param.eColorFormat);
2133
2134   /* We must find something here */
2135   g_assert (l != NULL);
2136   g_list_free_full (negotiation_map,
2137       (GDestroyNotify) gst_omx_video_negotiation_map_free);
2138
2139   err =
2140       gst_omx_component_set_parameter (self->dec,
2141       OMX_IndexParamVideoPortFormat, &param);
2142   if (err != OMX_ErrorNone) {
2143     GST_ERROR_OBJECT (self, "Failed to set video port format: %s (0x%08x)",
2144         gst_omx_error_to_string (err), err);
2145   }
2146
2147   gst_caps_unref (intersection);
2148   return (err == OMX_ErrorNone);
2149 }
2150
2151 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2152 static void
2153 gst_omx_video_dec_set_latency (GstOMXVideoDec * self)
2154 {
2155   GstClockTime latency;
2156   OMX_ALG_PARAM_REPORTED_LATENCY param;
2157   OMX_ERRORTYPE err;
2158
2159   GST_OMX_INIT_STRUCT (&param);
2160   err =
2161       gst_omx_component_get_parameter (self->dec,
2162       (OMX_INDEXTYPE) OMX_ALG_IndexParamReportedLatency, &param);
2163
2164   if (err != OMX_ErrorNone) {
2165     GST_WARNING_OBJECT (self, "Couldn't retrieve latency: %s (0x%08x)",
2166         gst_omx_error_to_string (err), err);
2167     return;
2168   }
2169
2170   GST_DEBUG_OBJECT (self, "retrieved latency of %d ms",
2171       (guint32) param.nLatency);
2172
2173   /* Convert to ns */
2174   latency = param.nLatency * GST_MSECOND;
2175
2176   gst_video_decoder_set_latency (GST_VIDEO_DECODER (self), latency, latency);
2177 }
2178 #endif
2179
2180 static gboolean
2181 gst_omx_video_dec_disable (GstOMXVideoDec * self)
2182 {
2183   GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
2184
2185 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2186   GstOMXPort *out_port =
2187       self->eglimage ? self->egl_out_port : self->dec_out_port;
2188 #else
2189   GstOMXPort *out_port = self->dec_out_port;
2190 #endif
2191
2192   GST_DEBUG_OBJECT (self, "Need to disable and drain decoder");
2193
2194   gst_omx_video_dec_drain (GST_VIDEO_DECODER (self));
2195   gst_omx_port_set_flushing (out_port, 5 * GST_SECOND, TRUE);
2196
2197   if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
2198     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2199     gst_omx_video_dec_stop (GST_VIDEO_DECODER (self));
2200     gst_omx_video_dec_close (GST_VIDEO_DECODER (self));
2201     GST_VIDEO_DECODER_STREAM_LOCK (self);
2202
2203     if (!gst_omx_video_dec_open (GST_VIDEO_DECODER (self)))
2204       return FALSE;
2205
2206     self->disabled = FALSE;
2207   } else {
2208 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2209     if (self->eglimage) {
2210       gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
2211       gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
2212       gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
2213       gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
2214     }
2215 #endif
2216
2217     /* Disabling at the same time input port and output port is only
2218      * required when a buffer is shared between the ports. This cannot
2219      * be the case for a decoder because its input and output buffers
2220      * are of different nature. So let's disable ports sequencially.
2221      * Starting from IL 1.2.0, this point has been clarified.
2222      * OMX_SendCommand will return an error if the IL client attempts to
2223      * call it when there is already an on-going command being processed.
2224      * The exception is for buffer sharing above and the event
2225      * OMX_EventPortNeedsDisable will be sent to request disabling the
2226      * other port at the same time. */
2227     if (gst_omx_port_set_enabled (self->dec_in_port, FALSE) != OMX_ErrorNone)
2228       return FALSE;
2229     if (gst_omx_port_wait_buffers_released (self->dec_in_port,
2230             5 * GST_SECOND) != OMX_ErrorNone)
2231       return FALSE;
2232     if (gst_omx_port_deallocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2233       return FALSE;
2234     if (gst_omx_port_wait_enabled (self->dec_in_port,
2235             1 * GST_SECOND) != OMX_ErrorNone)
2236       return FALSE;
2237
2238     if (gst_omx_port_set_enabled (out_port, FALSE) != OMX_ErrorNone)
2239       return FALSE;
2240     if (gst_omx_port_wait_buffers_released (out_port,
2241             1 * GST_SECOND) != OMX_ErrorNone)
2242       return FALSE;
2243     if (!gst_omx_video_dec_deallocate_output_buffers (self))
2244       return FALSE;
2245     if (gst_omx_port_wait_enabled (out_port, 1 * GST_SECOND) != OMX_ErrorNone)
2246       return FALSE;
2247
2248 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2249     if (self->eglimage) {
2250       OMX_STATETYPE egl_state;
2251
2252       egl_state = gst_omx_component_get_state (self->egl_render, 0);
2253       if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
2254
2255         if (egl_state > OMX_StateIdle) {
2256           gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
2257           gst_omx_component_set_state (self->dec, OMX_StateIdle);
2258           egl_state = gst_omx_component_get_state (self->egl_render,
2259               5 * GST_SECOND);
2260           gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
2261         }
2262         gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
2263         gst_omx_component_set_state (self->dec, OMX_StateLoaded);
2264
2265         gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
2266
2267         if (egl_state > OMX_StateLoaded) {
2268           gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
2269         }
2270
2271         gst_omx_component_set_state (self->dec, OMX_StateIdle);
2272
2273         gst_omx_component_set_state (self->dec, OMX_StateExecuting);
2274         gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2275       }
2276       self->eglimage = FALSE;
2277     }
2278 #endif
2279
2280     self->disabled = TRUE;
2281   }
2282   if (self->input_state)
2283     gst_video_codec_state_unref (self->input_state);
2284   self->input_state = NULL;
2285
2286   GST_DEBUG_OBJECT (self, "Decoder drained and disabled");
2287   return TRUE;
2288 }
2289
2290 static gboolean
2291 gst_omx_video_dec_allocate_in_buffers (GstOMXVideoDec * self)
2292 {
2293   switch (self->input_allocation) {
2294     case GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER:
2295       if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2296         return FALSE;
2297       break;
2298     case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC:
2299       if (gst_omx_port_use_dynamic_buffers (self->dec_in_port) != OMX_ErrorNone)
2300         return FALSE;
2301       break;
2302     case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER:
2303     default:
2304       /* Not supported */
2305       g_return_val_if_reached (FALSE);
2306   }
2307
2308   return TRUE;
2309 }
2310
2311 static gboolean
2312 check_input_alignment (GstOMXVideoDec * self, GstMapInfo * map)
2313 {
2314   OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->dec_in_port->port_def;
2315
2316   if (port_def->nBufferAlignment &&
2317       (GPOINTER_TO_UINT (map->data) & (port_def->nBufferAlignment - 1)) != 0) {
2318     GST_DEBUG_OBJECT (self,
2319         "input buffer is not properly aligned (address: %p alignment: %u bytes), can't use dynamic allocation",
2320         map->data, (guint32) port_def->nBufferAlignment);
2321     return FALSE;
2322   }
2323
2324   return TRUE;
2325 }
2326
2327 /* Check if @inbuf's alignment matches the requirements to use the
2328  * dynamic buffer mode. */
2329 static gboolean
2330 can_use_dynamic_buffer_mode (GstOMXVideoDec * self, GstBuffer * inbuf)
2331 {
2332   gboolean result = TRUE;
2333   guint i;
2334
2335   for (i = 0; i < gst_buffer_n_memory (inbuf) && result; i++) {
2336     GstMemory *mem = gst_buffer_peek_memory (inbuf, i);
2337     GstMapInfo map;
2338
2339     if (!gst_memory_map (mem, &map, GST_MAP_READ)) {
2340       GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2341           ("failed to map input buffer"));
2342       return FALSE;
2343     }
2344
2345     result = check_input_alignment (self, &map);
2346
2347     gst_memory_unmap (mem, &map);
2348   }
2349
2350   return result;
2351 }
2352
2353 /* Choose the allocation mode for input buffers depending of what's supported by
2354  * the component and the size/alignment of the input buffer. */
2355 static GstOMXBufferAllocation
2356 gst_omx_video_dec_pick_input_allocation_mode (GstOMXVideoDec * self,
2357     GstBuffer * inbuf)
2358 {
2359   if (!gst_omx_is_dynamic_allocation_supported ())
2360     return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2361
2362   if (can_use_dynamic_buffer_mode (self, inbuf)) {
2363     GST_DEBUG_OBJECT (self,
2364         "input buffer is properly aligned, use dynamic allocation");
2365     return GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
2366   }
2367
2368   GST_DEBUG_OBJECT (self, "let input buffer allocate its buffers");
2369   return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
2370 }
2371
2372 static gboolean
2373 gst_omx_video_dec_ensure_nb_in_buffers (GstOMXVideoDec * self)
2374 {
2375   GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
2376
2377   if ((klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL)) {
2378     if (!gst_omx_port_ensure_buffer_count_actual (self->dec_in_port, 0))
2379       return FALSE;
2380   }
2381
2382   return TRUE;
2383 }
2384
2385 static gboolean
2386 gst_omx_video_dec_enable (GstOMXVideoDec * self, GstBuffer * input)
2387 {
2388   GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
2389
2390   GST_DEBUG_OBJECT (self, "Enabling component");
2391
2392   self->input_allocation = gst_omx_video_dec_pick_input_allocation_mode (self,
2393       input);
2394
2395   if (self->disabled) {
2396     if (!gst_omx_video_dec_ensure_nb_in_buffers (self))
2397       return FALSE;
2398     if (gst_omx_port_set_enabled (self->dec_in_port, TRUE) != OMX_ErrorNone)
2399       return FALSE;
2400     if (!gst_omx_video_dec_allocate_in_buffers (self))
2401       return FALSE;
2402
2403     if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2404       if (gst_omx_port_set_enabled (self->dec_out_port, TRUE) != OMX_ErrorNone)
2405         return FALSE;
2406       if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2407         return FALSE;
2408
2409       if (gst_omx_port_wait_enabled (self->dec_out_port,
2410               5 * GST_SECOND) != OMX_ErrorNone)
2411         return FALSE;
2412     }
2413
2414     if (gst_omx_port_wait_enabled (self->dec_in_port,
2415             5 * GST_SECOND) != OMX_ErrorNone)
2416       return FALSE;
2417     if (gst_omx_port_mark_reconfigured (self->dec_in_port) != OMX_ErrorNone)
2418       return FALSE;
2419   } else {
2420     if (!gst_omx_video_dec_negotiate (self))
2421       GST_LOG_OBJECT (self, "Negotiation failed, will get output format later");
2422
2423     if (!gst_omx_video_dec_ensure_nb_in_buffers (self))
2424       return FALSE;
2425
2426     if (!(klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2427       /* Disable output port */
2428       if (gst_omx_port_set_enabled (self->dec_out_port, FALSE) != OMX_ErrorNone)
2429         return FALSE;
2430
2431       if (gst_omx_port_wait_enabled (self->dec_out_port,
2432               1 * GST_SECOND) != OMX_ErrorNone)
2433         return FALSE;
2434
2435       if (gst_omx_component_set_state (self->dec,
2436               OMX_StateIdle) != OMX_ErrorNone)
2437         return FALSE;
2438
2439       /* Need to allocate buffers to reach Idle state */
2440       if (!gst_omx_video_dec_allocate_in_buffers (self))
2441         return FALSE;
2442     } else {
2443       if (gst_omx_component_set_state (self->dec,
2444               OMX_StateIdle) != OMX_ErrorNone)
2445         return FALSE;
2446
2447       /* Need to allocate buffers to reach Idle state */
2448       if (!gst_omx_video_dec_allocate_in_buffers (self))
2449         return FALSE;
2450       if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2451         return FALSE;
2452     }
2453
2454     if (gst_omx_component_get_state (self->dec,
2455             GST_CLOCK_TIME_NONE) != OMX_StateIdle)
2456       return FALSE;
2457
2458     if (gst_omx_component_set_state (self->dec,
2459             OMX_StateExecuting) != OMX_ErrorNone)
2460       return FALSE;
2461
2462     if (gst_omx_component_get_state (self->dec,
2463             GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
2464       return FALSE;
2465   }
2466
2467   /* Unset flushing to allow ports to accept data again */
2468   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
2469   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
2470
2471   if (gst_omx_component_get_last_error (self->dec) != OMX_ErrorNone) {
2472     GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
2473         gst_omx_component_get_last_error_string (self->dec),
2474         gst_omx_component_get_last_error (self->dec));
2475     return FALSE;
2476   }
2477
2478   self->disabled = FALSE;
2479
2480   return TRUE;
2481 }
2482
2483 static OMX_COLOR_FORMATTYPE
2484 get_color_format_from_chroma (const gchar * chroma_format,
2485     guint bit_depth_luma, guint bit_depth_chroma)
2486 {
2487   if (chroma_format == NULL)
2488     goto out;
2489
2490   if (!g_strcmp0 (chroma_format, "4:0:0") && bit_depth_chroma == 0) {
2491     switch (bit_depth_luma) {
2492       case 1:
2493         return OMX_COLOR_FormatMonochrome;
2494       case 2:
2495         return OMX_COLOR_FormatL2;
2496       case 4:
2497         return OMX_COLOR_FormatL4;
2498       case 8:
2499         return OMX_COLOR_FormatL8;
2500       case 16:
2501         return OMX_COLOR_FormatL16;
2502       case 24:
2503         return OMX_COLOR_FormatL24;
2504       case 32:
2505         return OMX_COLOR_FormatL32;
2506     }
2507     goto out;
2508   }
2509
2510   if (bit_depth_luma == 8 && bit_depth_chroma == 8) {
2511     if (!g_strcmp0 (chroma_format, "4:2:0"))
2512       return OMX_COLOR_FormatYUV420SemiPlanar;
2513     else if (!g_strcmp0 (chroma_format, "4:2:2"))
2514       return OMX_COLOR_FormatYUV422SemiPlanar;
2515   }
2516 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2517   if (bit_depth_luma == 10 && bit_depth_chroma == 10) {
2518     if (!g_strcmp0 (chroma_format, "4:2:0"))
2519       return (OMX_COLOR_FORMATTYPE)
2520           OMX_ALG_COLOR_FormatYUV420SemiPlanar10bitPacked;
2521     else if (!g_strcmp0 (chroma_format, "4:2:2"))
2522       return (OMX_COLOR_FORMATTYPE)
2523           OMX_ALG_COLOR_FormatYUV422SemiPlanar10bitPacked;
2524   }
2525 #endif
2526
2527 out:
2528   return OMX_COLOR_FormatUnused;
2529 }
2530
2531 static gboolean
2532 gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
2533     GstVideoCodecState * state)
2534 {
2535   GstOMXVideoDec *self;
2536   GstOMXVideoDecClass *klass;
2537   GstVideoInfo *info = &state->info;
2538   gboolean is_format_change = FALSE;
2539   gboolean needs_disable = FALSE;
2540   OMX_PARAM_PORTDEFINITIONTYPE port_def;
2541   OMX_U32 framerate_q16 = gst_omx_video_calculate_framerate_q16 (info);
2542
2543   self = GST_OMX_VIDEO_DEC (decoder);
2544   klass = GST_OMX_VIDEO_DEC_GET_CLASS (decoder);
2545
2546   GST_DEBUG_OBJECT (self, "Setting new caps %" GST_PTR_FORMAT, state->caps);
2547
2548   if (!self->dmabuf
2549       && gst_caps_features_contains (gst_caps_get_features (state->caps, 0),
2550           GST_CAPS_FEATURE_MEMORY_DMABUF)) {
2551     GST_WARNING_OBJECT (self,
2552         "caps has the 'memory:DMABuf' feature but decoder cannot produce dmabuf");
2553     return FALSE;
2554   }
2555
2556   gst_omx_port_get_port_definition (self->dec_in_port, &port_def);
2557
2558   /* Check if the caps change is a real format change or if only irrelevant
2559    * parts of the caps have changed or nothing at all.
2560    */
2561   is_format_change |= port_def.format.video.nFrameWidth != info->width;
2562   is_format_change |= port_def.format.video.nFrameHeight != info->height;
2563   is_format_change |= (port_def.format.video.xFramerate == 0
2564       && info->fps_n != 0)
2565       || !gst_omx_video_is_equal_framerate_q16 (port_def.format.
2566       video.xFramerate, framerate_q16);
2567   is_format_change |= (self->codec_data != state->codec_data);
2568   if (klass->is_format_change)
2569     is_format_change |=
2570         klass->is_format_change (self, self->dec_in_port, state);
2571
2572   needs_disable =
2573       gst_omx_component_get_state (self->dec,
2574       GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
2575   /* If the component is not in Loaded state and a real format change happens
2576    * we have to disable the port and re-allocate all buffers. If no real
2577    * format change happened we can just exit here.
2578    */
2579   if (needs_disable && !is_format_change) {
2580     GST_DEBUG_OBJECT (self,
2581         "Already running and caps did not change the format");
2582     if (self->input_state)
2583       gst_video_codec_state_unref (self->input_state);
2584     self->input_state = gst_video_codec_state_ref (state);
2585     return TRUE;
2586   }
2587
2588   if (needs_disable && is_format_change) {
2589     if (!gst_omx_video_dec_disable (self))
2590       return FALSE;
2591
2592     if (!self->disabled) {
2593       /* The local port_def is now obsolete so get it again. */
2594       gst_omx_port_get_port_definition (self->dec_in_port, &port_def);
2595     }
2596   }
2597
2598   port_def.format.video.nFrameWidth = info->width;
2599   port_def.format.video.nFrameHeight = info->height;
2600   port_def.format.video.xFramerate = framerate_q16;
2601
2602   if (klass->cdata.hacks & GST_OMX_HACK_PASS_COLOR_FORMAT_TO_DECODER) {
2603     /* Let the decoder know the colar format of the encoded input stream.
2604      * It may use it to pre-allocate its internal buffers and so save time when
2605      * it will actually start to decode. */
2606     GstStructure *s;
2607     const gchar *chroma_format;
2608     guint bit_depth_luma, bit_depth_chroma;
2609
2610     s = gst_caps_get_structure (state->caps, 0);
2611     chroma_format = gst_structure_get_string (s, "chroma-format");
2612     if (s && gst_structure_get_uint (s, "bit-depth-luma", &bit_depth_luma) &&
2613         gst_structure_get_uint (s, "bit-depth-chroma", &bit_depth_chroma)) {
2614       OMX_COLOR_FORMATTYPE color_format;
2615
2616       color_format =
2617           get_color_format_from_chroma (chroma_format,
2618           bit_depth_luma, bit_depth_chroma);
2619       if (color_format != OMX_COLOR_FormatUnused) {
2620         GST_DEBUG_OBJECT (self, "Setting input eColorFormat to %d",
2621             color_format);
2622         port_def.format.video.eColorFormat = color_format;
2623       } else {
2624         GST_WARNING_OBJECT (self,
2625             "Unsupported input color format: %s (luma %d bits, chroma %d bits)",
2626             chroma_format, bit_depth_luma, bit_depth_chroma);
2627       }
2628     } else {
2629       GST_DEBUG_OBJECT (self,
2630           "Input color format info not present in caps, can't pass them to decoder");
2631     }
2632   }
2633
2634   GST_DEBUG_OBJECT (self, "Setting inport port definition");
2635
2636   if (gst_omx_port_update_port_definition (self->dec_in_port,
2637           &port_def) != OMX_ErrorNone)
2638     return FALSE;
2639
2640   if (klass->set_format) {
2641     if (!klass->set_format (self, self->dec_in_port, state)) {
2642       GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
2643       return FALSE;
2644     }
2645   }
2646
2647   GST_DEBUG_OBJECT (self, "Updating ports definition");
2648   if (gst_omx_port_update_port_definition (self->dec_out_port,
2649           NULL) != OMX_ErrorNone)
2650     return FALSE;
2651   if (gst_omx_port_update_port_definition (self->dec_in_port,
2652           NULL) != OMX_ErrorNone)
2653     return FALSE;
2654
2655   gst_buffer_replace (&self->codec_data, state->codec_data);
2656   self->input_state = gst_video_codec_state_ref (state);
2657
2658 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
2659   gst_omx_video_dec_set_latency (self);
2660 #endif
2661
2662   self->downstream_flow_ret = GST_FLOW_OK;
2663   return TRUE;
2664 }
2665
2666 static gboolean
2667 gst_omx_video_dec_flush (GstVideoDecoder * decoder)
2668 {
2669   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
2670   OMX_ERRORTYPE err = OMX_ErrorNone;
2671
2672   GST_DEBUG_OBJECT (self, "Flushing decoder");
2673
2674   if (gst_omx_component_get_state (self->dec, 0) == OMX_StateLoaded)
2675     return TRUE;
2676
2677   /* 0) Pause the components */
2678   if (gst_omx_component_get_state (self->dec, 0) == OMX_StateExecuting) {
2679     gst_omx_component_set_state (self->dec, OMX_StatePause);
2680     gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2681   }
2682 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2683   if (self->eglimage) {
2684     if (gst_omx_component_get_state (self->egl_render, 0) == OMX_StateExecuting) {
2685       gst_omx_component_set_state (self->egl_render, OMX_StatePause);
2686       gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
2687     }
2688   }
2689 #endif
2690
2691   /* 1) Flush the ports */
2692   GST_DEBUG_OBJECT (self, "flushing ports");
2693   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
2694   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
2695
2696 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2697   if (self->eglimage) {
2698     gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
2699     gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
2700   }
2701 #endif
2702
2703   /* 2) Wait until the srcpad loop is stopped,
2704    * unlock GST_VIDEO_DECODER_STREAM_LOCK to prevent deadlocks
2705    * caused by using this lock from inside the loop function */
2706   GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2707   gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
2708   GST_DEBUG_OBJECT (self, "Flushing -- task stopped");
2709   GST_VIDEO_DECODER_STREAM_LOCK (self);
2710
2711   /* 3) Resume components */
2712   gst_omx_component_set_state (self->dec, OMX_StateExecuting);
2713   gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2714 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2715   if (self->eglimage) {
2716     gst_omx_component_set_state (self->egl_render, OMX_StateExecuting);
2717     gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
2718   }
2719 #endif
2720
2721   /* 4) Unset flushing to allow ports to accept data again */
2722   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
2723   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
2724
2725 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2726   if (self->eglimage) {
2727     gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
2728     gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
2729     err = gst_omx_port_populate (self->egl_out_port);
2730     gst_omx_port_mark_reconfigured (self->egl_out_port);
2731   } else {
2732     err = gst_omx_port_populate (self->dec_out_port);
2733   }
2734 #else
2735   err = gst_omx_port_populate (self->dec_out_port);
2736 #endif
2737
2738   if (err != OMX_ErrorNone) {
2739     GST_WARNING_OBJECT (self, "Failed to populate output port: %s (0x%08x)",
2740         gst_omx_error_to_string (err), err);
2741   }
2742
2743   /* Reset our state */
2744   self->last_upstream_ts = 0;
2745   self->downstream_flow_ret = GST_FLOW_OK;
2746   self->started = FALSE;
2747   GST_DEBUG_OBJECT (self, "Flush finished");
2748
2749   return TRUE;
2750 }
2751
2752 static GstFlowReturn
2753 gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
2754     GstVideoCodecFrame * frame)
2755 {
2756   GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2757   GstOMXVideoDec *self;
2758   GstOMXPort *port;
2759   GstOMXBuffer *buf;
2760   GstBuffer *codec_data = NULL;
2761   guint offset = 0, size;
2762   GstClockTime timestamp, duration;
2763   OMX_ERRORTYPE err;
2764   gboolean done = FALSE;
2765   gboolean first_ouput_buffer = TRUE;
2766   guint memory_idx = 0;         /* only used in dynamic buffer mode */
2767
2768   self = GST_OMX_VIDEO_DEC (decoder);
2769
2770   GST_DEBUG_OBJECT (self, "Handling frame");
2771
2772   if (self->downstream_flow_ret != GST_FLOW_OK) {
2773     gst_video_codec_frame_unref (frame);
2774     return self->downstream_flow_ret;
2775   }
2776
2777   if (!self->started) {
2778     if (!GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
2779       gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
2780       return GST_FLOW_OK;
2781     }
2782
2783     if (gst_omx_port_is_flushing (self->dec_out_port)) {
2784       if (!gst_omx_video_dec_enable (self, frame->input_buffer))
2785         goto enable_error;
2786     }
2787
2788     GST_DEBUG_OBJECT (self, "Starting task");
2789     gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self),
2790         (GstTaskFunction) gst_omx_video_dec_loop, decoder, NULL);
2791   }
2792
2793   timestamp = frame->pts;
2794   duration = frame->duration;
2795   port = self->dec_in_port;
2796
2797   size = gst_buffer_get_size (frame->input_buffer);
2798   while (!done) {
2799     /* Make sure to release the base class stream lock, otherwise
2800      * _loop() can't call _finish_frame() and we might block forever
2801      * because no input buffers are released */
2802     GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2803     acq_ret = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
2804
2805     if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
2806       GST_VIDEO_DECODER_STREAM_LOCK (self);
2807       goto component_error;
2808     } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
2809       GST_VIDEO_DECODER_STREAM_LOCK (self);
2810       goto flushing;
2811     } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
2812       /* Reallocate all buffers */
2813       err = gst_omx_port_set_enabled (port, FALSE);
2814       if (err != OMX_ErrorNone) {
2815         GST_VIDEO_DECODER_STREAM_LOCK (self);
2816         goto reconfigure_error;
2817       }
2818
2819       err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
2820       if (err != OMX_ErrorNone) {
2821         GST_VIDEO_DECODER_STREAM_LOCK (self);
2822         goto reconfigure_error;
2823       }
2824
2825       err = gst_omx_port_deallocate_buffers (port);
2826       if (err != OMX_ErrorNone) {
2827         GST_VIDEO_DECODER_STREAM_LOCK (self);
2828         goto reconfigure_error;
2829       }
2830
2831       err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
2832       if (err != OMX_ErrorNone) {
2833         GST_VIDEO_DECODER_STREAM_LOCK (self);
2834         goto reconfigure_error;
2835       }
2836
2837       if (!gst_omx_video_dec_ensure_nb_in_buffers (self)) {
2838         GST_VIDEO_DECODER_STREAM_LOCK (self);
2839         goto reconfigure_error;
2840       }
2841
2842       err = gst_omx_port_set_enabled (port, TRUE);
2843       if (err != OMX_ErrorNone) {
2844         GST_VIDEO_DECODER_STREAM_LOCK (self);
2845         goto reconfigure_error;
2846       }
2847
2848       if (!gst_omx_video_dec_allocate_in_buffers (self)) {
2849         GST_VIDEO_DECODER_STREAM_LOCK (self);
2850         goto reconfigure_error;
2851       }
2852
2853       err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
2854       if (err != OMX_ErrorNone) {
2855         GST_VIDEO_DECODER_STREAM_LOCK (self);
2856         goto reconfigure_error;
2857       }
2858
2859       err = gst_omx_port_mark_reconfigured (port);
2860       if (err != OMX_ErrorNone) {
2861         GST_VIDEO_DECODER_STREAM_LOCK (self);
2862         goto reconfigure_error;
2863       }
2864
2865       /* Now get a new buffer and fill it */
2866       GST_VIDEO_DECODER_STREAM_LOCK (self);
2867       continue;
2868     }
2869     GST_VIDEO_DECODER_STREAM_LOCK (self);
2870
2871     g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
2872
2873     if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
2874       gst_omx_port_release_buffer (port, buf);
2875       goto full_buffer;
2876     }
2877
2878     if (self->downstream_flow_ret != GST_FLOW_OK) {
2879       gst_omx_port_release_buffer (port, buf);
2880       goto flow_error;
2881     }
2882
2883     if (self->codec_data) {
2884       GST_DEBUG_OBJECT (self, "Passing codec data to the component");
2885
2886       codec_data = self->codec_data;
2887
2888       if (self->input_allocation ==
2889           GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
2890         /* Map the full buffer, this may lead to copying if for some reason its
2891          * content is split on more than one memory but that seems unlikely and
2892          * the codec data aren't supposed to be that big anyway. */
2893         if (!gst_omx_buffer_map_buffer (buf, codec_data))
2894           goto map_failed;
2895       } else {
2896         if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <
2897             gst_buffer_get_size (codec_data)) {
2898           gst_omx_port_release_buffer (port, buf);
2899           goto too_large_codec_data;
2900         }
2901
2902         buf->omx_buf->nFilledLen = gst_buffer_get_size (codec_data);;
2903         gst_buffer_extract (codec_data, 0,
2904             buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
2905             buf->omx_buf->nFilledLen);
2906       }
2907
2908       buf->omx_buf->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
2909       buf->omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
2910
2911       if (GST_CLOCK_TIME_IS_VALID (timestamp))
2912         GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
2913             gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND,
2914                 GST_SECOND));
2915       else
2916         GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp, G_GUINT64_CONSTANT (0));
2917       buf->omx_buf->nTickCount = 0;
2918
2919       self->started = TRUE;
2920       err = gst_omx_port_release_buffer (port, buf);
2921       gst_buffer_replace (&self->codec_data, NULL);
2922       if (err != OMX_ErrorNone)
2923         goto release_error;
2924       /* Acquire new buffer for the actual frame */
2925       continue;
2926     }
2927
2928     /* Now handle the frame */
2929
2930     if (self->input_allocation == GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
2931       /* Transfer the buffer content per memory rather than mapping the full
2932        * buffer to prevent copies. */
2933       GstMemory *mem = gst_buffer_peek_memory (frame->input_buffer, memory_idx);
2934
2935       GST_LOG_OBJECT (self,
2936           "Transferring %" G_GSIZE_FORMAT " bytes to the component",
2937           gst_memory_get_sizes (mem, NULL, NULL));
2938
2939       if (!gst_omx_buffer_map_memory (buf, mem))
2940         goto map_failed;
2941
2942       if (!check_input_alignment (self, &buf->map)) {
2943         GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2944             ("input buffer now has wrong alignment/stride, can't use dynamic allocation any more"));
2945         return FALSE;
2946       }
2947
2948       memory_idx++;
2949       if (memory_idx == gst_buffer_n_memory (frame->input_buffer))
2950         done = TRUE;
2951     } else {
2952       /* Copy the buffer content in chunks of size as requested
2953        * by the port */
2954       buf->omx_buf->nFilledLen =
2955           MIN (size - offset, buf->omx_buf->nAllocLen - buf->omx_buf->nOffset);
2956
2957       GST_LOG_OBJECT (self,
2958           "Copying %d bytes (frame offset %d) to the component",
2959           (guint) buf->omx_buf->nFilledLen, offset);
2960
2961       gst_buffer_extract (frame->input_buffer, offset,
2962           buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
2963           buf->omx_buf->nFilledLen);
2964
2965       offset += buf->omx_buf->nFilledLen;
2966       if (offset == size)
2967         done = TRUE;
2968     }
2969
2970     if (timestamp != GST_CLOCK_TIME_NONE) {
2971       GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
2972           gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND));
2973       self->last_upstream_ts = timestamp;
2974     } else {
2975       GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp, G_GUINT64_CONSTANT (0));
2976     }
2977
2978     if (duration != GST_CLOCK_TIME_NONE && first_ouput_buffer) {
2979       buf->omx_buf->nTickCount =
2980           gst_util_uint64_scale (duration, OMX_TICKS_PER_SECOND, GST_SECOND);
2981       self->last_upstream_ts += duration;
2982     } else {
2983       buf->omx_buf->nTickCount = 0;
2984     }
2985
2986     if (first_ouput_buffer && GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame))
2987       buf->omx_buf->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
2988
2989     /* TODO: Set flags
2990      *   - OMX_BUFFERFLAG_DECODEONLY for buffers that are outside
2991      *     the segment
2992      */
2993
2994     if (done)
2995       buf->omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
2996
2997     self->started = TRUE;
2998     err = gst_omx_port_release_buffer (port, buf);
2999     if (err != OMX_ErrorNone)
3000       goto release_error;
3001
3002     first_ouput_buffer = FALSE;
3003   }
3004
3005   gst_video_codec_frame_unref (frame);
3006
3007   GST_DEBUG_OBJECT (self, "Passed frame to component");
3008
3009   return self->downstream_flow_ret;
3010
3011 full_buffer:
3012   {
3013     gst_video_codec_frame_unref (frame);
3014     GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
3015         ("Got OpenMAX buffer with no free space (%p, %u/%u)", buf,
3016             (guint) buf->omx_buf->nOffset, (guint) buf->omx_buf->nAllocLen));
3017     return GST_FLOW_ERROR;
3018   }
3019
3020 flow_error:
3021   {
3022     gst_video_codec_frame_unref (frame);
3023
3024     return self->downstream_flow_ret;
3025   }
3026
3027 too_large_codec_data:
3028   {
3029     gst_video_codec_frame_unref (frame);
3030     GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
3031         ("codec_data larger than supported by OpenMAX port "
3032             "(%" G_GSIZE_FORMAT " > %u)", gst_buffer_get_size (codec_data),
3033             (guint) self->dec_in_port->port_def.nBufferSize));
3034     return GST_FLOW_ERROR;
3035   }
3036
3037 map_failed:
3038   {
3039     gst_video_codec_frame_unref (frame);
3040     GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
3041         ("failed to map input buffer"));
3042     return GST_FLOW_ERROR;
3043   }
3044
3045 enable_error:
3046   {
3047     /* Report the OMX error, if any */
3048     if (gst_omx_component_get_last_error (self->dec) != OMX_ErrorNone)
3049       GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
3050           ("Failed to enable OMX decoder: %s (0x%08x)",
3051               gst_omx_component_get_last_error_string (self->dec),
3052               gst_omx_component_get_last_error (self->dec)));
3053     else
3054       GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
3055           ("Failed to enable OMX decoder"));
3056     gst_video_codec_frame_unref (frame);
3057     return GST_FLOW_ERROR;
3058   }
3059
3060 component_error:
3061   {
3062     gst_video_codec_frame_unref (frame);
3063     GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
3064         ("OpenMAX component in error state %s (0x%08x)",
3065             gst_omx_component_get_last_error_string (self->dec),
3066             gst_omx_component_get_last_error (self->dec)));
3067     return GST_FLOW_ERROR;
3068   }
3069
3070 flushing:
3071   {
3072     gst_video_codec_frame_unref (frame);
3073     GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
3074     return GST_FLOW_FLUSHING;
3075   }
3076 reconfigure_error:
3077   {
3078     gst_video_codec_frame_unref (frame);
3079     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
3080         ("Unable to reconfigure input port"));
3081     return GST_FLOW_ERROR;
3082   }
3083 release_error:
3084   {
3085     gst_video_codec_frame_unref (frame);
3086     GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
3087         ("Failed to relase input buffer to component: %s (0x%08x)",
3088             gst_omx_error_to_string (err), err));
3089     return GST_FLOW_ERROR;
3090   }
3091 }
3092
3093 static GstFlowReturn
3094 gst_omx_video_dec_drain (GstVideoDecoder * decoder)
3095 {
3096   gboolean ret;
3097   ret = gst_omx_video_dec_finish (decoder);
3098   gst_omx_video_dec_flush (decoder);
3099   return ret;
3100 }
3101
3102 static GstFlowReturn
3103 gst_omx_video_dec_finish (GstVideoDecoder * decoder)
3104 {
3105   GstOMXVideoDec *self;
3106   GstOMXVideoDecClass *klass;
3107   GstOMXBuffer *buf;
3108   GstOMXAcquireBufferReturn acq_ret;
3109   OMX_ERRORTYPE err;
3110
3111   self = GST_OMX_VIDEO_DEC (decoder);
3112
3113   GST_DEBUG_OBJECT (self, "Draining component");
3114
3115   klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
3116
3117   if (!self->started) {
3118     GST_DEBUG_OBJECT (self, "Component not started yet");
3119     return GST_FLOW_OK;
3120   }
3121   self->started = FALSE;
3122
3123   if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
3124     GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
3125     return GST_FLOW_OK;
3126   }
3127
3128   /* Make sure to release the base class stream lock, otherwise
3129    * _loop() can't call _finish_frame() and we might block forever
3130    * because no input buffers are released */
3131   GST_VIDEO_DECODER_STREAM_UNLOCK (self);
3132
3133   /* Send an EOS buffer to the component and let the base
3134    * class drop the EOS event. We will send it later when
3135    * the EOS buffer arrives on the output port. */
3136   acq_ret = gst_omx_port_acquire_buffer (self->dec_in_port, &buf, GST_OMX_WAIT);
3137   if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
3138     GST_VIDEO_DECODER_STREAM_LOCK (self);
3139     GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
3140         acq_ret);
3141     return GST_FLOW_ERROR;
3142   }
3143
3144   g_mutex_lock (&self->drain_lock);
3145   self->draining = TRUE;
3146   buf->omx_buf->nFilledLen = 0;
3147   GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
3148       gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
3149           GST_SECOND));
3150   buf->omx_buf->nTickCount = 0;
3151   buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
3152   err = gst_omx_port_release_buffer (self->dec_in_port, buf);
3153   if (err != OMX_ErrorNone) {
3154     GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
3155         gst_omx_error_to_string (err), err);
3156     g_mutex_unlock (&self->drain_lock);
3157     GST_VIDEO_DECODER_STREAM_LOCK (self);
3158     return GST_FLOW_ERROR;
3159   }
3160
3161   GST_DEBUG_OBJECT (self, "Waiting until component is drained");
3162
3163   if (G_UNLIKELY (self->dec->hacks & GST_OMX_HACK_DRAIN_MAY_NOT_RETURN)) {
3164     gint64 wait_until = g_get_monotonic_time () + G_TIME_SPAN_SECOND / 2;
3165
3166     if (!g_cond_wait_until (&self->drain_cond, &self->drain_lock, wait_until))
3167       GST_WARNING_OBJECT (self, "Drain timed out");
3168     else
3169       GST_DEBUG_OBJECT (self, "Drained component");
3170
3171   } else {
3172     g_cond_wait (&self->drain_cond, &self->drain_lock);
3173     GST_DEBUG_OBJECT (self, "Drained component");
3174   }
3175
3176   g_mutex_unlock (&self->drain_lock);
3177   GST_VIDEO_DECODER_STREAM_LOCK (self);
3178
3179   self->started = FALSE;
3180
3181   return GST_FLOW_OK;
3182 }
3183
3184 static gboolean
3185 gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
3186 {
3187   GstBufferPool *pool = NULL;
3188   GstStructure *config;
3189   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (bdec);
3190   guint i;
3191
3192 #if defined (HAVE_GST_GL)
3193   {
3194     GstCaps *caps;
3195     gint i, n;
3196     GstVideoInfo info;
3197
3198     gst_query_parse_allocation (query, &caps, NULL);
3199     if (caps && gst_video_info_from_caps (&info, caps)
3200         && info.finfo->format == GST_VIDEO_FORMAT_RGBA) {
3201       gboolean found = FALSE;
3202       GstCapsFeatures *feature = gst_caps_get_features (caps, 0);
3203       /* Prefer an EGLImage allocator if available and we want to use it */
3204       n = gst_query_get_n_allocation_params (query);
3205       for (i = 0; i < n; i++) {
3206         GstAllocator *allocator;
3207         GstAllocationParams params;
3208
3209         gst_query_parse_nth_allocation_param (query, i, &allocator, &params);
3210         if (allocator) {
3211           if (GST_IS_GL_MEMORY_EGL_ALLOCATOR (allocator)) {
3212             found = TRUE;
3213             gst_query_set_nth_allocation_param (query, 0, allocator, &params);
3214             while (gst_query_get_n_allocation_params (query) > 1)
3215               gst_query_remove_nth_allocation_param (query, 1);
3216           }
3217
3218           gst_object_unref (allocator);
3219
3220           if (found)
3221             break;
3222         }
3223       }
3224
3225       /* if try to negotiate with caps feature memory:EGLImage
3226        * and if allocator is not of type memory EGLImage then fails */
3227       if (feature
3228           && gst_caps_features_contains (feature,
3229               GST_CAPS_FEATURE_MEMORY_GL_MEMORY) && !found) {
3230         return FALSE;
3231       }
3232     }
3233   }
3234 #endif /* defined (HAVE_GST_GL) */
3235
3236   self->use_buffers = FALSE;
3237
3238   /* Importing OMX buffers from downstream isn't supported.
3239    * That wouldn't bring us much as the dynamic buffer mode already
3240    * prevent copies between OMX components. */
3241   i = 0;
3242   while (i < gst_query_get_n_allocation_pools (query)) {
3243     gst_query_parse_nth_allocation_pool (query, i, &pool, NULL, NULL, NULL);
3244     if (GST_IS_OMX_BUFFER_POOL (pool)) {
3245       GST_DEBUG_OBJECT (self, "Discard OMX pool from downstream");
3246       gst_query_remove_nth_allocation_pool (query, i);
3247     } else {
3248       GST_DEBUG_OBJECT (self,
3249           "Try using downstream buffers with OMX_UseBuffer");
3250       self->use_buffers = TRUE;
3251       i++;
3252     }
3253
3254     if (pool)
3255       gst_object_unref (pool);
3256   }
3257
3258   if (!GST_VIDEO_DECODER_CLASS
3259       (gst_omx_video_dec_parent_class)->decide_allocation (bdec, query))
3260     return FALSE;
3261
3262   g_assert (gst_query_get_n_allocation_pools (query) > 0);
3263   gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
3264   g_assert (pool != NULL);
3265
3266   config = gst_buffer_pool_get_config (pool);
3267   if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
3268     gst_buffer_pool_config_add_option (config,
3269         GST_BUFFER_POOL_OPTION_VIDEO_META);
3270   }
3271   gst_buffer_pool_set_config (pool, config);
3272   gst_object_unref (pool);
3273
3274   return TRUE;
3275 }
3276
3277 static gboolean
3278 gst_omx_video_dec_propose_allocation (GstVideoDecoder * bdec, GstQuery * query)
3279 {
3280   GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (bdec);
3281   guint size, num_buffers;
3282
3283   size = self->dec_in_port->port_def.nBufferSize;
3284   num_buffers = self->dec_in_port->port_def.nBufferCountMin + 1;
3285
3286   GST_DEBUG_OBJECT (self,
3287       "request at least %d buffers of size %d", num_buffers, size);
3288   gst_query_add_allocation_pool (query, NULL, size, num_buffers, 0);
3289
3290   return
3291       GST_VIDEO_DECODER_CLASS
3292       (gst_omx_video_dec_parent_class)->propose_allocation (bdec, query);
3293 }