675b0a0c4f25089fd634055a6cc217dff2abfe32
[platform/upstream/gst-plugins-base.git] / gst / videoconvert / gsttbmbufferpool.h
1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #include <gst/gst.h>
7 #include <gst/video/gstvideometa.h>
8 #include <gst/video/gstvideopool.h>
9 #include <string.h>
10
11 #ifdef USE_TBM_BUFFER
12 #include <mmf/mm_types.h>
13 #include <tbm_type.h>
14 #include <tbm_surface.h>
15 #include <tbm_bufmgr.h>
16 #endif
17
18 typedef struct _GstMMVideoMemory                GstMMVideoMemory;
19 typedef struct _GstMMVideoMemoryAllocator       GstMMVideoMemoryAllocator;
20 typedef struct _GstMMVideoMemoryAllocatorClass  GstMMVideoMemoryAllocatorClass;
21 typedef struct _GstMMBuffer                     GstMMBuffer;
22
23
24 struct _GstMMVideoMemory
25 {
26     GstMemory mem;
27     GstMMBuffer *mm_video_buffer;
28 };
29
30 struct _GstMMVideoMemoryAllocator
31 {
32   GstAllocator parent;
33 };
34
35 struct _GstMMVideoMemoryAllocatorClass
36 {
37   GstAllocatorClass parent_class;
38 };
39
40 struct _GstMMBuffer
41 {
42     MMVideoBuffer mm_buffer;
43     gint video_width;
44     gint video_height;
45     gint video_alignment;
46 };
47
48 #define GST_MM_VIDEO_MEMORY_TYPE "mmvideobuffer"
49 #define GST_TYPE_MM_BUFFER_POOL \
50   (gst_mm_buffer_pool_get_type()
51 #define GST_MM_BUFFER_POOL(obj) \
52   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OMX_MM_POOL,GstMMBufferPool))
53 typedef struct _GstMMBufferPool GstMMBufferPool;
54 typedef struct _GstMMBufferPoolClass GstMMBufferPoolClass;
55
56 struct _GstMMBufferPool
57 {
58   GstVideoBufferPool parent;
59
60   GstElement *element;
61
62   GstCaps *caps;
63   gboolean add_videometa;
64   GstVideoInfo video_info;
65
66   GstAllocator *allocator;
67
68   /* Set from outside this pool */
69   /* TRUE if we're currently allocating all our buffers */
70   gboolean allocating;
71
72   /* TRUE if the pool is not used anymore */
73   gboolean deactivated;
74
75   /* For populating the pool from another one */
76   GstBufferPool *other_pool;
77   GPtrArray *buffers;
78   GQueue *mm_buffers;
79
80   /* Used during acquire for output ports to
81    * specify which buffer has to be retrieved
82    * and during alloc, which buffer has to be
83    * wrapped
84    */
85   gint current_buffer_index;
86
87 #ifdef USE_TBM_BUFFER
88   tbm_bufmgr hTBMBufMgr;
89 #endif
90
91 };
92
93 struct _GstMMBufferPoolClass
94 {
95   GstVideoBufferPoolClass parent_class;
96 };
97
98 GstBufferPool *
99 gst_mm_buffer_pool_new (GstElement * element );
100
101 GType gst_mm_buffer_pool_get_type (void);
102
103 int new_calc_plane(int width, int height);
104 int gst_calculate_y_size(int width, int height);
105 int gst_calculate_uv_size(int width, int height);
106
107 #ifdef USE_TBM_BUFFER
108
109 /*MFC Buffer alignment macros*/
110 #define S5P_FIMV_DEC_BUF_ALIGN                  (8 * 1024)
111 #define S5P_FIMV_ENC_BUF_ALIGN                  (8 * 1024)
112 #define S5P_FIMV_NV12M_HALIGN                   16
113 #define S5P_FIMV_NV12M_LVALIGN                  16
114 #define S5P_FIMV_NV12M_CVALIGN                  8
115 #define S5P_FIMV_NV12MT_HALIGN                  128
116 #define S5P_FIMV_NV12MT_VALIGN                  64
117 #define S5P_FIMV_NV12M_SALIGN                   2048
118 #define S5P_FIMV_NV12MT_SALIGN                  8192
119
120 #define ALIGN(x, a)       (((x) + (a) - 1) & ~((a) - 1))
121
122 /* Buffer alignment defines */
123 #define SZ_1M                                   0x00100000
124 #define S5P_FIMV_D_ALIGN_PLANE_SIZE             64
125
126 #define S5P_FIMV_MAX_FRAME_SIZE                 (2 * SZ_1M)
127 #define S5P_FIMV_NUM_PIXELS_IN_MB_ROW           16
128 #define S5P_FIMV_NUM_PIXELS_IN_MB_COL           16
129
130 /* Macro */
131 #define ALIGN_TO_4KB(x)   ((((x) + (1 << 12) - 1) >> 12) << 12)
132 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
133 #define CHOOSE_MAX_SIZE(a,b) ((a) > (b) ? (a) : (b))
134
135 #endif
136
137 #if 0
138
139 static GQuark gst_tbm_buffer_data_quark = 0;
140
141
142 typedef struct _GstTBMBuffer GstTBMBuffer;
143 struct _GstTBMBuffer
144 {
145     GstBuffer *buffer;
146     void *mmBuffer;
147 };
148
149 #define GST_TBM_BUFFER_POOL(pool) ((GstTBMBufferPool *) pool)
150 typedef struct _GstTBMBufferPool GstTBMBufferPool;
151 typedef struct _GstTBMBufferPoolClass GstTBMBufferPoolClass;
152
153 struct _GstTBMBufferPool
154 {
155   GstVideoBufferPool parent;
156
157   GstElement *element;
158
159   GstCaps *caps;
160   gboolean add_videometa;
161   GstVideoInfo video_info;
162
163   /* Owned by element, element has to stop this pool before
164    * it destroys component or port */
165   GstElement *component;
166
167   GstAllocator *allocator;
168
169   /* Set from outside this pool */
170   /* TRUE if we're currently allocating all our buffers */
171   gboolean allocating;
172
173   /* TRUE if the pool is not used anymore */
174   gboolean deactivated;
175
176   /* For populating the pool from another one */
177   GstBufferPool *other_pool;
178   GPtrArray *buffers;
179
180   /* Used during acquire for output buffer to
181    * specify which buffer has to be retrieved
182    * and during alloc, which buffer has to be
183    * wrapped
184    */
185   gint current_buffer_index;
186 };
187
188 struct _GstTBMBufferPoolClass
189 {
190   GstVideoBufferPoolClass parent_class;
191 };
192
193 GType gst_tbm_buffer_pool_get_type (void);
194
195 G_DEFINE_TYPE (GstTBMBufferPool, gst_tbm_buffer_pool, GST_TYPE_BUFFER_POOL);
196
197 static gboolean
198 gst_tbm_buffer_pool_start (GstBufferPool * bpool)
199 {
200   GstTBMBufferPool *pool = GST_TBM_BUFFER_POOL (bpool);
201
202   /* Only allow to start the pool if we still are attached
203    * to a component and port */
204   GST_OBJECT_LOCK (pool);
205   if (!pool->component ) {
206     GST_OBJECT_UNLOCK (pool);
207     return FALSE;
208   }
209   GST_OBJECT_UNLOCK (pool);
210
211   return
212       GST_BUFFER_POOL_CLASS (gst_tbm_buffer_pool_parent_class)->start (bpool);
213 }
214
215 static gboolean
216 gst_tbm_buffer_pool_stop (GstBufferPool * bpool)
217 {
218   GstTBMBufferPool *pool = GST_TBM_BUFFER_POOL (bpool);
219
220   /* Remove any buffers that are there */
221   g_ptr_array_set_size (pool->buffers, 0);
222
223   if (pool->caps)
224     gst_caps_unref (pool->caps);
225   pool->caps = NULL;
226
227   pool->add_videometa = FALSE;
228
229   return GST_BUFFER_POOL_CLASS (gst_tbm_buffer_pool_parent_class)->stop (bpool);
230 }
231
232 static const gchar **
233 gst_tbm_buffer_pool_get_options (GstBufferPool * bpool)
234 {
235   static const gchar *raw_video_options[] =
236       { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL };
237   static const gchar *options[] = { NULL };
238   GstTBMBufferPool *pool = GST_TBM_BUFFER_POOL (bpool);
239
240   return options;
241 }
242
243 static gboolean
244 gst_tbm_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
245 {
246   GstTBMBufferPool *pool = GST_TBM_BUFFER_POOL (bpool);
247   GstCaps *caps;
248
249   GST_OBJECT_LOCK (pool);
250
251   if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
252     goto wrong_config;
253
254   if (caps == NULL)
255     goto no_caps;
256
257   if (pool->caps)
258     gst_caps_unref (pool->caps);
259   pool->caps = gst_caps_ref (caps);
260
261   GST_OBJECT_UNLOCK (pool);
262
263   return GST_BUFFER_POOL_CLASS (gst_tbm_buffer_pool_parent_class)->set_config
264       (bpool, config);
265
266   /* ERRORS */
267 wrong_config:
268   {
269     GST_OBJECT_UNLOCK (pool);
270     GST_WARNING_OBJECT (pool, "invalid config");
271     return FALSE;
272   }
273 no_caps:
274   {
275     GST_OBJECT_UNLOCK (pool);
276     GST_WARNING_OBJECT (pool, "no caps in config");
277     return FALSE;
278   }
279 wrong_video_caps:
280   {
281     GST_OBJECT_UNLOCK (pool);
282     GST_WARNING_OBJECT (pool,
283         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
284     return FALSE;
285   }
286 }
287
288 static GstFlowReturn
289 gst_tbm_buffer_pool_alloc_buffer (GstBufferPool * bpool,
290     GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
291 {
292   GstTBMBufferPool *pool = GST_TBM_BUFFER_POOL (bpool);
293   GstBuffer *buf;
294   GstTBMBuffer *tbm_buf;
295   GstMemory *mem;
296
297   g_return_val_if_fail (pool->allocating, GST_FLOW_ERROR);
298
299   tbm_buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index);
300   g_return_val_if_fail (tbm_buf != NULL, GST_FLOW_ERROR);
301
302     mem = gst_tbm_memory_allocator_alloc (pool->allocator, 0, tbm_buf);
303     buf = gst_buffer_new ();
304     gst_buffer_append_memory (buf, mem);
305     g_ptr_array_add (pool->buffers, buf);
306
307   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
308       gst_tbm_buffer_data_quark, tbm_buf, NULL);
309
310   *buffer = buf;
311
312   pool->current_buffer_index++;
313
314   return GST_FLOW_OK;
315 }
316
317 static void
318 gst_tbm_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
319 {
320   GstTBMBufferPool *pool = GST_TBM_BUFFER_POOL (bpool);
321
322   /* If the buffers belong to another pool, restore them now */
323   GST_OBJECT_LOCK (pool);
324   if (pool->other_pool) {
325     gst_object_replace ((GstObject **) & buffer->pool,
326         (GstObject *) pool->other_pool);
327   }
328   GST_OBJECT_UNLOCK (pool);
329
330   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer),
331       gst_tbm_buffer_data_quark, NULL, NULL);
332
333   GST_BUFFER_POOL_CLASS (gst_tbm_buffer_pool_parent_class)->free_buffer (bpool,
334       buffer);
335 }
336
337 static GstFlowReturn
338 gst_tbm_buffer_pool_acquire_buffer (GstBufferPool * bpool,
339     GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
340 {
341   GstFlowReturn ret;
342   GstTBMBufferPool *pool = GST_TBM_BUFFER_POOL (bpool);
343
344   if (pool->port->port_def.eDir == OMX_DirOutput) {
345     GstBuffer *buf;
346
347     g_return_val_if_fail (pool->current_buffer_index != -1, GST_FLOW_ERROR);
348
349     buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index);
350     g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
351     *buffer = buf;
352     ret = GST_FLOW_OK;
353
354     /* If it's our own memory we have to set the sizes */
355     if (!pool->other_pool) {
356       GstMemory *mem = gst_buffer_peek_memory (*buffer, 0);
357
358       g_assert (mem
359           && g_strcmp0 (mem->allocator->mem_type, GST_OMX_MEMORY_TYPE) == 0);
360       mem->size = ((GstOMXMemory *) mem)->buf->omx_buf->nFilledLen;
361       mem->offset = ((GstOMXMemory *) mem)->buf->omx_buf->nOffset;
362     }
363   } else {
364     /* Acquire any buffer that is available to be filled by upstream */
365     ret =
366         GST_BUFFER_POOL_CLASS (gst_tbm_buffer_pool_parent_class)->acquire_buffer
367         (bpool, buffer, params);
368   }
369
370   return ret;
371 }
372
373 static void
374 gst_tbm_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
375 {
376   GstTBMBufferPool *pool = GST_TBM_BUFFER_POOL (bpool);
377   OMX_ERRORTYPE err;
378   GstOMXBuffer *omx_buf;
379
380   g_assert (pool->component && pool->port);
381
382   if (!pool->allocating && !pool->deactivated) {
383     omx_buf =
384         gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer),
385         gst_omx_buffer_data_quark);
386     if (pool->port->port_def.eDir == OMX_DirOutput && !omx_buf->used) {
387       /* Release back to the port, can be filled again */
388       err = gst_omx_port_release_buffer (pool->port, omx_buf);
389       if (err != OMX_ErrorNone) {
390         GST_ELEMENT_ERROR (pool->element, LIBRARY, SETTINGS, (NULL),
391             ("Failed to relase output buffer to component: %s (0x%08x)",
392                 gst_omx_error_to_string (err), err));
393       }
394     } else if (!omx_buf->used) {
395       /* TODO: Implement.
396        *
397        * If not used (i.e. was not passed to the component) this should do
398        * the same as EmptyBufferDone.
399        * If it is used (i.e. was passed to the component) this should do
400        * nothing until EmptyBufferDone.
401        *
402        * EmptyBufferDone should release the buffer to the pool so it can
403        * be allocated again
404        *
405        * Needs something to call back here in EmptyBufferDone, like keeping
406        * a ref on the buffer in GstOMXBuffer until EmptyBufferDone... which
407        * would ensure that the buffer is always unused when this is called.
408        */
409       g_assert_not_reached ();
410       GST_BUFFER_POOL_CLASS (gst_tbm_buffer_pool_parent_class)->release_buffer
411           (bpool, buffer);
412     }
413   }
414 }
415
416 static void
417 gst_tbm_buffer_pool_finalize (GObject * object)
418 {
419   GstTBMBufferPool *pool = GST_TBM_BUFFER_POOL (object);
420
421   if (pool->element)
422     gst_object_unref (pool->element);
423   pool->element = NULL;
424
425   if (pool->buffers)
426     g_ptr_array_unref (pool->buffers);
427   pool->buffers = NULL;
428
429   if (pool->other_pool)
430     gst_object_unref (pool->other_pool);
431   pool->other_pool = NULL;
432
433   if (pool->allocator)
434     gst_object_unref (pool->allocator);
435   pool->allocator = NULL;
436
437   if (pool->caps)
438     gst_caps_unref (pool->caps);
439   pool->caps = NULL;
440
441   G_OBJECT_CLASS (gst_tbm_buffer_pool_parent_class)->finalize (object);
442 }
443
444 static void
445 gst_tbm_buffer_pool_class_init (GstTBMBufferPoolClass * klass)
446 {
447   GObjectClass *gobject_class = (GObjectClass *) klass;
448   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
449
450   gst_omx_buffer_data_quark = g_quark_from_static_string ("GstOMXBufferData");
451
452   gobject_class->finalize = gst_tbm_buffer_pool_finalize;
453   gstbufferpool_class->start = gst_tbm_buffer_pool_start;
454   gstbufferpool_class->stop = gst_tbm_buffer_pool_stop;
455   gstbufferpool_class->get_options = gst_tbm_buffer_pool_get_options;
456   gstbufferpool_class->set_config = gst_tbm_buffer_pool_set_config;
457   gstbufferpool_class->alloc_buffer = gst_tbm_buffer_pool_alloc_buffer;
458   gstbufferpool_class->free_buffer = gst_tbm_buffer_pool_free_buffer;
459   gstbufferpool_class->acquire_buffer = gst_tbm_buffer_pool_acquire_buffer;
460   gstbufferpool_class->release_buffer = gst_tbm_buffer_pool_release_buffer;
461 }
462
463 static void
464 gst_tbm_buffer_pool_init (GstTBMBufferPool * pool)
465 {
466   pool->buffers = g_ptr_array_new ();
467   pool->allocator = g_object_new (gst_omx_memory_allocator_get_type (), NULL);
468 }
469
470 static GstBufferPool *
471 gst_tbm_buffer_pool_new (GstElement * element, GstOMXComponent * component,
472     GstOMXPort * port)
473 {
474   GstTBMBufferPool *pool;
475
476   pool = g_object_new (gst_tbm_buffer_pool_get_type (), NULL);
477   pool->element = gst_object_ref (element);
478   pool->component = component;
479   pool->port = port;
480
481   return GST_BUFFER_POOL (pool);
482 }
483
484
485 #endif