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