waylandsink/waylandpool: improve debug message
[platform/upstream/gstreamer.git] / ext / wayland / waylandpool.c
1 /* GStreamer
2  * Copyright (C) 2012 Intel Corporation
3  * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
4
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 /* Object header */
26 #include "gstwaylandsink.h"
27 #include "wldisplay.h"
28 #include "wlvideoformat.h"
29
30 /* Debugging category */
31 #include <gst/gstinfo.h>
32
33 /* Helper functions */
34 #include <gst/video/video.h>
35 #include <gst/video/gstvideometa.h>
36 #include <gst/video/gstvideopool.h>
37
38 #include <errno.h>
39
40 /* wl metadata */
41 GType
42 gst_wl_meta_api_get_type (void)
43 {
44   static volatile GType type;
45   static const gchar *tags[] =
46       { "memory", "size", "colorspace", "orientation", NULL };
47
48   if (g_once_init_enter (&type)) {
49     GType _type = gst_meta_api_type_register ("GstWlMetaAPI", tags);
50     g_once_init_leave (&type, _type);
51   }
52   return type;
53 }
54
55 static void
56 gst_wl_meta_free (GstWlMeta * meta, GstBuffer * buffer)
57 {
58   gst_object_unref (meta->sink);
59   munmap (meta->data, meta->size);
60   wl_buffer_destroy (meta->wbuffer);
61 }
62
63 const GstMetaInfo *
64 gst_wl_meta_get_info (void)
65 {
66   static const GstMetaInfo *wl_meta_info = NULL;
67
68   if (g_once_init_enter (&wl_meta_info)) {
69     const GstMetaInfo *meta =
70         gst_meta_register (GST_WL_META_API_TYPE, "GstWlMeta",
71         sizeof (GstWlMeta), (GstMetaInitFunction) NULL,
72         (GstMetaFreeFunction) gst_wl_meta_free,
73         (GstMetaTransformFunction) NULL);
74     g_once_init_leave (&wl_meta_info, meta);
75   }
76   return wl_meta_info;
77 }
78
79 /* bufferpool */
80 static void gst_wayland_buffer_pool_finalize (GObject * object);
81 static gboolean gst_wayland_buffer_pool_set_config (GstBufferPool * pool,
82     GstStructure * config);
83 static gboolean gst_wayland_buffer_pool_start (GstBufferPool * pool);
84 static gboolean gst_wayland_buffer_pool_stop (GstBufferPool * pool);
85 static GstFlowReturn gst_wayland_buffer_pool_alloc (GstBufferPool * pool,
86     GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
87
88 #define gst_wayland_buffer_pool_parent_class parent_class
89 G_DEFINE_TYPE (GstWaylandBufferPool, gst_wayland_buffer_pool,
90     GST_TYPE_BUFFER_POOL);
91
92 static void
93 gst_wayland_buffer_pool_class_init (GstWaylandBufferPoolClass * klass)
94 {
95   GObjectClass *gobject_class = (GObjectClass *) klass;
96   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
97
98   gobject_class->finalize = gst_wayland_buffer_pool_finalize;
99
100   gstbufferpool_class->set_config = gst_wayland_buffer_pool_set_config;
101   gstbufferpool_class->start = gst_wayland_buffer_pool_start;
102   gstbufferpool_class->stop = gst_wayland_buffer_pool_stop;
103   gstbufferpool_class->alloc_buffer = gst_wayland_buffer_pool_alloc;
104 }
105
106 static void
107 gst_wayland_buffer_pool_init (GstWaylandBufferPool * self)
108 {
109   gst_video_info_init (&self->info);
110 }
111
112 static void
113 gst_wayland_buffer_pool_finalize (GObject * object)
114 {
115   GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object);
116
117   if (pool->wl_pool)
118     gst_wayland_buffer_pool_stop (GST_BUFFER_POOL (pool));
119
120   gst_object_unref (pool->sink);
121
122   G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object);
123 }
124
125 static gboolean
126 gst_wayland_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
127 {
128   GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
129   GstCaps *caps;
130
131   if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
132     goto wrong_config;
133
134   if (caps == NULL)
135     goto no_caps;
136
137   /* now parse the caps from the config */
138   if (!gst_video_info_from_caps (&self->info, caps))
139     goto wrong_caps;
140
141   GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT,
142       GST_VIDEO_INFO_WIDTH (&self->info), GST_VIDEO_INFO_HEIGHT (&self->info),
143       caps);
144
145   /*Fixme: Enable metadata checking handling based on the config of pool */
146
147   return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
148   /* ERRORS */
149 wrong_config:
150   {
151     GST_WARNING_OBJECT (pool, "invalid config");
152     return FALSE;
153   }
154 no_caps:
155   {
156     GST_WARNING_OBJECT (pool, "no caps in config");
157     return FALSE;
158   }
159 wrong_caps:
160   {
161     GST_WARNING_OBJECT (pool,
162         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
163     return FALSE;
164   }
165 }
166
167 static gboolean
168 gst_wayland_buffer_pool_start (GstBufferPool * pool)
169 {
170   GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
171   guint size = 0;
172   int fd;
173   char filename[1024];
174   static int init = 0;
175
176   GST_DEBUG_OBJECT (self, "Initializing wayland buffer pool");
177
178   /* configure */
179   size = GST_VIDEO_INFO_SIZE (&self->info) * 15;
180
181   /* allocate shm pool */
182   snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
183       "wayland-shm", init++, "XXXXXX");
184
185   fd = mkstemp (filename);
186   if (fd < 0) {
187     GST_ERROR_OBJECT (pool, "opening temp file %s failed: %s", filename,
188         strerror (errno));
189     return FALSE;
190   }
191   if (ftruncate (fd, size) < 0) {
192     GST_ERROR_OBJECT (pool, "ftruncate failed: %s", strerror (errno));
193     close (fd);
194     return FALSE;
195   }
196
197   self->data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
198   if (self->data == MAP_FAILED) {
199     GST_ERROR_OBJECT (pool, "mmap failed: %s", strerror (errno));
200     close (fd);
201     return FALSE;
202   }
203
204   self->wl_pool =
205       wl_shm_create_pool (self->sink->display->shm,
206       fd, size);
207   close (fd);
208
209   self->size = size;
210   self->used = 0;
211
212   return TRUE;
213 }
214
215 static gboolean
216 gst_wayland_buffer_pool_stop (GstBufferPool * pool)
217 {
218   GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
219
220   GST_DEBUG_OBJECT (self, "Stopping wayland buffer pool");
221
222   munmap (self->data, self->size);
223   wl_shm_pool_destroy (self->wl_pool);
224
225   self->wl_pool = NULL;
226   self->size = 0;
227   self->used = 0;
228
229   return TRUE;
230 }
231
232 static GstFlowReturn
233 gst_wayland_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
234     GstBufferPoolAcquireParams * params)
235 {
236   GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
237   gint width, height, stride;
238   gsize size;
239   enum wl_shm_format format;
240   gint offset;
241   void *data;
242   GstWlMeta *meta;
243
244   width = GST_VIDEO_INFO_WIDTH (&self->info);
245   height = GST_VIDEO_INFO_HEIGHT (&self->info);
246   stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 0);
247   size = GST_VIDEO_INFO_SIZE (&self->info);
248   format =
249       gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT (&self->info));
250
251   GST_DEBUG_OBJECT (self, "Allocating buffer of size %" G_GSSIZE_FORMAT
252       " (%d x %d, stride %d), format %s", size, width, height, stride,
253       gst_wayland_format_to_string (format));
254
255   /* try to reserve another memory block from the shm pool */
256   if (self->used + size > self->size)
257     goto no_buffer;
258
259   offset = self->used;
260   self->used += size;
261   data = ((gchar *) self->data) + offset;
262
263   /* create buffer and its metadata object */
264   *buffer = gst_buffer_new ();
265   meta = (GstWlMeta *) gst_buffer_add_meta (*buffer, GST_WL_META_INFO, NULL);
266   meta->sink = gst_object_ref (self->sink);
267   meta->wbuffer = wl_shm_pool_create_buffer (self->wl_pool, offset,
268       width, height, stride, format);
269   meta->data = data;
270   meta->size = size;
271
272   /* add the allocated memory on the GstBuffer */
273   gst_buffer_append_memory (*buffer,
274       gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
275           size, 0, size, NULL, NULL));
276
277   return GST_FLOW_OK;
278
279   /* ERROR */
280 no_buffer:
281   {
282     GST_WARNING_OBJECT (pool, "can't create buffer");
283     return GST_FLOW_ERROR;
284   }
285 }
286
287 GstBufferPool *
288 gst_wayland_buffer_pool_new (GstWaylandSink * waylandsink)
289 {
290   GstWaylandBufferPool *pool;
291
292   g_return_val_if_fail (GST_IS_WAYLAND_SINK (waylandsink), NULL);
293   pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL);
294   pool->sink = gst_object_ref (waylandsink);
295
296   return GST_BUFFER_POOL_CAST (pool);
297 }