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