254db32d89a2bf79adfca23d89c4bc1e3d6f535c
[platform/upstream/gst-plugins-base.git] / gst / videoconvert / gsttbmbufferpool.c
1
2 #include "gsttbmbufferpool.h"
3 #include <gst/video/gstvideofilter.h>
4
5 int new_calc_plane(int width, int height)
6 {
7     int mbX, mbY;
8
9     mbX = DIV_ROUND_UP(width, S5P_FIMV_NUM_PIXELS_IN_MB_ROW);
10     mbY = DIV_ROUND_UP(height, S5P_FIMV_NUM_PIXELS_IN_MB_COL);
11
12     if (width * height < S5P_FIMV_MAX_FRAME_SIZE)
13       mbY = (mbY + 1) / 2 * 2;
14
15     return ((mbX * S5P_FIMV_NUM_PIXELS_IN_MB_COL) *
16      (mbY * S5P_FIMV_NUM_PIXELS_IN_MB_ROW));
17 }
18
19 int new_calc_yplane(int width, int height)
20 {
21     return (ALIGN_TO_4KB(new_calc_plane(width, height) +
22               S5P_FIMV_D_ALIGN_PLANE_SIZE));
23 }
24
25 int new_calc_uvplane(int width, int height)
26 {
27     return (ALIGN_TO_4KB((new_calc_plane(width, height) >> 1) +
28               S5P_FIMV_D_ALIGN_PLANE_SIZE));
29 }
30
31 int
32 calc_plane(int width, int height)
33 {
34     int mbX, mbY;
35
36     mbX = ALIGN(width, S5P_FIMV_NV12MT_HALIGN);
37     mbY = ALIGN(height, S5P_FIMV_NV12MT_VALIGN);
38
39     return ALIGN(mbX * mbY, S5P_FIMV_DEC_BUF_ALIGN);
40 }
41
42 int
43 calc_yplane(int width, int height)
44 {
45     int mbX, mbY;
46
47     mbX = ALIGN(width + 24, S5P_FIMV_NV12MT_HALIGN);
48     mbY = ALIGN(height + 16, S5P_FIMV_NV12MT_VALIGN);
49
50     return ALIGN(mbX * mbY, S5P_FIMV_DEC_BUF_ALIGN);
51 }
52
53 int
54 calc_uvplane(int width, int height)
55 {
56     int mbX, mbY;
57
58     mbX = ALIGN(width + 16, S5P_FIMV_NV12MT_HALIGN);
59     mbY = ALIGN(height + 4, S5P_FIMV_NV12MT_VALIGN);
60
61     return ALIGN((mbX * mbY)>>1, S5P_FIMV_DEC_BUF_ALIGN);
62 }
63
64 int
65 gst_calculate_y_size(int width, int height)
66 {
67    return CHOOSE_MAX_SIZE(calc_yplane(width,height),new_calc_yplane(width,height));
68 }
69
70 int
71 gst_calculate_uv_size(int width, int height)
72 {
73    return CHOOSE_MAX_SIZE(calc_uvplane(width,height),new_calc_uvplane(width,height));
74 }
75
76 static GstMemory *
77 gst_mm_memory_allocator_alloc_dummy (GstAllocator * allocator, gsize size,
78     GstAllocationParams * params)
79 {
80   g_assert_not_reached ();
81   return NULL;
82 }
83
84 static void
85 gst_mm_memory_allocator_free (GstAllocator * allocator, GstMemory * mem)
86 {
87   GstMMVideoMemory *omem = (GstMMVideoMemory *) mem;
88
89   /* TODO: We need to remember which memories are still used
90    * so we can wait until everything is released before allocating
91    * new memory
92    */
93
94   g_slice_free (GstMMVideoMemory, omem);
95 }
96
97 static gpointer
98 gst_mm_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
99 {
100   GstMMVideoMemory *omem = (GstMMVideoMemory *) mem;
101
102   return omem->mm_video_buffer;
103 }
104
105 static void
106 gst_mm_memory_unmap (GstMemory * mem)
107 {
108 }
109
110 static GstMemory *
111 gst_mm_memory_share (GstMemory * mem, gssize offset, gssize size)
112 {
113   g_assert_not_reached ();
114   return NULL;
115 }
116
117 GType gst_mm_memory_allocator_get_type (void);
118 G_DEFINE_TYPE (GstMMVideoMemoryAllocator, gst_mm_memory_allocator,
119     GST_TYPE_ALLOCATOR);
120
121 #define GST_TYPE_MM_MEMORY_ALLOCATOR   (gst_mm_memory_allocator_get_type())
122 #define GST_IS_MM_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MM_MEMORY_ALLOCATOR))
123
124 static void
125 gst_mm_memory_allocator_class_init (GstMMVideoMemoryAllocatorClass * klass)
126 {
127   GstAllocatorClass *allocator_class;
128
129   allocator_class = (GstAllocatorClass *) klass;
130
131   allocator_class->alloc = gst_mm_memory_allocator_alloc_dummy;
132   allocator_class->free = gst_mm_memory_allocator_free;
133 }
134
135 static void
136 gst_mm_memory_allocator_init (GstMMVideoMemoryAllocator * allocator)
137 {
138   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
139
140   alloc->mem_type = GST_MM_VIDEO_MEMORY_TYPE;
141   alloc->mem_map = gst_mm_memory_map;
142   alloc->mem_unmap = gst_mm_memory_unmap;
143   alloc->mem_share = gst_mm_memory_share;
144
145   /* default copy & is_span */
146
147   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
148 }
149
150 static GstMemory *
151 gst_mm_memory_allocator_alloc (GstAllocator * allocator, GstMemoryFlags flags,
152     GstMMBuffer * buf)
153 {
154   GstMMVideoMemory *mem;
155
156   /* FIXME: We don't allow sharing because we need to know
157    * when the memory becomes unused and can only then put
158    * it back to the pool. Which is done in the pool's release
159    * function
160    */
161   flags |= GST_MEMORY_FLAG_NO_SHARE;
162
163   mem = g_slice_new (GstMMVideoMemory);
164   /* the shared memory is always readonly */
165   gst_memory_init (GST_MEMORY_CAST (mem), flags, allocator, NULL,
166       sizeof(MMVideoBuffer), 1, 0, sizeof(MMVideoBuffer));
167
168   mem->mm_video_buffer = buf;
169
170   return GST_MEMORY_CAST (mem);
171 }
172
173 /* Subclassing GstBufferPool */
174
175
176
177 GType gst_mm_buffer_pool_get_type (void);
178
179 G_DEFINE_TYPE (GstMMBufferPool, gst_mm_buffer_pool, GST_TYPE_BUFFER_POOL);
180
181 static gboolean
182 gst_mm_buffer_pool_start (GstBufferPool * bpool)
183 {
184   return
185       GST_BUFFER_POOL_CLASS (gst_mm_buffer_pool_parent_class)->start (bpool);
186 }
187
188 static gboolean
189 gst_mm_buffer_pool_stop (GstBufferPool * bpool)
190 {
191   GstMMBufferPool *pool = GST_MM_BUFFER_POOL (bpool);
192
193   if(gst_buffer_pool_is_active (pool) == TRUE)
194       return FALSE;
195   /* Remove any buffers that are there */
196   if(pool->buffers != NULL){
197     g_ptr_array_set_size (pool->buffers, 0);
198     pool->buffers = NULL;
199   }
200
201   if (pool->caps)
202     gst_caps_unref (pool->caps);
203   pool->caps = NULL;
204
205   pool->add_videometa = FALSE;
206
207   return GST_BUFFER_POOL_CLASS (gst_mm_buffer_pool_parent_class)->stop (bpool);
208 }
209
210 static const gchar **
211 gst_mm_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   return options;
217 }
218
219 static gboolean
220 gst_mm_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
221 {
222   GstMMBufferPool *pool = GST_MM_BUFFER_POOL (bpool);
223   GstCaps *caps;
224
225   GST_OBJECT_LOCK (pool);
226
227   if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
228     goto wrong_config;
229
230   if (caps == NULL)
231     goto no_caps;
232
233   if (pool->caps)
234     gst_caps_unref (pool->caps);
235   pool->caps = gst_caps_ref (caps);
236
237   GST_OBJECT_UNLOCK (pool);
238
239   return GST_BUFFER_POOL_CLASS (gst_mm_buffer_pool_parent_class)->set_config
240       (bpool, config);
241
242   /* ERRORS */
243 wrong_config:
244   {
245     GST_OBJECT_UNLOCK (pool);
246     GST_WARNING_OBJECT (pool, "invalid config");
247     return FALSE;
248   }
249 no_caps:
250   {
251     GST_OBJECT_UNLOCK (pool);
252     GST_WARNING_OBJECT (pool, "no caps in config");
253     return FALSE;
254   }
255 }
256
257 static GstFlowReturn
258 gst_mm_buffer_pool_alloc_buffer (GstBufferPool * bpool,
259     GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
260 {
261   GstMMBufferPool *pool = GST_MM_BUFFER_POOL (bpool);
262   GstBuffer *buf = NULL;
263   GstMMBuffer *mm_buf = NULL;
264   GstMemory *mem;
265   void *mm_data = NULL;
266   MMVideoBuffer *mm_video_buf = NULL;
267   gsize offset[4] = { 0, };
268   gint stride[4] = { 0, };
269   int width, height;
270
271   mm_buf = (GstMMBuffer*) malloc(sizeof(GstMMBuffer));
272   mem = gst_mm_memory_allocator_alloc (pool->allocator, 0, mm_buf);
273   buf = gst_buffer_new ();
274   buf->pool = pool;
275   mem->size = sizeof(GstMMBuffer);
276   mem->offset = 0;
277   gst_buffer_append_memory (buf, mem);
278   offset[0] = offset[1] = 0;
279   stride[0] = stride[1] = 0;
280   gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
281         GST_VIDEO_INFO_FORMAT (&pool->video_info),
282         GST_VIDEO_INFO_WIDTH (&pool->video_info),
283         GST_VIDEO_INFO_HEIGHT (&pool->video_info),
284         GST_VIDEO_INFO_N_PLANES (&pool->video_info), offset, stride);
285
286   g_ptr_array_add (pool->buffers, buf);
287   GST_ERROR(" buffer:[%p], mm_buffer:[%p], mem:[%p] width:[%d] height:[%d]",buf, mm_buf, mem, GST_VIDEO_INFO_WIDTH (&pool->video_info),GST_VIDEO_INFO_HEIGHT (&pool->video_info));
288
289   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
290       gst_mm_buffer_data_quark, mm_buf, NULL);
291
292   /* Allocating second GstMemory for buffer */
293     width = GST_VIDEO_INFO_WIDTH (&pool->video_info);
294     height = GST_VIDEO_INFO_HEIGHT (&pool->video_info);
295     mm_data = g_malloc0(sizeof(MMVideoBuffer));
296     mm_video_buf = (MMVideoBuffer*) mm_data;
297     mm_video_buf->type = MM_VIDEO_BUFFER_TYPE_TBM_BO;
298     mm_video_buf->plane_num = 2;
299     /* Setting Y plane size */
300     mm_video_buf->size[0] = gst_calculate_y_size(width, height);
301     /* Setting UV plane size */
302     mm_video_buf->size[1] = gst_calculate_uv_size(width, height);
303     mm_video_buf->handle.bo[0] = tbm_bo_alloc(pool->hTBMBufMgr, mm_video_buf->size[0], TBM_BO_WC);
304     mm_video_buf->handle.bo[1] = tbm_bo_alloc(pool->hTBMBufMgr, mm_video_buf->size[1], TBM_BO_WC);
305
306     mm_video_buf->handle.dmabuf_fd[0] = (tbm_bo_get_handle(mm_video_buf->handle.bo[0], TBM_DEVICE_MM)).u32;
307     mm_video_buf->handle.dmabuf_fd[1] = (tbm_bo_get_handle(mm_video_buf->handle.bo[1], TBM_DEVICE_MM)).u32;
308     mm_video_buf->data[0] = (tbm_bo_map(mm_video_buf->handle.bo[0], TBM_DEVICE_CPU,TBM_OPTION_WRITE)).ptr;
309     mm_video_buf->data[1] = (tbm_bo_map(mm_video_buf->handle.bo[1], TBM_DEVICE_CPU,TBM_OPTION_WRITE)).ptr;
310     /* Setting stride height & width for Y plane */
311     mm_video_buf->stride_height[0] = mm_video_buf->height[0] = height;
312     mm_video_buf->stride_width[0] = mm_video_buf->width[0] = width;
313     /* Setting stride height & width for UV plane */
314     mm_video_buf->stride_height[1] = mm_video_buf->height[1] = height >> 1;
315     mm_video_buf->stride_width[1] = mm_video_buf->width[1] = width;
316
317     mem = gst_memory_new_wrapped(0,
318         mm_data, sizeof(MMVideoBuffer), 0, sizeof(MMVideoBuffer), mm_data, g_free);
319     GST_DEBUG("[%s] Appending 2 memory to gst buffer.",__FUNCTION__);
320     gst_buffer_append_memory(buf, mem);
321
322   *buffer = buf;
323
324   pool->current_buffer_index++;
325
326   return GST_FLOW_OK;
327 }
328
329
330 static void
331 gst_mm_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
332 {
333   MMVideoBuffer *mm_video_buf = NULL;
334   GstMemory *mem = NULL;
335   void *mm_data = NULL;
336   GstMMBufferPool *pool = GST_MM_BUFFER_POOL (bpool);
337
338   /* If the buffers belong to another pool, restore them now */
339   GST_OBJECT_LOCK (pool);
340   if (pool->other_pool) {
341     gst_object_replace ((GstObject **) & buffer->pool,
342         (GstObject *) pool->other_pool);
343   }
344   GST_OBJECT_UNLOCK (pool);
345
346   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer),
347       gst_mm_buffer_data_quark, NULL, NULL);
348
349 #ifdef USE_TBM_BUFFER
350   {
351   GstMapInfo map_info = GST_MAP_INFO_INIT;
352   mem = gst_buffer_peek_memory (buffer, 1);
353   if (mem != NULL) {
354       gst_memory_map(mem, &map_info, GST_MAP_READ);
355       mm_data = map_info.data;
356       gst_memory_unmap(mem, &map_info);
357       mm_video_buf = (MMVideoBuffer*) mm_data;
358       if(mm_video_buf != NULL && mm_video_buf->handle.bo[0] != NULL) {
359          tbm_bo_unmap(mm_video_buf->handle.bo[0]);
360          tbm_bo_unref(mm_video_buf->handle.bo[0]);
361       }
362       if(mm_video_buf != NULL && mm_video_buf->handle.bo[1] != NULL) {
363          tbm_bo_unmap(mm_video_buf->handle.bo[1]);
364          tbm_bo_unref(mm_video_buf->handle.bo[1]);
365       }
366     }
367   }
368 #endif
369   GST_BUFFER_POOL_CLASS (gst_mm_buffer_pool_parent_class)->free_buffer (bpool,
370       buffer);
371 }
372
373 static GstFlowReturn
374 gst_mm_buffer_pool_acquire_buffer (GstBufferPool * bpool,
375     GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
376 {
377   GstFlowReturn ret;
378   GstMMBuffer *temp = NULL;
379   GstMMVideoMemory *temp_video_memory = NULL;
380   GstMMBufferPool *pool = GST_MM_BUFFER_POOL (bpool);
381
382   GstBuffer *buf;
383   int i ,n;
384
385   n = pool->buffers->len;
386   if(g_queue_is_empty(pool->mm_buffers)) {
387       GST_ERROR(" mm_buffers is queue is empty.");
388       return GST_FLOW_ERROR;
389   }
390   temp = g_queue_pop_head(pool->mm_buffers);
391   for(i = 0; i < n; i++) {
392       temp_video_memory = g_ptr_array_index(pool->buffers,i);
393       temp_video_memory->mm_video_buffer = gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (temp_video_memory),
394         gst_mm_buffer_data_quark);
395       if(temp_video_memory->mm_video_buffer == temp)
396           break;
397    }
398    if(i == n) {
399        GST_ERROR(": mm_buffer is not found in buffers list.");
400        return GST_FLOW_ERROR;
401    }
402
403    pool->current_buffer_index = i;
404    g_return_val_if_fail (pool->current_buffer_index != -1, GST_FLOW_ERROR);
405    GST_DEBUG(" Acquiring buffer at index:[%d]",pool->current_buffer_index);
406    buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index);
407    GST_DEBUG("\ buffer:[%p]",buf);
408    g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
409    *buffer = buf;
410    ret = GST_FLOW_OK;
411
412   return ret;
413 }
414
415 static void
416 gst_mm_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
417 {
418   GstMMBufferPool *pool = GST_MM_BUFFER_POOL (bpool);
419   GstMMBuffer *mm_buf;
420
421   if (!pool->allocating && !pool->deactivated) {
422     mm_buf =
423         gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer),
424         gst_mm_buffer_data_quark);
425     if(mm_buf != NULL) {
426         g_queue_push_tail(pool->mm_buffers, mm_buf);
427     }
428   }
429 }
430
431 static void
432 gst_mm_buffer_pool_finalize (GObject * object)
433 {
434   GstMMBufferPool *pool = GST_MM_BUFFER_POOL (object);
435
436   if (pool->element)
437     gst_object_unref (pool->element);
438   pool->element = NULL;
439
440   if (pool->buffers)
441     g_ptr_array_unref (pool->buffers);
442   pool->buffers = NULL;
443
444   if (pool->other_pool)
445     gst_object_unref (pool->other_pool);
446   pool->other_pool = NULL;
447
448   if (pool->allocator)
449     gst_object_unref (pool->allocator);
450   pool->allocator = NULL;
451
452   if (pool->caps)
453     gst_caps_unref (pool->caps);
454   pool->caps = NULL;
455
456   G_OBJECT_CLASS (gst_mm_buffer_pool_parent_class)->finalize (object);
457 }
458
459 static void
460 gst_mm_buffer_pool_class_init (GstMMBufferPoolClass * klass)
461 {
462   GObjectClass *gobject_class = (GObjectClass *) klass;
463   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
464
465   gst_mm_buffer_data_quark = g_quark_from_static_string ("GstMMBufferData");
466
467   gobject_class->finalize = gst_mm_buffer_pool_finalize;
468   gstbufferpool_class->start = gst_mm_buffer_pool_start;
469   gstbufferpool_class->stop = gst_mm_buffer_pool_stop;
470   gstbufferpool_class->get_options = gst_mm_buffer_pool_get_options;
471   gstbufferpool_class->set_config = gst_mm_buffer_pool_set_config;
472   gstbufferpool_class->alloc_buffer = gst_mm_buffer_pool_alloc_buffer;
473   gstbufferpool_class->free_buffer = gst_mm_buffer_pool_free_buffer;
474   gstbufferpool_class->acquire_buffer = gst_mm_buffer_pool_acquire_buffer;
475   gstbufferpool_class->release_buffer = gst_mm_buffer_pool_release_buffer;
476 }
477
478 static void
479 gst_mm_buffer_pool_init (GstMMBufferPool * pool)
480 {
481
482   pool->buffers = g_ptr_array_new ();
483   pool->allocator = g_object_new (gst_mm_memory_allocator_get_type (), NULL);
484   pool->other_pool = NULL;
485   pool->mm_buffers = g_queue_new();
486
487 #ifdef USE_TBM_BUFFER
488   pool->hTBMBufMgr = tbm_bufmgr_init(-1);
489   if(pool->hTBMBufMgr == NULL) {
490    GST_ERROR ("TBM initialization failed.");
491   }
492 #endif
493
494 }
495
496 GstBufferPool *
497 gst_mm_buffer_pool_new (GstElement * trans )
498 {
499   GstMMBufferPool *pool;
500   GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
501
502   pool = g_object_new (gst_mm_buffer_pool_get_type (), NULL);
503   pool->video_info = filter->out_info;
504
505   pool->element = gst_object_ref (trans);
506
507   return GST_BUFFER_POOL (pool);
508 }
509
510