1 /* GStreamer Wayland video sink
3 * Copyright (C) 2012 Intel Corporation
4 * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
5 * Copyright (C) 2014 Collabora Ltd.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
23 #include "wlshmallocator.h"
24 #include "wlvideoformat.h"
25 #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
26 #include "tizen-wlvideoformat.h"
27 #include <tbm_surface_internal.h>
35 #include <sys/types.h>
37 GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
38 #define GST_CAT_DEFAULT gstwayland_debug
40 G_DEFINE_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST_TYPE_ALLOCATOR);
43 gst_wl_fwrite_data (gchar * file, gpointer data, guint size)
47 fp = fopen (file, "wb");
51 fwrite ((gchar *) data, sizeof (gchar), size, fp);
58 gst_wl_tbm_dump_normal_raw_video (gpointer bo, guint size, guint dump_count,
61 tbm_bo_handle virtual_addr;
65 g_return_if_fail (bo != NULL);
67 virtual_addr = tbm_bo_get_handle (bo, TBM_DEVICE_CPU);
68 if (!virtual_addr.ptr) {
69 strerror_r (errno, err_str, sizeof (err_str));
70 GST_ERROR ("get tbm bo handle failed: %s(%d)", err_str, errno);
74 snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump",
76 ret = gst_wl_fwrite_data (file_name, virtual_addr.ptr, size);
78 GST_ERROR ("_write_rawdata() failed");
84 gst_wl_tbm_dump_native_raw_video (GstWlDisplay * display, guint dump_count)
89 tbm_bo_handle virtual_addr;
92 g_return_if_fail (display != NULL);
94 if (dump_count > display->total_dump) {
95 display->dump_video = FALSE;
98 /* get virtual addr with bo and TBM_DEVICD_CPU */
99 virtual_addr = tbm_bo_get_handle (display->bo[0], TBM_DEVICE_CPU);
100 if (!virtual_addr.ptr) {
101 strerror_r (errno, err_str, sizeof (err_str));
102 GST_ERROR ("get tbm bo handle failed: %s(%d)", err_str, errno);
106 snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump",
109 fp = fopen (file_name, "wb");
112 data = (gchar *) virtual_addr.ptr;
115 for (i = 0; i < display->height[0]; i++) {
116 fwrite (data, display->width[0], 1, fp);
117 data += display->stride_width[0];
120 if (display->bo[1] == NULL) {
122 data = (gchar *) virtual_addr.ptr +
123 (display->stride_width[0] * display->stride_height[0]);
124 GST_LOG ("UV: virtual_addr.ptr(%p)", data);
127 virtual_addr = tbm_bo_get_handle (display->bo[1], TBM_DEVICE_CPU);
128 if (!virtual_addr.ptr) {
129 strerror_r (errno, err_str, sizeof (err_str));
130 GST_ERROR ("get tbm bo handle failed: %s(%d)", err_str, errno);
134 data = (gchar *) virtual_addr.ptr;
138 for (i = 0; i < display->height[1]; i++) {
139 fwrite (data, display->width[1], 1, fp);
140 data += display->stride_width[1];
147 gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size,
148 GstAllocationParams * params)
150 GstWlShmAllocator *self = GST_WL_SHM_ALLOCATOR (allocator);
160 #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
161 if (self->display->USE_TBM) {
162 tbm_bo_handle virtual_addr;
164 idx = self->display->tbm_bo_idx++;
166 self->display->tbm_bufmgr =
167 wayland_tbm_client_get_bufmgr (self->display->tbm_client);
168 g_return_val_if_fail (self->display->tbm_bufmgr != NULL, NULL);
170 self->display->tbm_bo[idx] =
171 tbm_bo_alloc (self->display->tbm_bufmgr, size, TBM_BO_DEFAULT);
172 if (G_UNLIKELY (!self->display->tbm_bo[idx])) {
173 strerror_r (errno, err_str, sizeof (err_str));
174 GST_ERROR_OBJECT (self, "alloc tbm bo(size:%d) failed: %s(%d)", size,
178 GST_LOG ("display->tbm_bo[%d]=(%p)", idx, self->display->tbm_bo[idx]);
179 virtual_addr.ptr = NULL;
181 tbm_bo_get_handle (self->display->tbm_bo[idx], TBM_DEVICE_CPU);
182 if (G_UNLIKELY (!virtual_addr.ptr)) {
183 strerror_r (errno, err_str, sizeof (err_str));
184 GST_ERROR_OBJECT (self, "get tbm bo handle failed: %s(%d)", err_str,
186 tbm_bo_unref (self->display->tbm_bo[idx]);
187 self->display->tbm_bo[idx] = NULL;
188 self->display->tbm_bo_idx--;
192 mem = g_slice_new0 (GstWlShmMemory);
193 gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator,
194 NULL, size, 0, 0, size);
195 mem->data = virtual_addr.ptr;
196 mem->tbm_bo_ptr = self->display->tbm_bo[idx];
197 GST_LOG ("mem(%p) mem->data(%p) virtual_addr.ptr(%p) size(%d)", mem,
198 mem->data, virtual_addr.ptr, size);
200 return (GstMemory *) mem;
202 } else { /* USE SHM */
203 /* TODO: make use of the allocation params, if necessary */
205 /* allocate shm pool */
206 snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
207 "wayland-shm", init++, "XXXXXX");
208 GST_LOG ("opening temp file %s", filename);
210 fd = g_mkstemp (filename);
212 GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename,
216 if (ftruncate (fd, size) < 0) {
217 GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno));
222 data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
223 if (data == MAP_FAILED) {
224 GST_ERROR_OBJECT (self, "mmap failed: %s", strerror (errno));
231 mem = g_slice_new0 (GstWlShmMemory);
232 gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator,
233 NULL, size, 0, 0, size);
237 return (GstMemory *) mem;
240 #else /* open source */
241 /* TODO: make use of the allocation params, if necessary */
243 /* allocate shm pool */
244 snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
245 "wayland-shm", init++, "XXXXXX");
247 fd = g_mkstemp (filename);
249 GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename,
253 if (ftruncate (fd, size) < 0) {
254 GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno));
259 data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
260 if (data == MAP_FAILED) {
261 GST_ERROR_OBJECT (self, "mmap failed: %s", strerror (errno));
268 mem = g_slice_new0 (GstWlShmMemory);
269 gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL,
274 return (GstMemory *) mem;
279 gst_wl_shm_allocator_free (GstAllocator * allocator, GstMemory * memory)
281 GstWlShmMemory *shm_mem = (GstWlShmMemory *) memory;
283 GST_LOG ("shm_mem->fd(%d)", shm_mem->fd);
284 if (shm_mem->fd != -1)
286 munmap (shm_mem->data, memory->maxsize);
288 g_slice_free (GstWlShmMemory, shm_mem);
292 gst_wl_shm_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
295 return ((GstWlShmMemory *) mem)->data;
299 gst_wl_shm_mem_unmap (GstMemory * mem)
304 gst_wl_shm_allocator_class_init (GstWlShmAllocatorClass * klass)
306 GstAllocatorClass *alloc_class = (GstAllocatorClass *) klass;
309 alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_alloc);
310 alloc_class->free = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_free);
314 gst_wl_shm_allocator_init (GstWlShmAllocator * self)
317 self->parent_instance.mem_type = GST_ALLOCATOR_WL_SHM;
318 self->parent_instance.mem_map = gst_wl_shm_mem_map;
319 self->parent_instance.mem_unmap = gst_wl_shm_mem_unmap;
321 GST_OBJECT_FLAG_SET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
325 gst_wl_shm_allocator_register (void)
328 gst_allocator_register (GST_ALLOCATOR_WL_SHM,
329 g_object_new (GST_TYPE_WL_SHM_ALLOCATOR, NULL));
333 gst_wl_shm_allocator_get (void)
336 return gst_allocator_find (GST_ALLOCATOR_WL_SHM);
340 gst_is_wl_shm_memory (GstMemory * mem)
343 return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM);
347 gst_is_wl_memory (GstMemory * mem)
350 return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM);
354 gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
355 const GstVideoInfo * info)
357 GstWlShmMemory *shm_mem = (GstWlShmMemory *) mem;
358 gint width, height, stride, offset;
360 enum wl_shm_format format;
361 struct wl_shm_pool *wl_pool;
362 struct wl_buffer *wbuffer;
365 #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
366 if (display->USE_TBM) {
367 tbm_surface_info_s ts_info;
370 if (display->is_native_format == TRUE) {
371 /* In case of native format, use MMVideoBuffer data instead of GstVideoInfo */
372 if (display->dump_video)
373 gst_wl_tbm_dump_native_raw_video (display, display->dump_count++);
375 width = display->width[0];
376 height = display->height[0];
377 format = gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (info));
378 offset = display->stride_width[0] * display->stride_height[0];
379 ts_info.width = width;
380 ts_info.height = height;
381 ts_info.format = format;
382 ts_info.bpp = tbm_surface_internal_get_bpp (ts_info.format);
383 ts_info.num_planes = tbm_surface_internal_get_num_planes (ts_info.format);
384 ts_info.planes[0].size = display->plane_size[0];
385 ts_info.planes[1].size = display->plane_size[1];
386 ts_info.planes[0].stride = display->stride_width[0];
387 ts_info.planes[1].stride = display->stride_width[1];
388 ts_info.planes[0].offset = 0;
389 ts_info.planes[1].offset = (display->bo[1]) ? 0 : offset;
392 ("set tbm_surface_info_s: width(%d) height(%d) format(%s) bpp(%d) num_planes(%d)",
393 ts_info.width, ts_info.height, gst_wl_tbm_format_to_string (format),
394 ts_info.bpp, ts_info.num_planes);
396 ("set tbm_surface_info_s: planse[0].stride(%d) planes[1].stride(%d) planes[0].offset(%d) planes[1].offset(%d)",
397 ts_info.planes[0].stride, ts_info.planes[1].stride,
398 ts_info.planes[0].offset, ts_info.planes[1].offset);
400 num_bo = (display->bo[1]) ? 2 : 1;
401 GST_LOG ("num_bo(%d)", num_bo);
404 tbm_surface_internal_create_with_bos (&ts_info,
405 (tbm_bo *) display->bo, num_bo);
406 GST_LOG ("create tbm surface(%p)", display->tsurface);
408 wayland_tbm_client_create_buffer (display->tbm_client,
412 width = GST_VIDEO_INFO_WIDTH (info);
413 height = GST_VIDEO_INFO_HEIGHT (info);
414 stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
415 size = GST_VIDEO_INFO_SIZE (info);
417 format = gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (info));
418 g_return_val_if_fail (gst_is_wl_memory (mem), NULL);
419 g_return_val_if_fail (size <= mem->size, NULL);
420 g_return_val_if_fail (shm_mem->fd != -1, NULL);
422 GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
423 G_GSSIZE_FORMAT " (%d x %d, stride %d)", size, width, height, stride);
425 if (display->dump_video) {
426 gst_wl_tbm_dump_normal_raw_video (shm_mem->tbm_bo_ptr, size,
427 display->dump_count++, display->total_dump);
428 if (display->dump_count > display->total_dump)
429 display->dump_video = FALSE;
432 ts_info.width = width;
433 ts_info.height = height;
434 ts_info.format = format;
435 ts_info.bpp = tbm_surface_internal_get_bpp (ts_info.format);
436 ts_info.num_planes = tbm_surface_internal_get_num_planes (ts_info.format);
437 ts_info.planes[0].stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
438 ts_info.planes[1].stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 1);
439 ts_info.planes[2].stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 2);
440 ts_info.planes[0].offset = GST_VIDEO_INFO_PLANE_OFFSET (info, 0);
441 ts_info.planes[1].offset = GST_VIDEO_INFO_PLANE_OFFSET (info, 1);
442 ts_info.planes[2].offset = GST_VIDEO_INFO_PLANE_OFFSET (info, 2);
444 GST_LOG ("tbm_bo (%p)", shm_mem->tbm_bo_ptr);
447 tbm_surface_internal_create_with_bos (&ts_info,
448 (tbm_bo *) & shm_mem->tbm_bo_ptr, 1);
450 wayland_tbm_client_create_buffer (display->tbm_client,
453 GST_LOG ("create wbuffer(%p)", wbuffer);
455 } else { /* USE SHM */
456 width = GST_VIDEO_INFO_WIDTH (info);
457 height = GST_VIDEO_INFO_HEIGHT (info);
458 stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
459 size = GST_VIDEO_INFO_SIZE (info);
460 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info));
461 g_return_val_if_fail (gst_is_wl_memory (mem), NULL);
462 g_return_val_if_fail (size <= mem->size, NULL);
463 g_return_val_if_fail (shm_mem->fd != -1, NULL);
465 GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
466 G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height,
467 stride, gst_wl_shm_format_to_string (format));
469 wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size);
471 wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride, format);
473 wl_shm_pool_destroy (wl_pool);
475 display->buffer_width = width;
476 display->buffer_height = height;
477 GST_LOG ("buffer_width(%d) buffer_height(%d)", display->buffer_width,
478 display->buffer_height);
481 #else /* open source */
482 width = GST_VIDEO_INFO_WIDTH (info);
483 height = GST_VIDEO_INFO_HEIGHT (info);
484 stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
485 size = GST_VIDEO_INFO_SIZE (info);
486 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info));
487 g_return_val_if_fail (gst_is_wl_shm_memory (mem), NULL);
488 g_return_val_if_fail (size <= mem->size, NULL);
489 g_return_val_if_fail (shm_mem->fd != -1, NULL);
491 GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
492 G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height,
493 stride, gst_wl_shm_format_to_string (format));
495 wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size);
496 wbuffer = wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride,
501 wl_shm_pool_destroy (wl_pool);