2 * Copyright (C) 2012 Intel Corporation
3 * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
4 * Copyright (C) 2014 Collabora Ltd.
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.
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.
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., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
26 #include "waylandpool.h"
27 #include "wldisplay.h"
28 #include "wlvideoformat.h"
36 #include <sys/types.h>
37 #ifdef GST_WLSINK_ENHANCEMENT
41 int _write_rawdata (const char *file, const void *data, unsigned int size);
45 GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
46 #define GST_CAT_DEFAULT gstwayland_debug
50 gst_wl_meta_api_get_type (void)
52 static volatile GType type;
53 static const gchar *tags[] =
54 { "memory", "size", "colorspace", "orientation", NULL };
56 if (g_once_init_enter (&type)) {
57 GType _type = gst_meta_api_type_register ("GstWlMetaAPI", tags);
58 g_once_init_leave (&type, _type);
64 gst_wl_meta_free (GstWlMeta * meta, GstBuffer * buffer)
66 GST_DEBUG ("destroying wl_buffer %p", meta->wbuffer);
67 wl_buffer_destroy (meta->wbuffer);
71 gst_wl_meta_get_info (void)
73 static const GstMetaInfo *wl_meta_info = NULL;
75 if (g_once_init_enter (&wl_meta_info)) {
76 const GstMetaInfo *meta =
77 gst_meta_register (GST_WL_META_API_TYPE, "GstWlMeta",
78 sizeof (GstWlMeta), (GstMetaInitFunction) NULL,
79 (GstMetaFreeFunction) gst_wl_meta_free,
80 (GstMetaTransformFunction) NULL);
81 g_once_init_leave (&wl_meta_info, meta);
87 static void gst_wayland_buffer_pool_finalize (GObject * object);
88 static gboolean gst_wayland_buffer_pool_set_config (GstBufferPool * pool,
89 GstStructure * config);
90 static gboolean gst_wayland_buffer_pool_start (GstBufferPool * pool);
91 static gboolean gst_wayland_buffer_pool_stop (GstBufferPool * pool);
92 static GstFlowReturn gst_wayland_buffer_pool_alloc (GstBufferPool * pool,
93 GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
95 #ifdef GST_WLSINK_ENHANCEMENT
97 static void gst_wayland_tizen_buffer_pool_finalize (GObject * object);
98 static gboolean gst_wayland_tizen_buffer_pool_start (GstBufferPool * pool);
99 static gboolean gst_wayland_tizen_buffer_pool_stop (GstBufferPool * pool);
100 static GstFlowReturn gst_wayland_tizen_buffer_pool_alloc (GstBufferPool * pool,
101 GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
102 static void tizen_buffer_release (void *data, struct wl_buffer *wl_buffer);
105 #define gst_wayland_buffer_pool_parent_class parent_class
106 G_DEFINE_TYPE (GstWaylandBufferPool, gst_wayland_buffer_pool,
107 GST_TYPE_BUFFER_POOL);
110 gst_wayland_buffer_pool_class_init (GstWaylandBufferPoolClass * klass)
114 GObjectClass *gobject_class = (GObjectClass *) klass;
115 GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
117 gstbufferpool_class->set_config = gst_wayland_buffer_pool_set_config;
118 #ifdef GST_WLSINK_ENHANCEMENT
119 gobject_class->finalize = gst_wayland_tizen_buffer_pool_finalize;
120 gstbufferpool_class->start = gst_wayland_tizen_buffer_pool_start;
121 gstbufferpool_class->stop = gst_wayland_tizen_buffer_pool_stop;
122 gstbufferpool_class->alloc_buffer = gst_wayland_tizen_buffer_pool_alloc;
124 gobject_class->finalize = gst_wayland_buffer_pool_finalize;
125 gstbufferpool_class->start = gst_wayland_buffer_pool_start;
126 gstbufferpool_class->stop = gst_wayland_buffer_pool_stop;
127 gstbufferpool_class->alloc_buffer = gst_wayland_buffer_pool_alloc;
132 gst_wayland_buffer_pool_init (GstWaylandBufferPool * self)
136 gst_video_info_init (&self->info);
137 g_mutex_init (&self->buffers_map_mutex);
138 self->buffers_map = g_hash_table_new (g_direct_hash, g_direct_equal);
142 gst_wayland_buffer_pool_finalize (GObject * object)
146 GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object);
149 gst_wayland_buffer_pool_stop (GST_BUFFER_POOL (pool));
151 g_mutex_clear (&pool->buffers_map_mutex);
152 g_hash_table_unref (pool->buffers_map);
154 g_object_unref (pool->display);
156 G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object);
160 buffer_release (void *data, struct wl_buffer *wl_buffer)
164 GstWaylandBufferPool *self = data;
168 g_mutex_lock (&self->buffers_map_mutex);
169 buffer = g_hash_table_lookup (self->buffers_map, wl_buffer);
171 GST_LOG_OBJECT (self, "wl_buffer::release (GstBuffer: %p)", buffer);
174 meta = gst_buffer_get_wl_meta (buffer);
175 if (meta->used_by_compositor) {
176 meta->used_by_compositor = FALSE;
177 /* unlock before unref because stop() may be called from here */
178 g_mutex_unlock (&self->buffers_map_mutex);
179 gst_buffer_unref (buffer);
183 g_mutex_unlock (&self->buffers_map_mutex);
186 static const struct wl_buffer_listener buffer_listener = {
191 gst_wayland_compositor_acquire_buffer (GstWaylandBufferPool * self,
198 meta = gst_buffer_get_wl_meta (buffer);
199 g_return_if_fail (meta != NULL);
200 g_return_if_fail (meta->pool == self);
201 g_return_if_fail (meta->used_by_compositor == FALSE);
203 meta->used_by_compositor = TRUE;
204 gst_buffer_ref (buffer);
208 unref_used_buffers (gpointer key, gpointer value, gpointer data)
212 GstBuffer *buffer = value;
213 GstWlMeta *meta = gst_buffer_get_wl_meta (buffer);
214 GList **to_unref = data;
216 g_return_if_fail (meta != NULL);
218 if (meta->used_by_compositor) {
219 meta->used_by_compositor = FALSE;
220 *to_unref = g_list_prepend (*to_unref, buffer);
225 gst_wayland_compositor_release_all_buffers (GstWaylandBufferPool * self)
229 GList *to_unref = NULL;
231 g_mutex_lock (&self->buffers_map_mutex);
232 g_hash_table_foreach (self->buffers_map, unref_used_buffers, &to_unref);
233 g_mutex_unlock (&self->buffers_map_mutex);
235 /* unref without the lock because stop() may be called from here */
237 g_list_free_full (to_unref, (GDestroyNotify) gst_buffer_unref);
242 gst_wayland_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
246 GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
249 if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
255 /* now parse the caps from the config */
256 if (!gst_video_info_from_caps (&self->info, caps))
259 GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT,
260 GST_VIDEO_INFO_WIDTH (&self->info), GST_VIDEO_INFO_HEIGHT (&self->info),
263 /*Fixme: Enable metadata checking handling based on the config of pool */
265 return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
269 GST_WARNING_OBJECT (pool, "invalid config");
274 GST_WARNING_OBJECT (pool, "no caps in config");
279 GST_WARNING_OBJECT (pool,
280 "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
286 gst_wayland_buffer_pool_start (GstBufferPool * pool)
290 GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
292 GST_DEBUG_OBJECT (self, "Initializing wayland buffer pool");
299 GST_DEBUG_OBJECT (self, "Initializing wayland buffer pool");
302 size = GST_VIDEO_INFO_SIZE (&self->info) * 15;
304 /* allocate shm pool */
305 snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
306 "wayland-shm", init++, "XXXXXX");
308 fd = mkstemp (filename);
310 GST_ERROR_OBJECT (pool, "opening temp file %s failed: %s", filename,
314 if (ftruncate (fd, size) < 0) {
315 GST_ERROR_OBJECT (pool, "ftruncate failed: %s", strerror (errno));
320 self->data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
321 if (self->data == MAP_FAILED) {
322 GST_ERROR_OBJECT (pool, "mmap failed: %s", strerror (errno));
327 self->wl_pool = wl_shm_create_pool (self->display->shm, fd, size);
335 return GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
339 gst_wayland_buffer_pool_stop (GstBufferPool * pool)
343 GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
345 GST_DEBUG_OBJECT (self, "Stopping wayland buffer pool");
347 munmap (self->data, self->size);
348 wl_shm_pool_destroy (self->wl_pool);
350 self->wl_pool = NULL;
354 /* all buffers are about to be destroyed;
355 * we should no longer do anything with them */
356 g_mutex_lock (&self->buffers_map_mutex);
357 g_hash_table_remove_all (self->buffers_map);
358 g_mutex_unlock (&self->buffers_map_mutex);
360 return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
364 gst_wayland_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
365 GstBufferPoolAcquireParams * params)
369 GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
371 gint width, height, stride;
373 enum wl_shm_format format;
378 width = GST_VIDEO_INFO_WIDTH (&self->info);
379 height = GST_VIDEO_INFO_HEIGHT (&self->info);
380 stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 0);
381 size = GST_VIDEO_INFO_SIZE (&self->info);
383 gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT (&self->info));
385 GST_DEBUG_OBJECT (self, "Allocating buffer of size %" G_GSSIZE_FORMAT
386 " (%d x %d, stride %d), format %s", size, width, height, stride,
387 gst_wayland_format_to_string (format));
388 /* try to reserve another memory block from the shm pool */
389 if (self->used + size > self->size)
395 data = ((gchar *) self->data) + offset;
397 /* create buffer and its metadata object */
398 *buffer = gst_buffer_new ();
399 meta = (GstWlMeta *) gst_buffer_add_meta (*buffer, GST_WL_META_INFO, NULL);
402 meta->wbuffer = wl_shm_pool_create_buffer (self->wl_pool, offset,
403 width, height, stride, format);
404 meta->used_by_compositor = FALSE;
406 /* configure listening to wl_buffer.release */
407 g_mutex_lock (&self->buffers_map_mutex);
408 g_hash_table_insert (self->buffers_map, meta->wbuffer, *buffer);
409 g_mutex_unlock (&self->buffers_map_mutex);
411 wl_buffer_add_listener (meta->wbuffer, &buffer_listener, self);
413 /* add the allocated memory on the GstBuffer */
414 gst_buffer_append_memory (*buffer,
415 gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
416 size, 0, size, NULL, NULL));
423 GST_WARNING_OBJECT (pool, "can't create buffer");
424 return GST_FLOW_ERROR;
429 gst_wayland_buffer_pool_new (GstWlDisplay * display)
433 GstWaylandBufferPool *pool;
435 g_return_val_if_fail (GST_IS_WL_DISPLAY (display), NULL);
436 pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL);
437 pool->display = g_object_ref (display);
439 return GST_BUFFER_POOL_CAST (pool);
442 #ifdef GST_WLSINK_ENHANCEMENT
445 gst_wayland_tizen_buffer_pool_start (GstBufferPool * pool)
449 GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
451 GST_DEBUG_OBJECT (self, "Initializing tizen buffer pool");
453 tbm_bo_handle vitual_addr;
456 if (self->display->is_special_format == TRUE) {
457 /*in case of SN12 or ST12 video format */
458 size = self->display->native_video_size * 15;
459 vitual_addr.ptr = NULL;
462 /*in case of normal video format */
463 size = GST_VIDEO_INFO_SIZE (&self->info) * 15;
465 self->display->tbm_bufmgr = tbm_bufmgr_init (self->display->drm_fd);
466 g_return_if_fail (self->display->tbm_bufmgr != NULL);
468 self->display->tbm_bo =
469 tbm_bo_alloc (self->display->tbm_bufmgr, size, TBM_BO_DEFAULT);
470 if (!self->display->tbm_bo) {
471 GST_ERROR_OBJECT (pool, "alloc tbm bo(size:%d) failed: %s", size,
473 tbm_bufmgr_deinit (self->display->tbm_bufmgr);
474 self->display->tbm_bufmgr = NULL;
478 vitual_addr = tbm_bo_get_handle (self->display->tbm_bo, TBM_DEVICE_CPU);
479 if (!vitual_addr.ptr) {
480 GST_ERROR_OBJECT (pool, "get tbm bo handle failed: %s", strerror (errno));
481 tbm_bo_unref (self->display->tbm_bo);
482 tbm_bufmgr_deinit (self->display->tbm_bufmgr);
483 self->display->tbm_bo = NULL;
484 self->display->tbm_bufmgr = NULL;
489 self->data = vitual_addr.ptr;
493 return GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
497 gst_wayland_tizen_buffer_pool_stop (GstBufferPool * pool)
501 GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
503 GST_DEBUG_OBJECT (self, "Stopping tizen buffer pool");
508 /* all buffers are about to be destroyed;
509 * we should no longer do anything with them */
510 g_mutex_lock (&self->buffers_map_mutex);
511 g_hash_table_remove_all (self->buffers_map);
512 g_mutex_unlock (&self->buffers_map_mutex);
514 return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
518 gst_wayland_tizen_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
519 GstBufferPoolAcquireParams * params)
523 GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
527 enum tizen_buffer_pool_format format;
531 tbm_bo_handle vitual_addr;
533 if (self->display->is_special_format == TRUE) {
534 /*in case of SN12 or ST12 video format */
535 unsigned int name[NV_BUF_PLANE_NUM];
536 unsigned int offset[NV_BUF_PLANE_NUM] = { 0, };
537 unsigned int stride[NV_BUF_PLANE_NUM] = { 0, };
538 width = GST_VIDEO_INFO_WIDTH (&self->info);
539 height = GST_VIDEO_INFO_HEIGHT (&self->info);
540 size = self->display->native_video_size;
543 gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT
547 vitual_addr = tbm_bo_get_handle (self->display->bo[0], TBM_DEVICE_CPU);
548 if (!vitual_addr.ptr) {
549 GST_ERROR_OBJECT (pool, "get tbm bo handle failed: %s", strerror (errno));
552 self->data = vitual_addr.ptr;
553 data = ((gchar *) self->data);
558 sprintf (file_name, "/root/WLSINK_OUT_DUMP_%2.2d.dump", dump_cnt++);
559 ret = _write_rawdata (file_name, vitual_addr.ptr,size);
561 GST_ERROR_OBJECT (pool, "_write_rawdata() failed");
565 /* create buffer and its metadata object */
566 *buffer = gst_buffer_new ();
567 meta = (GstWlMeta *) gst_buffer_add_meta (*buffer, GST_WL_META_INFO, NULL);
569 GST_DEBUG ("TBM bo %p %p %p", self->display->bo[0],
570 self->display->bo[1], 0);
571 for (int i = 0; i < NV_BUF_PLANE_NUM; i++) {
572 if (self->display->bo[i] != NULL) {
573 name[i] = tbm_bo_export (self->display->bo[i]);
578 offset[i] = offset[i - 1] + self->display->plane_size[i - 1];
581 stride[i] = self->display->stride_width[i];
585 tizen_buffer_pool_create_planar_buffer (self->display->
586 tizen_buffer_pool, width, height, format, name[0], offset[0], stride[0],
587 name[1], offset[1], stride[1], 0, 0, 0);
588 meta->used_by_compositor = FALSE;
590 GST_DEBUG ("tizen_buffer_pool_create_planar_buffer create wl_buffer %p",
595 /*in case of normal video format */
596 width = GST_VIDEO_INFO_WIDTH (&self->info);
597 height = GST_VIDEO_INFO_HEIGHT (&self->info);
598 stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 0);
599 size = GST_VIDEO_INFO_SIZE (&self->info);
601 gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT
604 GST_DEBUG_OBJECT (self, "Allocating buffer of size %" G_GSSIZE_FORMAT
605 " (%d x %d, stride %d), format %s", size, width, height, stride,
606 gst_wayland_format_to_string (format));
608 /* try to reserve another memory block from the shm pool */
609 if (self->used + size > self->size)
612 data_offset = self->used;
615 data = ((gchar *) self->data) + data_offset;
617 /* create buffer and its metadata object */
618 *buffer = gst_buffer_new ();
619 meta = (GstWlMeta *) gst_buffer_add_meta (*buffer, GST_WL_META_INFO, NULL);
623 tizen_buffer_pool_create_buffer (self->display->tizen_buffer_pool,
624 tbm_bo_export (self->display->tbm_bo), width, height, stride, format);
625 meta->used_by_compositor = FALSE;
628 /* configure listening to wl_buffer.release */
629 g_mutex_lock (&self->buffers_map_mutex);
630 g_hash_table_insert (self->buffers_map, meta->wbuffer, *buffer);
631 g_mutex_unlock (&self->buffers_map_mutex);
633 wl_buffer_add_listener (meta->wbuffer, &buffer_listener, self);
635 /* add the allocated memory on the GstBuffer */
636 gst_buffer_append_memory (*buffer,
637 gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
638 size, 0, size, NULL, NULL));
644 GST_WARNING_OBJECT (pool, "can't create buffer");
645 return GST_FLOW_ERROR;
650 gst_wayland_tizen_buffer_pool_finalize (GObject * object)
654 GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object);
656 if (pool->display->tizen_buffer_pool) {
657 gst_wayland_tizen_buffer_pool_stop (GST_BUFFER_POOL (pool));
662 g_mutex_clear (&pool->buffers_map_mutex);
663 g_hash_table_unref (pool->buffers_map);
665 g_object_unref (pool->display);
667 G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object);
673 _write_rawdata (const char *file, const void *data, unsigned int size)
677 fp = fopen (file, "wb");
681 fwrite ((char *) data, sizeof (char), size, fp);