2dffbee7668afd21b5027ec2c4cacd1e5ee4b0eb
[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
27 GST_DEBUG_CATEGORY_STATIC (gst_tizen_vidbufpool_debug);
28 #define GST_CAT_DEFAULT gst_tizen_vidbufpool_debug
29
30 static GQuark gst_tizen_buffer_data_quark = 0;
31
32 static void gst_tizen_buffer_pool_finalize (GObject * object);
33
34 #define DEBUG_INIT \
35     GST_DEBUG_CATEGORY_INIT (gst_tizen_vidbufpool_debug, "tizenvideopool", 0, \
36     "Tizen bufferpool");
37
38 #define gst_tizen_buffer_pool_parent_class parent_class
39 G_DEFINE_TYPE_WITH_CODE (GstTizenBufferPool, gst_tizen_buffer_pool,
40     GST_TYPE_BUFFER_POOL, DEBUG_INIT);
41
42 struct _GstTizenBufferPoolPrivate
43 {
44   GstAllocator *allocator;
45 };
46
47 static const gchar **
48 gst_tizen_buffer_pool_get_options (GstBufferPool * pool)
49 {
50   static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
51     GST_BUFFER_POOL_OPTION_TIZEN_META, NULL
52   };
53
54   return options;
55 }
56
57 static gboolean
58 gst_tizen_buffer_pool_set_config (GstBufferPool * pool,
59     GstStructure * config)
60 {
61   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (pool);
62   GstVideoInfo info;
63   GstCaps *caps;
64   tbm_format format;
65   tbm_surface_h surface;
66   guint min_buffers, max_buffers;
67   int size;
68
69   if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers, &max_buffers))
70     goto wrong_config;
71
72   if (caps == NULL)
73     goto no_caps;
74
75   /* now parse the caps from the config */
76   if (!gst_video_info_from_caps (&info, caps))
77     goto wrong_caps;
78
79   if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_UNKNOWN)
80     goto unknown_format;
81
82   _tpool->info = info;
83
84   format = gst_video_format_to_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
85
86   surface = tbm_surface_create (GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info), format);
87   size = tbm_surface_internal_get_size (surface);
88
89   tbm_surface_destroy (surface);
90
91   /* enable metadata based on config of the pool */
92   _tpool->add_videometa =  gst_buffer_pool_config_has_option (config,
93       GST_BUFFER_POOL_OPTION_VIDEO_META);
94
95   /* parse extra alignment info */
96   _tpool->add_tizenmeta = gst_buffer_pool_config_has_option (config,
97       GST_BUFFER_POOL_OPTION_TIZEN_META);
98
99   gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
100       max_buffers);
101
102   GST_DEBUG_OBJECT (_tpool, "min : %u, max : %u, size : %d", min_buffers, max_buffers, size);
103   return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
104
105   /* ERRORS */
106 wrong_config:
107   {
108     GST_WARNING_OBJECT (pool, "invalid config");
109     return FALSE;
110   }
111 no_caps:
112   {
113     GST_WARNING_OBJECT (pool, "no caps in config");
114     return FALSE;
115   }
116 wrong_caps:
117   {
118     GST_WARNING_OBJECT (pool,
119         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
120     return FALSE;
121   }
122 unknown_format:
123   {
124     GST_WARNING_OBJECT (_tpool, "failed to get format from caps %"
125         GST_PTR_FORMAT, caps);
126     GST_ELEMENT_ERROR (_tpool, RESOURCE, WRITE,
127         ("Failed to create output image buffer of %dx%d pixels",
128             info.width, info.height),
129
130         ("Invalid input caps %" GST_PTR_FORMAT, caps));
131     return FALSE;
132   }
133 }
134
135 static void
136 _destroy_tbm_surface (struct UserPtrData *data)
137 {
138   tbm_surface_internal_destroy ((tbm_surface_h)data);
139   GST_DEBUG ("destroy surface %p", data);
140 }
141
142 /* This function handles GstBuffer creation */
143 static GstFlowReturn
144 gst_tizen_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
145     GstBufferPoolAcquireParams * params)
146 {
147   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (pool);
148   GstVideoInfo *info;
149   GstBuffer *buf;
150   GstMemory *tizen_mem;
151   gint offsets[4] = {0, };
152
153   GST_DEBUG_OBJECT (pool, "gst_tizen_buffer_pool_alloc");
154   info = &_tpool->info;
155
156   if (!(buf = gst_buffer_new ()))
157     goto no_buffer;
158
159   GST_DEBUG_OBJECT (pool, "buffer new :%dx%d : %p", GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), buf);
160   if (!(tizen_mem = gst_tizen_allocator_alloc ((GstAllocator *)_tpool->allocator, info)))
161     goto mem_create_failed;
162
163   gst_buffer_append_memory (buf, tizen_mem);
164
165   GST_DEBUG_OBJECT (pool, "mem allocated : %p, %dx%d n_plane : %d",
166       buf, GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info));
167
168   if (_tpool->add_videometa) {
169     GstVideoMeta *vmeta;
170
171     GST_DEBUG_OBJECT (pool, "adding GstVideoMeta");
172     /* these are just the defaults for now */
173
174     vmeta = gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
175         GST_VIDEO_INFO_FORMAT (info),
176         GST_VIDEO_INFO_WIDTH (info),
177         GST_VIDEO_INFO_HEIGHT (info),
178         GST_VIDEO_INFO_N_PLANES (info), offsets, info->stride);
179
180     vmeta->map = gst_tizen_video_memory_map;
181     vmeta->unmap = gst_tizen_video_memory_unmap;
182   }
183
184   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
185       gst_tizen_buffer_data_quark, gst_tizen_memory_get_surface (tizen_mem), (GDestroyNotify) _destroy_tbm_surface);
186
187   *buffer = buf;
188   g_ptr_array_add (_tpool->buffers, buf);
189   g_atomic_int_inc (&_tpool->current_buffer_index);
190   g_atomic_int_inc (&_tpool->outstandings);
191
192   return GST_FLOW_OK;
193
194   /* ERROR */
195 no_buffer:
196   {
197     GST_WARNING_OBJECT (pool, "Couldn't create buffer");
198     return GST_FLOW_ERROR;
199   }
200
201 mem_create_failed:
202   {
203     GST_WARNING_OBJECT (pool, "Couldn't create GstTizen Memory");
204     return GST_FLOW_ERROR;
205   }
206 }
207
208
209 static GstFlowReturn
210 gst_tizen_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
211     GstBufferPoolAcquireParams * params)
212 {
213   GstFlowReturn ret;
214   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (bpool);
215   GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
216   gint i, n;
217
218   ret = pclass->acquire_buffer (bpool, buffer, params);
219   if (ret != GST_FLOW_OK) {
220     GST_WARNING_OBJECT (_tpool, "Couldn't acquire buffer");
221     return ret;
222   }
223
224   n = _tpool->buffers->len;
225   for (i = 0; i < n; i++) {
226     GstBuffer *tmp = g_ptr_array_index (_tpool->buffers, i);
227
228     if (tmp == *buffer)
229       break;
230   }
231   g_assert (i != n);
232   g_atomic_int_set(&_tpool->current_buffer_index, i);
233
234   GST_BUFFER_TIMESTAMP (*buffer) = GST_CLOCK_TIME_NONE;
235   GST_BUFFER_OFFSET (*buffer) = GST_BUFFER_OFFSET_NONE;
236   GST_BUFFER_OFFSET_END (*buffer) = GST_BUFFER_OFFSET_NONE;
237
238   g_atomic_int_inc (&_tpool->outstandings);
239
240   g_mutex_lock (&_tpool->lock);
241   _tpool->empty = FALSE;
242   g_mutex_unlock (&_tpool->lock);
243
244   GST_DEBUG_OBJECT (_tpool, "acquire buffer %p, current index %d, num_live_buffer %d", *buffer, i, _tpool->outstandings);
245
246   return GST_FLOW_OK;
247 }
248
249 void
250 gst_tizen_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
251 {
252   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (bpool);
253
254   GST_BUFFER_POOL_CLASS (gst_tizen_buffer_pool_parent_class)->release_buffer (bpool, buffer);
255
256   if (g_atomic_int_dec_and_test(&_tpool->outstandings)) {
257     g_mutex_lock (&_tpool->lock);
258     _tpool->empty = TRUE;
259     g_mutex_unlock (&_tpool->lock);
260   }
261   GST_DEBUG_OBJECT (_tpool, "release buffer %p, outstandings %d", buffer, _tpool->outstandings);
262 }
263
264 static void
265 gst_tizen_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
266 {
267   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (bpool);
268   GST_DEBUG_OBJECT (_tpool, "free buffer %p, %d", buffer, _tpool->outstandings);
269
270   gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer),
271       gst_tizen_buffer_data_quark, NULL, NULL);
272
273   GST_BUFFER_POOL_CLASS (gst_tizen_buffer_pool_parent_class)->free_buffer (bpool,
274       buffer);
275 }
276
277 static void
278 gst_tizen_buffer_pool_dispose (GObject * object)
279 {
280   GstTizenBufferPool *_tpool = GST_TIZEN_BUFFER_POOL_CAST (object);
281
282   if (_tpool->allocator) {
283     gst_object_unref (_tpool->allocator);
284     _tpool->allocator = NULL;
285   }
286
287   if (_tpool->buffers) {
288     g_ptr_array_unref (_tpool->buffers);
289     _tpool->buffers = NULL;
290   }
291
292   GST_DEBUG_OBJECT (_tpool, "dispose pool");
293   G_OBJECT_CLASS (parent_class)->dispose (object);
294 }
295
296 static void
297 gst_tizen_buffer_pool_finalize (GObject * object)
298 {
299   GstTizenBufferPool *pool = GST_TIZEN_BUFFER_POOL_CAST (object);
300
301
302   g_mutex_clear (&pool->lock);
303
304   G_OBJECT_CLASS (gst_tizen_buffer_pool_parent_class)->finalize (object);
305 }
306
307 GstBufferPool *
308 gst_tizen_buffer_pool_new ()
309 {
310   return GST_BUFFER_POOL_CAST (g_object_new (GST_TYPE_TIZEN_BUFFER_POOL, NULL));
311 }
312
313 static void
314 gst_tizen_buffer_pool_class_init (GstTizenBufferPoolClass * klass)
315 {
316   GObjectClass *gobject_class = (GObjectClass *) klass;
317   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
318
319   gst_tizen_buffer_data_quark = g_quark_from_static_string ("GstTizenBufferData");
320
321   gobject_class->dispose = gst_tizen_buffer_pool_dispose;
322   gobject_class->finalize = gst_tizen_buffer_pool_finalize;
323
324   gstbufferpool_class->get_options = gst_tizen_buffer_pool_get_options;
325   gstbufferpool_class->set_config = gst_tizen_buffer_pool_set_config;
326   gstbufferpool_class->alloc_buffer = gst_tizen_buffer_pool_alloc;
327   gstbufferpool_class->free_buffer = gst_tizen_buffer_pool_free_buffer;
328   gstbufferpool_class->acquire_buffer = gst_tizen_buffer_pool_acquire_buffer;
329   gstbufferpool_class->release_buffer = gst_tizen_buffer_pool_release_buffer;
330 }
331
332 static void
333 gst_tizen_buffer_pool_init (GstTizenBufferPool * pool)
334 {
335   g_mutex_init (&pool->lock);
336   pool->priv = gst_tizen_buffer_pool_get_instance_private (pool);
337   pool->buffers = g_ptr_array_new ();
338   pool->allocator = gst_tizen_allocator_new ();
339   g_atomic_int_set(&pool->outstandings, 0);
340   GST_LOG_OBJECT (pool, "Tizen buffer pool init %p", pool);
341 }
342