omxvideodec: support interlace-mode=interleaved input
[platform/upstream/gstreamer.git] / omx / gstomxbufferpool.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-2019, Collabora Ltd.
5  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
6  *           George Kiagiadakis <george.kiagiadakis@collabora.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation
11  * version 2.1 of the License.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "gstomxbufferpool.h"
29 #include "gstomxvideo.h"
30
31 #include <gst/allocators/gstdmabuf.h>
32
33 GST_DEBUG_CATEGORY_STATIC (gst_omx_buffer_pool_debug_category);
34 #define GST_CAT_DEFAULT gst_omx_buffer_pool_debug_category
35
36 enum
37 {
38   SIG_ALLOCATE,
39   LAST_SIGNAL
40 };
41
42 static guint signals[LAST_SIGNAL] = { 0 };
43
44 /* Buffer pool for the buffers of an OpenMAX port.
45  *
46  * This pool is only used if we either passed buffers from another
47  * pool to the OMX port or provide the OMX buffers directly to other
48  * elements.
49  *
50  * An output buffer is in the pool if it is currently owned by the port,
51  * i.e. after OMX_FillThisBuffer(). An output buffer is outside
52  * the pool after it was taken from the port after it was handled
53  * by the port, i.e. FillBufferDone.
54  *
55  * An input buffer is in the pool if it is currently available to be filled
56  * upstream. It will be put back into the pool when it has been processed by
57  * OMX, (EmptyBufferDone).
58  *
59  * Buffers can be allocated by us (OMX_AllocateBuffer()) or allocated
60  * by someone else and (temporarily) passed to this pool
61  * (OMX_UseBuffer(), OMX_UseEGLImage()). In the latter case the pool of
62  * the buffer will be overriden, and restored in free_buffer(). Other
63  * buffers are just freed there.
64  *
65  * The pool always has a fixed number of minimum and maximum buffers
66  * and these are allocated while starting the pool and released afterwards.
67  * They correspond 1:1 to the OMX buffers of the port, which are allocated
68  * before the pool is started.
69  *
70  * Acquiring an output buffer from this pool happens after the OMX buffer has
71  * been acquired from the port. gst_buffer_pool_acquire_buffer() is
72  * supposed to return the buffer that corresponds to the OMX buffer.
73  *
74  * For buffers provided to upstream, the buffer will be passed to
75  * the component manually when it arrives and then unreffed. If the
76  * buffer is released before reaching the component it will be just put
77  * back into the pool as if EmptyBufferDone has happened. If it was
78  * passed to the component, it will be back into the pool when it was
79  * released and EmptyBufferDone has happened.
80  *
81  * For buffers provided to downstream, the buffer will be returned
82  * back to the component (OMX_FillThisBuffer()) when it is released.
83  *
84  * This pool uses a special allocator object, GstOMXAllocator. The main purpose
85  * of this allocator is to track GstMemory objects in the same way that a
86  * GstBufferPool tracks buffers. When a buffer is inserted into this pool
87  * (either because it was just allocated or because it was released back to
88  * the pool), its memory is ripped off and is tracked separately by the
89  * allocator. When a buffer is then acquired, we acquire the corresponding
90  * GstMemory from the allocator and put it back in the buffer.
91  *
92  * This allocator mechanism allows us to track memory that has been shared
93  * with buffers that are not part of this pool. When a memory is shared, then
94  * its ref count is > 1, which means it will not be released to the allocator
95  * until the sub-memory is destroyed.
96  *
97  * When a memory returns to the allocator, the allocator fires the
98  * omxbuf-released signal, which is handled by the buffer pool to return the
99  * omx buffer to the port or the queue.
100  */
101
102 #define DEBUG_INIT \
103   GST_DEBUG_CATEGORY_INIT (gst_omx_buffer_pool_debug_category, "omxbufferpool", 0, \
104       "debug category for gst-omx buffer pool base class");
105
106 G_DEFINE_TYPE_WITH_CODE (GstOMXBufferPool, gst_omx_buffer_pool,
107     GST_TYPE_BUFFER_POOL, DEBUG_INIT);
108
109 static void gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool,
110     GstBuffer * buffer);
111
112 static gboolean
113 gst_omx_buffer_pool_start (GstBufferPool * bpool)
114 {
115   GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
116   gboolean has_buffers;
117   GstStructure *config;
118   guint min, max;
119   GstOMXAllocatorForeignMemMode mode;
120
121   /* Only allow to start the pool if we still are attached
122    * to a component and port */
123   GST_OBJECT_LOCK (pool);
124   if (!pool->component || !pool->port) {
125     GST_OBJECT_UNLOCK (pool);
126     return FALSE;
127   }
128
129   pool->port->using_pool = TRUE;
130
131   has_buffers = (pool->port->buffers != NULL);
132   GST_OBJECT_UNLOCK (pool);
133
134   config = gst_buffer_pool_get_config (bpool);
135   gst_buffer_pool_config_get_params (config, NULL, NULL, &min, &max);
136   gst_structure_free (config);
137   if (max > min) {
138     GST_WARNING_OBJECT (bpool,
139         "max (%d) cannot be higher than min (%d) as pool cannot allocate buffers on the fly",
140         max, min);
141     return FALSE;
142   }
143
144   if (!has_buffers) {
145     gboolean result = FALSE;
146
147     GST_DEBUG_OBJECT (bpool, "Buffers not yet allocated on port %d of %s",
148         pool->port->index, pool->component->name);
149
150     g_signal_emit (pool, signals[SIG_ALLOCATE], 0, &result);
151
152     if (!result) {
153       GST_WARNING_OBJECT (bpool,
154           "Element failed to allocate buffers, can't start pool");
155       return FALSE;
156     }
157   }
158
159   g_assert (pool->port->buffers);
160
161   if (pool->other_pool)
162     /* Importing buffers from downstream, either normal or dmabuf ones */
163     mode = GST_OMX_ALLOCATOR_FOREIGN_MEM_OTHER_POOL;
164   else if (pool->output_mode == GST_OMX_BUFFER_MODE_DMABUF)
165     /* Exporting dmabuf */
166     mode = GST_OMX_ALLOCATOR_FOREIGN_MEM_DMABUF;
167   else
168     /* Exporting normal buffers */
169     mode = GST_OMX_ALLOCATOR_FOREIGN_MEM_NONE;
170
171   if (!gst_omx_allocator_configure (pool->allocator, min, mode))
172     return FALSE;
173
174   if (!gst_omx_allocator_set_active (pool->allocator, TRUE))
175     return FALSE;
176
177   return
178       GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->start (bpool);
179 }
180
181 static gboolean
182 gst_omx_buffer_pool_stop (GstBufferPool * bpool)
183 {
184   GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
185
186   /* Remove any buffers that are there */
187   g_ptr_array_set_size (pool->buffers, 0);
188
189   GST_DEBUG_OBJECT (pool, "deactivating OMX allocator");
190   gst_omx_allocator_set_active (pool->allocator, FALSE);
191
192   /* ensure all memories have been deallocated;
193    * this may take a while if some memories are being shared
194    * and therefore are in use somewhere else in the pipeline */
195   gst_omx_allocator_wait_inactive (pool->allocator);
196
197   GST_DEBUG_OBJECT (pool, "deallocate OMX buffers");
198   gst_omx_port_deallocate_buffers (pool->port);
199
200   if (pool->caps)
201     gst_caps_unref (pool->caps);
202   pool->caps = NULL;
203
204   pool->add_videometa = FALSE;
205   pool->deactivated = TRUE;
206   pool->port->using_pool = TRUE;
207
208   return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->stop (bpool);
209 }
210
211 static const gchar **
212 gst_omx_buffer_pool_get_options (GstBufferPool * bpool)
213 {
214   static const gchar *raw_video_options[] =
215       { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL };
216   static const gchar *options[] = { NULL };
217   GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
218
219   GST_OBJECT_LOCK (pool);
220   if (pool->port && pool->port->port_def.eDomain == OMX_PortDomainVideo
221       && pool->port->port_def.format.video.eCompressionFormat ==
222       OMX_VIDEO_CodingUnused) {
223     GST_OBJECT_UNLOCK (pool);
224     return raw_video_options;
225   }
226   GST_OBJECT_UNLOCK (pool);
227
228   return options;
229 }
230
231 static gboolean
232 gst_omx_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
233 {
234   GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
235   GstCaps *caps;
236   guint size, min;
237   GstStructure *fake_config;
238   gboolean ret;
239
240   GST_OBJECT_LOCK (pool);
241
242   if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min, NULL))
243     goto wrong_config;
244
245   if (caps == NULL)
246     goto no_caps;
247
248   if (pool->port && pool->port->port_def.eDomain == OMX_PortDomainVideo
249       && pool->port->port_def.format.video.eCompressionFormat ==
250       OMX_VIDEO_CodingUnused) {
251     GstVideoInfo info;
252
253     /* now parse the caps from the config */
254     if (!gst_video_info_from_caps (&info, caps))
255       goto wrong_video_caps;
256
257     /* enable metadata based on config of the pool */
258     pool->add_videometa =
259         gst_buffer_pool_config_has_option (config,
260         GST_BUFFER_POOL_OPTION_VIDEO_META);
261
262     pool->video_info = info;
263   }
264
265   if (pool->caps)
266     gst_caps_unref (pool->caps);
267   pool->caps = gst_caps_ref (caps);
268
269   /* Ensure max=min as the pool won't be able to allocate more buffers while active */
270   gst_buffer_pool_config_set_params (config, caps, size, min, min);
271
272   GST_OBJECT_UNLOCK (pool);
273
274   /* give a fake config to the parent default_set_config() with size == 0
275    * this prevents default_release_buffer() from free'ing the buffers, since
276    * we release them with no memory */
277   fake_config = gst_structure_copy (config);
278   gst_buffer_pool_config_set_params (fake_config, caps, 0, min, min);
279
280   ret = GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->set_config
281       (bpool, fake_config);
282   gst_structure_free (fake_config);
283
284   return ret;
285
286   /* ERRORS */
287 wrong_config:
288   {
289     GST_OBJECT_UNLOCK (pool);
290     GST_WARNING_OBJECT (pool, "invalid config");
291     return FALSE;
292   }
293 no_caps:
294   {
295     GST_OBJECT_UNLOCK (pool);
296     GST_WARNING_OBJECT (pool, "no caps in config");
297     return FALSE;
298   }
299 wrong_video_caps:
300   {
301     GST_OBJECT_UNLOCK (pool);
302     GST_WARNING_OBJECT (pool,
303         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
304     return FALSE;
305   }
306 }
307
308 static GstFlowReturn
309 gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool,
310     GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
311 {
312   GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
313   GstBuffer *buf;
314   GstMemory *mem;
315   GstMemory *foreign_mem = NULL;
316
317   if (pool->other_pool) {
318     guint n;
319
320     buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index);
321     g_assert (pool->other_pool == buf->pool);
322     gst_object_replace ((GstObject **) & buf->pool, NULL);
323
324     n = gst_buffer_n_memory (buf);
325     g_return_val_if_fail (n == 1, GST_FLOW_ERROR);
326
327     /* rip the memory out of the buffer;
328      * we like to keep them separate in this pool */
329     foreign_mem = gst_buffer_get_memory (buf, 0);
330     gst_buffer_remove_all_memory (buf);
331
332     if (pool->add_videometa) {
333       GstVideoMeta *meta;
334
335       meta = gst_buffer_get_video_meta (buf);
336       if (!meta) {
337         gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE,
338             GST_VIDEO_INFO_FORMAT (&pool->video_info),
339             GST_VIDEO_INFO_WIDTH (&pool->video_info),
340             GST_VIDEO_INFO_HEIGHT (&pool->video_info));
341       }
342     }
343
344     pool->need_copy = FALSE;
345   } else {
346     const guint nstride = pool->port->port_def.format.video.nStride;
347     const guint nslice = pool->port->port_def.format.video.nSliceHeight;
348     gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
349     gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };
350
351     buf = gst_buffer_new ();
352
353     switch (GST_VIDEO_INFO_FORMAT (&pool->video_info)) {
354       case GST_VIDEO_FORMAT_ABGR:
355       case GST_VIDEO_FORMAT_ARGB:
356       case GST_VIDEO_FORMAT_RGB16:
357       case GST_VIDEO_FORMAT_BGR16:
358       case GST_VIDEO_FORMAT_YUY2:
359       case GST_VIDEO_FORMAT_UYVY:
360       case GST_VIDEO_FORMAT_YVYU:
361       case GST_VIDEO_FORMAT_GRAY8:
362         break;
363       case GST_VIDEO_FORMAT_I420:
364         stride[1] = nstride / 2;
365         offset[1] = offset[0] + stride[0] * nslice;
366         stride[2] = nstride / 2;
367         offset[2] = offset[1] + (stride[1] * nslice / 2);
368         break;
369       case GST_VIDEO_FORMAT_NV12:
370       case GST_VIDEO_FORMAT_NV12_10LE32:
371       case GST_VIDEO_FORMAT_NV16:
372       case GST_VIDEO_FORMAT_NV16_10LE32:
373         stride[1] = nstride;
374         offset[1] = offset[0] + stride[0] * nslice;
375         break;
376       default:
377         g_assert_not_reached ();
378         break;
379     }
380
381     if (pool->add_videometa) {
382       pool->need_copy = FALSE;
383     } else {
384       GstVideoInfo info;
385       gboolean need_copy = FALSE;
386       gint i;
387
388       gst_video_info_init (&info);
389       gst_video_info_set_format (&info,
390           GST_VIDEO_INFO_FORMAT (&pool->video_info),
391           GST_VIDEO_INFO_WIDTH (&pool->video_info),
392           GST_VIDEO_INFO_HEIGHT (&pool->video_info));
393
394       for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&pool->video_info); i++) {
395         if (info.stride[i] != stride[i] || info.offset[i] != offset[i]) {
396           GST_DEBUG_OBJECT (pool,
397               "Need to copy output frames because of stride/offset mismatch: plane %d stride %d (expected: %d) offset %"
398               G_GSIZE_FORMAT " (expected: %" G_GSIZE_FORMAT
399               ") nStride: %d nSliceHeight: %d ", i, stride[i], info.stride[i],
400               offset[i], info.offset[i], nstride, nslice);
401
402           need_copy = TRUE;
403           break;
404         }
405       }
406
407       pool->need_copy = need_copy;
408     }
409
410     if (pool->need_copy || pool->add_videometa) {
411       /* We always add the videometa. It's the job of the user
412        * to copy the buffer if pool->need_copy is TRUE
413        */
414       GstVideoMeta *meta;
415       GstVideoAlignment align;
416
417       meta = gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
418           GST_VIDEO_INFO_FORMAT (&pool->video_info),
419           GST_VIDEO_INFO_WIDTH (&pool->video_info),
420           GST_VIDEO_INFO_HEIGHT (&pool->video_info),
421           GST_VIDEO_INFO_N_PLANES (&pool->video_info), offset, stride);
422
423       if (gst_omx_video_get_port_padding (pool->port, &pool->video_info,
424               &align))
425         gst_video_meta_set_alignment (meta, align);
426     }
427   }
428
429   mem = gst_omx_allocator_allocate (pool->allocator, pool->current_buffer_index,
430       foreign_mem);
431   if (!mem)
432     return GST_FLOW_ERROR;
433
434   if (pool->output_mode == GST_OMX_BUFFER_MODE_DMABUF) {
435     GstMapInfo map;
436
437     if (!gst_caps_features_contains (gst_caps_get_features (pool->caps, 0),
438             GST_CAPS_FEATURE_MEMORY_DMABUF)) {
439       /* Check if the memory is actually mappable */
440       if (!gst_memory_map (mem, &map, GST_MAP_READWRITE)) {
441         GST_ERROR_OBJECT (pool,
442             "dmabuf memory is not mappable but caps does not have the 'memory:DMABuf' feature");
443         gst_memory_unref (mem);
444         return GST_FLOW_ERROR;
445       }
446
447       gst_memory_unmap (mem, &map);
448     }
449   }
450
451   /* mem still belongs to the allocator; do not add it in the buffer just yet */
452
453   *buffer = buf;
454
455   pool->current_buffer_index++;
456
457   return GST_FLOW_OK;
458 }
459
460 /* called by the allocator when we are using other_pool in order
461  * to restore the foreign GstMemory back to its original GstBuffer */
462 static void
463 on_allocator_foreign_mem_released (GstOMXAllocator * allocator,
464     gint index, GstMemory * mem, GstOMXBufferPool * pool)
465 {
466   GstBuffer *buf;
467
468   buf = g_ptr_array_index (pool->buffers, index);
469   gst_buffer_append_memory (buf, mem);
470
471   /* the buffer consumed the passed reference.
472    * we still need one more reference for the allocator */
473   gst_memory_ref (mem);
474 }
475
476 static void
477 gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
478 {
479   GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
480
481   /* If the buffers belong to another pool, restore them now */
482   GST_OBJECT_LOCK (pool);
483   if (pool->other_pool) {
484     gst_object_replace ((GstObject **) & buffer->pool,
485         (GstObject *) pool->other_pool);
486   }
487   GST_OBJECT_UNLOCK (pool);
488
489   GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->free_buffer (bpool,
490       buffer);
491 }
492
493 static GstFlowReturn
494 gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
495     GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
496 {
497   GstFlowReturn ret;
498   GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
499   GstMemory *mem;
500
501   if (pool->port->port_def.eDir == OMX_DirOutput) {
502     g_return_val_if_fail (pool->current_buffer_index != -1, GST_FLOW_ERROR);
503
504     ret = gst_omx_allocator_acquire (pool->allocator, &mem,
505         pool->current_buffer_index, NULL);
506     if (ret != GST_FLOW_OK)
507       return ret;
508
509     /* If it's our own memory we have to set the sizes */
510     if (!pool->other_pool) {
511       GstOMXBuffer *omx_buf = gst_omx_memory_get_omx_buf (mem);
512       mem->size = omx_buf->omx_buf->nFilledLen;
513       mem->offset = omx_buf->omx_buf->nOffset;
514     }
515   } else {
516     /* Acquire any buffer that is available to be filled by upstream */
517     GstOMXBuffer *omx_buf;
518     GstOMXAcquireBufferReturn r;
519     GstOMXWait wait = GST_OMX_WAIT;
520
521     if (params && (params->flags & GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT))
522       wait = GST_OMX_DONT_WAIT;
523
524     r = gst_omx_port_acquire_buffer (pool->port, &omx_buf, wait);
525     if (r == GST_OMX_ACQUIRE_BUFFER_OK) {
526       ret = gst_omx_allocator_acquire (pool->allocator, &mem, -1, omx_buf);
527       if (ret != GST_FLOW_OK)
528         return ret;
529     } else if (r == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
530       return GST_FLOW_FLUSHING;
531     } else {
532       return GST_FLOW_ERROR;
533     }
534   }
535
536   /* get some GstBuffer available in this pool */
537   ret = GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->acquire_buffer
538       (bpool, buffer, params);
539
540   if (ret == GST_FLOW_OK) {
541     /* attach the acquired memory on it */
542     gst_buffer_append_memory (*buffer, mem);
543   } else {
544     gst_memory_unref (mem);
545   }
546
547   return ret;
548 }
549
550 static void
551 gst_omx_buffer_pool_reset_buffer (GstBufferPool * bpool, GstBuffer * buffer)
552 {
553   GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
554   guint n;
555
556   n = gst_buffer_n_memory (buffer);
557   if (G_UNLIKELY (n != 1)) {
558     GST_ERROR_OBJECT (pool, "Released buffer does not have 1 memory... "
559         "(n = %u) something went terribly wrong", n);
560   }
561
562   /* rip the memory out of the buffer;
563    * we like to keep them separate in this pool.
564    * if this was the last ref count of the memory, it will be returned
565    * to the allocator, otherwise it will be returned later */
566   gst_buffer_remove_all_memory (buffer);
567
568   /* reset before removing the TAG_MEMORY flag so that the parent impl
569    * doesn't try to restore the original buffer size */
570   GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->reset_buffer
571       (bpool, buffer);
572
573   /* pretend nothing happened to the memory to avoid discarding the buffer */
574   GST_MINI_OBJECT_FLAG_UNSET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
575 }
576
577 static void
578 on_allocator_omxbuf_released (GstOMXAllocator * allocator,
579     GstOMXBuffer * omx_buf, GstOMXBufferPool * pool)
580 {
581   OMX_ERRORTYPE err;
582
583   if (pool->port->port_def.eDir == OMX_DirOutput && !omx_buf->used &&
584       !pool->deactivated) {
585     /* Release back to the port, can be filled again */
586     err = gst_omx_port_release_buffer (pool->port, omx_buf);
587
588     if (err != OMX_ErrorNone) {
589       GST_ELEMENT_ERROR (pool->element, LIBRARY, SETTINGS, (NULL),
590           ("Failed to relase output buffer to component: %s (0x%08x)",
591               gst_omx_error_to_string (err), err));
592     }
593   } else if (pool->port->port_def.eDir == OMX_DirInput) {
594     gst_omx_port_requeue_buffer (pool->port, omx_buf);
595   }
596 }
597
598 static void
599 gst_omx_buffer_pool_finalize (GObject * object)
600 {
601   GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (object);
602
603   if (pool->element)
604     gst_object_unref (pool->element);
605   pool->element = NULL;
606
607   if (pool->buffers)
608     g_ptr_array_unref (pool->buffers);
609   pool->buffers = NULL;
610
611   if (pool->other_pool)
612     gst_object_unref (pool->other_pool);
613   pool->other_pool = NULL;
614
615   if (pool->allocator)
616     gst_object_unref (pool->allocator);
617   pool->allocator = NULL;
618
619   if (pool->caps)
620     gst_caps_unref (pool->caps);
621   pool->caps = NULL;
622
623   g_clear_pointer (&pool->component, gst_omx_component_unref);
624
625   G_OBJECT_CLASS (gst_omx_buffer_pool_parent_class)->finalize (object);
626 }
627
628 static void
629 gst_omx_buffer_pool_class_init (GstOMXBufferPoolClass * klass)
630 {
631   GObjectClass *gobject_class = (GObjectClass *) klass;
632   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
633
634   gobject_class->finalize = gst_omx_buffer_pool_finalize;
635   gstbufferpool_class->start = gst_omx_buffer_pool_start;
636   gstbufferpool_class->stop = gst_omx_buffer_pool_stop;
637   gstbufferpool_class->get_options = gst_omx_buffer_pool_get_options;
638   gstbufferpool_class->set_config = gst_omx_buffer_pool_set_config;
639   gstbufferpool_class->alloc_buffer = gst_omx_buffer_pool_alloc_buffer;
640   gstbufferpool_class->free_buffer = gst_omx_buffer_pool_free_buffer;
641   gstbufferpool_class->acquire_buffer = gst_omx_buffer_pool_acquire_buffer;
642   gstbufferpool_class->reset_buffer = gst_omx_buffer_pool_reset_buffer;
643
644   signals[SIG_ALLOCATE] = g_signal_new ("allocate",
645       G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
646       G_TYPE_BOOLEAN, 0);
647 }
648
649 static void
650 gst_omx_buffer_pool_init (GstOMXBufferPool * pool)
651 {
652   pool->buffers = g_ptr_array_new ();
653 }
654
655 GstBufferPool *
656 gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component,
657     GstOMXPort * port, GstOMXBufferMode output_mode)
658 {
659   GstOMXBufferPool *pool;
660
661   pool = g_object_new (gst_omx_buffer_pool_get_type (), NULL);
662   pool->element = gst_object_ref (element);
663   pool->component = gst_omx_component_ref (component);
664   pool->port = port;
665   pool->output_mode = output_mode;
666   pool->allocator = gst_omx_allocator_new (component, port);
667
668   g_signal_connect_object (pool->allocator, "omxbuf-released",
669       (GCallback) on_allocator_omxbuf_released, pool, 0);
670   g_signal_connect_object (pool->allocator, "foreign-mem-released",
671       (GCallback) on_allocator_foreign_mem_released, pool, 0);
672
673   return GST_BUFFER_POOL (pool);
674 }