Merge remote-tracking branch 'gst-plugins-base/tizen_gst_1.19.2' into tizen_gst_1...
[platform/upstream/gstreamer.git] / gst-libs / gst / allocators / gsttizenbufferpool.c
1 /*
2  * GStreamer tizen buffer pool
3  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4  * Author: Sejun Park <sejun79.park@samsung.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gsttizenbufferpool.h"
26 #include <tbm_surface_internal.h>
27
28 GST_DEBUG_CATEGORY_STATIC (gst_tizen_vidbufpool_debug);
29 #define GST_CAT_DEFAULT gst_tizen_vidbufpool_debug
30
31 static GQuark gst_tizen_buffer_data_quark = 0;
32
33 static void gst_tizen_buffer_pool_finalize (GObject * object);
34
35 #define DEBUG_INIT \
36     GST_DEBUG_CATEGORY_INIT (gst_tizen_vidbufpool_debug, "tizenvideopool", 0, \
37     "Tizen bufferpool");
38
39 #define gst_tizen_buffer_pool_parent_class parent_class
40 G_DEFINE_TYPE_WITH_CODE (GstTizenBufferPool, gst_tizen_buffer_pool,
41     GST_TYPE_BUFFER_POOL, DEBUG_INIT);
42
43 struct _GstTizenBufferPoolPrivate
44 {
45   GstAllocator *allocator;
46 };
47
48 static const gchar **
49 gst_tizen_buffer_pool_get_options (GstBufferPool * pool)
50 {
51   static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
52     GST_BUFFER_POOL_OPTION_TIZEN_META, NULL
53   };
54
55   return options;
56 }
57
58 static gboolean
59 gst_tizen_buffer_pool_set_config (GstBufferPool * pool,
60     GstStructure * config)
61 {
62   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (pool);
63   GstVideoInfo info;
64   GstCaps *caps;
65   tbm_format format;
66   tbm_surface_h surface;
67   guint min_buffers, max_buffers;
68   int size;
69
70   if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers, &max_buffers))
71     goto wrong_config;
72
73   if (caps == NULL)
74     goto no_caps;
75
76   /* now parse the caps from the config */
77   if (!gst_video_info_from_caps (&info, caps))
78     goto wrong_caps;
79
80   if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_UNKNOWN)
81     goto unknown_format;
82
83   _tpool->info = info;
84
85   format = gst_video_format_to_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
86
87   surface = tbm_surface_create (GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info), format);
88   size = tbm_surface_internal_get_size (surface);
89
90   tbm_surface_destroy (surface);
91
92   /* enable metadata based on config of the pool */
93   _tpool->add_videometa =  gst_buffer_pool_config_has_option (config,
94       GST_BUFFER_POOL_OPTION_VIDEO_META);
95
96   /* parse extra alignment info */
97   _tpool->add_tizenmeta = gst_buffer_pool_config_has_option (config,
98       GST_BUFFER_POOL_OPTION_TIZEN_META);
99
100   gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
101       max_buffers);
102
103   GST_DEBUG_OBJECT (_tpool, "min : %u, max : %u, size : %d", min_buffers, max_buffers, size);
104   return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
105
106   /* ERRORS */
107 wrong_config:
108   {
109     GST_WARNING_OBJECT (pool, "invalid config");
110     return FALSE;
111   }
112 no_caps:
113   {
114     GST_WARNING_OBJECT (pool, "no caps in config");
115     return FALSE;
116   }
117 wrong_caps:
118   {
119     GST_WARNING_OBJECT (pool,
120         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
121     return FALSE;
122   }
123 unknown_format:
124   {
125     GST_WARNING_OBJECT (_tpool, "failed to get format from caps %"
126         GST_PTR_FORMAT, caps);
127     GST_ELEMENT_ERROR (_tpool, RESOURCE, WRITE,
128         ("Failed to create output image buffer of %dx%d pixels",
129             info.width, info.height),
130
131         ("Invalid input caps %" GST_PTR_FORMAT, caps));
132     return FALSE;
133   }
134 }
135
136 static void
137 _destroy_tbm_surface (tbm_surface_h surface)
138 {
139   GST_DEBUG ("destroy surface %p", surface);
140   tbm_surface_internal_destroy (surface);
141 }
142
143 /* This function handles GstBuffer creation */
144 static GstFlowReturn
145 gst_tizen_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
146     GstBufferPoolAcquireParams * params)
147 {
148   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (pool);
149   GstVideoInfo *info;
150   GstBuffer *buf;
151   GstMemory *tizen_mem;
152   gsize offsets[4] = {0, };
153
154   GST_DEBUG_OBJECT (pool, "gst_tizen_buffer_pool_alloc");
155   info = &_tpool->info;
156
157   if (!(buf = gst_buffer_new ()))
158     goto no_buffer;
159
160   GST_DEBUG_OBJECT (pool, "buffer new :%dx%d : %p", GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), buf);
161   if (!(tizen_mem = gst_tizen_allocator_alloc ((GstAllocator *)_tpool->allocator, info)))
162     goto mem_create_failed;
163
164   gst_buffer_append_memory (buf, tizen_mem);
165
166   GST_DEBUG_OBJECT (pool, "mem allocated : %p, %dx%d n_plane : %d",
167       buf, GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info));
168
169   if (_tpool->add_videometa) {
170     GstVideoMeta *vmeta;
171
172     GST_DEBUG_OBJECT (pool, "adding GstVideoMeta");
173     /* these are just the defaults for now */
174
175     vmeta = gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
176         GST_VIDEO_INFO_FORMAT (info),
177         GST_VIDEO_INFO_WIDTH (info),
178         GST_VIDEO_INFO_HEIGHT (info),
179         GST_VIDEO_INFO_N_PLANES (info), offsets, info->stride);
180
181     vmeta->map = gst_tizen_video_meta_map;
182     vmeta->unmap = gst_tizen_video_meta_unmap;
183   }
184
185   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
186       gst_tizen_buffer_data_quark, gst_tizen_memory_get_surface (tizen_mem), (GDestroyNotify) _destroy_tbm_surface);
187
188   *buffer = buf;
189   g_ptr_array_add (_tpool->buffers, buf);
190   g_atomic_int_inc (&_tpool->current_buffer_index);
191   g_atomic_int_inc (&_tpool->outstandings);
192
193   return GST_FLOW_OK;
194
195   /* ERROR */
196 no_buffer:
197   {
198     GST_WARNING_OBJECT (pool, "Couldn't create buffer");
199     return GST_FLOW_ERROR;
200   }
201
202 mem_create_failed:
203   {
204     GST_WARNING_OBJECT (pool, "Couldn't create GstTizen Memory");
205     return GST_FLOW_ERROR;
206   }
207 }
208
209
210 static GstFlowReturn
211 gst_tizen_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
212     GstBufferPoolAcquireParams * params)
213 {
214   GstFlowReturn ret;
215   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (bpool);
216   GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
217   gint i, n;
218
219   ret = pclass->acquire_buffer (bpool, buffer, params);
220   if (ret != GST_FLOW_OK) {
221     GST_WARNING_OBJECT (_tpool, "Couldn't acquire buffer");
222     return ret;
223   }
224
225   n = _tpool->buffers->len;
226   for (i = 0; i < n; i++) {
227     GstBuffer *tmp = g_ptr_array_index (_tpool->buffers, i);
228
229     if (tmp == *buffer)
230       break;
231   }
232   g_assert (i != n);
233   g_atomic_int_set(&_tpool->current_buffer_index, i);
234
235   GST_BUFFER_TIMESTAMP (*buffer) = GST_CLOCK_TIME_NONE;
236   GST_BUFFER_OFFSET (*buffer) = GST_BUFFER_OFFSET_NONE;
237   GST_BUFFER_OFFSET_END (*buffer) = GST_BUFFER_OFFSET_NONE;
238
239   g_atomic_int_inc (&_tpool->outstandings);
240
241   g_mutex_lock (&_tpool->lock);
242   _tpool->empty = FALSE;
243   g_mutex_unlock (&_tpool->lock);
244
245   GST_DEBUG_OBJECT (_tpool, "acquire buffer %p, current index %d, num_live_buffer %d", *buffer, i, _tpool->outstandings);
246
247   return GST_FLOW_OK;
248 }
249
250 static void
251 gst_tizen_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
252 {
253   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (bpool);
254
255   GST_BUFFER_POOL_CLASS (gst_tizen_buffer_pool_parent_class)->release_buffer (bpool, buffer);
256
257   if (g_atomic_int_dec_and_test(&_tpool->outstandings)) {
258     g_mutex_lock (&_tpool->lock);
259     _tpool->empty = TRUE;
260     g_mutex_unlock (&_tpool->lock);
261   }
262   GST_DEBUG_OBJECT (_tpool, "release buffer %p, outstandings %d", buffer, _tpool->outstandings);
263 }
264
265 static void
266 gst_tizen_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
267 {
268   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (bpool);
269   GST_DEBUG_OBJECT (_tpool, "free buffer %p, %d", buffer, _tpool->outstandings);
270
271   gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer),
272       gst_tizen_buffer_data_quark, NULL, NULL);
273
274   GST_BUFFER_POOL_CLASS (gst_tizen_buffer_pool_parent_class)->free_buffer (bpool,
275       buffer);
276 }
277
278 static void
279 gst_tizen_buffer_pool_dispose (GObject * object)
280 {
281   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (object);
282
283   if (_tpool->allocator) {
284     gst_object_unref (_tpool->allocator);
285     _tpool->allocator = NULL;
286   }
287
288   if (_tpool->buffers) {
289     g_ptr_array_unref (_tpool->buffers);
290     _tpool->buffers = NULL;
291   }
292
293   GST_DEBUG_OBJECT (_tpool, "dispose pool");
294   G_OBJECT_CLASS (parent_class)->dispose (object);
295 }
296
297 static void
298 gst_tizen_buffer_pool_finalize (GObject * object)
299 {
300   GstTizenBufferPool *pool = GST_TIZEN_BUFFER_POOL_CAST (object);
301
302
303   g_mutex_clear (&pool->lock);
304
305   G_OBJECT_CLASS (gst_tizen_buffer_pool_parent_class)->finalize (object);
306 }
307
308 static void
309 gst_tizen_buffer_pool_init (GstTizenBufferPool * pool)
310 {
311   g_mutex_init (&pool->lock);
312   pool->priv = gst_tizen_buffer_pool_get_instance_private (pool);
313   pool->buffers = g_ptr_array_new ();
314   pool->allocator = gst_tizen_allocator_new ();
315   g_atomic_int_set(&pool->outstandings, 0);
316   GST_LOG_OBJECT (pool, "Tizen buffer pool init %p", pool);
317 }
318
319 static void
320 gst_tizen_buffer_pool_class_init (GstTizenBufferPoolClass * klass)
321 {
322   GObjectClass *gobject_class = (GObjectClass *) klass;
323   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
324
325   gst_tizen_buffer_data_quark = g_quark_from_static_string ("GstTizenBufferData");
326
327   gobject_class->dispose = gst_tizen_buffer_pool_dispose;
328   gobject_class->finalize = gst_tizen_buffer_pool_finalize;
329
330   gstbufferpool_class->get_options = gst_tizen_buffer_pool_get_options;
331   gstbufferpool_class->set_config = gst_tizen_buffer_pool_set_config;
332   gstbufferpool_class->alloc_buffer = gst_tizen_buffer_pool_alloc;
333   gstbufferpool_class->free_buffer = gst_tizen_buffer_pool_free_buffer;
334   gstbufferpool_class->acquire_buffer = gst_tizen_buffer_pool_acquire_buffer;
335   gstbufferpool_class->release_buffer = gst_tizen_buffer_pool_release_buffer;
336 }
337
338 GstBufferPool *
339 gst_tizen_buffer_pool_new (void)
340 {
341   return GST_BUFFER_POOL_CAST (g_object_new (GST_TYPE_TIZEN_BUFFER_POOL, NULL));
342 }