blob: c6fd9a2228d8557b1d1a033c189c270a1dc5ed61 [file] [log] [blame]
/* GStreamer Wayland video sink
*
* Copyright (C) 2016 STMicroelectronics SA
* Copyright (C) 2016 Fabien Dessenne <fabien.dessenne@st.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gst/allocators/gstdmabuf.h>
#include <gst/allocators/gstdmabufmeta.h>
#include <gst/allocators/gstphymemmeta.h>
#include "wllinuxdmabuf.h"
#include "wlvideoformat.h"
GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
#define GST_CAT_DEFAULT gstwayland_debug
typedef struct
{
GMutex lock;
GCond cond;
struct wl_buffer *wbuf;
} ConstructBufferData;
static void
create_succeeded (void *data, struct zwp_linux_buffer_params_v1 *params,
struct wl_buffer *new_buffer)
{
ConstructBufferData *d = data;
g_mutex_lock (&d->lock);
d->wbuf = new_buffer;
zwp_linux_buffer_params_v1_destroy (params);
g_cond_signal (&d->cond);
g_mutex_unlock (&d->lock);
}
static void
create_failed (void *data, struct zwp_linux_buffer_params_v1 *params)
{
ConstructBufferData *d = data;
g_mutex_lock (&d->lock);
d->wbuf = NULL;
zwp_linux_buffer_params_v1_destroy (params);
g_cond_signal (&d->cond);
g_mutex_unlock (&d->lock);
}
static const struct zwp_linux_buffer_params_v1_listener params_listener = {
create_succeeded,
create_failed
};
struct wl_buffer *
gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf,
GstWlDisplay * display, const GstVideoInfo * info)
{
GstMemory *mem;
int format;
guint i, width, height;
guint nplanes, flags = 0;
struct zwp_linux_buffer_params_v1 *params;
gint64 timeout;
ConstructBufferData data;
GstDmabufMeta *dmabuf_meta;
gint64 drm_modifier = 0;
GstPhyMemMeta *phymemmeta = NULL;
g_return_val_if_fail (gst_wl_display_check_format_for_dmabuf (display,
GST_VIDEO_INFO_FORMAT (info)), NULL);
mem = gst_buffer_peek_memory (buf, 0);
format = gst_video_format_to_wl_dmabuf_format (GST_VIDEO_INFO_FORMAT (info));
g_cond_init (&data.cond);
g_mutex_init (&data.lock);
g_mutex_lock (&data.lock);
width = GST_VIDEO_INFO_WIDTH (info);
height = GST_VIDEO_INFO_HEIGHT (info);
nplanes = GST_VIDEO_INFO_N_PLANES (info);
dmabuf_meta = gst_buffer_get_dmabuf_meta (buf);
if (dmabuf_meta)
drm_modifier = dmabuf_meta->drm_modifier;
GST_DEBUG_OBJECT (display, "Creating wl_buffer from DMABuf of size %"
G_GSSIZE_FORMAT " (%d x %d), format %s modifier 0x%016"PRIx64, info->size, width, height,
gst_wl_dmabuf_format_to_string (format), drm_modifier);
/* Creation and configuration of planes */
params = zwp_linux_dmabuf_v1_create_params (display->dmabuf);
for (i = 0; i < nplanes; i++) {
guint offset, stride, mem_idx, length;
gsize skip;
offset = GST_VIDEO_INFO_PLANE_OFFSET (info, i);
stride = GST_VIDEO_INFO_PLANE_STRIDE (info, i);
if (gst_buffer_find_memory (buf, offset, 1, &mem_idx, &length, &skip)) {
GstMemory *m = gst_buffer_peek_memory (buf, mem_idx);
gint fd = gst_dmabuf_memory_get_fd (m);
zwp_linux_buffer_params_v1_add (params, fd, i, m->offset + skip,
stride, drm_modifier >> 32, drm_modifier & 0xffffffff);
} else {
GST_ERROR_OBJECT (mem->allocator, "memory does not seem to contain "
"enough data for the specified format");
zwp_linux_buffer_params_v1_destroy (params);
data.wbuf = NULL;
goto out;
}
}
if (GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_FLAG_INTERLACED)) {
GST_DEBUG_OBJECT (mem->allocator, "interlaced buffer");
flags = ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED;
if (!GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_FLAG_TFF)) {
GST_DEBUG_OBJECT (mem->allocator, "with bottom field first");
flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST;
}
}
phymemmeta = GST_PHY_MEM_META_GET (buf);
if (drm_modifier != 0 && phymemmeta) {
GST_DEBUG_OBJECT (display, "physical memory meta x_padding: %d y_padding: %d \
RFC luma offset: %d chroma offset: %d",
phymemmeta->x_padding, phymemmeta->y_padding, phymemmeta->rfc_luma_offset, phymemmeta->rfc_chroma_offset);
zwp_linux_buffer_params_v1_add_dtrc_meta (params, phymemmeta->rfc_chroma_offset, phymemmeta->rfc_luma_offset);
} else {
zwp_linux_buffer_params_v1_add_dtrc_meta (params, 0, 0);
}
/* Request buffer creation */
zwp_linux_buffer_params_v1_add_listener (params, &params_listener, &data);
zwp_linux_buffer_params_v1_create (params, width, height, format, flags);
/* Wait for the request answer */
wl_display_flush (display->display);
data.wbuf = (gpointer) 0x1;
timeout = g_get_monotonic_time () + G_TIME_SPAN_SECOND;
while (data.wbuf == (gpointer) 0x1) {
if (!g_cond_wait_until (&data.cond, &data.lock, timeout)) {
GST_ERROR_OBJECT (mem->allocator, "zwp_linux_buffer_params_v1 time out");
zwp_linux_buffer_params_v1_destroy (params);
data.wbuf = NULL;
}
}
out:
if (!data.wbuf) {
GST_ERROR_OBJECT (mem->allocator, "can't create linux-dmabuf buffer");
} else {
GST_DEBUG_OBJECT (mem->allocator, "created linux_dmabuf wl_buffer (%p):"
"%dx%d, fmt=%.4s, %d planes",
data.wbuf, width, height, (char *) &format, nplanes);
}
g_mutex_unlock (&data.lock);
g_mutex_clear (&data.lock);
g_cond_clear (&data.cond);
return data.wbuf;
}