f1cbc45d2f97aa3b14abc3e4d230b759557d21e4
[platform/upstream/gstreamer.git] / ext / wayland / wlshmallocator.c
1 /* GStreamer Wayland video sink
2  *
3  * Copyright (C) 2012 Intel Corporation
4  * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
5  * Copyright (C) 2014 Collabora Ltd.
6  *
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.
11  *
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.
16  *
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.
21  */
22
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>
28 #endif
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #include <sys/mman.h>
35 #include <sys/types.h>
36
37 GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
38 #define GST_CAT_DEFAULT gstwayland_debug
39
40 G_DEFINE_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST_TYPE_ALLOCATOR);
41
42 gint
43 gst_wl_fwrite_data (gchar * file, gpointer data, guint size)
44 {
45   FILE *fp;
46
47   fp = fopen (file, "wb");
48   if (fp == NULL)
49     return -1;
50
51   fwrite ((gchar *) data, sizeof (gchar), size, fp);
52   fclose (fp);
53
54   return 0;
55 }
56
57 static void
58 gst_wl_tbm_dump_normal_raw_video (gpointer bo, guint size, guint dump_count,
59     guint dump_total)
60 {
61   tbm_bo_handle virtual_addr;
62   gint ret;
63   gchar file_name[128];
64   gchar err_str[256];
65   g_return_if_fail (bo != NULL);
66
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);
71     return;
72   }
73
74   snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump",
75       dump_count);
76   ret = gst_wl_fwrite_data (file_name, virtual_addr.ptr, size);
77   if (ret) {
78     GST_ERROR ("_write_rawdata() failed");
79   }
80
81 }
82
83 static void
84 gst_wl_tbm_dump_native_raw_video (GstWlDisplay * display, guint dump_count)
85 {
86   gchar file_name[128];
87   gchar err_str[256];
88   FILE *fp;
89   tbm_bo_handle virtual_addr;
90   gchar *data;
91   int i;
92   g_return_if_fail (display != NULL);
93
94   if (dump_count > display->total_dump) {
95     display->dump_video = FALSE;
96     return;
97   }
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);
103     return;
104   }
105
106   snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump",
107       dump_count);
108
109   fp = fopen (file_name, "wb");
110   if (fp == NULL)
111     return;
112   data = (gchar *) virtual_addr.ptr;
113
114   /* Y */
115   for (i = 0; i < display->height[0]; i++) {
116     fwrite (data, display->width[0], 1, fp);
117     data += display->stride_width[0];
118   }
119
120   if (display->bo[1] == NULL) {
121     /* sprd */
122     data = (gchar *) virtual_addr.ptr +
123         (display->stride_width[0] * display->stride_height[0]);
124     GST_LOG ("UV: virtual_addr.ptr(%p)", data);
125   } else {
126     /* omx */
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);
131       fclose (fp);
132       return;
133     }
134     data = (gchar *) virtual_addr.ptr;
135   }
136
137   /* UV */
138   for (i = 0; i < display->height[1]; i++) {
139     fwrite (data, display->width[1], 1, fp);
140     data += display->stride_width[1];
141   }
142
143   fclose (fp);
144 }
145
146 static GstMemory *
147 gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size,
148     GstAllocationParams * params)
149 {
150   GstWlShmAllocator *self = GST_WL_SHM_ALLOCATOR (allocator);
151   char filename[1024];
152   static int init = 0;
153   int fd;
154   int idx;
155   gpointer data;
156   GstWlShmMemory *mem;
157   gchar err_str[256];
158   FUNCTION;
159
160 #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
161   if (self->display->USE_TBM) {
162     tbm_bo_handle virtual_addr;
163
164     idx = self->display->tbm_bo_idx++;
165
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);
169
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,
175           err_str, errno);
176       return FALSE;
177     }
178     GST_LOG ("display->tbm_bo[%d]=(%p)", idx, self->display->tbm_bo[idx]);
179     virtual_addr.ptr = NULL;
180     virtual_addr =
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,
185           errno);
186       tbm_bo_unref (self->display->tbm_bo[idx]);
187       self->display->tbm_bo[idx] = NULL;
188       self->display->tbm_bo_idx--;
189       return FALSE;
190     }
191
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);
199
200     return (GstMemory *) mem;
201
202   } else {                      /* USE SHM */
203     /* TODO: make use of the allocation params, if necessary */
204
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);
209
210     fd = g_mkstemp (filename);
211     if (fd < 0) {
212       GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename,
213           strerror (errno));
214       return NULL;
215     }
216     if (ftruncate (fd, size) < 0) {
217       GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno));
218       close (fd);
219       return NULL;
220     }
221
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));
225       close (fd);
226       return NULL;
227     }
228
229     unlink (filename);
230
231     mem = g_slice_new0 (GstWlShmMemory);
232     gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator,
233         NULL, size, 0, 0, size);
234     mem->data = data;
235     mem->fd = fd;
236
237     return (GstMemory *) mem;
238   }
239
240 #else /* open source */
241   /* TODO: make use of the allocation params, if necessary */
242
243   /* allocate shm pool */
244   snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
245       "wayland-shm", init++, "XXXXXX");
246
247   fd = g_mkstemp (filename);
248   if (fd < 0) {
249     GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename,
250         strerror (errno));
251     return NULL;
252   }
253   if (ftruncate (fd, size) < 0) {
254     GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno));
255     close (fd);
256     return NULL;
257   }
258
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));
262     close (fd);
263     return NULL;
264   }
265
266   unlink (filename);
267
268   mem = g_slice_new0 (GstWlShmMemory);
269   gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL,
270       size, 0, 0, size);
271   mem->data = data;
272   mem->fd = fd;
273
274   return (GstMemory *) mem;
275 #endif
276 }
277
278 static void
279 gst_wl_shm_allocator_free (GstAllocator * allocator, GstMemory * memory)
280 {
281   GstWlShmMemory *shm_mem = (GstWlShmMemory *) memory;
282   FUNCTION;
283   GST_LOG ("shm_mem->fd(%d)", shm_mem->fd);
284   if (shm_mem->fd != -1)
285     close (shm_mem->fd);
286   munmap (shm_mem->data, memory->maxsize);
287
288   g_slice_free (GstWlShmMemory, shm_mem);
289 }
290
291 static gpointer
292 gst_wl_shm_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
293 {
294   FUNCTION;
295   return ((GstWlShmMemory *) mem)->data;
296 }
297
298 static void
299 gst_wl_shm_mem_unmap (GstMemory * mem)
300 {
301 }
302
303 static void
304 gst_wl_shm_allocator_class_init (GstWlShmAllocatorClass * klass)
305 {
306   GstAllocatorClass *alloc_class = (GstAllocatorClass *) klass;
307   FUNCTION;
308
309   alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_alloc);
310   alloc_class->free = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_free);
311 }
312
313 static void
314 gst_wl_shm_allocator_init (GstWlShmAllocator * self)
315 {
316   FUNCTION;
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;
320
321   GST_OBJECT_FLAG_SET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
322 }
323
324 void
325 gst_wl_shm_allocator_register (void)
326 {
327   FUNCTION;
328   gst_allocator_register (GST_ALLOCATOR_WL_SHM,
329       g_object_new (GST_TYPE_WL_SHM_ALLOCATOR, NULL));
330 }
331
332 GstAllocator *
333 gst_wl_shm_allocator_get (void)
334 {
335   FUNCTION;
336   return gst_allocator_find (GST_ALLOCATOR_WL_SHM);
337 }
338
339 gboolean
340 gst_is_wl_shm_memory (GstMemory * mem)
341 {
342   FUNCTION;
343   return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM);
344 }
345
346 gboolean
347 gst_is_wl_memory (GstMemory * mem)
348 {
349   FUNCTION;
350   return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM);
351 }
352
353 struct wl_buffer *
354 gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
355     const GstVideoInfo * info)
356 {
357   GstWlShmMemory *shm_mem = (GstWlShmMemory *) mem;
358   gint width, height, stride, offset;
359   gsize size;
360   enum wl_shm_format format;
361   struct wl_shm_pool *wl_pool;
362   struct wl_buffer *wbuffer;
363   FUNCTION;
364
365 #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
366   if (display->USE_TBM) {
367     tbm_surface_info_s ts_info;
368     int num_bo;
369
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++);
374
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].stride = display->stride_width[0];
385       ts_info.planes[1].stride = display->stride_width[1];
386       ts_info.planes[0].offset = 0;
387       ts_info.planes[1].offset = (display->bo[1]) ? 0 : offset;
388
389       GST_LOG
390           ("set tbm_surface_info_s: width(%d) height(%d) format(%s) bpp(%d) num_planes(%d)",
391           ts_info.width, ts_info.height, gst_wl_tbm_format_to_string (format),
392           ts_info.bpp, ts_info.num_planes);
393       GST_LOG
394           ("set tbm_surface_info_s: planse[0].stride(%d) planes[1].stride(%d) planes[0].offset(%d) planes[1].offset(%d)",
395           ts_info.planes[0].stride, ts_info.planes[1].stride,
396           ts_info.planes[0].offset, ts_info.planes[1].offset);
397
398       num_bo = (display->bo[1]) ? 2 : 1;
399       GST_LOG ("num_bo(%d)", num_bo);
400
401       display->tsurface =
402           tbm_surface_internal_create_with_bos (&ts_info,
403           (tbm_bo *) display->bo, num_bo);
404       GST_LOG ("create tbm surface(%p)", display->tsurface);
405       wbuffer =
406           wayland_tbm_client_create_buffer (display->tbm_client,
407           display->tsurface);
408     } else {
409
410       width = GST_VIDEO_INFO_WIDTH (info);
411       height = GST_VIDEO_INFO_HEIGHT (info);
412       stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
413       size = GST_VIDEO_INFO_SIZE (info);
414
415       format = gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (info));
416       g_return_val_if_fail (gst_is_wl_memory (mem), NULL);
417       g_return_val_if_fail (size <= mem->size, NULL);
418       g_return_val_if_fail (shm_mem->fd != -1, NULL);
419
420       GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
421           G_GSSIZE_FORMAT " (%d x %d, stride %d)", size, width, height, stride);
422
423       if (display->dump_video) {
424         gst_wl_tbm_dump_normal_raw_video (shm_mem->tbm_bo_ptr, size,
425             display->dump_count++, display->total_dump);
426         if (display->dump_count > display->total_dump)
427           display->dump_video = FALSE;
428       }
429
430       ts_info.width = width;
431       ts_info.height = height;
432       ts_info.format = format;
433       ts_info.bpp = tbm_surface_internal_get_bpp (ts_info.format);
434       ts_info.num_planes = tbm_surface_internal_get_num_planes (ts_info.format);
435       ts_info.planes[0].stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
436       ts_info.planes[1].stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 1);
437       ts_info.planes[2].stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 2);
438       ts_info.planes[0].offset = GST_VIDEO_INFO_PLANE_OFFSET (info, 0);
439       ts_info.planes[1].offset = GST_VIDEO_INFO_PLANE_OFFSET (info, 1);
440       ts_info.planes[2].offset = GST_VIDEO_INFO_PLANE_OFFSET (info, 2);
441
442       GST_LOG ("tbm_bo (%p)", shm_mem->tbm_bo_ptr);
443
444       display->tsurface =
445           tbm_surface_internal_create_with_bos (&ts_info,
446           (tbm_bo *) & shm_mem->tbm_bo_ptr, 1);
447       wbuffer =
448           wayland_tbm_client_create_buffer (display->tbm_client,
449           display->tsurface);
450     }
451     GST_LOG ("create wbuffer(%p)", wbuffer);
452
453   } else {                      /* USE SHM */
454     width = GST_VIDEO_INFO_WIDTH (info);
455     height = GST_VIDEO_INFO_HEIGHT (info);
456     stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
457     size = GST_VIDEO_INFO_SIZE (info);
458     format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info));
459     g_return_val_if_fail (gst_is_wl_memory (mem), NULL);
460     g_return_val_if_fail (size <= mem->size, NULL);
461     g_return_val_if_fail (shm_mem->fd != -1, NULL);
462
463     GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
464         G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height,
465         stride, gst_wl_shm_format_to_string (format));
466
467     wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size);
468     wbuffer =
469         wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride, format);
470
471     wl_shm_pool_destroy (wl_pool);
472   }
473   display->buffer_width = width;
474   display->buffer_height = height;
475   GST_LOG ("buffer_width(%d) buffer_height(%d)", display->buffer_width,
476       display->buffer_height);
477   return wbuffer;
478
479 #else /* open source */
480   width = GST_VIDEO_INFO_WIDTH (info);
481   height = GST_VIDEO_INFO_HEIGHT (info);
482   stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
483   size = GST_VIDEO_INFO_SIZE (info);
484   format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info));
485   g_return_val_if_fail (gst_is_wl_shm_memory (mem), NULL);
486   g_return_val_if_fail (size <= mem->size, NULL);
487   g_return_val_if_fail (shm_mem->fd != -1, NULL);
488
489   GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
490       G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height,
491       stride, gst_wl_shm_format_to_string (format));
492
493   wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size);
494   wbuffer = wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride,
495       format);
496
497   close (shm_mem->fd);
498   shm_mem->fd = -1;
499   wl_shm_pool_destroy (wl_pool);
500
501   return wbuffer;
502 #endif
503 }