1 /* GStreamer Wayland video sink
2 *
3 * Copyright (C) 2016 STMicroelectronics SA
4 * Copyright (C) 2016 Fabien Dessenne <fabien.dessenne@st.com>
5 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <gst/allocators/gstdmabuf.h>
27
28 #include "wllinuxdmabuf.h"
29 #include "wlvideoformat.h"
30
31 GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
32 #define GST_CAT_DEFAULT gstwayland_debug
33
34 typedef struct
35 {
36 GMutex lock;
37 GCond cond;
38 struct wl_buffer *wbuf;
39 } ConstructBufferData;
40
41 static void
create_succeeded(void * data,struct zwp_linux_buffer_params_v1 * params,struct wl_buffer * new_buffer)42 create_succeeded (void *data, struct zwp_linux_buffer_params_v1 *params,
43 struct wl_buffer *new_buffer)
44 {
45 ConstructBufferData *d = data;
46
47 g_mutex_lock (&d->lock);
48 d->wbuf = new_buffer;
49 zwp_linux_buffer_params_v1_destroy (params);
50 g_cond_signal (&d->cond);
51 g_mutex_unlock (&d->lock);
52 }
53
54 static void
create_failed(void * data,struct zwp_linux_buffer_params_v1 * params)55 create_failed (void *data, struct zwp_linux_buffer_params_v1 *params)
56 {
57 ConstructBufferData *d = data;
58
59 g_mutex_lock (&d->lock);
60 d->wbuf = NULL;
61 zwp_linux_buffer_params_v1_destroy (params);
62 g_cond_signal (&d->cond);
63 g_mutex_unlock (&d->lock);
64 }
65
66 static const struct zwp_linux_buffer_params_v1_listener params_listener = {
67 create_succeeded,
68 create_failed
69 };
70
71 struct wl_buffer *
gst_wl_linux_dmabuf_construct_wl_buffer(GstBuffer * buf,GstWlDisplay * display,const GstVideoInfo * info)72 gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf,
73 GstWlDisplay * display, const GstVideoInfo * info)
74 {
75 GstMemory *mem;
76 int format;
77 guint i, width, height;
78 guint nplanes, flags = 0;
79 struct zwp_linux_buffer_params_v1 *params;
80 gint64 timeout;
81 ConstructBufferData data;
82
83 g_return_val_if_fail (gst_wl_display_check_format_for_dmabuf (display,
84 GST_VIDEO_INFO_FORMAT (info)), NULL);
85
86 mem = gst_buffer_peek_memory (buf, 0);
87 format = gst_video_format_to_wl_dmabuf_format (GST_VIDEO_INFO_FORMAT (info));
88
89 g_cond_init (&data.cond);
90 g_mutex_init (&data.lock);
91 g_mutex_lock (&data.lock);
92
93 width = GST_VIDEO_INFO_WIDTH (info);
94 height = GST_VIDEO_INFO_HEIGHT (info);
95 nplanes = GST_VIDEO_INFO_N_PLANES (info);
96
97 GST_DEBUG_OBJECT (display, "Creating wl_buffer from DMABuf of size %"
98 G_GSSIZE_FORMAT " (%d x %d), format %s", info->size, width, height,
99 gst_wl_dmabuf_format_to_string (format));
100
101 /* Creation and configuration of planes */
102 params = zwp_linux_dmabuf_v1_create_params (display->dmabuf);
103
104 for (i = 0; i < nplanes; i++) {
105 guint offset, stride, mem_idx, length;
106 gsize skip;
107
108 offset = GST_VIDEO_INFO_PLANE_OFFSET (info, i);
109 stride = GST_VIDEO_INFO_PLANE_STRIDE (info, i);
110 if (gst_buffer_find_memory (buf, offset, 1, &mem_idx, &length, &skip)) {
111 GstMemory *m = gst_buffer_peek_memory (buf, mem_idx);
112 gint fd = gst_dmabuf_memory_get_fd (m);
113 zwp_linux_buffer_params_v1_add (params, fd, i, m->offset + skip,
114 stride, 0, 0);
115 } else {
116 GST_ERROR_OBJECT (mem->allocator, "memory does not seem to contain "
117 "enough data for the specified format");
118 zwp_linux_buffer_params_v1_destroy (params);
119 data.wbuf = NULL;
120 goto out;
121 }
122 }
123
124 if (GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_FLAG_INTERLACED)) {
125 GST_DEBUG_OBJECT (mem->allocator, "interlaced buffer");
126 flags = ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED;
127
128 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_FLAG_TFF)) {
129 GST_DEBUG_OBJECT (mem->allocator, "with bottom field first");
130 flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST;
131 }
132 }
133
134 /* Request buffer creation */
135 zwp_linux_buffer_params_v1_add_listener (params, ¶ms_listener, &data);
136 zwp_linux_buffer_params_v1_create (params, width, height, format, flags);
137
138 /* Wait for the request answer */
139 wl_display_flush (display->display);
140 data.wbuf = (gpointer) 0x1;
141 timeout = g_get_monotonic_time () + G_TIME_SPAN_SECOND;
142 while (data.wbuf == (gpointer) 0x1) {
143 if (!g_cond_wait_until (&data.cond, &data.lock, timeout)) {
144 GST_ERROR_OBJECT (mem->allocator, "zwp_linux_buffer_params_v1 time out");
145 zwp_linux_buffer_params_v1_destroy (params);
146 data.wbuf = NULL;
147 }
148 }
149
150 out:
151 if (!data.wbuf) {
152 GST_ERROR_OBJECT (mem->allocator, "can't create linux-dmabuf buffer");
153 } else {
154 GST_DEBUG_OBJECT (mem->allocator, "created linux_dmabuf wl_buffer (%p):"
155 "%dx%d, fmt=%.4s, %d planes",
156 data.wbuf, width, height, (char *) &format, nplanes);
157 }
158
159 g_mutex_unlock (&data.lock);
160 g_mutex_clear (&data.lock);
161 g_cond_clear (&data.cond);
162
163 return data.wbuf;
164 }
165