added my Recipes
This commit is contained in:
@@ -0,0 +1,489 @@
|
||||
From bc7c1d8febed84d33f0e49272b7707059485d4b4 Mon Sep 17 00:00:00 2001
|
||||
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
Date: Tue, 28 Mar 2023 18:24:40 +0200
|
||||
Subject: [PATCH 01/17] kmsallocator: Port to the new DRM Dumb Allocator
|
||||
|
||||
This ports the KMS allocator to use the DRM Dumb allocator from the allocators
|
||||
library.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
sys/kms/gstkmsallocator.c | 237 +++++++++++++-------------------------
|
||||
sys/kms/gstkmsallocator.h | 5 +-
|
||||
2 files changed, 84 insertions(+), 158 deletions(-)
|
||||
|
||||
diff --git a/sys/kms/gstkmsallocator.c b/sys/kms/gstkmsallocator.c
|
||||
index 6687f3b..3d9ee0a 100644
|
||||
--- a/sys/kms/gstkmsallocator.c
|
||||
+++ b/sys/kms/gstkmsallocator.c
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <drm.h>
|
||||
|
||||
#include <gst/allocators/gstdmabuf.h>
|
||||
+#include <gst/allocators/gstdrmdumb.h>
|
||||
|
||||
#include "gstkmsallocator.h"
|
||||
#include "gstkmsutils.h"
|
||||
@@ -51,20 +52,12 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
#define GST_KMS_MEMORY_TYPE "KMSMemory"
|
||||
|
||||
-struct kms_bo
|
||||
-{
|
||||
- void *ptr;
|
||||
- size_t size;
|
||||
- unsigned handle;
|
||||
- unsigned int refs;
|
||||
-};
|
||||
-
|
||||
struct _GstKMSAllocatorPrivate
|
||||
{
|
||||
int fd;
|
||||
/* protected by GstKMSAllocator object lock */
|
||||
GList *mem_cache;
|
||||
- GstAllocator *dmabuf_alloc;
|
||||
+ GstAllocator *dumb_alloc;
|
||||
};
|
||||
|
||||
#define parent_class gst_kms_allocator_parent_class
|
||||
@@ -101,92 +94,40 @@ check_fd (GstKMSAllocator * alloc)
|
||||
return alloc->priv->fd > -1;
|
||||
}
|
||||
|
||||
-static void
|
||||
-gst_kms_allocator_memory_reset (GstKMSAllocator * allocator, GstKMSMemory * mem)
|
||||
-{
|
||||
- int err;
|
||||
- struct drm_mode_destroy_dumb arg = { 0, };
|
||||
-
|
||||
- if (!check_fd (allocator))
|
||||
- return;
|
||||
-
|
||||
- if (mem->fb_id) {
|
||||
- GST_DEBUG_OBJECT (allocator, "removing fb id %d", mem->fb_id);
|
||||
- drmModeRmFB (allocator->priv->fd, mem->fb_id);
|
||||
- mem->fb_id = 0;
|
||||
- }
|
||||
-
|
||||
- if (!mem->bo)
|
||||
- return;
|
||||
-
|
||||
- if (mem->bo->ptr != NULL) {
|
||||
- GST_WARNING_OBJECT (allocator, "destroying mapped bo (refcount=%d)",
|
||||
- mem->bo->refs);
|
||||
- munmap (mem->bo->ptr, mem->bo->size);
|
||||
- mem->bo->ptr = NULL;
|
||||
- }
|
||||
-
|
||||
- arg.handle = mem->bo->handle;
|
||||
-
|
||||
- err = drmIoctl (allocator->priv->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
|
||||
- if (err)
|
||||
- GST_WARNING_OBJECT (allocator,
|
||||
- "Failed to destroy dumb buffer object: %s %d",
|
||||
- g_strerror (errno), errno);
|
||||
-
|
||||
- g_free (mem->bo);
|
||||
- mem->bo = NULL;
|
||||
-}
|
||||
-
|
||||
static gboolean
|
||||
gst_kms_allocator_memory_create (GstKMSAllocator * allocator,
|
||||
GstKMSMemory * kmsmem, GstVideoInfo * vinfo)
|
||||
{
|
||||
- gint i, ret, h;
|
||||
- struct drm_mode_create_dumb arg = { 0, };
|
||||
- guint32 fmt;
|
||||
+ gint i, h;
|
||||
gint num_planes = GST_VIDEO_INFO_N_PLANES (vinfo);
|
||||
gsize offs = 0;
|
||||
+ guint32 pitch;
|
||||
|
||||
if (kmsmem->bo)
|
||||
return TRUE;
|
||||
|
||||
- if (!check_fd (allocator))
|
||||
- return FALSE;
|
||||
-
|
||||
- kmsmem->bo = g_malloc0 (sizeof (*kmsmem->bo));
|
||||
+ kmsmem->bo = gst_drm_dumb_allocator_alloc (allocator->priv->dumb_alloc,
|
||||
+ gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo)),
|
||||
+ GST_VIDEO_INFO_WIDTH (vinfo), GST_VIDEO_INFO_HEIGHT (vinfo), &pitch);
|
||||
if (!kmsmem->bo)
|
||||
- return FALSE;
|
||||
-
|
||||
- fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo));
|
||||
- arg.bpp = gst_drm_bpp_from_drm (fmt);
|
||||
- arg.width = GST_VIDEO_INFO_WIDTH (vinfo);
|
||||
- h = GST_VIDEO_INFO_HEIGHT (vinfo);
|
||||
- arg.height = gst_drm_height_from_drm (fmt, h);
|
||||
-
|
||||
- ret = drmIoctl (allocator->priv->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
|
||||
- if (ret)
|
||||
goto create_failed;
|
||||
|
||||
- if (!arg.pitch)
|
||||
+ if (!pitch)
|
||||
goto done;
|
||||
|
||||
+ h = GST_VIDEO_INFO_HEIGHT (vinfo);
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
- guint32 pitch;
|
||||
-
|
||||
- if (!arg.pitch)
|
||||
- continue;
|
||||
+ guint32 stride;
|
||||
|
||||
/* Overwrite the video info's stride and offset using the pitch calculcated
|
||||
* by the kms driver. */
|
||||
- pitch = gst_video_format_info_extrapolate_stride (vinfo->finfo, i,
|
||||
- arg.pitch);
|
||||
+ stride = gst_video_format_info_extrapolate_stride (vinfo->finfo, i, pitch);
|
||||
GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i) = pitch;
|
||||
GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i) = offs;
|
||||
|
||||
/* Note that we cannot negotiate special padding betweem each planes,
|
||||
* hence using the display height here. */
|
||||
- offs += pitch * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, h);
|
||||
+ offs += stride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, h);
|
||||
|
||||
GST_DEBUG_OBJECT (allocator, "Created BO plane %i with stride %i and "
|
||||
"offset %" G_GSIZE_FORMAT, i,
|
||||
@@ -198,10 +139,6 @@ gst_kms_allocator_memory_create (GstKMSAllocator * allocator,
|
||||
GST_VIDEO_INFO_SIZE (vinfo) = offs;
|
||||
|
||||
done:
|
||||
- kmsmem->bo->handle = arg.handle;
|
||||
- /* will be used a memory maxsize */
|
||||
- kmsmem->bo->size = arg.size;
|
||||
-
|
||||
/* Validate the size to prevent overflow */
|
||||
if (kmsmem->bo->size < GST_VIDEO_INFO_SIZE (vinfo)) {
|
||||
GST_ERROR_OBJECT (allocator,
|
||||
@@ -218,8 +155,6 @@ create_failed:
|
||||
{
|
||||
GST_ERROR_OBJECT (allocator, "Failed to create buffer object: %s (%d)",
|
||||
g_strerror (errno), errno);
|
||||
- g_free (kmsmem->bo);
|
||||
- kmsmem->bo = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -233,7 +168,16 @@ gst_kms_allocator_free (GstAllocator * allocator, GstMemory * mem)
|
||||
alloc = GST_KMS_ALLOCATOR (allocator);
|
||||
kmsmem = (GstKMSMemory *) mem;
|
||||
|
||||
- gst_kms_allocator_memory_reset (alloc, kmsmem);
|
||||
+ if (check_fd (alloc) && kmsmem->fb_id) {
|
||||
+ GST_DEBUG_OBJECT (allocator, "removing fb id %d", kmsmem->fb_id);
|
||||
+ drmModeRmFB (alloc->priv->fd, kmsmem->fb_id);
|
||||
+ kmsmem->fb_id = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (kmsmem->bo) {
|
||||
+ gst_memory_unref (kmsmem->bo);
|
||||
+ kmsmem->bo = NULL;
|
||||
+ }
|
||||
g_slice_free (GstKMSMemory, kmsmem);
|
||||
}
|
||||
|
||||
@@ -276,6 +220,22 @@ gst_kms_allocator_get_property (GObject * object, guint prop_id,
|
||||
}
|
||||
}
|
||||
|
||||
+static void
|
||||
+gst_kms_allocator_constructed (GObject * obj)
|
||||
+{
|
||||
+ GstKMSAllocator *alloc;
|
||||
+
|
||||
+ alloc = GST_KMS_ALLOCATOR (obj);
|
||||
+
|
||||
+ /* Should be called after the properties are set */
|
||||
+ g_assert (check_fd (alloc));
|
||||
+ alloc->priv->dumb_alloc =
|
||||
+ gst_drm_dumb_allocator_new_with_fd (alloc->priv->fd);
|
||||
+
|
||||
+ /* Its already opened and we already checked for dumb allocation support */
|
||||
+ g_assert (alloc->priv->dumb_alloc);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
gst_kms_allocator_finalize (GObject * obj)
|
||||
{
|
||||
@@ -285,8 +245,8 @@ gst_kms_allocator_finalize (GObject * obj)
|
||||
|
||||
gst_kms_allocator_clear_cache (GST_ALLOCATOR (alloc));
|
||||
|
||||
- if (alloc->priv->dmabuf_alloc)
|
||||
- gst_object_unref (alloc->priv->dmabuf_alloc);
|
||||
+ if (alloc->priv->dumb_alloc)
|
||||
+ gst_object_unref (alloc->priv->dumb_alloc);
|
||||
|
||||
if (check_fd (alloc))
|
||||
close (alloc->priv->fd);
|
||||
@@ -307,11 +267,12 @@ gst_kms_allocator_class_init (GstKMSAllocatorClass * klass)
|
||||
|
||||
gobject_class->set_property = gst_kms_allocator_set_property;
|
||||
gobject_class->get_property = gst_kms_allocator_get_property;
|
||||
+ gobject_class->constructed = gst_kms_allocator_constructed;
|
||||
gobject_class->finalize = gst_kms_allocator_finalize;
|
||||
|
||||
g_props[PROP_DRM_FD] = g_param_spec_int ("drm-fd", "DRM fd",
|
||||
"DRM file descriptor", -1, G_MAXINT, -1,
|
||||
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
|
||||
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, PROP_N, g_props);
|
||||
}
|
||||
@@ -320,46 +281,20 @@ static gpointer
|
||||
gst_kms_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
|
||||
{
|
||||
GstKMSMemory *kmsmem;
|
||||
- GstKMSAllocator *alloc;
|
||||
- int err;
|
||||
- gpointer out;
|
||||
- struct drm_mode_map_dumb arg = { 0, };
|
||||
-
|
||||
- alloc = (GstKMSAllocator *) mem->allocator;
|
||||
-
|
||||
- if (!check_fd (alloc))
|
||||
- return NULL;
|
||||
|
||||
kmsmem = (GstKMSMemory *) mem;
|
||||
if (!kmsmem->bo)
|
||||
return NULL;
|
||||
|
||||
- /* Reuse existing buffer object mapping if possible */
|
||||
- if (kmsmem->bo->ptr != NULL) {
|
||||
+ if (kmsmem->bo_map.data)
|
||||
goto out;
|
||||
- }
|
||||
|
||||
- arg.handle = kmsmem->bo->handle;
|
||||
-
|
||||
- err = drmIoctl (alloc->priv->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
|
||||
- if (err) {
|
||||
- GST_ERROR_OBJECT (alloc, "Failed to get offset of buffer object: %s %d",
|
||||
- g_strerror (errno), errno);
|
||||
- return NULL;
|
||||
- }
|
||||
-
|
||||
- out = mmap (0, kmsmem->bo->size,
|
||||
- PROT_READ | PROT_WRITE, MAP_SHARED, alloc->priv->fd, arg.offset);
|
||||
- if (out == MAP_FAILED) {
|
||||
- GST_ERROR_OBJECT (alloc, "Failed to map dumb buffer object: %s %d",
|
||||
- g_strerror (errno), errno);
|
||||
+ if (!gst_memory_map (kmsmem->bo, &kmsmem->bo_map, flags))
|
||||
return NULL;
|
||||
- }
|
||||
- kmsmem->bo->ptr = out;
|
||||
|
||||
out:
|
||||
- g_atomic_int_inc (&kmsmem->bo->refs);
|
||||
- return kmsmem->bo->ptr;
|
||||
+ g_atomic_int_inc (&kmsmem->bo_map_refs);
|
||||
+ return kmsmem->bo_map.data;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -367,16 +302,13 @@ gst_kms_memory_unmap (GstMemory * mem)
|
||||
{
|
||||
GstKMSMemory *kmsmem;
|
||||
|
||||
- if (!check_fd ((GstKMSAllocator *) mem->allocator))
|
||||
- return;
|
||||
-
|
||||
kmsmem = (GstKMSMemory *) mem;
|
||||
if (!kmsmem->bo)
|
||||
return;
|
||||
|
||||
- if (g_atomic_int_dec_and_test (&kmsmem->bo->refs)) {
|
||||
- munmap (kmsmem->bo->ptr, kmsmem->bo->size);
|
||||
- kmsmem->bo->ptr = NULL;
|
||||
+ if (g_atomic_int_dec_and_test (&kmsmem->bo_map_refs)) {
|
||||
+ gst_memory_unmap (kmsmem->bo, &kmsmem->bo_map);
|
||||
+ kmsmem->bo_map.data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,11 +346,12 @@ gst_kms_allocator_new (int fd)
|
||||
* which are relative to the GstBuffer start. */
|
||||
static gboolean
|
||||
gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem,
|
||||
- gsize in_offsets[GST_VIDEO_MAX_PLANES], GstVideoInfo * vinfo)
|
||||
+ gsize in_offsets[GST_VIDEO_MAX_PLANES], GstVideoInfo * vinfo,
|
||||
+ guint32 bo_handles[4])
|
||||
{
|
||||
gint i, ret;
|
||||
gint num_planes = GST_VIDEO_INFO_N_PLANES (vinfo);
|
||||
- guint32 w, h, fmt, bo_handles[4] = { 0, };
|
||||
+ guint32 w, h, fmt;
|
||||
guint32 pitches[4] = { 0, };
|
||||
guint32 offsets[4] = { 0, };
|
||||
|
||||
@@ -430,11 +363,6 @@ gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem,
|
||||
fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo));
|
||||
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
- if (kmsmem->bo)
|
||||
- bo_handles[i] = kmsmem->bo->handle;
|
||||
- else
|
||||
- bo_handles[i] = kmsmem->gem_handle[i];
|
||||
-
|
||||
pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i);
|
||||
offsets[i] = in_offsets[i];
|
||||
}
|
||||
@@ -459,6 +387,8 @@ gst_kms_allocator_bo_alloc (GstAllocator * allocator, GstVideoInfo * vinfo)
|
||||
GstKMSAllocator *alloc;
|
||||
GstKMSMemory *kmsmem;
|
||||
GstMemory *mem;
|
||||
+ guint32 bo_handle[4] = { 0, };
|
||||
+ gint i;
|
||||
|
||||
kmsmem = g_slice_new0 (GstKMSMemory);
|
||||
if (!kmsmem)
|
||||
@@ -474,9 +404,13 @@ gst_kms_allocator_bo_alloc (GstAllocator * allocator, GstVideoInfo * vinfo)
|
||||
}
|
||||
|
||||
gst_memory_init (mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL,
|
||||
- kmsmem->bo->size, 0, 0, GST_VIDEO_INFO_SIZE (vinfo));
|
||||
+ kmsmem->bo->maxsize, 0, 0, GST_VIDEO_INFO_SIZE (vinfo));
|
||||
+
|
||||
+ for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vinfo); i++)
|
||||
+ bo_handle[i] = gst_drm_dumb_memory_get_handle (kmsmem->bo);
|
||||
|
||||
- if (!gst_kms_allocator_add_fb (alloc, kmsmem, vinfo->offset, vinfo))
|
||||
+ if (!gst_kms_allocator_add_fb (alloc, kmsmem, vinfo->offset, vinfo,
|
||||
+ bo_handle))
|
||||
goto fail;
|
||||
|
||||
return mem;
|
||||
@@ -495,6 +429,7 @@ gst_kms_allocator_dmabuf_import (GstAllocator * allocator, gint * prime_fds,
|
||||
GstKMSMemory *kmsmem;
|
||||
GstMemory *mem;
|
||||
gint i, ret;
|
||||
+ guint32 gem_handle[4] = { 0, };
|
||||
|
||||
g_return_val_if_fail (n_planes <= GST_VIDEO_MAX_PLANES, FALSE);
|
||||
|
||||
@@ -508,42 +443,41 @@ gst_kms_allocator_dmabuf_import (GstAllocator * allocator, gint * prime_fds,
|
||||
|
||||
alloc = GST_KMS_ALLOCATOR (allocator);
|
||||
for (i = 0; i < n_planes; i++) {
|
||||
- ret = drmPrimeFDToHandle (alloc->priv->fd, prime_fds[i],
|
||||
- &kmsmem->gem_handle[i]);
|
||||
+ ret = drmPrimeFDToHandle (alloc->priv->fd, prime_fds[i], &gem_handle[i]);
|
||||
if (ret)
|
||||
goto import_fd_failed;
|
||||
}
|
||||
|
||||
- if (!gst_kms_allocator_add_fb (alloc, kmsmem, offsets, vinfo))
|
||||
+ if (!gst_kms_allocator_add_fb (alloc, kmsmem, offsets, vinfo, gem_handle))
|
||||
goto failed;
|
||||
|
||||
+done:
|
||||
for (i = 0; i < n_planes; i++) {
|
||||
- struct drm_gem_close arg = { kmsmem->gem_handle[i], };
|
||||
+ struct drm_gem_close arg = { gem_handle[i], };
|
||||
gint err;
|
||||
|
||||
+ if (!gem_handle[i])
|
||||
+ continue;
|
||||
+
|
||||
err = drmIoctl (alloc->priv->fd, DRM_IOCTL_GEM_CLOSE, &arg);
|
||||
if (err)
|
||||
GST_WARNING_OBJECT (allocator,
|
||||
"Failed to close GEM handle: %s %d", g_strerror (errno), errno);
|
||||
-
|
||||
- kmsmem->gem_handle[i] = 0;
|
||||
}
|
||||
|
||||
return kmsmem;
|
||||
|
||||
/* ERRORS */
|
||||
import_fd_failed:
|
||||
- {
|
||||
- GST_ERROR_OBJECT (alloc, "Failed to import prime fd %d: %s (%d)",
|
||||
- prime_fds[i], g_strerror (errno), errno);
|
||||
- /* fallback */
|
||||
- }
|
||||
+ GST_ERROR_OBJECT (alloc, "Failed to import prime fd %d: %s (%d)",
|
||||
+ prime_fds[i], g_strerror (errno), errno);
|
||||
+ /* fallthrough */
|
||||
|
||||
failed:
|
||||
- {
|
||||
- gst_memory_unref (mem);
|
||||
- return NULL;
|
||||
- }
|
||||
+ gst_memory_unref (mem);
|
||||
+ mem = NULL;
|
||||
+ kmsmem = NULL;
|
||||
+ goto done;
|
||||
}
|
||||
|
||||
GstMemory *
|
||||
@@ -552,30 +486,21 @@ gst_kms_allocator_dmabuf_export (GstAllocator * allocator, GstMemory * _kmsmem)
|
||||
GstKMSMemory *kmsmem = (GstKMSMemory *) _kmsmem;
|
||||
GstKMSAllocator *alloc = GST_KMS_ALLOCATOR (allocator);
|
||||
GstMemory *mem;
|
||||
- gint ret;
|
||||
- gint prime_fd;
|
||||
|
||||
/* We can only export DUMB buffers */
|
||||
g_return_val_if_fail (kmsmem->bo, NULL);
|
||||
|
||||
-
|
||||
- ret = drmPrimeHandleToFD (alloc->priv->fd, kmsmem->bo->handle,
|
||||
- DRM_CLOEXEC | DRM_RDWR, &prime_fd);
|
||||
- if (ret)
|
||||
+ mem = gst_drm_dumb_memory_export_dmabuf (kmsmem->bo);
|
||||
+ if (!mem)
|
||||
goto export_fd_failed;
|
||||
|
||||
- if (G_UNLIKELY (alloc->priv->dmabuf_alloc == NULL))
|
||||
- alloc->priv->dmabuf_alloc = gst_dmabuf_allocator_new ();
|
||||
-
|
||||
- mem = gst_dmabuf_allocator_alloc (alloc->priv->dmabuf_alloc, prime_fd,
|
||||
- gst_memory_get_sizes (_kmsmem, NULL, NULL));
|
||||
-
|
||||
/* Populate the cache so KMSSink can find the kmsmem back when it receives
|
||||
* one of these DMABuf. This call takes ownership of the kmsmem. */
|
||||
gst_kms_allocator_cache (allocator, mem, _kmsmem);
|
||||
|
||||
- GST_DEBUG_OBJECT (alloc, "Exported bo handle %d as %d", kmsmem->bo->handle,
|
||||
- prime_fd);
|
||||
+ GST_DEBUG_OBJECT (alloc, "Exported bo handle %d as %d",
|
||||
+ gst_drm_dumb_memory_get_handle (kmsmem->bo),
|
||||
+ gst_dmabuf_memory_get_fd (mem));
|
||||
|
||||
return mem;
|
||||
|
||||
@@ -583,7 +508,7 @@ gst_kms_allocator_dmabuf_export (GstAllocator * allocator, GstMemory * _kmsmem)
|
||||
export_fd_failed:
|
||||
{
|
||||
GST_ERROR_OBJECT (alloc, "Failed to export bo handle %d: %s (%d)",
|
||||
- kmsmem->bo->handle, g_strerror (errno), ret);
|
||||
+ gst_drm_dumb_memory_get_handle (kmsmem->bo), g_strerror (errno), errno);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
diff --git a/sys/kms/gstkmsallocator.h b/sys/kms/gstkmsallocator.h
|
||||
index 9d00126..258efba 100644
|
||||
--- a/sys/kms/gstkmsallocator.h
|
||||
+++ b/sys/kms/gstkmsallocator.h
|
||||
@@ -56,8 +56,9 @@ struct _GstKMSMemory
|
||||
GstMemory parent;
|
||||
|
||||
guint32 fb_id;
|
||||
- guint32 gem_handle[GST_VIDEO_MAX_PLANES];
|
||||
- struct kms_bo *bo;
|
||||
+ GstMemory *bo;
|
||||
+ GstMapInfo bo_map;
|
||||
+ gint bo_map_refs;
|
||||
};
|
||||
|
||||
struct _GstKMSAllocator
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
From 930fb463ebf2fffed6a8e8f8b05594082fb2a3c2 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Wed, 15 Feb 2023 11:49:38 -0500
|
||||
Subject: [PATCH 02/17] gtkwaylandsink: Remove redefine of
|
||||
GST_CAPS_FEATURE_MEMORY_DMABUF
|
||||
|
||||
Instead just include the appropriate header file. There is no meson deps
|
||||
modification as gstallocators_dep is already part of gstwayland_dep.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 10 +++-------
|
||||
1 file changed, 3 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index e4dd06e..35367ca 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -25,13 +25,13 @@
|
||||
#endif
|
||||
|
||||
#include "gstgtkwaylandsink.h"
|
||||
+#include "gstgtkutils.h"
|
||||
+#include "gtkgstwaylandwidget.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
+#include <gst/allocators/allocators.h>
|
||||
#include <gst/wayland/wayland.h>
|
||||
|
||||
-#include "gstgtkutils.h"
|
||||
-#include "gtkgstwaylandwidget.h"
|
||||
-
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
#include <gdk/gdkwayland.h>
|
||||
#else
|
||||
@@ -41,10 +41,6 @@
|
||||
#define GST_CAT_DEFAULT gst_debug_gtk_wayland_sink
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
-#ifndef GST_CAPS_FEATURE_MEMORY_DMABUF
|
||||
-#define GST_CAPS_FEATURE_MEMORY_DMABUF "memory:DMABuf"
|
||||
-#endif
|
||||
-
|
||||
#define WL_VIDEO_FORMATS \
|
||||
"{ BGRx, BGRA, RGBx, xBGR, xRGB, RGBA, ABGR, ARGB, RGB, BGR, " \
|
||||
"RGB16, BGR16, YUY2, YVYU, UYVY, AYUV, NV12, NV21, NV16, NV61, " \
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
From 4b6f23a997485355aeca22193c317184fe74a28c Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Wed, 15 Feb 2023 12:13:16 -0500
|
||||
Subject: [PATCH 03/17] waylandsink: Stop modifying the display GstVideoInfo
|
||||
|
||||
The video_info is supposed to match the display dimentions, but as soon as we
|
||||
get a padded video buffer, we modify it. This has side effect later on and
|
||||
maybe cause bad frames.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 22 +++++++++-------------
|
||||
ext/wayland/gstwaylandsink.c | 18 +++++++-----------
|
||||
2 files changed, 16 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 35367ca..dc1e3c3 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -982,7 +982,7 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
GstWlBuffer *wlbuffer;
|
||||
GstVideoMeta *vmeta;
|
||||
GstVideoFormat format;
|
||||
- GstVideoInfo old_vinfo;
|
||||
+ GstVideoInfo src_vinfo;
|
||||
GstMemory *mem;
|
||||
struct wl_buffer *wbuf = NULL;
|
||||
|
||||
@@ -1023,23 +1023,23 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
/* update video info from video meta */
|
||||
mem = gst_buffer_peek_memory (buffer, 0);
|
||||
|
||||
- old_vinfo = priv->video_info;
|
||||
+ src_vinfo = priv->video_info;
|
||||
vmeta = gst_buffer_get_video_meta (buffer);
|
||||
if (vmeta) {
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < vmeta->n_planes; i++) {
|
||||
- priv->video_info.offset[i] = vmeta->offset[i];
|
||||
- priv->video_info.stride[i] = vmeta->stride[i];
|
||||
+ src_vinfo.offset[i] = vmeta->offset[i];
|
||||
+ src_vinfo.stride[i] = vmeta->stride[i];
|
||||
}
|
||||
- priv->video_info.size = gst_buffer_get_size (buffer);
|
||||
+ src_vinfo.size = gst_buffer_get_size (buffer);
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (self,
|
||||
"buffer %" GST_PTR_FORMAT " does not have a wl_buffer from our "
|
||||
"display, creating it", buffer);
|
||||
|
||||
- format = GST_VIDEO_INFO_FORMAT (&priv->video_info);
|
||||
+ format = GST_VIDEO_INFO_FORMAT (&src_vinfo);
|
||||
if (gst_wl_display_check_format_for_dmabuf (priv->display, format)) {
|
||||
guint i, nb_dmabuf = 0;
|
||||
|
||||
@@ -1049,21 +1049,17 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
|
||||
if (nb_dmabuf && (nb_dmabuf == gst_buffer_n_memory (buffer)))
|
||||
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, priv->display,
|
||||
- &priv->video_info);
|
||||
+ &src_vinfo);
|
||||
}
|
||||
|
||||
if (!wbuf && gst_wl_display_check_format_for_shm (priv->display, format)) {
|
||||
if (gst_buffer_n_memory (buffer) == 1 && gst_is_fd_memory (mem))
|
||||
wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, priv->display,
|
||||
- &priv->video_info);
|
||||
+ &src_vinfo);
|
||||
|
||||
/* If nothing worked, copy into our internal pool */
|
||||
if (!wbuf) {
|
||||
GstVideoFrame src, dst;
|
||||
- GstVideoInfo src_info = priv->video_info;
|
||||
-
|
||||
- /* rollback video info changes */
|
||||
- priv->video_info = old_vinfo;
|
||||
|
||||
/* we don't know how to create a wl_buffer directly from the provided
|
||||
* memory, so we have to copy the data to shm memory that we know how
|
||||
@@ -1115,7 +1111,7 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
GST_MAP_WRITE))
|
||||
goto dst_map_failed;
|
||||
|
||||
- if (!gst_video_frame_map (&src, &src_info, buffer, GST_MAP_READ)) {
|
||||
+ if (!gst_video_frame_map (&src, &src_vinfo, buffer, GST_MAP_READ)) {
|
||||
gst_video_frame_unmap (&dst);
|
||||
goto src_map_failed;
|
||||
}
|
||||
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
||||
index 2f116bf..6dd0807 100644
|
||||
--- a/ext/wayland/gstwaylandsink.c
|
||||
+++ b/ext/wayland/gstwaylandsink.c
|
||||
@@ -741,7 +741,7 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
GstWlBuffer *wlbuffer;
|
||||
GstVideoMeta *vmeta;
|
||||
GstVideoFormat format;
|
||||
- GstVideoInfo old_vinfo;
|
||||
+ GstVideoInfo src_vinfo;
|
||||
GstMemory *mem;
|
||||
struct wl_buffer *wbuf = NULL;
|
||||
|
||||
@@ -794,16 +794,16 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
/* update video info from video meta */
|
||||
mem = gst_buffer_peek_memory (buffer, 0);
|
||||
|
||||
- old_vinfo = self->video_info;
|
||||
+ src_vinfo = self->video_info;
|
||||
vmeta = gst_buffer_get_video_meta (buffer);
|
||||
if (vmeta) {
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < vmeta->n_planes; i++) {
|
||||
- self->video_info.offset[i] = vmeta->offset[i];
|
||||
- self->video_info.stride[i] = vmeta->stride[i];
|
||||
+ src_vinfo.offset[i] = vmeta->offset[i];
|
||||
+ src_vinfo.stride[i] = vmeta->stride[i];
|
||||
}
|
||||
- self->video_info.size = gst_buffer_get_size (buffer);
|
||||
+ src_vinfo.size = gst_buffer_get_size (buffer);
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (self,
|
||||
@@ -820,7 +820,7 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
|
||||
if (nb_dmabuf && (nb_dmabuf == gst_buffer_n_memory (buffer)))
|
||||
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, self->display,
|
||||
- &self->video_info);
|
||||
+ &src_vinfo);
|
||||
}
|
||||
|
||||
if (!wbuf && gst_wl_display_check_format_for_shm (self->display, format)) {
|
||||
@@ -831,10 +831,6 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
/* If nothing worked, copy into our internal pool */
|
||||
if (!wbuf) {
|
||||
GstVideoFrame src, dst;
|
||||
- GstVideoInfo src_info = self->video_info;
|
||||
-
|
||||
- /* rollback video info changes */
|
||||
- self->video_info = old_vinfo;
|
||||
|
||||
/* we don't know how to create a wl_buffer directly from the provided
|
||||
* memory, so we have to copy the data to shm memory that we know how
|
||||
@@ -886,7 +882,7 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
GST_MAP_WRITE))
|
||||
goto dst_map_failed;
|
||||
|
||||
- if (!gst_video_frame_map (&src, &src_info, buffer, GST_MAP_READ)) {
|
||||
+ if (!gst_video_frame_map (&src, &src_vinfo, buffer, GST_MAP_READ)) {
|
||||
gst_video_frame_unmap (&dst);
|
||||
goto src_map_failed;
|
||||
}
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
From baf873c06399c6ad6062cc1a96cc1b0bfc0edf3c Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Wed, 15 Feb 2023 12:34:27 -0500
|
||||
Subject: [PATCH 04/17] gtkwaylandsink: Force a redraw on resolution change
|
||||
|
||||
As we don't render into the widget directly, there is no "initial" draw
|
||||
happening. As a side effect, the internal aspect ratio adapted display
|
||||
width/height is never initialize leading to assertions when handling navigation
|
||||
events.
|
||||
|
||||
gst_video_center_rect: assertion 'src->h != 0' failed
|
||||
|
||||
Simply queue a redraw after setting the widget format in order to fix the issue.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index dc1e3c3..5288614 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -875,6 +875,12 @@ gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
return FALSE;
|
||||
}
|
||||
+
|
||||
+ /* Ensure queue_draw get executed and internal display size get initialized.
|
||||
+ * This does not happen otherwise as we don't draw in the widget
|
||||
+ */
|
||||
+ gtk_gst_base_widget_queue_draw (GTK_GST_BASE_WIDGET (priv->gtk_widget));
|
||||
+
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
priv->use_dmabuf = use_dmabuf;
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
From 9084a960a565ed80d34c41c7b0ab4f4a716a4f54 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Wed, 15 Feb 2023 13:11:36 -0500
|
||||
Subject: [PATCH] waylandsink: Let the baseclass know when frames are dropped
|
||||
|
||||
This is using the new GST_BASE_SINK_FLOW_DROPPED return value.
|
||||
With this change, fpsdisplaysink will properly report the
|
||||
render and dropped rate.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 2 ++
|
||||
ext/wayland/gstwaylandsink.c | 1 +
|
||||
2 files changed, 3 insertions(+)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 5288614bd7..acc32882ce 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -1006,6 +1006,7 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
if (!priv->wl_window) {
|
||||
GST_LOG_OBJECT (self,
|
||||
"buffer %" GST_PTR_FORMAT " dropped (waiting for window)", buffer);
|
||||
+ ret = GST_BASE_SINK_FLOW_DROPPED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -1013,6 +1014,7 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
if (priv->redraw_pending) {
|
||||
GST_LOG_OBJECT (self, "buffer %" GST_PTR_FORMAT " dropped (redraw pending)",
|
||||
buffer);
|
||||
+ ret = GST_BASE_SINK_FLOW_DROPPED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
||||
index 6dd0807820..bbbcb93932 100644
|
||||
--- a/ext/wayland/gstwaylandsink.c
|
||||
+++ b/ext/wayland/gstwaylandsink.c
|
||||
@@ -773,6 +773,7 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
if (self->redraw_pending) {
|
||||
GST_LOG_OBJECT (self, "buffer %" GST_PTR_FORMAT " dropped (redraw pending)",
|
||||
buffer);
|
||||
+ ret = GST_BASE_SINK_FLOW_DROPPED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
From 79405fb8592f22d62b4faa2f7098b814cc2a0d49 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Thu, 16 Feb 2023 13:54:42 -0500
|
||||
Subject: [PATCH 06/17] waylandsink: Refactor internal pool handling
|
||||
|
||||
This is to make it easier to support more then one allocators
|
||||
including falling back from one to another.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 101 +++++++++++++++++++++--------------
|
||||
ext/wayland/gstwaylandsink.c | 101 +++++++++++++++++++++--------------
|
||||
ext/wayland/gstwaylandsink.h | 1 +
|
||||
3 files changed, 124 insertions(+), 79 deletions(-)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 1afad32..8967d97 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -109,6 +109,7 @@ typedef struct _GstGtkWaylandSinkPrivate
|
||||
|
||||
gboolean video_info_changed;
|
||||
GstVideoInfo video_info;
|
||||
+ GstCaps *caps;
|
||||
|
||||
gboolean redraw_pending;
|
||||
GMutex render_lock;
|
||||
@@ -200,6 +201,7 @@ gst_gtk_wayland_sink_finalize (GObject * object)
|
||||
gst_gtk_wayland_sink_get_instance_private (self);
|
||||
|
||||
g_clear_object (&priv->gtk_widget);
|
||||
+ gst_clear_caps (&priv->caps);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
@@ -801,30 +803,57 @@ gst_gtk_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
|
||||
return caps;
|
||||
}
|
||||
|
||||
-static GstBufferPool *
|
||||
-gst_gtk_wayland_create_pool (GstGtkWaylandSink * self, GstCaps * caps)
|
||||
+static gboolean
|
||||
+gst_gtk_wayland_update_pool (GstGtkWaylandSink * self, GstAllocator * allocator)
|
||||
{
|
||||
GstGtkWaylandSinkPrivate *priv =
|
||||
gst_gtk_wayland_sink_get_instance_private (self);
|
||||
- GstBufferPool *pool = NULL;
|
||||
- GstStructure *structure;
|
||||
gsize size = priv->video_info.size;
|
||||
- GstAllocator *alloc;
|
||||
+ GstStructure *config;
|
||||
|
||||
- pool = gst_wl_video_buffer_pool_new ();
|
||||
+ /* Pools with outstanding buffer cannot be reconfigured, so we must use
|
||||
+ * a new pool. */
|
||||
+ if (priv->pool) {
|
||||
+ gst_buffer_pool_set_active (priv->pool, FALSE);
|
||||
+ gst_object_unref (priv->pool);
|
||||
+ }
|
||||
+ priv->pool = gst_wl_video_buffer_pool_new ();
|
||||
|
||||
- structure = gst_buffer_pool_get_config (pool);
|
||||
- gst_buffer_pool_config_set_params (structure, caps, size, 2, 0);
|
||||
+ config = gst_buffer_pool_get_config (priv->pool);
|
||||
+ gst_buffer_pool_config_set_params (config, priv->caps, size, 2, 0);
|
||||
+ gst_buffer_pool_config_set_allocator (config, allocator, NULL);
|
||||
|
||||
- alloc = gst_wl_shm_allocator_get ();
|
||||
- gst_buffer_pool_config_set_allocator (structure, alloc, NULL);
|
||||
- if (!gst_buffer_pool_set_config (pool, structure)) {
|
||||
- g_object_unref (pool);
|
||||
- pool = NULL;
|
||||
+ if (!gst_buffer_pool_set_config (priv->pool, config))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ return gst_buffer_pool_set_active (priv->pool, TRUE);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_gtk_wayland_activate_shm_pool (GstGtkWaylandSink * self)
|
||||
+{
|
||||
+ GstGtkWaylandSinkPrivate *priv =
|
||||
+ gst_gtk_wayland_sink_get_instance_private (self);
|
||||
+ GstAllocator *alloc = NULL;
|
||||
+
|
||||
+ if (priv->pool && gst_buffer_pool_is_active (priv->pool)) {
|
||||
+ GstStructure *config = gst_buffer_pool_get_config (priv->pool);
|
||||
+ gboolean is_shm = FALSE;
|
||||
+
|
||||
+ if (gst_buffer_pool_config_get_allocator (config, &alloc, NULL) && alloc)
|
||||
+ is_shm = GST_IS_WL_SHM_ALLOCATOR (alloc);
|
||||
+
|
||||
+ gst_structure_free (config);
|
||||
+
|
||||
+ if (is_shm)
|
||||
+ return TRUE;
|
||||
}
|
||||
- g_object_unref (alloc);
|
||||
|
||||
- return pool;
|
||||
+ alloc = gst_wl_shm_allocator_get ();
|
||||
+ gst_gtk_wayland_update_pool (self, alloc);
|
||||
+ gst_object_unref (alloc);
|
||||
+
|
||||
+ return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -845,10 +874,11 @@ gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
format = GST_VIDEO_INFO_FORMAT (&priv->video_info);
|
||||
priv->video_info_changed = TRUE;
|
||||
|
||||
- /* create a new pool for the new caps */
|
||||
- if (priv->pool)
|
||||
- gst_object_unref (priv->pool);
|
||||
- priv->pool = gst_gtk_wayland_create_pool (self, caps);
|
||||
+ /* free pooled buffer used with previous caps */
|
||||
+ if (priv->pool) {
|
||||
+ gst_buffer_pool_set_active (priv->pool, FALSE);
|
||||
+ gst_clear_object (&priv->pool);
|
||||
+ }
|
||||
|
||||
use_dmabuf = gst_caps_features_contains (gst_caps_get_features (caps, 0),
|
||||
GST_CAPS_FEATURE_MEMORY_DMABUF);
|
||||
@@ -884,6 +914,8 @@ gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
priv->use_dmabuf = use_dmabuf;
|
||||
+ /* Will be used to create buffer pools */
|
||||
+ gst_caps_replace (&priv->caps, caps);
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -914,8 +946,14 @@ gst_gtk_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
|
||||
|
||||
gst_query_parse_allocation (query, &caps, &need_pool);
|
||||
|
||||
- if (need_pool)
|
||||
- pool = gst_gtk_wayland_create_pool (self, caps);
|
||||
+ if (need_pool) {
|
||||
+ GstStructure *config;
|
||||
+ pool = gst_wl_video_buffer_pool_new ();
|
||||
+ config = gst_buffer_pool_get_config (pool);
|
||||
+ gst_buffer_pool_config_set_allocator (config,
|
||||
+ gst_wl_shm_allocator_get (), NULL);
|
||||
+ gst_buffer_pool_set_config (pool, config);
|
||||
+ }
|
||||
|
||||
gst_query_add_allocation_pool (query, pool, priv->video_info.size, 2, 0);
|
||||
if (pool)
|
||||
@@ -1077,25 +1115,10 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
"buffer %" GST_PTR_FORMAT " cannot have a wl_buffer, "
|
||||
"copying to wl_shm memory", buffer);
|
||||
|
||||
- /* priv->pool always exists (created in set_caps), but it may not
|
||||
- * be active if upstream is not using it */
|
||||
- if (!gst_buffer_pool_is_active (priv->pool)) {
|
||||
- GstStructure *config;
|
||||
- GstCaps *caps;
|
||||
|
||||
- config = gst_buffer_pool_get_config (priv->pool);
|
||||
- gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL);
|
||||
-
|
||||
- /* revert back to default strides and offsets */
|
||||
- gst_video_info_from_caps (&priv->video_info, caps);
|
||||
- gst_buffer_pool_config_set_params (config, caps, priv->video_info.size,
|
||||
- 2, 0);
|
||||
-
|
||||
- /* This is a video pool, it should not fail with basic settings */
|
||||
- if (!gst_buffer_pool_set_config (priv->pool, config) ||
|
||||
- !gst_buffer_pool_set_active (priv->pool, TRUE))
|
||||
- goto activate_failed;
|
||||
- }
|
||||
+ /* ensure the internal pool is configured for SHM */
|
||||
+ if (!gst_gtk_wayland_activate_shm_pool (self))
|
||||
+ goto activate_failed;
|
||||
|
||||
ret = gst_buffer_pool_acquire_buffer (priv->pool, &to_render, NULL);
|
||||
if (ret != GST_FLOW_OK)
|
||||
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
||||
index 7077ee9..b9b6267 100644
|
||||
--- a/ext/wayland/gstwaylandsink.c
|
||||
+++ b/ext/wayland/gstwaylandsink.c
|
||||
@@ -315,6 +315,8 @@ gst_wayland_sink_finalize (GObject * object)
|
||||
if (self->pool)
|
||||
gst_object_unref (self->pool);
|
||||
|
||||
+ gst_clear_caps (&self->caps);
|
||||
+
|
||||
g_free (self->display_name);
|
||||
|
||||
g_mutex_clear (&self->display_lock);
|
||||
@@ -578,28 +580,53 @@ gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
|
||||
return caps;
|
||||
}
|
||||
|
||||
-static GstBufferPool *
|
||||
-gst_wayland_create_pool (GstWaylandSink * self, GstCaps * caps)
|
||||
+static gboolean
|
||||
+gst_wayland_update_pool (GstWaylandSink * self, GstAllocator * allocator)
|
||||
{
|
||||
- GstBufferPool *pool = NULL;
|
||||
- GstStructure *structure;
|
||||
gsize size = self->video_info.size;
|
||||
- GstAllocator *alloc;
|
||||
+ GstStructure *config;
|
||||
|
||||
- pool = gst_wl_video_buffer_pool_new ();
|
||||
+ /* Pools with outstanding buffer cannot be reconfigured, so we must use
|
||||
+ * a new pool. */
|
||||
+ if (self->pool) {
|
||||
+ gst_buffer_pool_set_active (self->pool, FALSE);
|
||||
+ gst_object_unref (self->pool);
|
||||
+ }
|
||||
+ self->pool = gst_wl_video_buffer_pool_new ();
|
||||
|
||||
- structure = gst_buffer_pool_get_config (pool);
|
||||
- gst_buffer_pool_config_set_params (structure, caps, size, 2, 0);
|
||||
+ config = gst_buffer_pool_get_config (self->pool);
|
||||
+ gst_buffer_pool_config_set_params (config, self->caps, size, 2, 0);
|
||||
+ gst_buffer_pool_config_set_allocator (config, allocator, NULL);
|
||||
|
||||
- alloc = gst_wl_shm_allocator_get ();
|
||||
- gst_buffer_pool_config_set_allocator (structure, alloc, NULL);
|
||||
- if (!gst_buffer_pool_set_config (pool, structure)) {
|
||||
- g_object_unref (pool);
|
||||
- pool = NULL;
|
||||
+ if (!gst_buffer_pool_set_config (self->pool, config))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ return gst_buffer_pool_set_active (self->pool, TRUE);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_wayland_activate_shm_pool (GstWaylandSink * self)
|
||||
+{
|
||||
+ GstAllocator *alloc = NULL;
|
||||
+
|
||||
+ if (self->pool && gst_buffer_pool_is_active (self->pool)) {
|
||||
+ GstStructure *config = gst_buffer_pool_get_config (self->pool);
|
||||
+ gboolean is_shm = FALSE;
|
||||
+
|
||||
+ if (gst_buffer_pool_config_get_allocator (config, &alloc, NULL) && alloc)
|
||||
+ is_shm = GST_IS_WL_SHM_ALLOCATOR (alloc);
|
||||
+
|
||||
+ gst_structure_free (config);
|
||||
+
|
||||
+ if (is_shm)
|
||||
+ return TRUE;
|
||||
}
|
||||
- g_object_unref (alloc);
|
||||
|
||||
- return pool;
|
||||
+ alloc = gst_wl_shm_allocator_get ();
|
||||
+ gst_wayland_update_pool (self, alloc);
|
||||
+ gst_object_unref (alloc);
|
||||
+
|
||||
+ return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -618,10 +645,11 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
format = GST_VIDEO_INFO_FORMAT (&self->video_info);
|
||||
self->video_info_changed = TRUE;
|
||||
|
||||
- /* create a new pool for the new caps */
|
||||
- if (self->pool)
|
||||
- gst_object_unref (self->pool);
|
||||
- self->pool = gst_wayland_create_pool (self, caps);
|
||||
+ /* free pooled buffer used with previous caps */
|
||||
+ if (self->pool) {
|
||||
+ gst_buffer_pool_set_active (self->pool, FALSE);
|
||||
+ gst_clear_object (&self->pool);
|
||||
+ }
|
||||
|
||||
use_dmabuf = gst_caps_features_contains (gst_caps_get_features (caps, 0),
|
||||
GST_CAPS_FEATURE_MEMORY_DMABUF);
|
||||
@@ -639,6 +667,9 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
|
||||
self->use_dmabuf = use_dmabuf;
|
||||
|
||||
+ /* Will be used to create buffer pools */
|
||||
+ gst_caps_replace (&self->caps, caps);
|
||||
+
|
||||
return TRUE;
|
||||
|
||||
invalid_format:
|
||||
@@ -666,8 +697,14 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
|
||||
|
||||
gst_query_parse_allocation (query, &caps, &need_pool);
|
||||
|
||||
- if (need_pool)
|
||||
- pool = gst_wayland_create_pool (self, caps);
|
||||
+ if (need_pool) {
|
||||
+ GstStructure *config;
|
||||
+ pool = gst_wl_video_buffer_pool_new ();
|
||||
+ config = gst_buffer_pool_get_config (pool);
|
||||
+ gst_buffer_pool_config_set_allocator (config,
|
||||
+ gst_wl_shm_allocator_get (), NULL);
|
||||
+ gst_buffer_pool_set_config (pool, config);
|
||||
+ }
|
||||
|
||||
gst_query_add_allocation_pool (query, pool, self->video_info.size, 2, 0);
|
||||
if (pool)
|
||||
@@ -844,25 +881,9 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
"buffer %" GST_PTR_FORMAT " cannot have a wl_buffer, "
|
||||
"copying to wl_shm memory", buffer);
|
||||
|
||||
- /* self->pool always exists (created in set_caps), but it may not
|
||||
- * be active if upstream is not using it */
|
||||
- if (!gst_buffer_pool_is_active (self->pool)) {
|
||||
- GstStructure *config;
|
||||
- GstCaps *caps;
|
||||
-
|
||||
- config = gst_buffer_pool_get_config (self->pool);
|
||||
- gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL);
|
||||
-
|
||||
- /* revert back to default strides and offsets */
|
||||
- gst_video_info_from_caps (&self->video_info, caps);
|
||||
- gst_buffer_pool_config_set_params (config, caps, self->video_info.size,
|
||||
- 2, 0);
|
||||
-
|
||||
- /* This is a video pool, it should not fail with basic settings */
|
||||
- if (!gst_buffer_pool_set_config (self->pool, config) ||
|
||||
- !gst_buffer_pool_set_active (self->pool, TRUE))
|
||||
- goto activate_failed;
|
||||
- }
|
||||
+ /* ensure the internal pool is configured for SHM */
|
||||
+ if (!gst_wayland_activate_shm_pool (self))
|
||||
+ goto activate_failed;
|
||||
|
||||
ret = gst_buffer_pool_acquire_buffer (self->pool, &to_render, NULL);
|
||||
if (ret != GST_FLOW_OK)
|
||||
diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h
|
||||
index 3243d8c..1ff50d1 100644
|
||||
--- a/ext/wayland/gstwaylandsink.h
|
||||
+++ b/ext/wayland/gstwaylandsink.h
|
||||
@@ -56,6 +56,7 @@ struct _GstWaylandSink
|
||||
gboolean video_info_changed;
|
||||
GstVideoInfo video_info;
|
||||
gboolean fullscreen;
|
||||
+ GstCaps *caps;
|
||||
|
||||
gchar *display_name;
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
From 60b5f9809703c6668e566a8133b000ec2c3c0dfc Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Thu, 16 Feb 2023 14:31:10 -0500
|
||||
Subject: [PATCH 07/17] gtkwaylandsink: Fix display/wl_window/pool leaks
|
||||
|
||||
These were leaked in the GTK implementation of the sink.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 8967d97..0c74a91 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -200,6 +200,10 @@ gst_gtk_wayland_sink_finalize (GObject * object)
|
||||
GstGtkWaylandSinkPrivate *priv =
|
||||
gst_gtk_wayland_sink_get_instance_private (self);
|
||||
|
||||
+ g_clear_object (&priv->display);
|
||||
+ g_clear_object (&priv->wl_window);
|
||||
+ g_clear_object (&priv->pool);
|
||||
+
|
||||
g_clear_object (&priv->gtk_widget);
|
||||
gst_clear_caps (&priv->caps);
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
From 38ee1f8e97429506db0ca9c0c2ac61da4f00ba5d Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Thu, 16 Feb 2023 21:12:08 -0500
|
||||
Subject: [PATCH 08/17] wllinuxdmabuf: Handle video meta inside the importer
|
||||
|
||||
This allow simplifying the GstVideoInfo handling in the sinks. Instead
|
||||
of having to update a video info for the import, the sink can simply pass the
|
||||
video info associated with the caps and rely on the VideoMeta in the GstBuffer
|
||||
to obtain the appropriate offset and stride.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 22 ++++------------------
|
||||
ext/wayland/gstwaylandsink.c | 18 ++----------------
|
||||
gst-libs/gst/wayland/gstwllinuxdmabuf.c | 13 +++++++++++--
|
||||
3 files changed, 17 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 0c74a91..c46207c 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -1028,9 +1028,7 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
gst_gtk_wayland_sink_get_instance_private (self);
|
||||
GstBuffer *to_render;
|
||||
GstWlBuffer *wlbuffer;
|
||||
- GstVideoMeta *vmeta;
|
||||
GstVideoFormat format;
|
||||
- GstVideoInfo src_vinfo;
|
||||
GstMemory *mem;
|
||||
struct wl_buffer *wbuf = NULL;
|
||||
|
||||
@@ -1073,23 +1071,11 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
/* update video info from video meta */
|
||||
mem = gst_buffer_peek_memory (buffer, 0);
|
||||
|
||||
- src_vinfo = priv->video_info;
|
||||
- vmeta = gst_buffer_get_video_meta (buffer);
|
||||
- if (vmeta) {
|
||||
- gint i;
|
||||
-
|
||||
- for (i = 0; i < vmeta->n_planes; i++) {
|
||||
- src_vinfo.offset[i] = vmeta->offset[i];
|
||||
- src_vinfo.stride[i] = vmeta->stride[i];
|
||||
- }
|
||||
- src_vinfo.size = gst_buffer_get_size (buffer);
|
||||
- }
|
||||
-
|
||||
GST_LOG_OBJECT (self,
|
||||
"buffer %" GST_PTR_FORMAT " does not have a wl_buffer from our "
|
||||
"display, creating it", buffer);
|
||||
|
||||
- format = GST_VIDEO_INFO_FORMAT (&src_vinfo);
|
||||
+ format = GST_VIDEO_INFO_FORMAT (&priv->video_info);
|
||||
if (gst_wl_display_check_format_for_dmabuf (priv->display, format)) {
|
||||
guint i, nb_dmabuf = 0;
|
||||
|
||||
@@ -1099,13 +1085,13 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
|
||||
if (nb_dmabuf && (nb_dmabuf == gst_buffer_n_memory (buffer)))
|
||||
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, priv->display,
|
||||
- &src_vinfo);
|
||||
+ &priv->video_info);
|
||||
}
|
||||
|
||||
if (!wbuf && gst_wl_display_check_format_for_shm (priv->display, format)) {
|
||||
if (gst_buffer_n_memory (buffer) == 1 && gst_is_fd_memory (mem))
|
||||
wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, priv->display,
|
||||
- &src_vinfo);
|
||||
+ &priv->video_info);
|
||||
|
||||
/* If nothing worked, copy into our internal pool */
|
||||
if (!wbuf) {
|
||||
@@ -1146,7 +1132,7 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
GST_MAP_WRITE))
|
||||
goto dst_map_failed;
|
||||
|
||||
- if (!gst_video_frame_map (&src, &src_vinfo, buffer, GST_MAP_READ)) {
|
||||
+ if (!gst_video_frame_map (&src, &priv->video_info, buffer, GST_MAP_READ)) {
|
||||
gst_video_frame_unmap (&dst);
|
||||
goto src_map_failed;
|
||||
}
|
||||
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
||||
index b9b6267..aa39447 100644
|
||||
--- a/ext/wayland/gstwaylandsink.c
|
||||
+++ b/ext/wayland/gstwaylandsink.c
|
||||
@@ -779,9 +779,7 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
GstWaylandSink *self = GST_WAYLAND_SINK (vsink);
|
||||
GstBuffer *to_render;
|
||||
GstWlBuffer *wlbuffer;
|
||||
- GstVideoMeta *vmeta;
|
||||
GstVideoFormat format;
|
||||
- GstVideoInfo src_vinfo;
|
||||
GstMemory *mem;
|
||||
struct wl_buffer *wbuf = NULL;
|
||||
|
||||
@@ -835,18 +833,6 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
/* update video info from video meta */
|
||||
mem = gst_buffer_peek_memory (buffer, 0);
|
||||
|
||||
- src_vinfo = self->video_info;
|
||||
- vmeta = gst_buffer_get_video_meta (buffer);
|
||||
- if (vmeta) {
|
||||
- gint i;
|
||||
-
|
||||
- for (i = 0; i < vmeta->n_planes; i++) {
|
||||
- src_vinfo.offset[i] = vmeta->offset[i];
|
||||
- src_vinfo.stride[i] = vmeta->stride[i];
|
||||
- }
|
||||
- src_vinfo.size = gst_buffer_get_size (buffer);
|
||||
- }
|
||||
-
|
||||
GST_LOG_OBJECT (self,
|
||||
"buffer %" GST_PTR_FORMAT " does not have a wl_buffer from our "
|
||||
"display, creating it", buffer);
|
||||
@@ -861,7 +847,7 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
|
||||
if (nb_dmabuf && (nb_dmabuf == gst_buffer_n_memory (buffer)))
|
||||
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, self->display,
|
||||
- &src_vinfo);
|
||||
+ &self->video_info);
|
||||
}
|
||||
|
||||
if (!wbuf && gst_wl_display_check_format_for_shm (self->display, format)) {
|
||||
@@ -907,7 +893,7 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
GST_MAP_WRITE))
|
||||
goto dst_map_failed;
|
||||
|
||||
- if (!gst_video_frame_map (&src, &src_vinfo, buffer, GST_MAP_READ)) {
|
||||
+ if (!gst_video_frame_map (&src, &self->video_info, buffer, GST_MAP_READ)) {
|
||||
gst_video_frame_unmap (&dst);
|
||||
goto src_map_failed;
|
||||
}
|
||||
diff --git a/gst-libs/gst/wayland/gstwllinuxdmabuf.c b/gst-libs/gst/wayland/gstwllinuxdmabuf.c
|
||||
index d6ee6ec..4b33d05 100644
|
||||
--- a/gst-libs/gst/wayland/gstwllinuxdmabuf.c
|
||||
+++ b/gst-libs/gst/wayland/gstwllinuxdmabuf.c
|
||||
@@ -88,6 +88,9 @@ gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf,
|
||||
GstMemory *mem;
|
||||
int format;
|
||||
guint i, width, height;
|
||||
+ const gsize *offsets = info->offset;
|
||||
+ const gint *strides = info->stride;
|
||||
+ GstVideoMeta *vmeta;
|
||||
guint nplanes, flags = 0;
|
||||
struct zwp_linux_buffer_params_v1 *params;
|
||||
gint64 timeout;
|
||||
@@ -107,6 +110,12 @@ gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf,
|
||||
height = GST_VIDEO_INFO_HEIGHT (info);
|
||||
nplanes = GST_VIDEO_INFO_N_PLANES (info);
|
||||
|
||||
+ vmeta = gst_buffer_get_video_meta (buf);
|
||||
+ if (vmeta) {
|
||||
+ offsets = vmeta->offset;
|
||||
+ strides = vmeta->stride;
|
||||
+ }
|
||||
+
|
||||
GST_DEBUG_OBJECT (display, "Creating wl_buffer from DMABuf of size %"
|
||||
G_GSSIZE_FORMAT " (%d x %d), format %s", info->size, width, height,
|
||||
gst_wl_dmabuf_format_to_string (format));
|
||||
@@ -119,8 +128,8 @@ gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf,
|
||||
guint offset, stride, mem_idx, length;
|
||||
gsize skip;
|
||||
|
||||
- offset = GST_VIDEO_INFO_PLANE_OFFSET (info, i);
|
||||
- stride = GST_VIDEO_INFO_PLANE_STRIDE (info, i);
|
||||
+ offset = offsets[i];
|
||||
+ stride = strides[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);
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
From d9b34f66193a5a4ac60df33ec80e0da76d197fe4 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Fri, 17 Feb 2023 09:42:42 -0500
|
||||
Subject: [PATCH 09/17] wlvideoformat: Fix sign issue for DRM fourcc
|
||||
|
||||
DRM fourcc ared defined as 32bit unsigned in, but the format helper was passing
|
||||
an int, while using a unsigned int internally. This is a API/ABI break, but
|
||||
the API is still unstable.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
gst-libs/gst/wayland/gstwldisplay.c | 2 +-
|
||||
gst-libs/gst/wayland/gstwllinuxdmabuf.c | 4 ++--
|
||||
gst-libs/gst/wayland/gstwlvideoformat.c | 6 +++---
|
||||
gst-libs/gst/wayland/gstwlvideoformat.h | 2 +-
|
||||
4 files changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/gst-libs/gst/wayland/gstwldisplay.c b/gst-libs/gst/wayland/gstwldisplay.c
|
||||
index 1f83cb2..a9da274 100644
|
||||
--- a/gst-libs/gst/wayland/gstwldisplay.c
|
||||
+++ b/gst-libs/gst/wayland/gstwldisplay.c
|
||||
@@ -226,7 +226,7 @@ gst_wl_display_check_format_for_dmabuf (GstWlDisplay * self,
|
||||
return FALSE;
|
||||
|
||||
dmabuf_fmt = gst_video_format_to_wl_dmabuf_format (format);
|
||||
- if (dmabuf_fmt == (guint) - 1)
|
||||
+ if (!dmabuf_fmt)
|
||||
return FALSE;
|
||||
|
||||
formats = priv->dmabuf_formats;
|
||||
diff --git a/gst-libs/gst/wayland/gstwllinuxdmabuf.c b/gst-libs/gst/wayland/gstwllinuxdmabuf.c
|
||||
index 4b33d05..deb5d32 100644
|
||||
--- a/gst-libs/gst/wayland/gstwllinuxdmabuf.c
|
||||
+++ b/gst-libs/gst/wayland/gstwllinuxdmabuf.c
|
||||
@@ -175,8 +175,8 @@ out:
|
||||
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);
|
||||
+ "%dx%d, fmt=%" GST_FOURCC_FORMAT ", %d planes",
|
||||
+ data.wbuf, width, height, GST_FOURCC_ARGS (format), nplanes);
|
||||
}
|
||||
|
||||
g_mutex_unlock (&data.lock);
|
||||
diff --git a/gst-libs/gst/wayland/gstwlvideoformat.c b/gst-libs/gst/wayland/gstwlvideoformat.c
|
||||
index 44a9536..49d927a 100644
|
||||
--- a/gst-libs/gst/wayland/gstwlvideoformat.c
|
||||
+++ b/gst-libs/gst/wayland/gstwlvideoformat.c
|
||||
@@ -48,7 +48,7 @@ gst_wl_videoformat_init_once (void)
|
||||
typedef struct
|
||||
{
|
||||
enum wl_shm_format wl_shm_format;
|
||||
- guint dma_format;
|
||||
+ guint32 dma_format;
|
||||
GstVideoFormat gst_format;
|
||||
} wl_VideoFormat;
|
||||
|
||||
@@ -96,7 +96,7 @@ gst_video_format_to_wl_shm_format (GstVideoFormat format)
|
||||
return -1;
|
||||
}
|
||||
|
||||
-gint
|
||||
+guint32
|
||||
gst_video_format_to_wl_dmabuf_format (GstVideoFormat format)
|
||||
{
|
||||
guint i;
|
||||
@@ -106,7 +106,7 @@ gst_video_format_to_wl_dmabuf_format (GstVideoFormat format)
|
||||
return wl_formats[i].dma_format;
|
||||
|
||||
GST_WARNING ("wayland dmabuf video format not found");
|
||||
- return -1;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
GstVideoFormat
|
||||
diff --git a/gst-libs/gst/wayland/gstwlvideoformat.h b/gst-libs/gst/wayland/gstwlvideoformat.h
|
||||
index bc36a08..bbacde3 100644
|
||||
--- a/gst-libs/gst/wayland/gstwlvideoformat.h
|
||||
+++ b/gst-libs/gst/wayland/gstwlvideoformat.h
|
||||
@@ -36,7 +36,7 @@ GST_WL_API
|
||||
enum wl_shm_format gst_video_format_to_wl_shm_format (GstVideoFormat format);
|
||||
|
||||
GST_WL_API
|
||||
-gint gst_video_format_to_wl_dmabuf_format (GstVideoFormat format);
|
||||
+guint32 gst_video_format_to_wl_dmabuf_format (GstVideoFormat format);
|
||||
|
||||
GST_WL_API
|
||||
GstVideoFormat gst_wl_shm_format_to_video_format (enum wl_shm_format wl_format);
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
From c5c879049ee10ff0f1a54b90cbb317bca09933a6 Mon Sep 17 00:00:00 2001
|
||||
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
Date: Wed, 29 Mar 2023 13:09:09 +0200
|
||||
Subject: [PATCH 10/17] wlvideobufferpool: Add DRM Dumb buffer support
|
||||
|
||||
This allow the wayland buffer pool to use a GstDRMDumbAllocator
|
||||
if it has been configured to do so.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
gst-libs/gst/wayland/gstwlvideobufferpool.c | 200 +++++++++++++++++++-
|
||||
gst-libs/gst/wayland/gstwlvideobufferpool.h | 10 +-
|
||||
2 files changed, 200 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/gst-libs/gst/wayland/gstwlvideobufferpool.c b/gst-libs/gst/wayland/gstwlvideobufferpool.c
|
||||
index b367d9f..3292056 100644
|
||||
--- a/gst-libs/gst/wayland/gstwlvideobufferpool.c
|
||||
+++ b/gst-libs/gst/wayland/gstwlvideobufferpool.c
|
||||
@@ -24,8 +24,198 @@
|
||||
|
||||
#include "gstwlvideobufferpool.h"
|
||||
|
||||
-G_DEFINE_TYPE (GstWlVideoBufferPool, gst_wl_video_buffer_pool,
|
||||
- GST_TYPE_VIDEO_BUFFER_POOL);
|
||||
+#include <gst/allocators/allocators.h>
|
||||
+#include <drm_fourcc.h>
|
||||
+
|
||||
+GST_DEBUG_CATEGORY (gst_wl_videobufferpool_debug);
|
||||
+#define GST_CAT_DEFAULT gst_wl_videobufferpool_debug
|
||||
+
|
||||
+struct _GstWlVideoBufferPool
|
||||
+{
|
||||
+ GstVideoBufferPool parent;
|
||||
+ GstAllocator *allocator;
|
||||
+ GstVideoInfo vinfo;
|
||||
+};
|
||||
+
|
||||
+#define gst_wl_video_buffer_pool_parent_class parent_class
|
||||
+G_DEFINE_TYPE_WITH_CODE (GstWlVideoBufferPool, gst_wl_video_buffer_pool,
|
||||
+ GST_TYPE_VIDEO_BUFFER_POOL,
|
||||
+ GST_DEBUG_CATEGORY_INIT (gst_wl_videobufferpool_debug,
|
||||
+ "wl_videobufferpool", 0, "wl_dmabuf library"));
|
||||
+
|
||||
+static void
|
||||
+gst_wl_update_video_info_from_pitch (GstVideoInfo * vinfo, gint n_planes,
|
||||
+ guint32 pitch)
|
||||
+{
|
||||
+ gint i;
|
||||
+ gsize offs = 0;
|
||||
+ guint32 height = GST_VIDEO_INFO_HEIGHT (vinfo);
|
||||
+
|
||||
+ if (!pitch)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 0; i < n_planes; i++) {
|
||||
+ guint32 plane_pitch;
|
||||
+
|
||||
+ /* Overwrite the video info's stride and offset using the pitch calculcated
|
||||
+ * by the kms driver. */
|
||||
+ plane_pitch = gst_video_format_info_extrapolate_stride (vinfo->finfo, i,
|
||||
+ pitch);
|
||||
+ GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i) = plane_pitch;
|
||||
+ GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i) = offs;
|
||||
+
|
||||
+ /* Note that we cannot negotiate special padding betweem each planes,
|
||||
+ * hence using the display height here. */
|
||||
+ offs += plane_pitch
|
||||
+ * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, height);
|
||||
+
|
||||
+ GST_DEBUG ("Updated plane %i with stride %i and "
|
||||
+ "offset %" G_GSIZE_FORMAT "(from pitch %u)", i,
|
||||
+ GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i),
|
||||
+ GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i), pitch);
|
||||
+ }
|
||||
+
|
||||
+ /* Update with the size use for display, excluding any padding at the end */
|
||||
+ GST_VIDEO_INFO_SIZE (vinfo) = offs;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_wl_video_buffer_pool_start (GstBufferPool * pool)
|
||||
+{
|
||||
+ GstWlVideoBufferPool *self = GST_WL_VIDEO_BUFFER_POOL (pool);
|
||||
+ GstStructure *config = gst_buffer_pool_get_config (pool);
|
||||
+ GstCaps *caps;
|
||||
+ GstAllocator *allocator;
|
||||
+ gboolean ret = FALSE;
|
||||
+ GstVideoFormat format;
|
||||
+
|
||||
+ if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
|
||||
+ goto wrong_config;
|
||||
+
|
||||
+ if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
|
||||
+ goto wrong_config;
|
||||
+
|
||||
+ /* now parse the caps from the config */
|
||||
+ if (!gst_video_info_from_caps (&self->vinfo, caps))
|
||||
+ goto wrong_caps;
|
||||
+
|
||||
+ format = GST_VIDEO_INFO_FORMAT (&self->vinfo);
|
||||
+ if (!gst_video_format_to_wl_dmabuf_format (format))
|
||||
+ goto unsupported_pixel_format;
|
||||
+
|
||||
+ if (GST_IS_DRM_DUMB_ALLOCATOR (allocator)) {
|
||||
+ if (!gst_drm_dumb_allocator_has_prime_export (allocator))
|
||||
+ goto no_prime_export;
|
||||
+
|
||||
+ self->allocator = gst_object_ref (allocator);
|
||||
+ }
|
||||
+
|
||||
+ /* all good */
|
||||
+ ret = GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
|
||||
+
|
||||
+done:
|
||||
+ gst_structure_free (config);
|
||||
+ return ret;
|
||||
+
|
||||
+wrong_config:
|
||||
+ {
|
||||
+ GST_WARNING_OBJECT (pool, "invalid config");
|
||||
+ goto done;
|
||||
+ }
|
||||
+wrong_caps:
|
||||
+ {
|
||||
+ GST_WARNING_OBJECT (pool,
|
||||
+ "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
|
||||
+ goto done;
|
||||
+ }
|
||||
+unsupported_pixel_format:
|
||||
+ {
|
||||
+ GST_WARNING_OBJECT (pool, "no support for %s pixel format",
|
||||
+ gst_video_format_to_string (format));
|
||||
+ goto done;
|
||||
+ }
|
||||
+no_prime_export:
|
||||
+ {
|
||||
+ GST_WARNING_OBJECT (self,
|
||||
+ "not using DRM Dumb allocator as it can't export DMABuf.");
|
||||
+ goto done;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_wl_video_buffer_pool_stop (GstBufferPool * pool)
|
||||
+{
|
||||
+ GstWlVideoBufferPool *self = GST_WL_VIDEO_BUFFER_POOL (pool);
|
||||
+ gst_clear_object (&self->allocator);
|
||||
+ gst_video_info_init (&self->vinfo);
|
||||
+ return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
|
||||
+}
|
||||
+
|
||||
+static GstFlowReturn
|
||||
+gst_wl_video_buffer_pool_alloc_buffer (GstBufferPool * pool,
|
||||
+ GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
|
||||
+{
|
||||
+ GstWlVideoBufferPool *self = GST_WL_VIDEO_BUFFER_POOL (pool);
|
||||
+ guint32 pitch;
|
||||
+ GstBuffer *buf;
|
||||
+ GstMemory *drm_mem, *dma_mem;
|
||||
+ gsize dumbbuf_size;
|
||||
+ GstVideoFormat format = GST_VIDEO_INFO_FORMAT (&self->vinfo);
|
||||
+ guint32 drm_fourcc = gst_video_format_to_wl_dmabuf_format (format);
|
||||
+
|
||||
+ if (!self->allocator)
|
||||
+ return GST_BUFFER_POOL_CLASS (parent_class)->alloc_buffer (pool, buffer,
|
||||
+ params);
|
||||
+
|
||||
+ drm_mem = gst_drm_dumb_allocator_alloc (self->allocator,
|
||||
+ drm_fourcc, GST_VIDEO_INFO_WIDTH (&self->vinfo),
|
||||
+ GST_VIDEO_INFO_HEIGHT (&self->vinfo), &pitch);
|
||||
+ if (!drm_mem)
|
||||
+ goto alloc_failed;
|
||||
+
|
||||
+ dma_mem = gst_drm_dumb_memory_export_dmabuf (drm_mem);
|
||||
+
|
||||
+ gst_memory_unref (drm_mem);
|
||||
+ drm_mem = NULL;
|
||||
+
|
||||
+ gst_wl_update_video_info_from_pitch (&self->vinfo,
|
||||
+ GST_VIDEO_INFO_N_PLANES (&self->vinfo), pitch);
|
||||
+
|
||||
+ gst_memory_get_sizes (dma_mem, NULL, &dumbbuf_size);
|
||||
+ if (dumbbuf_size < GST_VIDEO_INFO_SIZE (&self->vinfo)) {
|
||||
+ GST_ERROR_OBJECT (self,
|
||||
+ "DUMB buffer has a size of %" G_GSIZE_FORMAT
|
||||
+ " but we require at least %" G_GSIZE_FORMAT " to hold a frame",
|
||||
+ dumbbuf_size, GST_VIDEO_INFO_SIZE (&self->vinfo));
|
||||
+ goto buffer_too_small;
|
||||
+ }
|
||||
+
|
||||
+ gst_memory_resize (dma_mem, 0, GST_VIDEO_INFO_SIZE (&self->vinfo));
|
||||
+
|
||||
+ buf = gst_buffer_new ();
|
||||
+ gst_buffer_append_memory (buf, dma_mem);
|
||||
+ gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
|
||||
+ GST_VIDEO_INFO_FORMAT (&self->vinfo), GST_VIDEO_INFO_WIDTH (&self->vinfo),
|
||||
+ GST_VIDEO_INFO_HEIGHT (&self->vinfo),
|
||||
+ GST_VIDEO_INFO_N_PLANES (&self->vinfo),
|
||||
+ self->vinfo.offset, self->vinfo.stride);
|
||||
+
|
||||
+ *buffer = buf;
|
||||
+
|
||||
+ return GST_FLOW_OK;
|
||||
+
|
||||
+ /* ERRORS */
|
||||
+alloc_failed:
|
||||
+ {
|
||||
+ GST_ERROR_OBJECT (self, "failed to allocate DRM Dumb buffer.");
|
||||
+ return GST_FLOW_ERROR;
|
||||
+ }
|
||||
+buffer_too_small:
|
||||
+ {
|
||||
+ GST_ERROR_OBJECT (self, "dumb buffer too small to store an image.");
|
||||
+ return GST_FLOW_ERROR;
|
||||
+ }
|
||||
+}
|
||||
|
||||
static const gchar **
|
||||
gst_wl_video_buffer_pool_get_options (GstBufferPool * pool)
|
||||
@@ -39,11 +229,15 @@ gst_wl_video_buffer_pool_class_init (GstWlVideoBufferPoolClass * klass)
|
||||
{
|
||||
GstBufferPoolClass *pool_class = GST_BUFFER_POOL_CLASS (klass);
|
||||
pool_class->get_options = gst_wl_video_buffer_pool_get_options;
|
||||
+ pool_class->start = gst_wl_video_buffer_pool_start;
|
||||
+ pool_class->stop = gst_wl_video_buffer_pool_stop;
|
||||
+ pool_class->alloc_buffer = gst_wl_video_buffer_pool_alloc_buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
-gst_wl_video_buffer_pool_init (GstWlVideoBufferPool * pool)
|
||||
+gst_wl_video_buffer_pool_init (GstWlVideoBufferPool * self)
|
||||
{
|
||||
+ gst_video_info_init (&self->vinfo);
|
||||
}
|
||||
|
||||
GstBufferPool *
|
||||
diff --git a/gst-libs/gst/wayland/gstwlvideobufferpool.h b/gst-libs/gst/wayland/gstwlvideobufferpool.h
|
||||
index 297afbc..fe04186 100644
|
||||
--- a/gst-libs/gst/wayland/gstwlvideobufferpool.h
|
||||
+++ b/gst-libs/gst/wayland/gstwlvideobufferpool.h
|
||||
@@ -26,20 +26,16 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
-/* A tiny GstVideoBufferPool subclass that modify the options to remove
|
||||
+/* A GstVideoBufferPool subclass that modify the options to remove
|
||||
* VideoAlignment. To support VideoAlignment we would need to pass the padded
|
||||
* width/height + stride and use the viewporter interface to crop, a bit like
|
||||
* we use to do with XV. It would still be quite limited. It's a bit retro,
|
||||
- * hopefully there will be a better Wayland interface in the future. */
|
||||
+ * hopefully there will be a better Wayland interface in the future. This buffer
|
||||
+ * pool also support GstDRMDumbAllocator. */
|
||||
|
||||
#define GST_TYPE_WL_VIDEO_BUFFER_POOL (gst_wl_video_buffer_pool_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GstWlVideoBufferPool, gst_wl_video_buffer_pool, GST, WL_VIDEO_BUFFER_POOL, GstVideoBufferPool);
|
||||
|
||||
-struct _GstWlVideoBufferPool
|
||||
-{
|
||||
- GstVideoBufferPool parent;
|
||||
-};
|
||||
-
|
||||
GST_WL_API
|
||||
GstBufferPool * gst_wl_video_buffer_pool_new (void);
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,411 @@
|
||||
From d5807fc0840117a8472922d69df76ddebf633325 Mon Sep 17 00:00:00 2001
|
||||
From: Colin Kinloch <colin.kinloch@collabora.com>
|
||||
Date: Thu, 16 Feb 2023 16:21:33 -0500
|
||||
Subject: [PATCH 11/17] wayladnsink: Add DRM Dumb allocator support
|
||||
|
||||
If the input is not a DMABuf, attempt to copy into a DRM Dumb
|
||||
buffer and import it has a DMABuf. This will offload the
|
||||
compositor from actually doing this copy (needed to handle SHM)
|
||||
and may allow the software decoded stream to be rendered to
|
||||
an HW layer, or even reach through some better accelerated
|
||||
GL import path.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 121 ++++++++++++++++++++++++++++++++++-
|
||||
ext/wayland/gstwaylandsink.c | 110 +++++++++++++++++++++++++++++++
|
||||
ext/wayland/gstwaylandsink.h | 3 +
|
||||
3 files changed, 233 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index c46207c..438294b 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -87,7 +87,8 @@ enum
|
||||
PROP_0,
|
||||
PROP_WIDGET,
|
||||
PROP_DISPLAY,
|
||||
- PROP_ROTATE_METHOD
|
||||
+ PROP_ROTATE_METHOD,
|
||||
+ PROP_DRM_DEVICE,
|
||||
};
|
||||
|
||||
typedef struct _GstGtkWaylandSinkPrivate
|
||||
@@ -119,6 +120,9 @@ typedef struct _GstGtkWaylandSinkPrivate
|
||||
GstVideoOrientationMethod current_rotate_method;
|
||||
|
||||
struct wl_callback *callback;
|
||||
+
|
||||
+ gchar *drm_device;
|
||||
+ gboolean skip_dumb_buffer_copy;
|
||||
} GstGtkWaylandSinkPrivate;
|
||||
|
||||
#define gst_gtk_wayland_sink_parent_class parent_class
|
||||
@@ -161,6 +165,17 @@ gst_gtk_wayland_sink_class_init (GstGtkWaylandSinkClass * klass)
|
||||
GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
+ /**
|
||||
+ * GstGtkWaylandSink:drm-device:
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+ g_object_class_install_property (gobject_class, PROP_DRM_DEVICE,
|
||||
+ g_param_spec_string ("drm-device", "DRM Device", "Path of the "
|
||||
+ "DRM device to use for dumb buffer allocation",
|
||||
+ NULL,
|
||||
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
|
||||
+
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_gtk_wayland_sink_change_state);
|
||||
|
||||
@@ -207,6 +222,8 @@ gst_gtk_wayland_sink_finalize (GObject * object)
|
||||
g_clear_object (&priv->gtk_widget);
|
||||
gst_clear_caps (&priv->caps);
|
||||
|
||||
+ g_free (priv->drm_device);
|
||||
+
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -379,6 +396,11 @@ gst_gtk_wayland_sink_get_property (GObject * object, guint prop_id,
|
||||
case PROP_ROTATE_METHOD:
|
||||
g_value_set_enum (value, priv->current_rotate_method);
|
||||
break;
|
||||
+ case PROP_DRM_DEVICE:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ g_value_set_string (value, priv->drm_device);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -390,12 +412,19 @@ gst_gtk_wayland_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstGtkWaylandSink *self = GST_GTK_WAYLAND_SINK (object);
|
||||
+ GstGtkWaylandSinkPrivate *priv =
|
||||
+ gst_gtk_wayland_sink_get_instance_private (self);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_ROTATE_METHOD:
|
||||
gst_gtk_wayland_sink_set_rotate_method (self, g_value_get_enum (value),
|
||||
FALSE);
|
||||
break;
|
||||
+ case PROP_DRM_DEVICE:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ priv->drm_device = g_value_dup_string (value);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -710,6 +739,8 @@ gst_gtk_wayland_sink_change_state (GstElement * element,
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
+ g_clear_object (&priv->pool);
|
||||
+ /* fallthrough */
|
||||
case GST_STATE_CHANGE_NULL_TO_NULL:
|
||||
gst_gtk_invoke_on_main ((GThreadFunc)
|
||||
gst_gtk_wayland_sink_stop_on_main, element);
|
||||
@@ -860,6 +891,41 @@ gst_gtk_wayland_activate_shm_pool (GstGtkWaylandSink * self)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+gst_gtk_wayland_activate_drm_dumb_pool (GstGtkWaylandSink * self)
|
||||
+{
|
||||
+ GstGtkWaylandSinkPrivate *priv =
|
||||
+ gst_gtk_wayland_sink_get_instance_private (self);
|
||||
+ GstAllocator *alloc;
|
||||
+
|
||||
+ if (!priv->drm_device)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (priv->pool && gst_buffer_pool_is_active (priv->pool)) {
|
||||
+ GstStructure *config = gst_buffer_pool_get_config (priv->pool);
|
||||
+ gboolean ret = FALSE;
|
||||
+ gboolean is_drm_dumb = FALSE;
|
||||
+
|
||||
+ ret = gst_buffer_pool_config_get_allocator (config, &alloc, NULL);
|
||||
+ gst_structure_free (config);
|
||||
+
|
||||
+ if (ret && alloc)
|
||||
+ is_drm_dumb = GST_IS_DRM_DUMB_ALLOCATOR (alloc);
|
||||
+
|
||||
+ if (is_drm_dumb)
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
+ alloc = gst_drm_dumb_allocator_new_with_device_path (priv->drm_device);
|
||||
+ if (!alloc)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ gst_gtk_wayland_update_pool (self, alloc);
|
||||
+ gst_object_unref (alloc);
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
{
|
||||
@@ -877,6 +943,7 @@ gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
|
||||
format = GST_VIDEO_INFO_FORMAT (&priv->video_info);
|
||||
priv->video_info_changed = TRUE;
|
||||
+ priv->skip_dumb_buffer_copy = FALSE;
|
||||
|
||||
/* free pooled buffer used with previous caps */
|
||||
if (priv->pool) {
|
||||
@@ -1086,8 +1153,60 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
if (nb_dmabuf && (nb_dmabuf == gst_buffer_n_memory (buffer)))
|
||||
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, priv->display,
|
||||
&priv->video_info);
|
||||
+
|
||||
+ /* DMABuf did not work, let try and make this a dmabuf, it does not matter
|
||||
+ * if it was a SHM since the compositor needs to copy that anyway, and
|
||||
+ * offloading the compositor from a copy helps maintaining a smoother
|
||||
+ * desktop.
|
||||
+ */
|
||||
+ if (!priv->skip_dumb_buffer_copy) {
|
||||
+ GstVideoFrame src, dst;
|
||||
+
|
||||
+ if (!gst_gtk_wayland_activate_drm_dumb_pool (self)) {
|
||||
+ priv->skip_dumb_buffer_copy = TRUE;
|
||||
+ goto handle_shm;
|
||||
+ }
|
||||
+
|
||||
+ ret = gst_buffer_pool_acquire_buffer (priv->pool, &to_render, NULL);
|
||||
+ if (ret != GST_FLOW_OK)
|
||||
+ goto no_buffer;
|
||||
+
|
||||
+ wlbuffer = gst_buffer_get_wl_buffer (priv->display, to_render);
|
||||
+
|
||||
+ /* attach a wl_buffer if there isn't one yet */
|
||||
+ if (G_UNLIKELY (!wlbuffer)) {
|
||||
+ wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (to_render,
|
||||
+ priv->display, &priv->video_info);
|
||||
+
|
||||
+ if (G_UNLIKELY (!wbuf)) {
|
||||
+ GST_WARNING_OBJECT (self, "failed to import DRM Dumb dmabuf");
|
||||
+ gst_clear_buffer (&to_render);
|
||||
+ priv->skip_dumb_buffer_copy = TRUE;
|
||||
+ goto handle_shm;
|
||||
+ }
|
||||
+
|
||||
+ wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, priv->display);
|
||||
+ }
|
||||
+
|
||||
+ if (!gst_video_frame_map (&dst, &priv->video_info, to_render,
|
||||
+ GST_MAP_WRITE))
|
||||
+ goto dst_map_failed;
|
||||
+
|
||||
+ if (!gst_video_frame_map (&src, &priv->video_info, buffer, GST_MAP_READ)) {
|
||||
+ gst_video_frame_unmap (&dst);
|
||||
+ goto src_map_failed;
|
||||
+ }
|
||||
+
|
||||
+ gst_video_frame_copy (&dst, &src);
|
||||
+
|
||||
+ gst_video_frame_unmap (&src);
|
||||
+ gst_video_frame_unmap (&dst);
|
||||
+
|
||||
+ goto render;
|
||||
+ }
|
||||
}
|
||||
|
||||
+handle_shm:
|
||||
if (!wbuf && gst_wl_display_check_format_for_shm (priv->display, format)) {
|
||||
if (gst_buffer_n_memory (buffer) == 1 && gst_is_fd_memory (mem))
|
||||
wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, priv->display,
|
||||
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
||||
index aa39447..bb7fcff 100644
|
||||
--- a/ext/wayland/gstwaylandsink.c
|
||||
+++ b/ext/wayland/gstwaylandsink.c
|
||||
@@ -61,6 +61,7 @@ enum
|
||||
PROP_DISPLAY,
|
||||
PROP_FULLSCREEN,
|
||||
PROP_ROTATE_METHOD,
|
||||
+ PROP_DRM_DEVICE,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
@@ -177,6 +178,18 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
|
||||
GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
+ /**
|
||||
+ * waylandsink:drm-device:
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+ g_object_class_install_property (gobject_class, PROP_DRM_DEVICE,
|
||||
+ g_param_spec_string ("drm-device", "DRM Device", "Path of the "
|
||||
+ "DRM device to use for dumb buffer allocation",
|
||||
+ NULL,
|
||||
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
|
||||
+
|
||||
+
|
||||
/**
|
||||
* waylandsink:render-rectangle:
|
||||
*
|
||||
@@ -266,6 +279,11 @@ gst_wayland_sink_get_property (GObject * object,
|
||||
g_value_set_enum (value, self->current_rotate_method);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
break;
|
||||
+ case PROP_DRM_DEVICE:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ g_value_set_string (value, self->drm_device);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -293,6 +311,11 @@ gst_wayland_sink_set_property (GObject * object,
|
||||
gst_wayland_sink_set_rotate_method (self, g_value_get_enum (value),
|
||||
FALSE);
|
||||
break;
|
||||
+ case PROP_DRM_DEVICE:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ self->drm_device = g_value_dup_string (value);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -318,6 +341,7 @@ gst_wayland_sink_finalize (GObject * object)
|
||||
gst_clear_caps (&self->caps);
|
||||
|
||||
g_free (self->display_name);
|
||||
+ g_free (self->drm_device);
|
||||
|
||||
g_mutex_clear (&self->display_lock);
|
||||
g_mutex_clear (&self->render_lock);
|
||||
@@ -629,6 +653,39 @@ gst_wayland_activate_shm_pool (GstWaylandSink * self)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+gst_wayland_activate_drm_dumb_pool (GstWaylandSink * self)
|
||||
+{
|
||||
+ GstAllocator *alloc;
|
||||
+
|
||||
+ if (!self->drm_device)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (self->pool && gst_buffer_pool_is_active (self->pool)) {
|
||||
+ GstStructure *config = gst_buffer_pool_get_config (self->pool);
|
||||
+ gboolean ret = FALSE;
|
||||
+ gboolean is_drm_dumb = FALSE;
|
||||
+
|
||||
+ ret = gst_buffer_pool_config_get_allocator (config, &alloc, NULL);
|
||||
+ gst_structure_free (config);
|
||||
+
|
||||
+ if (ret && alloc)
|
||||
+ is_drm_dumb = GST_IS_DRM_DUMB_ALLOCATOR (alloc);
|
||||
+
|
||||
+ if (is_drm_dumb)
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
+ alloc = gst_drm_dumb_allocator_new_with_device_path (self->drm_device);
|
||||
+ if (!alloc)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ gst_wayland_update_pool (self, alloc);
|
||||
+ gst_object_unref (alloc);
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
{
|
||||
@@ -644,6 +701,7 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
|
||||
format = GST_VIDEO_INFO_FORMAT (&self->video_info);
|
||||
self->video_info_changed = TRUE;
|
||||
+ self->skip_dumb_buffer_copy = FALSE;
|
||||
|
||||
/* free pooled buffer used with previous caps */
|
||||
if (self->pool) {
|
||||
@@ -848,8 +906,60 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
if (nb_dmabuf && (nb_dmabuf == gst_buffer_n_memory (buffer)))
|
||||
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, self->display,
|
||||
&self->video_info);
|
||||
+
|
||||
+ /* DMABuf did not work, let try and make this a dmabuf, it does not matter
|
||||
+ * if it was a SHM since the compositor needs to copy that anyway, and
|
||||
+ * offloading the compositor from a copy helps maintaining a smoother
|
||||
+ * desktop.
|
||||
+ */
|
||||
+ if (!self->skip_dumb_buffer_copy) {
|
||||
+ GstVideoFrame src, dst;
|
||||
+
|
||||
+ if (!gst_wayland_activate_drm_dumb_pool (self)) {
|
||||
+ self->skip_dumb_buffer_copy = TRUE;
|
||||
+ goto handle_shm;
|
||||
+ }
|
||||
+
|
||||
+ ret = gst_buffer_pool_acquire_buffer (self->pool, &to_render, NULL);
|
||||
+ if (ret != GST_FLOW_OK)
|
||||
+ goto no_buffer;
|
||||
+
|
||||
+ wlbuffer = gst_buffer_get_wl_buffer (self->display, to_render);
|
||||
+
|
||||
+ /* attach a wl_buffer if there isn't one yet */
|
||||
+ if (G_UNLIKELY (!wlbuffer)) {
|
||||
+ wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (to_render,
|
||||
+ self->display, &self->video_info);
|
||||
+
|
||||
+ if (G_UNLIKELY (!wbuf)) {
|
||||
+ GST_WARNING_OBJECT (self, "failed to import DRM Dumb dmabuf");
|
||||
+ gst_clear_buffer (&to_render);
|
||||
+ self->skip_dumb_buffer_copy = TRUE;
|
||||
+ goto handle_shm;
|
||||
+ }
|
||||
+
|
||||
+ wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, self->display);
|
||||
+ }
|
||||
+
|
||||
+ if (!gst_video_frame_map (&dst, &self->video_info, to_render,
|
||||
+ GST_MAP_WRITE))
|
||||
+ goto dst_map_failed;
|
||||
+
|
||||
+ if (!gst_video_frame_map (&src, &self->video_info, buffer, GST_MAP_READ)) {
|
||||
+ gst_video_frame_unmap (&dst);
|
||||
+ goto src_map_failed;
|
||||
+ }
|
||||
+
|
||||
+ gst_video_frame_copy (&dst, &src);
|
||||
+
|
||||
+ gst_video_frame_unmap (&src);
|
||||
+ gst_video_frame_unmap (&dst);
|
||||
+
|
||||
+ goto render;
|
||||
+ }
|
||||
}
|
||||
|
||||
+handle_shm:
|
||||
if (!wbuf && gst_wl_display_check_format_for_shm (self->display, format)) {
|
||||
if (gst_buffer_n_memory (buffer) == 1 && gst_is_fd_memory (mem))
|
||||
wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, self->display,
|
||||
diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h
|
||||
index 1ff50d1..ca3400e 100644
|
||||
--- a/ext/wayland/gstwaylandsink.h
|
||||
+++ b/ext/wayland/gstwaylandsink.h
|
||||
@@ -69,6 +69,9 @@ struct _GstWaylandSink
|
||||
GstVideoOrientationMethod current_rotate_method;
|
||||
|
||||
struct wl_callback *callback;
|
||||
+
|
||||
+ gchar *drm_device;
|
||||
+ gboolean skip_dumb_buffer_copy;
|
||||
};
|
||||
|
||||
struct _GstWaylandSinkClass
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
From f0e7d7840db7a27d29127acdd42a09ea7450c969 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Fri, 17 Feb 2023 12:10:25 -0500
|
||||
Subject: [PATCH 12/17] bad: Update doc cache for waylandsink changes
|
||||
|
||||
A new drm-device property has been added.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
docs/plugins/gst_plugins_cache.json | 24 ++++++++++++++++++++++++
|
||||
1 file changed, 24 insertions(+)
|
||||
|
||||
diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json
|
||||
index 50128fb..4ea6d90 100644
|
||||
--- a/docs/plugins/gst_plugins_cache.json
|
||||
+++ b/docs/plugins/gst_plugins_cache.json
|
||||
@@ -29462,6 +29462,18 @@
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
+ "drm-device": {
|
||||
+ "blurb": "Path of the DRM device to use for dumb buffer allocation",
|
||||
+ "conditionally-available": false,
|
||||
+ "construct": false,
|
||||
+ "construct-only": true,
|
||||
+ "controllable": false,
|
||||
+ "default": "NULL",
|
||||
+ "mutable": "null",
|
||||
+ "readable": true,
|
||||
+ "type": "gchararray",
|
||||
+ "writable": true
|
||||
+ },
|
||||
"rotate-method": {
|
||||
"blurb": "rotate method",
|
||||
"conditionally-available": false,
|
||||
@@ -236521,6 +236533,18 @@
|
||||
"type": "gchararray",
|
||||
"writable": true
|
||||
},
|
||||
+ "drm-device": {
|
||||
+ "blurb": "Path of the DRM device to use for dumb buffer allocation",
|
||||
+ "conditionally-available": false,
|
||||
+ "construct": false,
|
||||
+ "construct-only": true,
|
||||
+ "controllable": false,
|
||||
+ "default": "NULL",
|
||||
+ "mutable": "null",
|
||||
+ "readable": true,
|
||||
+ "type": "gchararray",
|
||||
+ "writable": true
|
||||
+ },
|
||||
"fullscreen": {
|
||||
"blurb": "Whether the surface should be made fullscreen ",
|
||||
"conditionally-available": false,
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
From 0bc64942a8f0c1b49e2488b52f083c5545b1079c Mon Sep 17 00:00:00 2001
|
||||
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
Date: Wed, 29 Mar 2023 13:11:55 +0200
|
||||
Subject: [PATCH 14/17] WAYLANDSINK: use card0a as default drm-device
|
||||
|
||||
Signed-off-by: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
---
|
||||
ext/wayland/gstwaylandsink.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
||||
index bb7fcff..8cf8e36 100644
|
||||
--- a/ext/wayland/gstwaylandsink.c
|
||||
+++ b/ext/wayland/gstwaylandsink.c
|
||||
@@ -186,7 +186,7 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
|
||||
g_object_class_install_property (gobject_class, PROP_DRM_DEVICE,
|
||||
g_param_spec_string ("drm-device", "DRM Device", "Path of the "
|
||||
"DRM device to use for dumb buffer allocation",
|
||||
- NULL,
|
||||
+ "/dev/dri/card0",
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
From a4873e027038d26e9fb43a03a016d2975e6b3ba3 Mon Sep 17 00:00:00 2001
|
||||
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
Date: Wed, 29 Mar 2023 13:14:01 +0200
|
||||
Subject: [PATCH 15/17] waylandsink: Uprank to secondary
|
||||
|
||||
Signed-off-by: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
---
|
||||
ext/wayland/gstwaylandsink.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
||||
index 8cf8e36..24a7174 100644
|
||||
--- a/ext/wayland/gstwaylandsink.c
|
||||
+++ b/ext/wayland/gstwaylandsink.c
|
||||
@@ -114,7 +114,7 @@ static void gst_wayland_sink_expose (GstVideoOverlay * overlay);
|
||||
G_DEFINE_TYPE_WITH_CODE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK,
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
|
||||
gst_wayland_sink_videooverlay_init));
|
||||
-GST_ELEMENT_REGISTER_DEFINE (waylandsink, "waylandsink", GST_RANK_MARGINAL,
|
||||
+GST_ELEMENT_REGISTER_DEFINE (waylandsink, "waylandsink", GST_RANK_SECONDARY+1,
|
||||
GST_TYPE_WAYLAND_SINK);
|
||||
|
||||
static void
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
From a028c20bb3ad4f17b60afacb2a5f2a624432b2d4 Mon Sep 17 00:00:00 2001
|
||||
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
Date: Wed, 29 Mar 2023 14:42:17 +0200
|
||||
Subject: [PATCH 16/17] gstwlshmallocator: correct WL API declaration
|
||||
|
||||
Signed-off-by: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
---
|
||||
gst-libs/gst/wayland/gstwlshmallocator.h | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/gst-libs/gst/wayland/gstwlshmallocator.h b/gst-libs/gst/wayland/gstwlshmallocator.h
|
||||
index 0e7e15d..dcbea6c 100644
|
||||
--- a/gst-libs/gst/wayland/gstwlshmallocator.h
|
||||
+++ b/gst-libs/gst/wayland/gstwlshmallocator.h
|
||||
@@ -30,6 +30,7 @@
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get_type ())
|
||||
+GST_WL_API
|
||||
G_DECLARE_FINAL_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST, WL_SHM_ALLOCATOR, GstFdAllocator);
|
||||
|
||||
#define GST_ALLOCATOR_WL_SHM "wl_shm"
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
From 31d07ae72c3b78936bd4a385f1f5a72a2171da8b Mon Sep 17 00:00:00 2001
|
||||
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
Date: Wed, 29 Mar 2023 14:46:04 +0200
|
||||
Subject: [PATCH 17/17] sts/3801>gtkwaylandsink: Destroy GstWlWindow when
|
||||
parent GtkWindow is destroyed
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4197>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index e32bbcc..9691255 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -961,6 +961,9 @@ gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
if (!gst_wl_display_check_format_for_dmabuf (priv->display, format))
|
||||
goto unsupported_format;
|
||||
} else if (!gst_wl_display_check_format_for_shm (priv->display, format)) {
|
||||
+ /* Note: we still support dmabuf in this case, but formats must also be
|
||||
+ * supported on SHM interface to ensure a fallback is possible as we are
|
||||
+ * not guarantied we'll get dmabuf in the buffers. */
|
||||
goto unsupported_format;
|
||||
}
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
From 11f6e311f37ca4aaf5bafb9bc646686905c5c377 Mon Sep 17 00:00:00 2001
|
||||
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
Date: Wed, 29 Mar 2023 18:28:39 +0200
|
||||
Subject: [PATCH] GTKWAYLANDSINK: use card0 as default drm-device
|
||||
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 9691255..985ac07 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -173,7 +173,7 @@ gst_gtk_wayland_sink_class_init (GstGtkWaylandSinkClass * klass)
|
||||
g_object_class_install_property (gobject_class, PROP_DRM_DEVICE,
|
||||
g_param_spec_string ("drm-device", "DRM Device", "Path of the "
|
||||
"DRM device to use for dumb buffer allocation",
|
||||
- NULL,
|
||||
+ "/dev/dri/card0",
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
gstelement_class->change_state =
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
From 5c44d0f7282ae768aa6c46ee63ea924847035963 Mon Sep 17 00:00:00 2001
|
||||
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
|
||||
Date: Tue, 30 May 2023 14:08:58 +0200
|
||||
Subject: [PATCH 19/19] waylandsink: Emit "map" signal boarder surface is ready
|
||||
|
||||
This allows gtkwaylandsink to queue a draw of its gtk widget at the
|
||||
correct time, avoiding a race.
|
||||
|
||||
Signed-off-by: Colin Kinloch <colin.kinloch@collabora.com>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 13 +++++++++++++
|
||||
gst-libs/gst/wayland/gstwlwindow.c | 7 ++++++-
|
||||
2 files changed, 19 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 985ac07..2debee6 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -462,6 +462,17 @@ scrollable_window_adjustment_changed_cb (GtkAdjustment * adjustment,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+static void
|
||||
+wl_window_map_cb (GstWlWindow * wl_window, GstGtkWaylandSink * self)
|
||||
+{
|
||||
+ GstGtkWaylandSinkPrivate *priv =
|
||||
+ gst_gtk_wayland_sink_get_instance_private (self);
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (self, "waylandsink surface is ready");
|
||||
+
|
||||
+ gtk_gst_base_widget_queue_draw (GTK_GST_BASE_WIDGET (priv->gtk_widget));
|
||||
+}
|
||||
+
|
||||
static void
|
||||
setup_wl_window (GstGtkWaylandSink * self)
|
||||
{
|
||||
@@ -488,6 +499,8 @@ setup_wl_window (GstGtkWaylandSink * self)
|
||||
wl_surface, &priv->render_lock);
|
||||
gst_wl_window_set_rotate_method (priv->wl_window,
|
||||
priv->current_rotate_method);
|
||||
+ g_signal_connect_object (priv->wl_window, "map",
|
||||
+ G_CALLBACK (wl_window_map_cb), self, 0);
|
||||
}
|
||||
|
||||
/* In order to position the subsurface correctly within a scrollable widget,
|
||||
diff --git a/gst-libs/gst/wayland/gstwlwindow.c b/gst-libs/gst/wayland/gstwlwindow.c
|
||||
index 4aa53c3..afdbc10 100644
|
||||
--- a/gst-libs/gst/wayland/gstwlwindow.c
|
||||
+++ b/gst-libs/gst/wayland/gstwlwindow.c
|
||||
@@ -79,6 +79,7 @@ G_DEFINE_TYPE_WITH_CODE (GstWlWindow, gst_wl_window, G_TYPE_OBJECT,
|
||||
enum
|
||||
{
|
||||
CLOSED,
|
||||
+ MAP,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@@ -155,6 +156,9 @@ gst_wl_window_class_init (GstWlWindowClass * klass)
|
||||
|
||||
signals[CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
+ signals[MAP] = g_signal_new ("map", G_TYPE_FROM_CLASS (gobject_class),
|
||||
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
+
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -344,7 +348,7 @@ error:
|
||||
|
||||
GstWlWindow *
|
||||
gst_wl_window_new_in_surface (GstWlDisplay * display,
|
||||
- struct wl_surface * parent, GMutex * render_lock)
|
||||
+ struct wl_surface *parent, GMutex * render_lock)
|
||||
{
|
||||
GstWlWindow *self;
|
||||
GstWlWindowPrivate *priv;
|
||||
@@ -509,6 +513,7 @@ gst_wl_window_render (GstWlWindow * self, GstWlBuffer * buffer,
|
||||
gst_wl_window_update_borders (self);
|
||||
wl_surface_commit (priv->area_surface_wrapper);
|
||||
priv->is_area_surface_mapped = TRUE;
|
||||
+ g_signal_emit (self, signals[MAP], 0);
|
||||
}
|
||||
} else {
|
||||
/* clear both video and parent surfaces */
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
From f7b4ff8313d4e2197bdb91d21cd0a7beb59b7b7c Mon Sep 17 00:00:00 2001
|
||||
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
||||
Date: Wed, 14 Jun 2023 11:24:49 +0200
|
||||
Subject: [PATCH 20/21] gtkwaylandsink: do not use drm dumb pool with DMAbuf
|
||||
buffers
|
||||
|
||||
There is no need to use our DRM dumb pool if buffer to
|
||||
render is already a DMABuf, just import it and render it.
|
||||
|
||||
This fixes a DMAbuf memory leakage identfied with command:
|
||||
watch "cat /sys/kernel/debug/dma_buf/bufinfo | grep attached "
|
||||
|
||||
Signed-off-by: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 6 +++++-
|
||||
ext/wayland/gstwaylandsink.c | 6 +++++-
|
||||
2 files changed, 10 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 2debee6..7537200 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -1175,12 +1175,16 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, priv->display,
|
||||
&priv->video_info);
|
||||
|
||||
+ if (wbuf)
|
||||
+ GST_LOG_OBJECT (self,
|
||||
+ "buffer %" GST_PTR_FORMAT " is DMABuf", buffer);
|
||||
+
|
||||
/* DMABuf did not work, let try and make this a dmabuf, it does not matter
|
||||
* if it was a SHM since the compositor needs to copy that anyway, and
|
||||
* offloading the compositor from a copy helps maintaining a smoother
|
||||
* desktop.
|
||||
*/
|
||||
- if (!priv->skip_dumb_buffer_copy) {
|
||||
+ if (!wbuf && !priv->skip_dumb_buffer_copy) {
|
||||
GstVideoFrame src, dst;
|
||||
|
||||
if (!gst_gtk_wayland_activate_drm_dumb_pool (self)) {
|
||||
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
||||
index 24a7174..1662241 100644
|
||||
--- a/ext/wayland/gstwaylandsink.c
|
||||
+++ b/ext/wayland/gstwaylandsink.c
|
||||
@@ -907,12 +907,16 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, self->display,
|
||||
&self->video_info);
|
||||
|
||||
+ if (wbuf)
|
||||
+ GST_LOG_OBJECT (self,
|
||||
+ "buffer %" GST_PTR_FORMAT " is DMABuf", buffer);
|
||||
+
|
||||
/* DMABuf did not work, let try and make this a dmabuf, it does not matter
|
||||
* if it was a SHM since the compositor needs to copy that anyway, and
|
||||
* offloading the compositor from a copy helps maintaining a smoother
|
||||
* desktop.
|
||||
*/
|
||||
- if (!self->skip_dumb_buffer_copy) {
|
||||
+ if (!wbuf && !self->skip_dumb_buffer_copy) {
|
||||
GstVideoFrame src, dst;
|
||||
|
||||
if (!gst_wayland_activate_drm_dumb_pool (self)) {
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,650 @@
|
||||
From ebb197aacf8cb21a79704851b045d28592848953 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Gaignard <benjamin.gaignard@collabora.com>
|
||||
Date: Mon, 16 Jan 2023 17:34:10 +0100
|
||||
Subject: [PATCH 1/5] codecs: Add base class for stateless vp8 encoder
|
||||
|
||||
Add stateless vp8 encoder base class and vp8 frame structure.
|
||||
---
|
||||
gst-libs/gst/codecs/gstvp8encoder.c | 351 ++++++++++++++++++++++++++++
|
||||
gst-libs/gst/codecs/gstvp8encoder.h | 81 +++++++
|
||||
gst-libs/gst/codecs/gstvp8frame.c | 66 ++++++
|
||||
gst-libs/gst/codecs/gstvp8frame.h | 70 ++++++
|
||||
gst-libs/gst/codecs/meson.build | 7 +-
|
||||
5 files changed, 574 insertions(+), 1 deletion(-)
|
||||
create mode 100644 gst-libs/gst/codecs/gstvp8encoder.c
|
||||
create mode 100644 gst-libs/gst/codecs/gstvp8encoder.h
|
||||
create mode 100644 gst-libs/gst/codecs/gstvp8frame.c
|
||||
create mode 100644 gst-libs/gst/codecs/gstvp8frame.h
|
||||
|
||||
diff --git a/gst-libs/gst/codecs/gstvp8encoder.c b/gst-libs/gst/codecs/gstvp8encoder.c
|
||||
new file mode 100644
|
||||
index 0000000..b105786
|
||||
--- /dev/null
|
||||
+++ b/gst-libs/gst/codecs/gstvp8encoder.c
|
||||
@@ -0,0 +1,351 @@
|
||||
+/* GStreamer
|
||||
+ * Copyright (C) 2022 Benjamin Gaignard <benjamin.gaignard@collabora.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 St, Fifth Floor,
|
||||
+ * Boston, MA 02110-1301, USA.
|
||||
+ */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+#include "config.h"
|
||||
+#endif
|
||||
+
|
||||
+#include "gstvp8encoder.h"
|
||||
+
|
||||
+#include <gst/video/video.h>
|
||||
+#include <gst/video/gstvideometa.h>
|
||||
+#include <gst/base/base.h>
|
||||
+
|
||||
+GST_DEBUG_CATEGORY (gst_vp8_encoder_debug);
|
||||
+#define GST_CAT_DEFAULT gst_vp8_encoder_debug
|
||||
+
|
||||
+#define VP8ENC_DEFAULT_KEYFRAME_INTERVAL 30
|
||||
+
|
||||
+#define VP8_MAX_QUALITY 63
|
||||
+#define VP8_MIN_QUALITY 0
|
||||
+
|
||||
+#define VP8_DEFAULT_BITRATE 100000
|
||||
+
|
||||
+enum
|
||||
+{
|
||||
+ PROP_0,
|
||||
+ PROP_KEYFRAME_INTERVAL,
|
||||
+ PROP_MAX_QUALITY,
|
||||
+ PROP_MIN_QUALITY,
|
||||
+ PROP_BITRATE,
|
||||
+};
|
||||
+
|
||||
+struct _GstVp8EncoderPrivate
|
||||
+{
|
||||
+ gint keyframe_interval;
|
||||
+
|
||||
+ guint32 last_keyframe;
|
||||
+
|
||||
+ guint64 targeted_bitrate;
|
||||
+ gint max_quality;
|
||||
+ gint min_quality;
|
||||
+ gint current_quality;
|
||||
+ guint64 used_bytes;
|
||||
+ guint64 nb_frames;
|
||||
+};
|
||||
+
|
||||
+#define parent_class gst_vp8_encoder_parent_class
|
||||
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVp8Encoder, gst_vp8_encoder,
|
||||
+ GST_TYPE_VIDEO_ENCODER,
|
||||
+ G_ADD_PRIVATE (GstVp8Encoder);
|
||||
+ GST_DEBUG_CATEGORY_INIT (gst_vp8_encoder_debug, "vp8encoder", 0,
|
||||
+ "Vp8 Video Encoder"));
|
||||
+
|
||||
+static void
|
||||
+gst_vp8_encoder_init (GstVp8Encoder * self)
|
||||
+{
|
||||
+ self->priv = gst_vp8_encoder_get_instance_private (self);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_vp8_encoder_finalize (GObject * object)
|
||||
+{
|
||||
+ G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_vp8_encoder_start (GstVideoEncoder * encoder)
|
||||
+{
|
||||
+ GstVp8Encoder *self = GST_VP8_ENCODER (encoder);
|
||||
+ GstVp8EncoderPrivate *priv = self->priv;
|
||||
+
|
||||
+ priv->last_keyframe = 0;
|
||||
+ priv->current_quality = priv->min_quality;
|
||||
+ priv->used_bytes = 0;
|
||||
+ priv->nb_frames = 0;
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_vp8_encoder_stop (GstVideoEncoder * encoder)
|
||||
+{
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_vp8_encoder_set_format (GstVideoEncoder * encoder,
|
||||
+ GstVideoCodecState * state)
|
||||
+{
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static GstFlowReturn
|
||||
+gst_vp8_encoder_set_quality (GstVp8Encoder * self, GstVp8Frame * vp8_frame)
|
||||
+{
|
||||
+ GstVp8EncoderPrivate *priv = self->priv;
|
||||
+ GstVideoEncoder *encoder = GST_VIDEO_ENCODER (self);
|
||||
+ GstVideoCodecState *output_state =
|
||||
+ gst_video_encoder_get_output_state (encoder);
|
||||
+ gint qp = priv->current_quality;
|
||||
+ guint64 bitrate = 0;
|
||||
+ guint fps_n = 30, fps_d = 1;
|
||||
+
|
||||
+ if (output_state == NULL)
|
||||
+ return qp;
|
||||
+
|
||||
+ if (GST_VIDEO_INFO_FPS_N (&output_state->info) != 0) {
|
||||
+ fps_n = GST_VIDEO_INFO_FPS_N (&output_state->info);
|
||||
+ fps_d = GST_VIDEO_INFO_FPS_D (&output_state->info);
|
||||
+ }
|
||||
+ gst_video_codec_state_unref (output_state);
|
||||
+
|
||||
+ bitrate = (priv->used_bytes * 8 * fps_n) / (priv->nb_frames * fps_d);
|
||||
+ if (bitrate > priv->targeted_bitrate) {
|
||||
+ qp++;
|
||||
+ }
|
||||
+
|
||||
+ if (bitrate < priv->targeted_bitrate) {
|
||||
+ qp--;
|
||||
+ }
|
||||
+
|
||||
+ if (qp > priv->max_quality)
|
||||
+ qp = priv->max_quality;
|
||||
+ if (qp < priv->min_quality)
|
||||
+ qp = priv->min_quality;
|
||||
+
|
||||
+ vp8_frame->quality = qp;
|
||||
+
|
||||
+ return GST_FLOW_OK;
|
||||
+}
|
||||
+
|
||||
+static GstFlowReturn
|
||||
+gst_vp8_encoder_set_frame_type (GstVp8Encoder * self, GstVp8Frame * vp8_frame)
|
||||
+{
|
||||
+ GstVp8EncoderPrivate *priv = self->priv;
|
||||
+ GstVideoCodecFrame *frame = vp8_frame->frame;
|
||||
+
|
||||
+ if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
|
||||
+ vp8_frame->type = GstVp8Keyframe;
|
||||
+ return GST_FLOW_OK;
|
||||
+ }
|
||||
+
|
||||
+ if ((frame->system_frame_number - priv->last_keyframe) >
|
||||
+ priv->keyframe_interval || frame->system_frame_number == 0) {
|
||||
+ /* Generate a keyframe */
|
||||
+ GST_DEBUG_OBJECT (self, "Generate a keyframe");
|
||||
+ vp8_frame->type = GstVp8Keyframe;
|
||||
+ return GST_FLOW_OK;
|
||||
+ }
|
||||
+
|
||||
+ /* Generate a interframe */
|
||||
+ GST_DEBUG_OBJECT (self, "Generate a interframe");
|
||||
+ vp8_frame->type = GstVp8Inter;
|
||||
+ return GST_FLOW_OK;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_vp8_encoder_mark_frame (GstVp8Encoder * self, GstVp8Frame * vp8_frame)
|
||||
+{
|
||||
+ GstVideoCodecFrame *frame = vp8_frame->frame;
|
||||
+ GstVp8EncoderPrivate *priv = self->priv;
|
||||
+
|
||||
+ switch (vp8_frame->type) {
|
||||
+ case GstVp8Keyframe:
|
||||
+ priv->last_keyframe = frame->system_frame_number;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ priv->current_quality = vp8_frame->quality;
|
||||
+ priv->used_bytes += gst_buffer_get_size (frame->output_buffer);
|
||||
+ priv->nb_frames++;
|
||||
+}
|
||||
+
|
||||
+static GstFlowReturn
|
||||
+gst_vp8_encoder_handle_frame (GstVideoEncoder * encoder,
|
||||
+ GstVideoCodecFrame * frame)
|
||||
+{
|
||||
+ GstVp8Encoder *self = GST_VP8_ENCODER (encoder);
|
||||
+ GstVp8EncoderClass *klass = GST_VP8_ENCODER_GET_CLASS (self);
|
||||
+ GstFlowReturn ret = GST_FLOW_OK;
|
||||
+ GstVp8Frame *vp8_frame = gst_vp8_frame_new (frame);
|
||||
+
|
||||
+ ret = gst_vp8_encoder_set_frame_type (self, vp8_frame);
|
||||
+ if (ret != GST_FLOW_OK)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = gst_vp8_encoder_set_quality (self, vp8_frame);
|
||||
+ if (ret != GST_FLOW_OK)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* TODO: add encoding parameters management here
|
||||
+ * for now just send the frame to encode */
|
||||
+ if (klass->encode_frame) {
|
||||
+ ret = klass->encode_frame (self, vp8_frame);
|
||||
+ if (ret == GST_FLOW_OK)
|
||||
+ gst_vp8_encoder_mark_frame (self, vp8_frame);
|
||||
+ }
|
||||
+
|
||||
+ gst_vp8_frame_unref (vp8_frame);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_vp8_encoder_get_property (GObject * object, guint property_id,
|
||||
+ GValue * value, GParamSpec * pspec)
|
||||
+{
|
||||
+ GstVp8Encoder *self = GST_VP8_ENCODER (object);
|
||||
+ GstVp8EncoderPrivate *priv = self->priv;
|
||||
+
|
||||
+ switch (property_id) {
|
||||
+ case PROP_KEYFRAME_INTERVAL:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ g_value_set_int (value, priv->keyframe_interval);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
+ case PROP_MAX_QUALITY:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ g_value_set_int (value, priv->max_quality);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
+ case PROP_MIN_QUALITY:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ g_value_set_int (value, priv->min_quality);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
+ case PROP_BITRATE:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ g_value_set_uint64 (value, priv->targeted_bitrate);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
+ default:
|
||||
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_vp8_encoder_set_property (GObject * object, guint property_id,
|
||||
+ const GValue * value, GParamSpec * pspec)
|
||||
+{
|
||||
+ GstVp8Encoder *self = GST_VP8_ENCODER (object);
|
||||
+ GstVp8EncoderPrivate *priv = self->priv;
|
||||
+
|
||||
+ switch (property_id) {
|
||||
+ case PROP_KEYFRAME_INTERVAL:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ priv->keyframe_interval = g_value_get_int (value);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
+ case PROP_MAX_QUALITY:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ priv->max_quality = g_value_get_int (value);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
+ case PROP_MIN_QUALITY:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ priv->min_quality = g_value_get_int (value);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
+ case PROP_BITRATE:
|
||||
+ GST_OBJECT_LOCK (self);
|
||||
+ priv->targeted_bitrate = g_value_get_uint64 (value);
|
||||
+ GST_OBJECT_UNLOCK (self);
|
||||
+ break;
|
||||
+ default:
|
||||
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_vp8_encoder_class_init (GstVp8EncoderClass * klass)
|
||||
+{
|
||||
+ GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
|
||||
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
+
|
||||
+ object_class->finalize = GST_DEBUG_FUNCPTR (gst_vp8_encoder_finalize);
|
||||
+ object_class->get_property = gst_vp8_encoder_get_property;
|
||||
+ object_class->set_property = gst_vp8_encoder_set_property;
|
||||
+
|
||||
+ encoder_class->start = GST_DEBUG_FUNCPTR (gst_vp8_encoder_start);
|
||||
+ encoder_class->stop = GST_DEBUG_FUNCPTR (gst_vp8_encoder_stop);
|
||||
+ encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_vp8_encoder_set_format);
|
||||
+ encoder_class->handle_frame =
|
||||
+ GST_DEBUG_FUNCPTR (gst_vp8_encoder_handle_frame);
|
||||
+
|
||||
+ /**
|
||||
+ * GstVp8Encoder:keyframe-interval:
|
||||
+ *
|
||||
+ *
|
||||
+ * Since: 1.2x
|
||||
+ */
|
||||
+ g_object_class_install_property (object_class, PROP_KEYFRAME_INTERVAL,
|
||||
+ g_param_spec_int ("keyframe-interval", "Keyframe Interval",
|
||||
+ "Interval between keyframes",
|
||||
+ 0, G_MAXINT, VP8ENC_DEFAULT_KEYFRAME_INTERVAL,
|
||||
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
|
||||
+
|
||||
+ /**
|
||||
+ * GstVp8Encoder:max-quality:
|
||||
+ *
|
||||
+ *
|
||||
+ * Since: 1.2x
|
||||
+ */
|
||||
+ g_object_class_install_property (object_class, PROP_MAX_QUALITY,
|
||||
+ g_param_spec_int ("max-quality", "Max Quality Level",
|
||||
+ "Set upper quality limit (lower number equates to higher quality but more bits)",
|
||||
+ VP8_MIN_QUALITY, VP8_MAX_QUALITY, VP8_MAX_QUALITY,
|
||||
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
|
||||
+
|
||||
+ /**
|
||||
+ * GstVp8Encoder:min-quality:
|
||||
+ *
|
||||
+ *
|
||||
+ * Since: 1.2x
|
||||
+ */
|
||||
+ g_object_class_install_property (object_class, PROP_MIN_QUALITY,
|
||||
+ g_param_spec_int ("min-quality", "Min Quality Level",
|
||||
+ "Set lower quality limit (lower number equates to higher quality but more bits)",
|
||||
+ VP8_MIN_QUALITY, VP8_MAX_QUALITY, VP8_MIN_QUALITY,
|
||||
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
|
||||
+
|
||||
+ /**
|
||||
+ * GstVp8Encoder:bitrate:
|
||||
+ *
|
||||
+ *
|
||||
+ * Since: 1.2x
|
||||
+ */
|
||||
+ g_object_class_install_property (object_class, PROP_BITRATE,
|
||||
+ g_param_spec_uint64 ("bitrate", "Targeted bitrate",
|
||||
+ "Set bitrate target",
|
||||
+ 0, UINT_MAX, VP8_DEFAULT_BITRATE,
|
||||
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
|
||||
+}
|
||||
diff --git a/gst-libs/gst/codecs/gstvp8encoder.h b/gst-libs/gst/codecs/gstvp8encoder.h
|
||||
new file mode 100644
|
||||
index 0000000..3999ed3
|
||||
--- /dev/null
|
||||
+++ b/gst-libs/gst/codecs/gstvp8encoder.h
|
||||
@@ -0,0 +1,81 @@
|
||||
+/* GStreamer
|
||||
+ * Copyright (C) 2022 Benjamin Gaignard <benjamin.gaignard@collabora.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 St, Fifth Floor,
|
||||
+ * Boston, MA 02110-1301, USA.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __GST_VP8_ENCODER_H__
|
||||
+#define __GST_VP8_ENCODER_H__
|
||||
+
|
||||
+#include <gst/codecs/codecs-prelude.h>
|
||||
+
|
||||
+#include <gst/video/video.h>
|
||||
+#include <gst/video/gstvideoencoder.h>
|
||||
+
|
||||
+#include "gstvp8frame.h"
|
||||
+
|
||||
+G_BEGIN_DECLS
|
||||
+#define GST_TYPE_VP8_ENCODER (gst_vp8_encoder_get_type())
|
||||
+#define GST_VP8_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP8_ENCODER,GstVp8Encoder))
|
||||
+#define GST_VP8_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP8_ENCODER,GstVp8EncoderClass))
|
||||
+#define GST_VP8_ENCODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_VP8_ENCODER,GstVp8EncoderClass))
|
||||
+#define GST_IS_VP8_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP8_ENCODER))
|
||||
+#define GST_IS_VP8_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP8_ENCODER))
|
||||
+#define GST_VP8_ENCODER_CAST(obj) ((GstVp8Encoder*)obj)
|
||||
+typedef struct _GstVp8Encoder GstVp8Encoder;
|
||||
+typedef struct _GstVp8EncoderClass GstVp8EncoderClass;
|
||||
+typedef struct _GstVp8EncoderPrivate GstVp8EncoderPrivate;
|
||||
+
|
||||
+/**
|
||||
+ * GstVp8Encoder:
|
||||
+ *
|
||||
+ * The opaque #GstVp8Encoder data structure.
|
||||
+ */
|
||||
+struct _GstVp8Encoder
|
||||
+{
|
||||
+ /*< private > */
|
||||
+ GstVideoEncoder parent;
|
||||
+
|
||||
+ /*< private > */
|
||||
+ GstVp8EncoderPrivate *priv;
|
||||
+ gpointer padding[GST_PADDING_LARGE];
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * GstVp8EncoderClass:
|
||||
+ */
|
||||
+struct _GstVp8EncoderClass
|
||||
+{
|
||||
+ GstVideoEncoderClass parent_class;
|
||||
+
|
||||
+ /**
|
||||
+ * GstVp8EncoderClass::encode_frame:
|
||||
+ * @encoder: a #GstVp8Encoder
|
||||
+ * @frame: a #GstVp8Frame
|
||||
+ *
|
||||
+ * Provide the frame to be encoded with the encode parameters (to be defined)
|
||||
+ */
|
||||
+ GstFlowReturn (*encode_frame) (GstVp8Encoder * encoder,
|
||||
+ GstVp8Frame * frame);
|
||||
+ /*< private > */
|
||||
+ gpointer padding[GST_PADDING_LARGE];
|
||||
+};
|
||||
+
|
||||
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstVp8Encoder, gst_object_unref)
|
||||
+ GST_CODECS_API GType gst_vp8_encoder_get_type (void);
|
||||
+
|
||||
+G_END_DECLS
|
||||
+#endif /* __GST_VP8_ENCODER_H__ */
|
||||
diff --git a/gst-libs/gst/codecs/gstvp8frame.c b/gst-libs/gst/codecs/gstvp8frame.c
|
||||
new file mode 100644
|
||||
index 0000000..6f26bd5
|
||||
--- /dev/null
|
||||
+++ b/gst-libs/gst/codecs/gstvp8frame.c
|
||||
@@ -0,0 +1,66 @@
|
||||
+/* GStreamer
|
||||
+ * Copyright (C) 2022 Benjamin Gaignard <benjamin.gaignard@collabora.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 St, Fifth Floor,
|
||||
+ * Boston, MA 02110-1301, USA.
|
||||
+ */
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+#include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#include "gstvp8frame.h"
|
||||
+
|
||||
+GST_DEBUG_CATEGORY_EXTERN (gst_vp8_encoder_debug);
|
||||
+#define GST_CAT_DEFAULT gst_vp8_encoder_debug
|
||||
+
|
||||
+GST_DEFINE_MINI_OBJECT_TYPE (GstVp8Frame, gst_vp8_frame);
|
||||
+
|
||||
+static void
|
||||
+_gst_vp8_frame_free (GstVp8Frame * frame)
|
||||
+{
|
||||
+ GST_TRACE ("Free frame %p", frame);
|
||||
+
|
||||
+ gst_video_codec_frame_unref (frame->frame);
|
||||
+
|
||||
+ g_free (frame);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * gst_vp8_frame_new:
|
||||
+ *
|
||||
+ * Create new #GstVp8Frame
|
||||
+ *
|
||||
+ * Returns: a new #GstVp8Frame
|
||||
+ */
|
||||
+GstVp8Frame *
|
||||
+gst_vp8_frame_new (GstVideoCodecFrame * f)
|
||||
+{
|
||||
+ GstVp8Frame *frame;
|
||||
+
|
||||
+ if (!f)
|
||||
+ return NULL;
|
||||
+
|
||||
+ frame = g_new0 (GstVp8Frame, 1);
|
||||
+
|
||||
+ gst_mini_object_init (GST_MINI_OBJECT_CAST (frame), 0,
|
||||
+ GST_TYPE_VP8_FRAME, NULL, NULL,
|
||||
+ (GstMiniObjectFreeFunction) _gst_vp8_frame_free);
|
||||
+
|
||||
+ frame->frame = gst_video_codec_frame_ref (f);
|
||||
+
|
||||
+ GST_TRACE ("New frame %p", frame);
|
||||
+
|
||||
+ return frame;
|
||||
+}
|
||||
diff --git a/gst-libs/gst/codecs/gstvp8frame.h b/gst-libs/gst/codecs/gstvp8frame.h
|
||||
new file mode 100644
|
||||
index 0000000..a3d5c21
|
||||
--- /dev/null
|
||||
+++ b/gst-libs/gst/codecs/gstvp8frame.h
|
||||
@@ -0,0 +1,70 @@
|
||||
+/* GStreamer
|
||||
+ * Copyright (C) 2022 Benjamin Gaignard <benjamin.gaignard@collabora.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 St, Fifth Floor,
|
||||
+ * Boston, MA 02110-1301, USA.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __GTS_VP8_FRAME_H__
|
||||
+#define __GTS_VP8_FRAME_H__
|
||||
+
|
||||
+#include <gst/codecs/codecs-prelude.h>
|
||||
+#include <gst/video/video.h>
|
||||
+
|
||||
+G_BEGIN_DECLS
|
||||
+
|
||||
+#define GST_TYPE_VP8_FRAME (gst_vp8_frame_get_type())
|
||||
+#define GST_IS_VP8_FRAME(obj) (GST_IS_MINI_OBJECT_TYPE(obj, GST_TYPE_VP8_FRAME))
|
||||
+#define GST_VP8_FRAME(obj) ((GstVp8Frame *)obj)
|
||||
+#define GST_VP8_FRAME_CAST(obj) (GST_VP8_FRAME(obj))
|
||||
+
|
||||
+typedef struct _GstVp8Frame GstVp8Frame;
|
||||
+
|
||||
+enum
|
||||
+{
|
||||
+ GstVp8Keyframe,
|
||||
+ GstVp8Inter,
|
||||
+};
|
||||
+
|
||||
+struct _GstVp8Frame
|
||||
+{
|
||||
+ GstMiniObject parent;
|
||||
+ gint type;
|
||||
+ gint quality;
|
||||
+
|
||||
+ GstVideoCodecFrame *frame;
|
||||
+};
|
||||
+
|
||||
+GST_CODECS_API
|
||||
+GType gst_vp8_frame_get_type (void);
|
||||
+
|
||||
+GST_CODECS_API
|
||||
+GstVp8Frame * gst_vp8_frame_new (GstVideoCodecFrame *f);
|
||||
+
|
||||
+static inline GstVp8Frame *
|
||||
+gst_vp8_frame_ref (GstVp8Frame * frame)
|
||||
+{
|
||||
+ return (GstVp8Frame *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (frame));
|
||||
+}
|
||||
+
|
||||
+static inline void
|
||||
+gst_vp8_frame_unref (GstVp8Frame * frame)
|
||||
+{
|
||||
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (frame));
|
||||
+}
|
||||
+
|
||||
+G_END_DECLS
|
||||
+
|
||||
+#endif /* __GTS_VP8_FRAME_H__ */
|
||||
diff --git a/gst-libs/gst/codecs/meson.build b/gst-libs/gst/codecs/meson.build
|
||||
index f2bec85..458d90d 100644
|
||||
--- a/gst-libs/gst/codecs/meson.build
|
||||
+++ b/gst-libs/gst/codecs/meson.build
|
||||
@@ -12,6 +12,8 @@ codecs_sources = files(
|
||||
'gstav1decoder.c',
|
||||
'gstav1picture.c',
|
||||
'gstvp9statefulparser.c',
|
||||
+ 'gstvp8encoder.c',
|
||||
+ 'gstvp8frame.c',
|
||||
)
|
||||
|
||||
codecs_headers = files(
|
||||
@@ -28,6 +30,8 @@ codecs_headers = files(
|
||||
'gstav1decoder.h',
|
||||
'gstav1picture.h',
|
||||
'gstvp9statefulparser.h',
|
||||
+ 'gstvp8encoder.h',
|
||||
+ 'gstvp8frame.h',
|
||||
)
|
||||
|
||||
cp_args = [
|
||||
@@ -66,6 +70,7 @@ if build_gir
|
||||
'--c-include=gst/codecs/gstvp9decoder.h',
|
||||
'--c-include=gst/codecs/gstvp8decoder.h',
|
||||
'--c-include=gst/codecs/gstmpeg2decoder.h',
|
||||
+ '--c-include=gst/codecs/gstvp8encoder.h',
|
||||
],
|
||||
'dependencies' : [gstvideo_dep, gstcodecparsers_dep]
|
||||
}
|
||||
@@ -81,4 +86,4 @@ gstcodecs_dep = declare_dependency(link_with : gstcodecs,
|
||||
include_directories : [libsinc],
|
||||
sources: gen_sources,
|
||||
dependencies : [gstvideo_dep, gstcodecparsers_dep])
|
||||
-meson.override_dependency(pkg_name, gstcodecs_dep)
|
||||
\ No newline at end of file
|
||||
+meson.override_dependency(pkg_name, gstcodecs_dep)
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
From 3addb9d9cc00a6f4bba6d57cee26ce8e47ee1f3d Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Gaignard <benjamin.gaignard@collabora.com>
|
||||
Date: Mon, 16 Jan 2023 17:27:35 +0100
|
||||
Subject: [PATCH 2/5] v4l2codecs: Add V4L2 VP8 stateless encode uAPI
|
||||
|
||||
Udpate v4l2 header files with the definitions and structures
|
||||
used for stateless VP8 encode.
|
||||
---
|
||||
sys/v4l2codecs/linux/v4l2-controls.h | 91 ++++++++++++++++++++++++++++
|
||||
sys/v4l2codecs/linux/videodev2.h | 2 +
|
||||
2 files changed, 93 insertions(+)
|
||||
|
||||
diff --git a/sys/v4l2codecs/linux/v4l2-controls.h b/sys/v4l2codecs/linux/v4l2-controls.h
|
||||
index 79625ee..8838a5d 100644
|
||||
--- a/sys/v4l2codecs/linux/v4l2-controls.h
|
||||
+++ b/sys/v4l2codecs/linux/v4l2-controls.h
|
||||
@@ -2771,6 +2771,97 @@ struct v4l2_ctrl_vp9_compressed_hdr {
|
||||
struct v4l2_vp9_mv_probs mv;
|
||||
};
|
||||
|
||||
+#define V4L2_CID_STATELESS_VP8_ENCODE_PARAMS (V4L2_CID_CODEC_STATELESS_BASE + 501)
|
||||
+
|
||||
+#define V4L2_VP8_FRAME_FLAG_SHOWFRAME 0x1
|
||||
+#define V4L2_VP8_FRAME_FLAG_GOLDEN_REFRESH 0x2
|
||||
+#define V4L2_VP8_FRAME_FLAG_ALTREF_REFRESH 0x4
|
||||
+#define V4L2_VP8_FRAME_FLAG_SEGMENT_ENABLED 0x8
|
||||
+#define V4L2_VP8_FRAME_FLAG_LOOP_FILTER_ADJ_ENABLED 0x10
|
||||
+#define V4L2_VP8_FRAME_FLAG_REFRESH_ENTROPY_PROBS 0x20
|
||||
+
|
||||
+#define V4L2_VP8_FRAME_TYPE_KEYFRAME 0
|
||||
+#define V4L2_VP8_FRAME_TYPE_INTER 1
|
||||
+
|
||||
+#define V4L2_VP8_FRAME_COLOR_SPACE_YUV 0
|
||||
+#define V4L2_VP8_FRAME_COLOR_SPACE_RESERVED 1
|
||||
+
|
||||
+#define V4L2_VP8_FRAME_CLAMPING_REQUIRED 0
|
||||
+#define V4L2_VP8_FRAME_CLAMPING_NO 1
|
||||
+
|
||||
+#define V4L2_VP8_FRAME_FILTER_TYPE_NORMAL 0
|
||||
+#define V4L2_VP8_FRAME_FILTER_TYPE_SIMPLE 1
|
||||
+
|
||||
+#define V4L2_VP8_FRAME_NBR_DCT_PARTITIONS_1 0
|
||||
+#define V4L2_VP8_FRAME_NBR_DCT_PARTITIONS_2 1
|
||||
+#define V4L2_VP8_FRAME_NBR_DCT_PARTITIONS_4 2
|
||||
+#define V4L2_VP8_FRAME_NBR_DCT_PARTITIONS_8 3
|
||||
+
|
||||
+#define V4L2_VP8_FRAME_GOLDEN_KEEP 0
|
||||
+#define V4L2_VP8_FRAME_GOLDEN_LASTFRAME 1
|
||||
+#define V4L2_VP8_FRAME_GOLDEN_ALTREF 2
|
||||
+
|
||||
+#define V4L2_VP8_FRAME_ALTREF_KEEP 0
|
||||
+#define V4L2_VP8_FRAME_ALTREF_LASTFRAME 1
|
||||
+#define V4L2_VP8_FRAME_ALTREF_GOLDEN 2
|
||||
+
|
||||
+#define V4L2_VP8_FRAME_REF_LAST 0
|
||||
+#define V4L2_VP8_FRAME_REF_GOLDEN 1
|
||||
+#define V4L2_VP8_FRAME_REF_ALT 2
|
||||
+
|
||||
+/**
|
||||
+ * struct v4l2_ctrl_vp8_encode_params - VP8 encode parameters
|
||||
+ * @flags: combination of V4L2_VP8_FRAME_FLAG_{} flags.
|
||||
+ * @frame_type: specifies the frame type (key or inter).
|
||||
+ * Set to one of V4L2_VP8_FRAME_TYPE_{}.
|
||||
+ * @color_space: defines the YUV color space of the sequence.
|
||||
+ * V4L2_VP8_FRAME_TYPE_INTER frames shall set this field to zero.
|
||||
+ * Set to one of V4L2_VP8_FRAME_COLOR_SPACE_{}.
|
||||
+ * @clamping_type: defines pixel value clamping type.
|
||||
+ * V4L2_VP8_FRAME_TYPE_INTER frames shall set this field to zero.
|
||||
+ * Set to one of V4L2_VP8_FRAME_CLAMPING_{}.
|
||||
+ * @loop_filter_type: selects the type of loop filter applied.
|
||||
+ * Set to one of V4L2_VP8_FRAME_FILTER_TYPE_{}.
|
||||
+ * @loop_filter_level: sets the strength of the applied loop filter.
|
||||
+ * Set to a value from the rage 0..63.
|
||||
+ * @sharpness_level: sets the sharpness of the applied loop filter.
|
||||
+ * Set to a value from the range 0..7.
|
||||
+ * @log2_nbr_of_dct_partitions: determines the number of separate partitions
|
||||
+ * containing the DCT coefficients of macroblocks.
|
||||
+ * Set to one of V4L2_VP8_FRAME_NBR_DCT_PARTITIONS_{}.
|
||||
+ * @prob_intra: indicates the probability of an intra macroblock.
|
||||
+ * Set to a value from the range 0..255.
|
||||
+ * @prob_last: indicates the probability that the last reference frame is used for inter-prediction.
|
||||
+ * Set to a value from the range 0..255.
|
||||
+ * @prob_gf: indicates the probability that the golden reference frame is used for inter-prediction.
|
||||
+ * Set to a value from the range 0..255.
|
||||
+ * @copy_buffer_to_golden: specifies the golden frame refresh strategy.
|
||||
+ * Set to one of V4L2_VP8_FRAME_FLAG_GOLDEN_{}.
|
||||
+ * @copy_buffer_to_alternate: specifies the atlref frame refresh strategy.
|
||||
+ * Set to one of V4L2_VP8_FRAME_FLAG_ALTREF_{}.
|
||||
+ * @reference_type: specifies what kind of reference to use for current inter frame.
|
||||
+ * V4L2_VP8_FRAME_TYPE_KEYFRAME shall set this field to zero.
|
||||
+ * Set to one of V4L2_VP8_FRAME_REF_{}.
|
||||
+ */
|
||||
+struct v4l2_ctrl_vp8_encode_params {
|
||||
+ __u32 flags;
|
||||
+ __u8 frame_type;
|
||||
+ __u8 color_space;
|
||||
+ __u8 clamping_type;
|
||||
+ __u8 loop_filter_type;
|
||||
+ __u8 loop_filter_level;
|
||||
+ __u8 sharpness_level;
|
||||
+ __u8 log2_nbr_of_dct_partitions;
|
||||
+ __u8 prob_intra;
|
||||
+ __u8 prob_last;
|
||||
+ __u8 prob_gf;
|
||||
+ __u8 copy_buffer_to_golden;
|
||||
+ __u8 copy_buffer_to_alternate;
|
||||
+ __u8 reference_type;
|
||||
+};
|
||||
+
|
||||
+#define V4L2_CID_STATELESS_VP8_ENCODE_QP (V4L2_CID_CODEC_STATELESS_BASE + 502)
|
||||
+
|
||||
/* MPEG-compression definitions kept for backwards compatibility */
|
||||
#define V4L2_CTRL_CLASS_MPEG V4L2_CTRL_CLASS_CODEC
|
||||
#define V4L2_CID_MPEG_CLASS V4L2_CID_CODEC_CLASS
|
||||
diff --git a/sys/v4l2codecs/linux/videodev2.h b/sys/v4l2codecs/linux/videodev2.h
|
||||
index 62cc050..687ac85 100644
|
||||
--- a/sys/v4l2codecs/linux/videodev2.h
|
||||
+++ b/sys/v4l2codecs/linux/videodev2.h
|
||||
@@ -1811,6 +1811,8 @@ enum v4l2_ctrl_type {
|
||||
V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS = 0x0272,
|
||||
V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX = 0x0273,
|
||||
V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS = 0x0274,
|
||||
+
|
||||
+ V4L2_CTRL_TYPE_VP8_ENCODE_PARAMS = 0x0280,
|
||||
};
|
||||
|
||||
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
|
||||
--
|
||||
2.25.1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,812 @@
|
||||
From 6b4f87ff52197510e6d4ca475ecdb5725473e60a Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Gaignard <benjamin.gaignard@collabora.com>
|
||||
Date: Mon, 16 Jan 2023 17:38:58 +0100
|
||||
Subject: [PATCH 4/5] v4l2codecs: Add V4L2 stateless VP8 encoder
|
||||
|
||||
Add element for V4L2 stateless VP8 encoder.
|
||||
Using v4l2 request to set driver configuration by using VP8 stateless controls.
|
||||
---
|
||||
sys/v4l2codecs/gstv4l2codecvp8enc.c | 716 ++++++++++++++++++++++++++++
|
||||
sys/v4l2codecs/gstv4l2codecvp8enc.h | 54 +++
|
||||
sys/v4l2codecs/meson.build | 1 +
|
||||
3 files changed, 771 insertions(+)
|
||||
create mode 100644 sys/v4l2codecs/gstv4l2codecvp8enc.c
|
||||
create mode 100644 sys/v4l2codecs/gstv4l2codecvp8enc.h
|
||||
|
||||
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.c b/sys/v4l2codecs/gstv4l2codecvp8enc.c
|
||||
new file mode 100644
|
||||
index 0000000..2f15caf
|
||||
--- /dev/null
|
||||
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.c
|
||||
@@ -0,0 +1,716 @@
|
||||
+/* GStreamer
|
||||
+ * Copyright (C) 2022 Benjamin Gaignard <benjamin.gaignard@collabora.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 St, Fifth Floor,
|
||||
+ * Boston, MA 02110-1301, USA.
|
||||
+ */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+#include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#include "gstv4l2codecallocator.h"
|
||||
+#include "gstv4l2codecpool.h"
|
||||
+#include "gstv4l2codecvp8enc.h"
|
||||
+#include "gstv4l2format.h"
|
||||
+
|
||||
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
||||
+
|
||||
+#define V4L2_MIN_KERNEL_VER_MAJOR 5
|
||||
+#define V4L2_MIN_KERNEL_VER_MINOR 17
|
||||
+#define V4L2_MIN_KERNEL_VERSION KERNEL_VERSION(V4L2_MIN_KERNEL_VER_MAJOR, V4L2_MIN_KERNEL_VER_MINOR, 0)
|
||||
+
|
||||
+GST_DEBUG_CATEGORY_STATIC (v4l2_vp8enc_debug);
|
||||
+#define GST_CAT_DEFAULT v4l2_vp8enc_debug
|
||||
+
|
||||
+enum
|
||||
+{
|
||||
+ PROP_0,
|
||||
+ PROP_LAST = PROP_0
|
||||
+};
|
||||
+
|
||||
+static GstStaticPadTemplate sink_template =
|
||||
+GST_STATIC_PAD_TEMPLATE (GST_VIDEO_ENCODER_SINK_NAME,
|
||||
+ GST_PAD_SINK, GST_PAD_ALWAYS,
|
||||
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS)));
|
||||
+
|
||||
+static GstStaticPadTemplate src_template =
|
||||
+GST_STATIC_PAD_TEMPLATE (GST_VIDEO_ENCODER_SRC_NAME,
|
||||
+ GST_PAD_SRC, GST_PAD_ALWAYS,
|
||||
+ GST_STATIC_CAPS ("video/x-vp8"));
|
||||
+
|
||||
+struct _vp8_frame_hdr
|
||||
+{
|
||||
+ guint8 tag[3];
|
||||
+ guint8 start_code[3];
|
||||
+ guint16 width;
|
||||
+ guint16 height;
|
||||
+};
|
||||
+
|
||||
+#define VP8_FRAME_HDR_INTRA_FLAG 0x0
|
||||
+#define VP8_FRAME_HDR_INTER_FLAG 0x1
|
||||
+#define VP8_FRAME_HDR_VERSION1_FLAG (1 << 1)
|
||||
+#define VP8_FRAME_HDR_SHOW_FRAME (1 << 4)
|
||||
+#define VP8_FRAME_HDR_WIDTH_MASK 0x3fff
|
||||
+#define VP8_FRAME_HDR_HEIGHT_MASK 0x3fff
|
||||
+
|
||||
+struct _GstV4l2CodecVp8Enc
|
||||
+{
|
||||
+ GstVp8Encoder parent;
|
||||
+ GstV4l2Encoder *encoder;
|
||||
+ GstVideoCodecState *output_state;
|
||||
+ GstVideoInfo vinfo;
|
||||
+ gint width;
|
||||
+ gint height;
|
||||
+ guint qp_max, qp_min;
|
||||
+
|
||||
+ GstV4l2CodecAllocator *sink_allocator;
|
||||
+ GstV4l2CodecAllocator *src_allocator;
|
||||
+ GstV4l2CodecPool *sink_pool;
|
||||
+ GstV4l2CodecPool *src_pool;
|
||||
+
|
||||
+ struct v4l2_ctrl_vp8_encode_params encode_params;
|
||||
+};
|
||||
+
|
||||
+G_DEFINE_ABSTRACT_TYPE (GstV4l2CodecVp8Enc, gst_v4l2_codec_vp8_enc,
|
||||
+ GST_TYPE_VP8_ENCODER);
|
||||
+
|
||||
+#define parent_class gst_v4l2_codec_vp8_enc_parent_class
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_open (GstVideoEncoder * encoder)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+ guint version;
|
||||
+
|
||||
+ if (!gst_v4l2_encoder_open (self->encoder)) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE,
|
||||
+ ("Failed to open VP8 encoder"),
|
||||
+ ("gst_v4l2_encoder_open() failed: %s", g_strerror (errno)));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ version = gst_v4l2_encoder_get_version (self->encoder);
|
||||
+ if (version < V4L2_MIN_KERNEL_VERSION)
|
||||
+ GST_WARNING_OBJECT (self,
|
||||
+ "V4L2 API v%u.%u too old, at least v%u.%u required",
|
||||
+ (version >> 16) & 0xff, (version >> 8) & 0xff,
|
||||
+ V4L2_MIN_KERNEL_VER_MAJOR, V4L2_MIN_KERNEL_VER_MINOR);
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (self, "open vp8 encoder");
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_api_check (GstV4l2Encoder * encoder)
|
||||
+{
|
||||
+ guint i, ret_size;
|
||||
+ /* *INDENT-OFF* */
|
||||
+ #define SET_ID(cid) .id = (cid), .name = #cid
|
||||
+ struct
|
||||
+ {
|
||||
+ const gchar *name;
|
||||
+ unsigned int id;
|
||||
+ unsigned int size;
|
||||
+ gboolean optional;
|
||||
+ } controls[] = {
|
||||
+ {
|
||||
+ SET_ID (V4L2_CID_STATELESS_VP8_ENCODE_PARAMS),
|
||||
+ .size = sizeof(struct v4l2_ctrl_vp8_encode_params),
|
||||
+ }, {
|
||||
+ SET_ID (V4L2_CID_STATELESS_VP8_ENCODE_QP),
|
||||
+ .size = sizeof(__u32),
|
||||
+ },
|
||||
+ };
|
||||
+ #undef SET_ID
|
||||
+ /* *INDENT-ON* */
|
||||
+
|
||||
+ /*
|
||||
+ * Compatibility check: make sure the pointer controls are
|
||||
+ * the right size.
|
||||
+ */
|
||||
+ for (i = 0; i < G_N_ELEMENTS (controls); i++) {
|
||||
+ gboolean control_found;
|
||||
+
|
||||
+ control_found = gst_v4l2_encoder_query_control_size (encoder,
|
||||
+ controls[i].id, &ret_size);
|
||||
+
|
||||
+ if (!controls[i].optional && !control_found) {
|
||||
+ GST_WARNING ("Driver is missing %s support.", controls[i].name);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (control_found && ret_size != controls[i].size) {
|
||||
+ GST_WARNING ("%s control size mismatch: got %d bytes but %d expected.",
|
||||
+ controls[i].name, ret_size, controls[i].size);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_close (GstVideoEncoder * encoder)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+ gst_v4l2_encoder_close (self->encoder);
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_reset_allocation (GstV4l2CodecVp8Enc * self)
|
||||
+{
|
||||
+ if (self->sink_allocator) {
|
||||
+ gst_v4l2_codec_allocator_detach (self->sink_allocator);
|
||||
+ g_clear_object (&self->sink_allocator);
|
||||
+ g_clear_object (&self->sink_pool);
|
||||
+ }
|
||||
+
|
||||
+ if (self->src_allocator) {
|
||||
+ gst_v4l2_codec_allocator_detach (self->src_allocator);
|
||||
+ g_clear_object (&self->src_allocator);
|
||||
+ g_clear_object (&self->src_pool);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_start (GstVideoEncoder * encoder)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (self, "start");
|
||||
+
|
||||
+ return GST_VIDEO_ENCODER_CLASS (parent_class)->start (encoder);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_stop (GstVideoEncoder * encoder)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (self, "stop");
|
||||
+
|
||||
+ gst_v4l2_encoder_streamoff (self->encoder, GST_PAD_SINK);
|
||||
+ gst_v4l2_encoder_streamoff (self->encoder, GST_PAD_SRC);
|
||||
+
|
||||
+ gst_v4l2_codec_vp8_enc_reset_allocation (self);
|
||||
+
|
||||
+ if (self->output_state)
|
||||
+ gst_video_codec_state_unref (self->output_state);
|
||||
+ self->output_state = NULL;
|
||||
+
|
||||
+ return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (encoder);
|
||||
+}
|
||||
+
|
||||
+static GstCaps *
|
||||
+gst_v4l2_codec_vp8_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+ GstCaps *caps, *result;
|
||||
+
|
||||
+ caps = gst_v4l2_encoder_list_sink_formats (self->encoder);
|
||||
+ GST_DEBUG_OBJECT (self, "Supported input formats: %" GST_PTR_FORMAT, caps);
|
||||
+
|
||||
+ result = gst_video_encoder_proxy_getcaps (encoder, caps, filter);
|
||||
+
|
||||
+ if (caps)
|
||||
+ gst_caps_unref (caps);
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (self, "Returning sink caps: %" GST_PTR_FORMAT, result);
|
||||
+
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_buffers_allocation (GstVideoEncoder * encoder)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (self, "buffers allocation");
|
||||
+
|
||||
+ g_clear_object (&self->sink_pool);
|
||||
+ g_clear_object (&self->src_pool);
|
||||
+ g_clear_object (&self->src_allocator);
|
||||
+
|
||||
+ self->sink_allocator = gst_v4l2_codec_encoder_allocator_new (self->encoder,
|
||||
+ GST_PAD_SINK, 4);
|
||||
+ if (!self->sink_allocator) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT,
|
||||
+ ("Not enough memory to allocate sink buffers."), (NULL));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ self->sink_pool =
|
||||
+ gst_v4l2_codec_pool_new (self->sink_allocator, &self->vinfo);
|
||||
+
|
||||
+ self->src_allocator = gst_v4l2_codec_encoder_allocator_new (self->encoder,
|
||||
+ GST_PAD_SRC, 4);
|
||||
+ if (!self->src_allocator) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT,
|
||||
+ ("Not enough memory to allocate source buffers."), (NULL));
|
||||
+ g_clear_object (&self->sink_allocator);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &self->vinfo);
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * encoder,
|
||||
+ GstVideoCodecState * state)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+ GstCaps *caps;
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (self, "Set format");
|
||||
+
|
||||
+ gst_v4l2_encoder_streamoff (self->encoder, GST_PAD_SINK);
|
||||
+ gst_v4l2_encoder_streamoff (self->encoder, GST_PAD_SRC);
|
||||
+
|
||||
+ gst_v4l2_codec_vp8_enc_reset_allocation (self);
|
||||
+
|
||||
+ if (!gst_v4l2_encoder_select_sink_format (self->encoder, &state->info,
|
||||
+ &self->vinfo)) {
|
||||
+ GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
|
||||
+ ("Failed to configure VP8 encoder"),
|
||||
+ ("gst_v4l2_encoder_select_sink_format() failed: %s",
|
||||
+ g_strerror (errno)));
|
||||
+ gst_v4l2_encoder_close (self->encoder);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (!gst_v4l2_encoder_set_src_fmt (self->encoder, &self->vinfo,
|
||||
+ V4L2_PIX_FMT_VP8_FRAME)) {
|
||||
+ GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported pixel format"),
|
||||
+ ("No support for %ux%u format VP8", state->info.width,
|
||||
+ state->info.height));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ self->width = state->info.width;
|
||||
+ self->height = state->info.height;
|
||||
+ gst_v4l2_codec_vp8_enc_buffers_allocation (encoder);
|
||||
+
|
||||
+ if (self->output_state)
|
||||
+ gst_video_codec_state_unref (self->output_state);
|
||||
+
|
||||
+ caps = gst_caps_new_empty_simple ("video/x-vp8");
|
||||
+
|
||||
+ self->output_state =
|
||||
+ gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
|
||||
+ caps, state);
|
||||
+
|
||||
+ if (GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder)) {
|
||||
+ if (!gst_v4l2_encoder_streamon (self->encoder, GST_PAD_SINK)) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
|
||||
+ ("Could not enable the encoder driver."),
|
||||
+ ("VIDIOC_STREAMON(SINK) failed: %s", g_strerror (errno)));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (!gst_v4l2_encoder_streamon (self->encoder, GST_PAD_SRC)) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
|
||||
+ ("Could not enable the encoder driver."),
|
||||
+ ("VIDIOC_STREAMON(SRC) failed: %s", g_strerror (errno)));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ gst_v4l2_codec_vp8_enc_get_qp_range (self->encoder, &self->qp_min,
|
||||
+ &self->qp_max);
|
||||
+
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_set_flushing (GstV4l2CodecVp8Enc * self,
|
||||
+ gboolean flushing)
|
||||
+{
|
||||
+ if (self->sink_allocator)
|
||||
+ gst_v4l2_codec_allocator_set_flushing (self->sink_allocator, flushing);
|
||||
+ if (self->src_allocator)
|
||||
+ gst_v4l2_codec_allocator_set_flushing (self->src_allocator, flushing);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_flush (GstVideoEncoder * encoder)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (self, "Flushing encoder state.");
|
||||
+
|
||||
+ gst_v4l2_encoder_flush (self->encoder);
|
||||
+ gst_v4l2_codec_vp8_enc_set_flushing (self, FALSE);
|
||||
+
|
||||
+ return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (encoder);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_sink_event (GstVideoEncoder * encoder, GstEvent * event)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+
|
||||
+ switch (GST_EVENT_TYPE (event)) {
|
||||
+ case GST_EVENT_FLUSH_START:
|
||||
+ GST_DEBUG_OBJECT (self, "flush start");
|
||||
+ gst_v4l2_codec_vp8_enc_set_flushing (self, TRUE);
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_event (encoder, event);
|
||||
+}
|
||||
+
|
||||
+static GstStateChangeReturn
|
||||
+gst_v4l2_codec_vp8_enc_change_state (GstElement * element,
|
||||
+ GstStateChange transition)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (element);
|
||||
+
|
||||
+ if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
|
||||
+ gst_v4l2_codec_vp8_enc_set_flushing (self, TRUE);
|
||||
+
|
||||
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_set_property (GObject * object, guint prop_id,
|
||||
+ const GValue * value, GParamSpec * pspec)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (object);
|
||||
+ GObject *dec = G_OBJECT (self->encoder);
|
||||
+
|
||||
+ switch (prop_id) {
|
||||
+ default:
|
||||
+ gst_v4l2_encoder_set_property (dec, prop_id - PROP_LAST, value, pspec);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_get_property (GObject * object, guint prop_id,
|
||||
+ GValue * value, GParamSpec * pspec)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (object);
|
||||
+ GObject *dec = G_OBJECT (self->encoder);
|
||||
+
|
||||
+ switch (prop_id) {
|
||||
+ default:
|
||||
+ gst_v4l2_encoder_get_property (dec, prop_id - PROP_LAST, value, pspec);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_copy_input_buffer (GstV4l2CodecVp8Enc * self,
|
||||
+ GstVideoCodecFrame * frame)
|
||||
+{
|
||||
+ GstVideoFrame src_frame;
|
||||
+ GstVideoFrame dest_frame;
|
||||
+ GstVideoInfo dest_vinfo;
|
||||
+ GstBuffer *buffer;
|
||||
+ GstFlowReturn flow_ret;
|
||||
+
|
||||
+ gst_video_info_set_format (&dest_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo),
|
||||
+ self->width, self->height);
|
||||
+
|
||||
+ flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->sink_pool),
|
||||
+ &buffer, NULL);
|
||||
+ if (flow_ret != GST_FLOW_OK) {
|
||||
+ if (flow_ret == GST_FLOW_FLUSHING)
|
||||
+ GST_DEBUG_OBJECT (self, "Frame encoding aborted, we are flushing.");
|
||||
+ else
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
|
||||
+ ("No more picture buffer available."), (NULL));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (!buffer)
|
||||
+ goto fail;
|
||||
+
|
||||
+ if (!gst_video_frame_map (&src_frame, &self->vinfo,
|
||||
+ frame->input_buffer, GST_MAP_READ))
|
||||
+ goto fail;
|
||||
+
|
||||
+ if (!gst_video_frame_map (&dest_frame, &dest_vinfo, buffer, GST_MAP_WRITE)) {
|
||||
+ gst_video_frame_unmap (&dest_frame);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ if (!gst_video_frame_copy (&dest_frame, &src_frame)) {
|
||||
+ gst_video_frame_unmap (&src_frame);
|
||||
+ gst_video_frame_unmap (&dest_frame);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ gst_video_frame_unmap (&src_frame);
|
||||
+ gst_video_frame_unmap (&dest_frame);
|
||||
+ gst_buffer_replace (&frame->input_buffer, buffer);
|
||||
+ gst_buffer_unref (buffer);
|
||||
+
|
||||
+ return TRUE;
|
||||
+
|
||||
+fail:
|
||||
+ GST_ERROR_OBJECT (self, "Failed copy input buffer.");
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_v4l2_codec_vp8_enc_ensure_output_bitstream (GstV4l2CodecVp8Enc * self,
|
||||
+ GstVideoCodecFrame * frame)
|
||||
+{
|
||||
+ GstFlowReturn flow_ret;
|
||||
+
|
||||
+ flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->src_pool),
|
||||
+ &frame->output_buffer, NULL);
|
||||
+ if (flow_ret != GST_FLOW_OK) {
|
||||
+ if (flow_ret == GST_FLOW_FLUSHING)
|
||||
+ GST_DEBUG_OBJECT (self, "Frame encoding aborted, we are flushing.");
|
||||
+ else
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
|
||||
+ ("No more encoded buffer available."), (NULL));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (!frame->output_buffer)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_fill_encode_params (GstVp8Encoder * encoder,
|
||||
+ GstVp8Frame * vp8_frame)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+
|
||||
+ switch (vp8_frame->type) {
|
||||
+ case GstVp8Keyframe:
|
||||
+ self->encode_params.frame_type = V4L2_VP8_FRAME_TYPE_KEYFRAME;
|
||||
+ self->encode_params.loop_filter_level = 26;
|
||||
+ break;
|
||||
+ case GstVp8Inter:
|
||||
+ default:
|
||||
+ self->encode_params.frame_type = V4L2_VP8_FRAME_TYPE_INTER;
|
||||
+ self->encode_params.loop_filter_level = 12;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ self->encode_params.flags = V4L2_VP8_FRAME_FLAG_SHOWFRAME;
|
||||
+}
|
||||
+
|
||||
+static guint
|
||||
+gst_v4l2_codec_vp8_enc_check_qp_range (GstV4l2CodecVp8Enc * self,
|
||||
+ GstVp8Frame * vp8_frame)
|
||||
+{
|
||||
+ if (vp8_frame->quality > self->qp_max)
|
||||
+ return self->qp_max;
|
||||
+ if (vp8_frame->quality < self->qp_min)
|
||||
+ return self->qp_min;
|
||||
+
|
||||
+ return vp8_frame->quality;
|
||||
+}
|
||||
+
|
||||
+static GstFlowReturn
|
||||
+gst_v4l2_codec_vp8_enc_encode_frame (GstVp8Encoder * encoder,
|
||||
+ GstVp8Frame * vp8_frame)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
|
||||
+ GstVideoEncoder *venc = GST_VIDEO_ENCODER (encoder);
|
||||
+ GstV4l2Request *request = NULL;
|
||||
+ GstFlowReturn ret = GST_FLOW_ERROR;
|
||||
+ GstVideoCodecFrame *frame = vp8_frame->frame;
|
||||
+ GstBuffer *resized_buffer;
|
||||
+ guint32 bytesused;
|
||||
+
|
||||
+ /* *INDENT-OFF* */
|
||||
+ struct v4l2_ext_control control[] = {
|
||||
+ {
|
||||
+ .id = V4L2_CID_STATELESS_VP8_ENCODE_PARAMS,
|
||||
+ .ptr = &self->encode_params,
|
||||
+ .size = sizeof (self->encode_params),
|
||||
+ }, {
|
||||
+ .id = V4L2_CID_STATELESS_VP8_ENCODE_QP,
|
||||
+ .value = gst_v4l2_codec_vp8_enc_check_qp_range (self, vp8_frame),
|
||||
+ .size = sizeof (guint),
|
||||
+ },
|
||||
+ };
|
||||
+ /* *INDENT-ON* */
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (self, "encode vp8 frame with quality = %d",
|
||||
+ vp8_frame->quality);
|
||||
+
|
||||
+ if (!gst_v4l2_codec_vp8_enc_ensure_output_bitstream (self, frame)) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT,
|
||||
+ ("Failed to allocate output buffer."), (NULL));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ if (!gst_v4l2_codec_vp8_enc_copy_input_buffer (self, frame)) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT,
|
||||
+ ("Failed to allocate/copy input buffer."), (NULL));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ request = gst_v4l2_encoder_alloc_request (self->encoder,
|
||||
+ frame->system_frame_number, frame->input_buffer, frame->output_buffer);
|
||||
+
|
||||
+ if (!request) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT,
|
||||
+ ("Failed to allocate a media request object."), (NULL));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ gst_v4l2_codec_vp8_enc_fill_encode_params (encoder, vp8_frame);
|
||||
+
|
||||
+ if (!gst_v4l2_encoder_set_controls (self->encoder, request, control,
|
||||
+ G_N_ELEMENTS (control))) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
|
||||
+ ("Driver did not accept the control parameters."), (NULL));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ if (!gst_v4l2_encoder_request_queue (request, 0)) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
|
||||
+ ("Driver did not accept the encode request."), (NULL));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ if (!gst_v4l2_encoder_request_set_done (request, &bytesused)) {
|
||||
+ GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
|
||||
+ ("Driver did not ack the request."), (NULL));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ gst_v4l2_encoder_request_unref (request);
|
||||
+
|
||||
+ resized_buffer = gst_buffer_copy_region (frame->output_buffer,
|
||||
+ GST_BUFFER_COPY_MEMORY | GST_BUFFER_COPY_DEEP, 0, bytesused);
|
||||
+ gst_buffer_replace (&frame->output_buffer, resized_buffer);
|
||||
+ gst_buffer_unref (resized_buffer);
|
||||
+
|
||||
+ return gst_video_encoder_finish_frame (venc, frame);
|
||||
+
|
||||
+done:
|
||||
+ if (request)
|
||||
+ gst_v4l2_encoder_request_unref (request);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_init (GstV4l2CodecVp8Enc * self)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_subinit (GstV4l2CodecVp8Enc * self,
|
||||
+ GstV4l2CodecVp8EncClass * klass)
|
||||
+{
|
||||
+ self->encoder = gst_v4l2_encoder_new (klass->device);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_dispose (GObject * object)
|
||||
+{
|
||||
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (object);
|
||||
+
|
||||
+ g_clear_object (&self->encoder);
|
||||
+
|
||||
+ G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_class_init (GstV4l2CodecVp8EncClass * klass)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_v4l2_codec_vp8_enc_subclass_init (GstV4l2CodecVp8EncClass * klass,
|
||||
+ GstV4l2CodecDevice * device)
|
||||
+{
|
||||
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
+ GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
|
||||
+ GstVp8EncoderClass *vp8encoder_class = GST_VP8_ENCODER_CLASS (klass);
|
||||
+
|
||||
+ gobject_class->set_property = gst_v4l2_codec_vp8_enc_set_property;
|
||||
+ gobject_class->get_property = gst_v4l2_codec_vp8_enc_get_property;
|
||||
+ gobject_class->dispose = gst_v4l2_codec_vp8_enc_dispose;
|
||||
+
|
||||
+ gst_element_class_set_static_metadata (element_class,
|
||||
+ "V4L2 Stateless VP8 Video Encoder",
|
||||
+ "Codec/Encoder/Video/Hardware",
|
||||
+ "A V4L2 based VP8 video encoder",
|
||||
+ "Benjamin Gaignard <benjamin.gaignard@collabora.com>");
|
||||
+
|
||||
+ gst_element_class_add_static_pad_template (element_class, &sink_template);
|
||||
+ gst_element_class_add_static_pad_template (element_class, &src_template);
|
||||
+
|
||||
+ element_class->change_state =
|
||||
+ GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_change_state);
|
||||
+
|
||||
+ encoder_class->open = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_open);
|
||||
+ encoder_class->close = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_close);
|
||||
+ encoder_class->start = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_start);
|
||||
+ encoder_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_stop);
|
||||
+ encoder_class->set_format =
|
||||
+ GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_set_format);
|
||||
+ encoder_class->flush = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_flush);
|
||||
+ encoder_class->sink_event =
|
||||
+ GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_sink_event);
|
||||
+ encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_getcaps);
|
||||
+ vp8encoder_class->encode_frame =
|
||||
+ GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_encode_frame);
|
||||
+
|
||||
+ klass->device = device;
|
||||
+ gst_v4l2_encoder_install_properties (gobject_class, PROP_LAST, device);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+gst_v4l2_codec_vp8_enc_register (GstPlugin * plugin, GstV4l2Encoder * encoder,
|
||||
+ GstV4l2CodecDevice * device, guint rank)
|
||||
+{
|
||||
+ gchar *element_name;
|
||||
+ guint version;
|
||||
+
|
||||
+ GST_DEBUG_CATEGORY_INIT (v4l2_vp8enc_debug, "v4l2codecs-vp8enc", 0,
|
||||
+ "V4L2 stateless VP8 encoder");
|
||||
+
|
||||
+ version = gst_v4l2_encoder_get_version (encoder);
|
||||
+ if (version < V4L2_MIN_KERNEL_VERSION)
|
||||
+ GST_WARNING ("V4L2 API v%u.%u too old, at least v%u.%u required",
|
||||
+ (version >> 16) & 0xff, (version >> 8) & 0xff,
|
||||
+ V4L2_MIN_KERNEL_VER_MAJOR, V4L2_MIN_KERNEL_VER_MINOR);
|
||||
+
|
||||
+ if (!gst_v4l2_codec_vp8_enc_api_check (encoder)) {
|
||||
+ GST_WARNING ("Not registering VP8 encoder as it failed ABI check.");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ gst_v4l2_encoder_register (plugin, GST_TYPE_V4L2_CODEC_VP8_ENC,
|
||||
+ (GClassInitFunc) gst_v4l2_codec_vp8_enc_subclass_init,
|
||||
+ gst_mini_object_ref (GST_MINI_OBJECT (device)),
|
||||
+ (GInstanceInitFunc) gst_v4l2_codec_vp8_enc_subinit,
|
||||
+ "v4l2sl%svp8enc", device, rank, &element_name);
|
||||
+}
|
||||
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.h b/sys/v4l2codecs/gstv4l2codecvp8enc.h
|
||||
new file mode 100644
|
||||
index 0000000..115b147
|
||||
--- /dev/null
|
||||
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.h
|
||||
@@ -0,0 +1,54 @@
|
||||
+/* GStreamer
|
||||
+ * Copyright (C) 2022 Benjamin Gaignard <benjamin.gaignard@collabora.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 St, Fifth Floor,
|
||||
+ * Boston, MA 02110-1301, USA.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __GST_V4L2_CODEC_VP8_ENC_H__
|
||||
+#define __GST_V4L2_CODEC_VP8_ENC_H__
|
||||
+
|
||||
+#define GST_USE_UNSTABLE_API
|
||||
+#include <gst/codecs/gstvp8encoder.h>
|
||||
+
|
||||
+#include "gstv4l2encoder.h"
|
||||
+
|
||||
+G_BEGIN_DECLS
|
||||
+
|
||||
+#define GST_TYPE_V4L2_CODEC_VP8_ENC (gst_v4l2_codec_vp8_enc_get_type())
|
||||
+#define GST_V4L2_CODEC_VP8_ENC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_CODEC_VP8_ENC,GstV4l2CodecVp8Enc))
|
||||
+#define GST_V4L2_CODEC_VP8_ENC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_CODEC_VP8_ENC,GstV4l2CodecVp8EncClass))
|
||||
+#define GST_V4L2_CODEC_VP8_ENC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_V4L2_CODEC_VP8_ENC, GstV4l2CodecVp8EncClass))
|
||||
+#define GST_IS_V4L2_CODEC_VP8_ENC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_CODEC_VP8_ENC))
|
||||
+#define GST_IS_V4L2_CODEC_VP8_ENC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_CODEC_VP8_ENC))
|
||||
+
|
||||
+typedef struct _GstV4l2CodecVp8Enc GstV4l2CodecVp8Enc;
|
||||
+typedef struct _GstV4l2CodecVp8EncClass GstV4l2CodecVp8EncClass;
|
||||
+
|
||||
+struct _GstV4l2CodecVp8EncClass
|
||||
+{
|
||||
+ GstVp8EncoderClass parent_class;
|
||||
+ GstV4l2CodecDevice *device;
|
||||
+};
|
||||
+
|
||||
+GType gst_v4l2_codec_vp8_enc_get_type (void);
|
||||
+void gst_v4l2_codec_vp8_enc_register (GstPlugin * plugin,
|
||||
+ GstV4l2Encoder * encoder,
|
||||
+ GstV4l2CodecDevice * device,
|
||||
+ guint rank);
|
||||
+
|
||||
+G_END_DECLS
|
||||
+
|
||||
+#endif /* __GST_V4L2_CODEC_VP8_ENC_H__ */
|
||||
diff --git a/sys/v4l2codecs/meson.build b/sys/v4l2codecs/meson.build
|
||||
index 53e8923..638c578 100644
|
||||
--- a/sys/v4l2codecs/meson.build
|
||||
+++ b/sys/v4l2codecs/meson.build
|
||||
@@ -12,6 +12,7 @@ v4l2codecs_sources = [
|
||||
'gstv4l2format.c',
|
||||
'gstv4l2codecalphadecodebin.c',
|
||||
'gstv4l2encoder.c',
|
||||
+ 'gstv4l2codecvp8enc.c',
|
||||
]
|
||||
|
||||
libgudev_dep = dependency('gudev-1.0', required: get_option('v4l2codecs'))
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
From 9f38752fa28cb43b1069fe6fa9ce7e1db5958962 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Gaignard <benjamin.gaignard@collabora.com>
|
||||
Date: Mon, 16 Jan 2023 17:40:30 +0100
|
||||
Subject: [PATCH 5/5] v4l2codecs: Register V4L2 stateless Vp8 encoder
|
||||
|
||||
If a v4l2 stateless VP8 encoder is detected register the matching
|
||||
element.
|
||||
---
|
||||
sys/v4l2codecs/plugin.c | 35 +++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 35 insertions(+)
|
||||
|
||||
diff --git a/sys/v4l2codecs/plugin.c b/sys/v4l2codecs/plugin.c
|
||||
index ac83e1b..7867474 100644
|
||||
--- a/sys/v4l2codecs/plugin.c
|
||||
+++ b/sys/v4l2codecs/plugin.c
|
||||
@@ -27,8 +27,10 @@
|
||||
#include "gstv4l2codech265dec.h"
|
||||
#include "gstv4l2codecmpeg2dec.h"
|
||||
#include "gstv4l2codecvp8dec.h"
|
||||
+#include "gstv4l2codecvp8enc.h"
|
||||
#include "gstv4l2codecvp9dec.h"
|
||||
#include "gstv4l2decoder.h"
|
||||
+#include "gstv4l2encoder.h"
|
||||
#include "linux/v4l2-controls.h"
|
||||
#include "linux/media.h"
|
||||
|
||||
@@ -91,6 +93,36 @@ register_video_decoder (GstPlugin * plugin, GstV4l2CodecDevice * device)
|
||||
g_object_unref (decoder);
|
||||
}
|
||||
|
||||
+static void
|
||||
+register_video_encoder (GstPlugin * plugin, GstV4l2CodecDevice * device)
|
||||
+{
|
||||
+ GstV4l2Encoder *encoder = gst_v4l2_encoder_new (device);
|
||||
+ gint i;
|
||||
+ guint32 fmt;
|
||||
+
|
||||
+ if (!gst_v4l2_encoder_open (encoder)) {
|
||||
+ g_object_unref (encoder);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; gst_v4l2_encoder_enum_src_formats (encoder, i, &fmt); i++) {
|
||||
+ switch (fmt) {
|
||||
+ case V4L2_PIX_FMT_VP8_FRAME:
|
||||
+ GST_INFO_OBJECT (encoder, "Registering %s as VP8 Encoder",
|
||||
+ device->name);
|
||||
+ gst_v4l2_codec_vp8_enc_register (plugin, encoder, device,
|
||||
+ GST_RANK_PRIMARY + 1);
|
||||
+ break;
|
||||
+ default:
|
||||
+ GST_FIXME_OBJECT (encoder, "%" GST_FOURCC_FORMAT " is not supported.",
|
||||
+ GST_FOURCC_ARGS (fmt));
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ g_object_unref (encoder);
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
@@ -112,6 +144,9 @@ plugin_init (GstPlugin * plugin)
|
||||
|
||||
if (device->function == MEDIA_ENT_F_PROC_VIDEO_DECODER)
|
||||
register_video_decoder (plugin, device);
|
||||
+
|
||||
+ if (device->function == MEDIA_ENT_F_PROC_VIDEO_ENCODER)
|
||||
+ register_video_encoder (plugin, device);
|
||||
}
|
||||
|
||||
gst_v4l2_codec_device_list_free (devices);
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
From 5cf87e34ad0aa98ceb004f68ea72498f490e6858 Mon Sep 17 00:00:00 2001
|
||||
From: Hugues Fruchet <hugues.fruchet@st.com>
|
||||
Date: Wed, 12 Dec 2018 12:04:03 +0100
|
||||
Subject: [PATCH 08/14] waylandsink: HACK: disable frame dropping while redraw
|
||||
is pending
|
||||
|
||||
This workaround is needed to reach 30fps video playback.
|
||||
|
||||
Redraw callback is received late, leading to many frames
|
||||
being dropped and so low framerate on display driver stage.
|
||||
The fact that redraw callback is received late is not yet understood
|
||||
but display subsystem is able to sustain a higher framerate
|
||||
than the one reached with redraw callback mechanism.
|
||||
This workaround consists to ignore redraw callback allowing to
|
||||
get back to the expected framerate performances.
|
||||
|
||||
Even if not observed yet, there is a risk of visible decoding artefacts
|
||||
due to the fact that downstream elements could rewrite in a frame
|
||||
being currently rendered by display subsystem...
|
||||
|
||||
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
|
||||
---
|
||||
ext/wayland/gstwaylandsink.c | 19 +++++++++++++++++++
|
||||
1 file changed, 19 insertions(+)
|
||||
|
||||
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
||||
index a5fb0cd..d98c53f 100644
|
||||
--- a/ext/wayland/gstwaylandsink.c
|
||||
+++ b/ext/wayland/gstwaylandsink.c
|
||||
@@ -806,10 +806,29 @@ render_last_buffer (GstWaylandSink * self, gboolean redraw)
|
||||
wlbuffer = gst_buffer_get_wl_buffer (self->display, self->last_buffer);
|
||||
surface = gst_wl_window_get_wl_surface (self->window);
|
||||
|
||||
+ /*
|
||||
+ * HACK: disable frame dropping while redraw is pending
|
||||
+ *
|
||||
+ * This workaround is needed to reach 30fps video playback.
|
||||
+ *
|
||||
+ * Redraw callback is received late, leading to many frames
|
||||
+ * being dropped and so low framerate on display driver stage.
|
||||
+ * The fact that redraw callback is received late is not yet understood
|
||||
+ * but display subsystem is able to sustain a higher framerate
|
||||
+ * than the one reached with redraw callback mechanism.
|
||||
+ * This workaround consists to ignore redraw callback allowing to
|
||||
+ * get back to the expected framerate performances.
|
||||
+ *
|
||||
+ * Why not observed yet, there is a risk of visible decoding artefacts
|
||||
+ * due to the fact that downstream elements could rewrite in a frame
|
||||
+ * being currently rendered by display subsystem...
|
||||
+ */
|
||||
+#if 0
|
||||
self->redraw_pending = TRUE;
|
||||
callback = wl_surface_frame (surface);
|
||||
self->callback = callback;
|
||||
wl_callback_add_listener (callback, &frame_callback_listener, self);
|
||||
+#endif
|
||||
|
||||
if (G_UNLIKELY (self->video_info_changed && !redraw)) {
|
||||
info = &self->video_info;
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
From cf7bb1dd6061de058c33dbc9cd268441af784309 Mon Sep 17 00:00:00 2001
|
||||
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
||||
Date: Tue, 8 Aug 2023 16:13:35 +0200
|
||||
Subject: [PATCH] v4l2codecs: add key frame signaling
|
||||
|
||||
Propagate V4L2 keyframe flags signaling to upstream elements
|
||||
by setting GstBuffer delta-unit flag & GstVideoCodecFrame sync point flag.
|
||||
|
||||
Signed-off-by: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
||||
---
|
||||
sys/v4l2codecs/gstv4l2codecvp8enc.c | 11 ++++++++++-
|
||||
sys/v4l2codecs/gstv4l2encoder.c | 7 ++++---
|
||||
sys/v4l2codecs/gstv4l2encoder.h | 2 +-
|
||||
3 files changed, 15 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.c b/sys/v4l2codecs/gstv4l2codecvp8enc.c
|
||||
index 2f15caf..71c7dd2 100644
|
||||
--- a/sys/v4l2codecs/gstv4l2codecvp8enc.c
|
||||
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.c
|
||||
@@ -542,6 +542,7 @@ gst_v4l2_codec_vp8_enc_encode_frame (GstVp8Encoder * encoder,
|
||||
GstVideoCodecFrame *frame = vp8_frame->frame;
|
||||
GstBuffer *resized_buffer;
|
||||
guint32 bytesused;
|
||||
+ guint32 flags;
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
struct v4l2_ext_control control[] = {
|
||||
@@ -596,7 +597,7 @@ gst_v4l2_codec_vp8_enc_encode_frame (GstVp8Encoder * encoder,
|
||||
goto done;
|
||||
}
|
||||
|
||||
- if (!gst_v4l2_encoder_request_set_done (request, &bytesused)) {
|
||||
+ if (!gst_v4l2_encoder_request_set_done (request, &bytesused, &flags)) {
|
||||
GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
|
||||
("Driver did not ack the request."), (NULL));
|
||||
goto done;
|
||||
@@ -609,6 +610,14 @@ gst_v4l2_codec_vp8_enc_encode_frame (GstVp8Encoder * encoder,
|
||||
gst_buffer_replace (&frame->output_buffer, resized_buffer);
|
||||
gst_buffer_unref (resized_buffer);
|
||||
|
||||
+ if (flags & V4L2_BUF_FLAG_KEYFRAME) {
|
||||
+ GST_BUFFER_FLAG_UNSET (frame->output_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
+ GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
|
||||
+ } else {
|
||||
+ GST_BUFFER_FLAG_SET (frame->output_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
+ GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
|
||||
+ }
|
||||
+
|
||||
return gst_video_encoder_finish_frame (venc, frame);
|
||||
|
||||
done:
|
||||
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
|
||||
index 5ae2cfa..e2ef423 100644
|
||||
--- a/sys/v4l2codecs/gstv4l2encoder.c
|
||||
+++ b/sys/v4l2codecs/gstv4l2encoder.c
|
||||
@@ -696,7 +696,7 @@ gst_v4l2_encoder_dequeue_sink (GstV4l2Encoder * self)
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_encoder_dequeue_src (GstV4l2Encoder * self, guint32 * out_frame_num,
|
||||
- guint32 * bytesused)
|
||||
+ guint32 * bytesused, guint32 * flags)
|
||||
{
|
||||
gint ret;
|
||||
struct v4l2_plane planes[GST_VIDEO_MAX_PLANES] = { {0} };
|
||||
@@ -718,6 +718,7 @@ gst_v4l2_encoder_dequeue_src (GstV4l2Encoder * self, guint32 * out_frame_num,
|
||||
|
||||
*out_frame_num = buf.timestamp.tv_usec;
|
||||
*bytesused = buf.m.planes[0].bytesused;
|
||||
+ *flags = buf.flags;
|
||||
|
||||
GST_TRACE_OBJECT (self, "Dequeued bitstream buffer %i, %d bytes used",
|
||||
buf.index, buf.m.planes[0].bytesused);
|
||||
@@ -1137,7 +1138,7 @@ gst_v4l2_encoder_request_queue (GstV4l2Request * request, guint flags)
|
||||
|
||||
gint
|
||||
gst_v4l2_encoder_request_set_done (GstV4l2Request * request,
|
||||
- guint32 * bytesused)
|
||||
+ guint32 * bytesused, guint32 * flags)
|
||||
{
|
||||
GstV4l2Encoder *encoder = request->encoder;
|
||||
GstV4l2Request *pending_req = NULL;
|
||||
@@ -1167,7 +1168,7 @@ gst_v4l2_encoder_request_set_done (GstV4l2Request * request,
|
||||
|
||||
if (!pending_req->hold_pic_buf) {
|
||||
guint32 frame_num = G_MAXUINT32;
|
||||
- if (!gst_v4l2_encoder_dequeue_src (encoder, &frame_num, bytesused)) {
|
||||
+ if (!gst_v4l2_encoder_dequeue_src (encoder, &frame_num, bytesused, flags)) {
|
||||
pending_req->failed = TRUE;
|
||||
} else if (frame_num != pending_req->frame_num) {
|
||||
GST_WARNING_OBJECT (encoder,
|
||||
diff --git a/sys/v4l2codecs/gstv4l2encoder.h b/sys/v4l2codecs/gstv4l2encoder.h
|
||||
index 7ff01a9..9acb0e3 100644
|
||||
--- a/sys/v4l2codecs/gstv4l2encoder.h
|
||||
+++ b/sys/v4l2codecs/gstv4l2encoder.h
|
||||
@@ -128,7 +128,7 @@ void gst_v4l2_encoder_ro_request_unref (GstV4l2Request * request);
|
||||
gboolean gst_v4l2_encoder_request_queue (GstV4l2Request * request,
|
||||
guint flags);
|
||||
|
||||
-gint gst_v4l2_encoder_request_set_done (GstV4l2Request * request, guint32 * bytesused);
|
||||
+gint gst_v4l2_encoder_request_set_done (GstV4l2Request * request, guint32 * bytesused, guint32 * flags);
|
||||
|
||||
gboolean gst_v4l2_encoder_request_failed (GstV4l2Request * request);
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
From 3ffaca250df9e72917ed3306d538474f44d7b1e2 Mon Sep 17 00:00:00 2001
|
||||
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
||||
Date: Thu, 17 Aug 2023 11:10:54 +0200
|
||||
Subject: [PATCH 2/2] gtkwaylandsink: HACK: disable frame dropping while redraw
|
||||
is pending
|
||||
|
||||
This workaround is needed to reach 30fps video playback.
|
||||
|
||||
Redraw callback is received late, leading to many frames
|
||||
being dropped and so low framerate on display driver stage.
|
||||
The fact that redraw callback is received late is not yet understood
|
||||
but display subsystem is able to sustain a higher framerate
|
||||
than the one reached with redraw callback mechanism.
|
||||
This workaround consists to ignore redraw callback allowing to
|
||||
get back to the expected framerate performances.
|
||||
|
||||
Even if not observed yet, there is a risk of visible decoding artefacts
|
||||
due to the fact that downstream elements could rewrite in a frame
|
||||
being currently rendered by display subsystem...
|
||||
|
||||
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 19 +++++++++++++++++++
|
||||
1 file changed, 19 insertions(+)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 26e4aa0..88cbe5d 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -1095,10 +1095,29 @@ render_last_buffer (GstGtkWaylandSink * self, gboolean redraw)
|
||||
wlbuffer = gst_buffer_get_wl_buffer (priv->display, priv->last_buffer);
|
||||
surface = gst_wl_window_get_wl_surface (priv->wl_window);
|
||||
|
||||
+ /*
|
||||
+ * HACK: disable frame dropping while redraw is pending
|
||||
+ *
|
||||
+ * This workaround is needed to reach 30fps video playback.
|
||||
+ *
|
||||
+ * Redraw callback is received late, leading to many frames
|
||||
+ * being dropped and so low framerate on display driver stage.
|
||||
+ * The fact that redraw callback is received late is not yet understood
|
||||
+ * but display subsystem is able to sustain a higher framerate
|
||||
+ * than the one reached with redraw callback mechanism.
|
||||
+ * This workaround consists to ignore redraw callback allowing to
|
||||
+ * get back to the expected framerate performances.
|
||||
+ *
|
||||
+ * Why not observed yet, there is a risk of visible decoding artefacts
|
||||
+ * due to the fact that downstream elements could rewrite in a frame
|
||||
+ * being currently rendered by display subsystem...
|
||||
+ */
|
||||
+#if 0
|
||||
priv->redraw_pending = TRUE;
|
||||
callback = wl_surface_frame (surface);
|
||||
priv->callback = callback;
|
||||
wl_callback_add_listener (callback, &frame_callback_listener, self);
|
||||
+#endif
|
||||
|
||||
if (G_UNLIKELY (priv->video_info_changed && !redraw)) {
|
||||
info = &priv->video_info;
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
From ec109f9a3b50f21227e15f45b1558b0f5c6f73ef Mon Sep 17 00:00:00 2001
|
||||
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
||||
Date: Wed, 16 Aug 2023 17:14:55 +0200
|
||||
Subject: [PATCH 1/2] gtkwaylandsink: cancel pending redraw callback on
|
||||
pause/resume
|
||||
|
||||
Pipeline freeze have been observed when doing intensive pause/resume
|
||||
on video playback.
|
||||
|
||||
Analysis shows that gtkwaylandsink element is stalled on state change
|
||||
from PLAYING to PAUSED or PAUSED to PLAYING.
|
||||
|
||||
There is a first problem when ASYNC state change is returned by parent
|
||||
class; in this case we prematurely return from state_change, fix that by
|
||||
checking GST_STATE_CHANGE_FAILURE instead.
|
||||
|
||||
The other problem is about eventual pending wayland listener callback
|
||||
(see redraw_callback mechanism) while changing state which cause
|
||||
further freeze of element. Fix this by destroying listener callback
|
||||
and resetting redraw_callback flag when going from PLAYING to PAUSED and
|
||||
PAUSED to PLAYING.
|
||||
|
||||
Signed-off-by: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
||||
---
|
||||
ext/gtk/gstgtkwaylandsink.c | 14 +++++++++++++-
|
||||
1 file changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
||||
index 0d6ea69..26e4aa0 100644
|
||||
--- a/ext/gtk/gstgtkwaylandsink.c
|
||||
+++ b/ext/gtk/gstgtkwaylandsink.c
|
||||
@@ -736,7 +736,7 @@ gst_gtk_wayland_sink_change_state (GstElement * element,
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
- if (ret != GST_STATE_CHANGE_SUCCESS)
|
||||
+ if (ret == GST_STATE_CHANGE_FAILURE)
|
||||
return ret;
|
||||
|
||||
switch (transition) {
|
||||
@@ -762,6 +762,18 @@ gst_gtk_wayland_sink_change_state (GstElement * element,
|
||||
priv->redraw_pending = FALSE;
|
||||
g_mutex_unlock (&priv->render_lock);
|
||||
break;
|
||||
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||
+ /* Destroy pending redraw callback otherwise
|
||||
+ * element may freeze */
|
||||
+ g_mutex_lock (&priv->render_lock);
|
||||
+ if (priv->callback) {
|
||||
+ wl_callback_destroy (priv->callback);
|
||||
+ priv->callback = NULL;
|
||||
+ }
|
||||
+ priv->redraw_pending = FALSE;
|
||||
+ g_mutex_unlock (&priv->render_lock);
|
||||
+ break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
From ee75c40eff3ed516535e8b150e5a17206e73d81a Mon Sep 17 00:00:00 2001
|
||||
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
||||
Date: Wed, 30 Aug 2023 10:48:22 +0200
|
||||
Subject: [PATCH 1/3] v4l2codecs: fix support of unaligned videos
|
||||
|
||||
Current implementation fails on frame input mapping when
|
||||
driver returns an aligned width & height.
|
||||
Fix this by ignoring aligned width & height returned by S_FMT,
|
||||
it is useless till buffer alignment is extrapolated later on
|
||||
from bytesperline and sizeimage S_FMT values.
|
||||
|
||||
Signed-off-by: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
||||
---
|
||||
sys/v4l2codecs/gstv4l2encoder.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
|
||||
index e2ef423..eabb74a 100644
|
||||
--- a/sys/v4l2codecs/gstv4l2encoder.c
|
||||
+++ b/sys/v4l2codecs/gstv4l2encoder.c
|
||||
@@ -415,6 +415,10 @@ gst_v4l2_encoder_select_sink_format (GstV4l2Encoder * self, GstVideoInfo * in,
|
||||
}
|
||||
}
|
||||
|
||||
+
|
||||
+ fmt.fmt.pix_mp.width = width;
|
||||
+ fmt.fmt.pix_mp.height = height;
|
||||
+
|
||||
if (!gst_v4l2_format_to_video_info (&fmt, out)) {
|
||||
GST_ERROR_OBJECT (self, "Unsupported V4L2 pixelformat %" GST_FOURCC_FORMAT,
|
||||
GST_FOURCC_ARGS (fmt.fmt.pix_mp.pixelformat));
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
|
||||
|
||||
SRC_URI:append = " \
|
||||
file://0001-kmsallocator-Port-to-the-new-DRM-Dumb-Allocator.patch \
|
||||
file://0002-gtkwaylandsink-Remove-redefine-of-GST_CAPS_FEATURE_M.patch \
|
||||
file://0003-waylandsink-Stop-modifying-the-display-GstVideoInfo.patch \
|
||||
file://0004-gtkwaylandsink-Force-a-redraw-on-resolution-change.patch \
|
||||
file://0005-waylandsink-Let-the-baseclass-know-when-frames-are-d.patch \
|
||||
file://0006-waylandsink-Refactor-internal-pool-handling.patch \
|
||||
file://0007-gtkwaylandsink-Fix-display-wl_window-pool-leaks.patch \
|
||||
file://0008-wllinuxdmabuf-Handle-video-meta-inside-the-importer.patch \
|
||||
file://0009-wlvideoformat-Fix-sign-issue-for-DRM-fourcc.patch \
|
||||
file://0010-wlvideobufferpool-Add-DRM-Dumb-buffer-support.patch \
|
||||
file://0011-wayladnsink-Add-DRM-Dumb-allocator-support.patch \
|
||||
file://0012-bad-Update-doc-cache-for-waylandsink-changes.patch \
|
||||
file://0014-WAYLANDSINK-use-card0a-as-default-drm-device.patch \
|
||||
file://0015-waylandsink-Uprank-to-secondary.patch \
|
||||
file://0016-gstwlshmallocator-correct-WL-API-declaration.patch \
|
||||
file://0017-gtkwaylandsink-Destroy-GstWlWindow-when-par.patch \
|
||||
file://0018-GTKWAYLANDSINK-use-card0-as-default-drm-device.patch \
|
||||
file://0019-waylandsink-Emit-map-signal-boarder-surface-is-ready.patch \
|
||||
file://0020-gtkwaylandsink-do-not-use-drm-dumb-pool-with-DMAbuf-.patch \
|
||||
file://0022-codecs-Add-base-class-for-stateless-vp8-encoder.patch \
|
||||
file://0023-v4l2codecs-Add-V4L2-VP8-stateless-encode-uAPI.patch \
|
||||
file://0024-v4l2codecs-Add-v4l2-encoder-class.patch \
|
||||
file://0025-v4l2codecs-Add-V4L2-stateless-VP8-encoder.patch \
|
||||
file://0026-v4l2codecs-Register-V4L2-stateless-Vp8-encoder.patch \
|
||||
file://0027-waylandsink-HACK-disable-frame-dropping-while-redraw.patch \
|
||||
file://0028-v4l2codecs-add-key-frame-signaling.patch \
|
||||
file://0029-gtkwaylandsink-HACK-disable-frame-dropping-while-red.patch \
|
||||
file://0030-gtkwaylandsink-cancel-pending-redraw-callback-on-pau.patch \
|
||||
file://0031-v4l2codecs-fix-support-of-unaligned-videos.patch \
|
||||
"
|
||||
|
||||
PACKAGECONFIG_GL ?= "${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'gles2 egl', '', d)}"
|
||||
PACKAGECONFIG[gtk3] = "-Dgtk3=enabled,-Dgtk3=disabled,gtk+3"
|
||||
|
||||
PACKAGECONFIG ?= " \
|
||||
${GSTREAMER_ORC} \
|
||||
${@bb.utils.contains('DISTRO_FEATURES', 'bluetooth', 'bluez', '', d)} \
|
||||
${@bb.utils.filter('DISTRO_FEATURES', 'directfb vulkan', d)} \
|
||||
${@bb.utils.contains('DISTRO_FEATURES', 'wayland', 'wayland gtk3', '', d)} \
|
||||
${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'gl', '', d)} \
|
||||
bz2 closedcaption curl dash dtls hls rsvg sbc smoothstreaming sndfile \
|
||||
ttml uvch264 webp \
|
||||
faac kms \
|
||||
v4l2codecs \
|
||||
"
|
||||
|
||||
do_install:append() {
|
||||
install -d ${D}${includedir}/gstreamer-1.0/wayland
|
||||
install -m 644 ${S}/gst-libs/gst/wayland/wayland.h ${D}${includedir}/gstreamer-1.0/wayland
|
||||
}
|
||||
@@ -0,0 +1,954 @@
|
||||
From 3923d3d4c64870a02f6f219c3444fdcb196dca23 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Wed, 8 Feb 2023 16:50:10 -0500
|
||||
Subject: [PATCH] allocators: Add a DRM Dumb Allocator
|
||||
|
||||
This allow allocating memory from any DRM driver that supports this
|
||||
method. It additionally allow exporting DMABuf. This allocator depends
|
||||
on libdrm and will be stubbed if the dependency is missing. This is derived
|
||||
from kmssink dumb allocator.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
gst-libs/gst/allocators/allocators.h | 1 +
|
||||
gst-libs/gst/allocators/gstdrmdumb.c | 755 +++++++++++++++++++++++++++
|
||||
gst-libs/gst/allocators/gstdrmdumb.h | 88 ++++
|
||||
gst-libs/gst/allocators/meson.build | 7 +-
|
||||
meson.build | 7 +
|
||||
meson_options.txt | 1 +
|
||||
6 files changed, 856 insertions(+), 3 deletions(-)
|
||||
create mode 100644 gst-libs/gst/allocators/gstdrmdumb.c
|
||||
create mode 100644 gst-libs/gst/allocators/gstdrmdumb.h
|
||||
|
||||
diff --git a/gst-libs/gst/allocators/allocators.h b/gst-libs/gst/allocators/allocators.h
|
||||
index b616aa2..65e7e81 100644
|
||||
--- a/gst-libs/gst/allocators/allocators.h
|
||||
+++ b/gst-libs/gst/allocators/allocators.h
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <gst/allocators/gstdmabuf.h>
|
||||
#include <gst/allocators/gstfdmemory.h>
|
||||
#include <gst/allocators/gstphysmemory.h>
|
||||
+#include <gst/allocators/gstdrmdumb.h>
|
||||
|
||||
#endif /* __GST_ALLOCATORS_H__ */
|
||||
|
||||
diff --git a/gst-libs/gst/allocators/gstdrmdumb.c b/gst-libs/gst/allocators/gstdrmdumb.c
|
||||
new file mode 100644
|
||||
index 0000000..c5c4834
|
||||
--- /dev/null
|
||||
+++ b/gst-libs/gst/allocators/gstdrmdumb.c
|
||||
@@ -0,0 +1,755 @@
|
||||
+/* GStreamer
|
||||
+ *
|
||||
+ * Copyright (C) 2023 Collabora
|
||||
+ * Copyright (C) 2016 Igalia
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
|
||||
+ * Javier Martin <javiermartin@by.com.es>
|
||||
+ * Colin Kinloch <colin.kinloch@collabora.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 St, Fifth Floor,
|
||||
+ * Boston, MA 02110-1301, USA.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+#include "config.h"
|
||||
+#endif
|
||||
+
|
||||
+#include "gstdrmdumb.h"
|
||||
+#include "gstdmabuf.h"
|
||||
+
|
||||
+/**
|
||||
+ * SECTION:gstdrmdumb
|
||||
+ * @title: GstDRMDumbAllocator
|
||||
+ * @short_description: Memory wrapper for Linux DRM Dumb memory
|
||||
+ * @see_also: #GstMemory
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+#include <fcntl.h>
|
||||
+#include <sys/ioctl.h>
|
||||
+#include <sys/mman.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+#include <drm.h>
|
||||
+#include <drm_fourcc.h>
|
||||
+#include <xf86drm.h>
|
||||
+#endif
|
||||
+
|
||||
+#define GST_CAT_DEFAULT drmdumballocator_debug
|
||||
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
+
|
||||
+#define GST_DRM_DUMB_MEMORY_TYPE "DRMDumbMemory"
|
||||
+
|
||||
+typedef struct _GstDRMDumbMemory GstDRMDumbMemory;
|
||||
+struct _GstDRMDumbMemory
|
||||
+{
|
||||
+ GstMemory parent;
|
||||
+
|
||||
+ gpointer ptr;
|
||||
+ gsize size;
|
||||
+ guint32 handle;
|
||||
+ guint refs;
|
||||
+};
|
||||
+
|
||||
+struct _GstDRMDumbAllocator
|
||||
+{
|
||||
+ GstAllocator parent;
|
||||
+
|
||||
+ gint drm_fd;
|
||||
+ gchar *drm_device_path;
|
||||
+
|
||||
+ /* protected by GstDRMDumbAllocator object lock */
|
||||
+ GstAllocator *dmabuf_alloc;
|
||||
+};
|
||||
+
|
||||
+#define parent_class gst_drm_dumb_allocator_parent_class
|
||||
+G_DEFINE_TYPE_WITH_CODE (GstDRMDumbAllocator, gst_drm_dumb_allocator,
|
||||
+ GST_TYPE_ALLOCATOR,
|
||||
+ GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "drmdumballocator", 0,
|
||||
+ "DRM dumb buffer allocator"));
|
||||
+enum
|
||||
+{
|
||||
+ PROP_DRM_FD = 1,
|
||||
+ PROP_DRM_DEVICE_PATH,
|
||||
+ PROP_N,
|
||||
+};
|
||||
+
|
||||
+static GParamSpec *g_props[PROP_N] = { NULL, };
|
||||
+
|
||||
+/**
|
||||
+ * gst_is_drm_dumb_memory:
|
||||
+ * @mem: the memory to be checked
|
||||
+ *
|
||||
+ * Returns: %TRUE if @mem is DRM Dumb memory, otherwise %FALSE
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+gboolean
|
||||
+gst_is_drm_dumb_memory (GstMemory * mem)
|
||||
+{
|
||||
+ return gst_memory_is_type (mem, GST_DRM_DUMB_MEMORY_TYPE);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * gst_drm_dumb_memory_get_handle:
|
||||
+ * @mem: the memory to get the handle from
|
||||
+ *
|
||||
+ * Return the DRM buffer object handle associated with @mem.
|
||||
+ *
|
||||
+ * Returns: the DRM buffer object handle associated with the memory, or 0.
|
||||
+ * The handle is still owned by the GstMemory and cannot be used
|
||||
+ * beyond the lifetime of this GstMemory unless it is being passed
|
||||
+ * to DRM driver, which does handle a refcount internally.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+guint32
|
||||
+gst_drm_dumb_memory_get_handle (GstMemory * mem)
|
||||
+{
|
||||
+ if (!gst_is_drm_dumb_memory (mem))
|
||||
+ return 0;
|
||||
+
|
||||
+ return ((GstDRMDumbMemory *) mem)->handle;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * gst_drm_dumb_memory_export_dmabuf:
|
||||
+ * @mem: the memory to export from
|
||||
+ *
|
||||
+ * Exports a DMABuf from the DRM Bumb buffer object. One can check if this
|
||||
+ * feature is supported using gst_drm_dumb_allocator_has_prime_export();
|
||||
+ *
|
||||
+ * Returns: a #GstMemory from #GstDmaBufAllocator wrapping the exported dma-buf
|
||||
+ * file descriptor.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+GstMemory *
|
||||
+gst_drm_dumb_memory_export_dmabuf (GstMemory * mem)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ GstDRMDumbMemory *drmmem = (GstDRMDumbMemory *) mem;
|
||||
+ GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (mem->allocator);
|
||||
+ GstMemory *dmamem;
|
||||
+ gint ret;
|
||||
+ gint prime_fd;
|
||||
+
|
||||
+ ret = drmPrimeHandleToFD (alloc->drm_fd, drmmem->handle,
|
||||
+ DRM_CLOEXEC | DRM_RDWR, &prime_fd);
|
||||
+ if (ret)
|
||||
+ goto export_fd_failed;
|
||||
+
|
||||
+ if (G_UNLIKELY (alloc->dmabuf_alloc == NULL))
|
||||
+ alloc->dmabuf_alloc = gst_dmabuf_allocator_new ();
|
||||
+
|
||||
+ dmamem = gst_dmabuf_allocator_alloc (alloc->dmabuf_alloc, prime_fd,
|
||||
+ gst_memory_get_sizes (mem, NULL, NULL));
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (alloc, "Exported bo handle %d as %d", drmmem->handle,
|
||||
+ prime_fd);
|
||||
+
|
||||
+ return dmamem;
|
||||
+
|
||||
+ /* ERRORS */
|
||||
+export_fd_failed:
|
||||
+ {
|
||||
+ GST_ERROR_OBJECT (alloc, "Failed to export bo handle %d: %s (%d)",
|
||||
+ drmmem->handle, g_strerror (errno), ret);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+#else
|
||||
+ return NULL;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+static guint32
|
||||
+gst_drm_height_from_drm (guint32 drmfmt, guint32 height)
|
||||
+{
|
||||
+ guint32 ret;
|
||||
+
|
||||
+ switch (drmfmt) {
|
||||
+ case DRM_FORMAT_YUV420:
|
||||
+ case DRM_FORMAT_YVU420:
|
||||
+ case DRM_FORMAT_YUV422:
|
||||
+ case DRM_FORMAT_NV12:
|
||||
+ case DRM_FORMAT_NV21:
|
||||
+ case DRM_FORMAT_P010:
|
||||
+ case DRM_FORMAT_P016:
|
||||
+ ret = height * 3 / 2;
|
||||
+ break;
|
||||
+ case DRM_FORMAT_NV16:
|
||||
+ case DRM_FORMAT_NV61:
|
||||
+ ret = height * 2;
|
||||
+ break;
|
||||
+ case DRM_FORMAT_NV24:
|
||||
+ ret = height * 3;
|
||||
+ break;
|
||||
+ default:
|
||||
+ ret = height;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static guint32
|
||||
+gst_drm_bpp_from_drm (guint32 drm_fourcc)
|
||||
+{
|
||||
+ guint32 bpp;
|
||||
+
|
||||
+ switch (drm_fourcc) {
|
||||
+ case DRM_FORMAT_YUV420:
|
||||
+ case DRM_FORMAT_YVU420:
|
||||
+ case DRM_FORMAT_YUV422:
|
||||
+ case DRM_FORMAT_NV12:
|
||||
+ case DRM_FORMAT_NV21:
|
||||
+ case DRM_FORMAT_NV16:
|
||||
+ case DRM_FORMAT_NV61:
|
||||
+ case DRM_FORMAT_NV24:
|
||||
+ bpp = 8;
|
||||
+ break;
|
||||
+ case DRM_FORMAT_P010:
|
||||
+ bpp = 10;
|
||||
+ break;
|
||||
+ case DRM_FORMAT_UYVY:
|
||||
+ case DRM_FORMAT_YUYV:
|
||||
+ case DRM_FORMAT_YVYU:
|
||||
+ case DRM_FORMAT_P016:
|
||||
+ case DRM_FORMAT_RGB565:
|
||||
+ case DRM_FORMAT_BGR565:
|
||||
+ bpp = 16;
|
||||
+ break;
|
||||
+ case DRM_FORMAT_BGR888:
|
||||
+ case DRM_FORMAT_RGB888:
|
||||
+ bpp = 24;
|
||||
+ break;
|
||||
+ default:
|
||||
+ bpp = 32;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return bpp;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+check_drm_fd (GstDRMDumbAllocator * alloc)
|
||||
+{
|
||||
+ return alloc->drm_fd > -1;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_allocator_open_device (GstDRMDumbAllocator * alloc,
|
||||
+ const gchar * path)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ gint fd = -1;
|
||||
+
|
||||
+ /* Ignore default constructor call */
|
||||
+ if (path == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ /* construct only */
|
||||
+ g_assert (alloc->drm_fd == -1);
|
||||
+ g_assert (alloc->drm_device_path == NULL);
|
||||
+
|
||||
+ fd = open (path, O_RDWR | O_CLOEXEC);
|
||||
+
|
||||
+ if (fd < 0) {
|
||||
+ GST_WARNING_OBJECT (alloc, "Failed to open DRM device at %s", path);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ alloc->drm_device_path = g_strdup (path);
|
||||
+ alloc->drm_fd = fd;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_allocator_set_fd (GstDRMDumbAllocator * alloc, gint fd)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ /* Ignore default constructor call */
|
||||
+ if (fd == -1)
|
||||
+ return;
|
||||
+
|
||||
+ /* construct only */
|
||||
+ g_assert (alloc->drm_fd == -1);
|
||||
+ g_assert (alloc->drm_device_path == NULL);
|
||||
+
|
||||
+ if (fd >= 0) {
|
||||
+ alloc->drm_device_path = drmGetDeviceNameFromFd2 (fd);
|
||||
+ if (!alloc->drm_device_path) {
|
||||
+ GST_WARNING_OBJECT (alloc, "Failed to verify DRM fd.");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (alloc, "Using external FD for %s",
|
||||
+ alloc->drm_device_path);
|
||||
+
|
||||
+ alloc->drm_fd = dup (fd);
|
||||
+ }
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_allocator_memory_reset (GstDRMDumbAllocator * alloc,
|
||||
+ GstDRMDumbMemory * mem)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ gint err;
|
||||
+ struct drm_mode_destroy_dumb arg = { 0, };
|
||||
+
|
||||
+ if (!mem->size)
|
||||
+ return;
|
||||
+
|
||||
+ if (!check_drm_fd (alloc))
|
||||
+ return;
|
||||
+
|
||||
+ if (mem->ptr != NULL) {
|
||||
+ GST_WARNING_OBJECT (alloc, "destroying mapped bo (refcount=%d)", mem->refs);
|
||||
+ munmap (mem->ptr, mem->size);
|
||||
+ mem->ptr = NULL;
|
||||
+ }
|
||||
+
|
||||
+ arg.handle = mem->handle;
|
||||
+
|
||||
+ err = drmIoctl (alloc->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
|
||||
+ if (err)
|
||||
+ GST_WARNING_OBJECT (alloc,
|
||||
+ "Failed to destroy dumb buffer object: %s %d",
|
||||
+ g_strerror (errno), errno);
|
||||
+
|
||||
+ mem->handle = -1;
|
||||
+ mem->size = 0;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+gst_drm_dumb_allocator_memory_create (GstDRMDumbAllocator * alloc,
|
||||
+ GstDRMDumbMemory * drmmem,
|
||||
+ guint32 drm_fourcc, guint32 width, guint32 height, guint32 * out_pitch)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ gint ret;
|
||||
+ struct drm_mode_create_dumb arg = { 0, };
|
||||
+
|
||||
+ if (drmmem->size)
|
||||
+ return TRUE;
|
||||
+
|
||||
+ if (!check_drm_fd (alloc))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ arg.bpp = gst_drm_bpp_from_drm (drm_fourcc);
|
||||
+ arg.width = width;
|
||||
+ arg.height = gst_drm_height_from_drm (drm_fourcc, height);
|
||||
+
|
||||
+ ret = drmIoctl (alloc->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
|
||||
+ if (ret)
|
||||
+ goto create_failed;
|
||||
+
|
||||
+ if (!arg.pitch) {
|
||||
+ GST_DEBUG_OBJECT (alloc,
|
||||
+ "DRM dumb buffer pitch not set, no need to modify vinfo");
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ GST_DEBUG_OBJECT (alloc,
|
||||
+ "DRM dumb buffer pitch is set, vinfo modification required");
|
||||
+ *out_pitch = arg.pitch;
|
||||
+
|
||||
+done:
|
||||
+ drmmem->handle = arg.handle;
|
||||
+ /* will be used used as maxsize of GstMemory */
|
||||
+ drmmem->size = arg.size;
|
||||
+
|
||||
+ return TRUE;
|
||||
+
|
||||
+ /* ERRORS */
|
||||
+create_failed:
|
||||
+ {
|
||||
+ GST_ERROR_OBJECT (alloc, "Failed to create buffer object: %s (%d)",
|
||||
+ g_strerror (errno), errno);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+#else
|
||||
+ return FALSE;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_allocator_free (GstAllocator * base_alloc, GstMemory * mem)
|
||||
+{
|
||||
+ GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (base_alloc);
|
||||
+ GstDRMDumbMemory *drmmem;
|
||||
+
|
||||
+ drmmem = (GstDRMDumbMemory *) mem;
|
||||
+
|
||||
+ gst_drm_dumb_allocator_memory_reset (alloc, drmmem);
|
||||
+ g_free (drmmem);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_allocator_set_property (GObject * object, guint prop_id,
|
||||
+ const GValue * value, GParamSpec * pspec)
|
||||
+{
|
||||
+ GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (object);
|
||||
+
|
||||
+ switch (prop_id) {
|
||||
+ case PROP_DRM_FD:
|
||||
+ gst_drm_dumb_allocator_set_fd (alloc, g_value_get_int (value));
|
||||
+ break;
|
||||
+ case PROP_DRM_DEVICE_PATH:
|
||||
+ gst_drm_dumb_allocator_open_device (alloc, g_value_get_string (value));
|
||||
+ break;
|
||||
+ default:
|
||||
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_allocator_get_property (GObject * object, guint prop_id,
|
||||
+ GValue * value, GParamSpec * pspec)
|
||||
+{
|
||||
+ GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (object);
|
||||
+
|
||||
+ switch (prop_id) {
|
||||
+ case PROP_DRM_FD:
|
||||
+ g_value_set_int (value, alloc->drm_fd);
|
||||
+ break;
|
||||
+ case PROP_DRM_DEVICE_PATH:
|
||||
+ g_value_set_string (value, alloc->drm_device_path);
|
||||
+ break;
|
||||
+ default:
|
||||
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_allocator_finalize (GObject * obj)
|
||||
+{
|
||||
+ GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (obj);
|
||||
+
|
||||
+ if (alloc->dmabuf_alloc)
|
||||
+ gst_object_unref (alloc->dmabuf_alloc);
|
||||
+
|
||||
+ g_free (alloc->drm_device_path);
|
||||
+ alloc->drm_device_path = NULL;
|
||||
+
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ if (alloc->drm_fd >= 0) {
|
||||
+ close (alloc->drm_fd);
|
||||
+ alloc->drm_fd = -1;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_allocator_class_init (GstDRMDumbAllocatorClass * klass)
|
||||
+{
|
||||
+ GObjectClass *gobject_class;
|
||||
+ GstAllocatorClass *allocator_class;
|
||||
+
|
||||
+ allocator_class = GST_ALLOCATOR_CLASS (klass);
|
||||
+ gobject_class = G_OBJECT_CLASS (klass);
|
||||
+
|
||||
+ allocator_class->free = gst_drm_dumb_allocator_free;
|
||||
+
|
||||
+ gobject_class->set_property = gst_drm_dumb_allocator_set_property;
|
||||
+ gobject_class->get_property = gst_drm_dumb_allocator_get_property;
|
||||
+ gobject_class->finalize = gst_drm_dumb_allocator_finalize;
|
||||
+
|
||||
+ /**
|
||||
+ * GstDRMDumbAllocator:drm-fd:
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+ g_props[PROP_DRM_FD] = g_param_spec_int ("drm-fd", "DRM fd",
|
||||
+ "DRM file descriptor", -1, G_MAXINT, -1,
|
||||
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
+
|
||||
+ /**
|
||||
+ * GstDRMDumbAllocator:drm-device-path:
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+ g_props[PROP_DRM_DEVICE_PATH] = g_param_spec_string ("drm-device-path",
|
||||
+ "DRM device path", "DRM device path", NULL,
|
||||
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
|
||||
+
|
||||
+ g_object_class_install_properties (gobject_class, PROP_N, g_props);
|
||||
+}
|
||||
+
|
||||
+static gpointer
|
||||
+gst_drm_dumb_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (mem->allocator);
|
||||
+ GstDRMDumbMemory *drmmem;
|
||||
+ gint err;
|
||||
+ gpointer out;
|
||||
+ struct drm_mode_map_dumb arg = { 0, };
|
||||
+
|
||||
+
|
||||
+ if (!check_drm_fd (alloc))
|
||||
+ return NULL;
|
||||
+
|
||||
+ drmmem = (GstDRMDumbMemory *) mem;
|
||||
+ if (!drmmem->size)
|
||||
+ return NULL;
|
||||
+
|
||||
+ /* Reuse existing buffer object mapping if possible */
|
||||
+ if (drmmem->ptr != NULL) {
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ arg.handle = drmmem->handle;
|
||||
+
|
||||
+ err = drmIoctl (alloc->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
|
||||
+ if (err) {
|
||||
+ GST_ERROR_OBJECT (alloc, "Failed to get offset of buffer object: %s %d",
|
||||
+ g_strerror (errno), errno);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ out = mmap (0, drmmem->size,
|
||||
+ PROT_READ | PROT_WRITE, MAP_SHARED, alloc->drm_fd, arg.offset);
|
||||
+ if (out == MAP_FAILED) {
|
||||
+ GST_ERROR_OBJECT (alloc, "Failed to map dumb buffer object: %s %d",
|
||||
+ g_strerror (errno), errno);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ drmmem->ptr = out;
|
||||
+
|
||||
+out:
|
||||
+ g_atomic_int_inc (&drmmem->refs);
|
||||
+ return drmmem->ptr;
|
||||
+
|
||||
+#else
|
||||
+ return NULL;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_memory_unmap (GstMemory * mem)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ GstDRMDumbMemory *drmmem;
|
||||
+
|
||||
+ if (!check_drm_fd ((GstDRMDumbAllocator *) mem->allocator))
|
||||
+ return;
|
||||
+
|
||||
+ drmmem = (GstDRMDumbMemory *) mem;
|
||||
+ if (!drmmem->size)
|
||||
+ return;
|
||||
+
|
||||
+ if (g_atomic_int_dec_and_test (&drmmem->refs)) {
|
||||
+ munmap (drmmem->ptr, drmmem->size);
|
||||
+ drmmem->ptr = NULL;
|
||||
+ }
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+gst_drm_dumb_allocator_init (GstDRMDumbAllocator * alloc)
|
||||
+{
|
||||
+ GstAllocator *base_alloc = GST_ALLOCATOR_CAST (alloc);
|
||||
+
|
||||
+ alloc->drm_fd = -1;
|
||||
+ alloc->drm_device_path = NULL;
|
||||
+
|
||||
+ base_alloc->mem_type = GST_DRM_DUMB_MEMORY_TYPE;
|
||||
+ base_alloc->mem_map = gst_drm_dumb_memory_map;
|
||||
+ base_alloc->mem_unmap = gst_drm_dumb_memory_unmap;
|
||||
+ /* Use the default, fallback copy function */
|
||||
+
|
||||
+ GST_OBJECT_FLAG_SET (alloc, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
|
||||
+}
|
||||
+
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+static gboolean
|
||||
+check_cap (GstDRMDumbAllocator * alloc)
|
||||
+{
|
||||
+ gint ret;
|
||||
+ guint64 has_dumb = 0;
|
||||
+
|
||||
+ if (!alloc)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (!check_drm_fd (alloc))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ ret = drmGetCap (alloc->drm_fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
|
||||
+ if (ret)
|
||||
+ GST_WARNING_OBJECT (alloc, "could not get dumb buffer capability");
|
||||
+
|
||||
+ return ! !(has_dumb);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+/**
|
||||
+ * gst_drm_dumb_allocator_new_with_fd:
|
||||
+ * @drm_fd: file descriptor of the DRM device
|
||||
+ *
|
||||
+ * Creates a new #GstDRMDumbAllocator for the specific file desciptor. This
|
||||
+ * function can fail if the file descriptor is not a DRM device or if
|
||||
+ * the DRM device does not support DUMB allocation.
|
||||
+ *
|
||||
+ * Returns: (transfer full) (nullable): a new DRM Dumb allocator. Use gst_object_unref()
|
||||
+ * to release the allocator after usage.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+
|
||||
+ */
|
||||
+GstAllocator *
|
||||
+gst_drm_dumb_allocator_new_with_fd (gint drm_fd)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ GstDRMDumbAllocator *alloc;
|
||||
+
|
||||
+ alloc = g_object_new (GST_TYPE_DRM_DUMB_ALLOCATOR, "drm-fd", drm_fd, NULL);
|
||||
+ gst_object_ref_sink (alloc);
|
||||
+
|
||||
+ if (!check_drm_fd (alloc))
|
||||
+ g_clear_object (&alloc);
|
||||
+
|
||||
+ if (!check_cap (alloc))
|
||||
+ g_clear_object (&alloc);
|
||||
+
|
||||
+ return alloc ? GST_ALLOCATOR (alloc) : NULL;
|
||||
+
|
||||
+#else
|
||||
+ return NULL;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * gst_drm_dumb_allocator_new_with_device_path:
|
||||
+ * @drm_device_path: path to the DRM device to open
|
||||
+ *
|
||||
+ * Creates a new #GstDRMDumbAllocator for the specific device path. This
|
||||
+ * function can fail if the path does not exist, is not a DRM device or if
|
||||
+ * the DRM device doesnot support DUMB allocation.
|
||||
+ *
|
||||
+ * Returns: (transfer full) (nullable): a new DRM Dumb allocator. Use gst_object_unref()
|
||||
+ * to release the allocator after usage.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+GstAllocator *
|
||||
+gst_drm_dumb_allocator_new_with_device_path (const gchar * drm_device_path)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ GstDRMDumbAllocator *alloc;
|
||||
+
|
||||
+ alloc = g_object_new (GST_TYPE_DRM_DUMB_ALLOCATOR,
|
||||
+ "drm-device-path", drm_device_path, NULL);
|
||||
+ gst_object_ref_sink (alloc);
|
||||
+
|
||||
+ if (!check_drm_fd (alloc))
|
||||
+ g_clear_object (&alloc);
|
||||
+
|
||||
+ if (!check_cap (alloc))
|
||||
+ g_clear_object (&alloc);
|
||||
+
|
||||
+ return alloc ? GST_ALLOCATOR (alloc) : NULL;
|
||||
+
|
||||
+#else
|
||||
+ return NULL;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * gst_drm_dumb_allocator_alloc:
|
||||
+ * @allocator: the allocator instance
|
||||
+ * @drm_fourcc: the DRM format to allocate for
|
||||
+ * @width: padded width for this allocation
|
||||
+ * @height: padded height for this allocation
|
||||
+ * @out_pitch: (out): the pitch as returned by the driver
|
||||
+ *
|
||||
+ * Allocated a DRM buffer object for the specific @drm_fourcc, @width and
|
||||
+ * @height. Note that the DRM Dumb allocation interface is agnostic to the
|
||||
+ * pixel format. This @drm_fourcc is converted into a bpp (bit-per-pixel)
|
||||
+ * number and the height is scaled according to the sub-sampling.
|
||||
+ *
|
||||
+ * Returns: (transfer full): a new DRM Dumb #GstMemory. Use gst_memory_unref()
|
||||
+ * to release the memory after usage.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+GstMemory *
|
||||
+gst_drm_dumb_allocator_alloc (GstAllocator * base_alloc,
|
||||
+ guint32 drm_fourcc, guint32 width, guint32 height, guint32 * out_pitch)
|
||||
+{
|
||||
+ GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (base_alloc);
|
||||
+ GstDRMDumbMemory *drmmem;
|
||||
+ GstMemory *mem;
|
||||
+
|
||||
+ drmmem = g_new0 (GstDRMDumbMemory, 1);
|
||||
+ mem = GST_MEMORY_CAST (drmmem);
|
||||
+
|
||||
+ if (!gst_drm_dumb_allocator_memory_create (alloc, drmmem,
|
||||
+ drm_fourcc, width, height, out_pitch)) {
|
||||
+ g_free (drmmem);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ gst_memory_init (mem, 0, base_alloc, NULL, drmmem->size, 0, 0, drmmem->size);
|
||||
+ return mem;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * gst_drm_dumb_allocator_has_prime_export:
|
||||
+ * @allocator: the #GstAllocator
|
||||
+ *
|
||||
+ * This function allow verifying if the driver support dma-buf exportation.
|
||||
+ *
|
||||
+ * Returns: %TRUE if the allocator support exporting dma-buf.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+gboolean
|
||||
+gst_drm_dumb_allocator_has_prime_export (GstAllocator * base_alloc)
|
||||
+{
|
||||
+#ifdef HAVE_LIBDRM
|
||||
+ GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (base_alloc);
|
||||
+ gint ret;
|
||||
+ guint64 has_prime = 0;
|
||||
+
|
||||
+ if (!check_drm_fd (alloc))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ ret = drmGetCap (alloc->drm_fd, DRM_CAP_PRIME, &has_prime);
|
||||
+ if (ret)
|
||||
+ GST_WARNING_OBJECT (alloc, "could not get prime capability");
|
||||
+
|
||||
+ return ! !(has_prime & DRM_PRIME_CAP_EXPORT);
|
||||
+
|
||||
+#else
|
||||
+ return FALSE;
|
||||
+#endif
|
||||
+}
|
||||
diff --git a/gst-libs/gst/allocators/gstdrmdumb.h b/gst-libs/gst/allocators/gstdrmdumb.h
|
||||
new file mode 100644
|
||||
index 0000000..fa5f5ed
|
||||
--- /dev/null
|
||||
+++ b/gst-libs/gst/allocators/gstdrmdumb.h
|
||||
@@ -0,0 +1,88 @@
|
||||
+/* GStreamer
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Igalia
|
||||
+ * Copyright (C) 2023 Collabora
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
|
||||
+ * Javier Martin <javiermartin@by.com.es>
|
||||
+ * Colin Kinloch <colin.kinloch@collabora.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 St, Fifth Floor,
|
||||
+ * Boston, MA 02110-1301, USA.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#pragma once
|
||||
+
|
||||
+#include <gst/gst.h>
|
||||
+#include <gst/allocators/allocators-prelude.h>
|
||||
+
|
||||
+G_BEGIN_DECLS
|
||||
+
|
||||
+/**
|
||||
+ * GstDRMDumbAllocator:
|
||||
+ *
|
||||
+ * Private intance object for #GstDRMDumbAllocator.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+
|
||||
+/**
|
||||
+ * GstDRMDumbAllocatorClass.parent_class:
|
||||
+ *
|
||||
+ * Parent Class.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+
|
||||
+/**
|
||||
+ * GST_TYPE_DRM_DUMB_ALLOCATOR:
|
||||
+ *
|
||||
+ * Macro that returns the #GstDRMDumbAllocator type.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+#define GST_TYPE_DRM_DUMB_ALLOCATOR gst_drm_dumb_allocator_get_type ()
|
||||
+GST_ALLOCATORS_API
|
||||
+G_DECLARE_FINAL_TYPE (GstDRMDumbAllocator, gst_drm_dumb_allocator,
|
||||
+ GST, DRM_DUMB_ALLOCATOR, GstAllocator);
|
||||
+
|
||||
+GST_ALLOCATORS_API
|
||||
+gboolean gst_is_drm_dumb_memory (GstMemory * mem);
|
||||
+
|
||||
+GST_ALLOCATORS_API
|
||||
+guint32 gst_drm_dumb_memory_get_handle (GstMemory * mem);
|
||||
+
|
||||
+GST_ALLOCATORS_API
|
||||
+GstMemory* gst_drm_dumb_memory_export_dmabuf (GstMemory * mem);
|
||||
+
|
||||
+GST_ALLOCATORS_API
|
||||
+GstAllocator * gst_drm_dumb_allocator_new_with_fd (gint drm_fd);
|
||||
+
|
||||
+GST_ALLOCATORS_API
|
||||
+GstAllocator * gst_drm_dumb_allocator_new_with_device_path (const gchar *drm_device_path);
|
||||
+
|
||||
+GST_ALLOCATORS_API
|
||||
+GstMemory * gst_drm_dumb_allocator_alloc (GstAllocator * allocator,
|
||||
+ guint32 drm_fourcc,
|
||||
+ guint32 width,
|
||||
+ guint32 height,
|
||||
+ guint32 *out_pitch);
|
||||
+
|
||||
+GST_ALLOCATORS_API
|
||||
+gboolean gst_drm_dumb_allocator_has_prime_export (GstAllocator * allocator);
|
||||
+
|
||||
+G_END_DECLS
|
||||
diff --git a/gst-libs/gst/allocators/meson.build b/gst-libs/gst/allocators/meson.build
|
||||
index 6ee0bfd..879c2fc 100644
|
||||
--- a/gst-libs/gst/allocators/meson.build
|
||||
+++ b/gst-libs/gst/allocators/meson.build
|
||||
@@ -4,10 +4,11 @@ gst_allocators_headers = files([
|
||||
'gstfdmemory.h',
|
||||
'gstphysmemory.h',
|
||||
'gstdmabuf.h',
|
||||
+ 'gstdrmdumb.h',
|
||||
])
|
||||
install_headers(gst_allocators_headers, subdir : 'gstreamer-1.0/gst/allocators/')
|
||||
|
||||
-gst_allocators_sources = files([ 'gstdmabuf.c', 'gstfdmemory.c', 'gstphysmemory.c'])
|
||||
+gst_allocators_sources = files([ 'gstdrmdumb.c', 'gstdmabuf.c', 'gstfdmemory.c', 'gstphysmemory.c'])
|
||||
gstallocators = library('gstallocators-@0@'.format(api_version),
|
||||
gst_allocators_sources,
|
||||
c_args : gst_plugins_base_args + ['-DBUILDING_GST_ALLOCATORS', '-DG_LOG_DOMAIN="GStreamer-Allocators"'],
|
||||
@@ -16,12 +17,12 @@ gstallocators = library('gstallocators-@0@'.format(api_version),
|
||||
soversion : soversion,
|
||||
darwin_versions : osxversion,
|
||||
install : true,
|
||||
- dependencies : [gst_dep],
|
||||
+ dependencies : [libdrm_dep, gst_dep],
|
||||
)
|
||||
|
||||
pkg_name = 'gstreamer-allocators-1.0'
|
||||
pkgconfig.generate(gstallocators,
|
||||
- libraries : [gst_dep],
|
||||
+ libraries : [libdrm_dep, gst_dep],
|
||||
variables : pkgconfig_variables,
|
||||
subdirs : pkgconfig_subdirs,
|
||||
name : pkg_name,
|
||||
diff --git a/meson.build b/meson.build
|
||||
index 19a8347..699af91 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -305,6 +305,13 @@ if get_option('default_library') == 'static'
|
||||
gst_plugins_base_args += ['-DGST_STATIC_COMPILATION']
|
||||
endif
|
||||
|
||||
+libdrm_dep = dependency('libdrm', version : '>= 2.4.98',
|
||||
+ required : get_option('drm'),
|
||||
+ fallback: ['libdrm', 'ext_libdrm']
|
||||
+)
|
||||
+
|
||||
+core_conf.set('HAVE_LIBDRM', libdrm_dep.found())
|
||||
+
|
||||
# X11 checks are for sys/ and tests/
|
||||
x11_dep = dependency('x11', required : get_option('x11'))
|
||||
# GIO is used by the GIO plugin, and by the TCP, SDP, and RTSP plugins
|
||||
diff --git a/meson_options.txt b/meson_options.txt
|
||||
index 50ec6aa..0db1840 100644
|
||||
--- a/meson_options.txt
|
||||
+++ b/meson_options.txt
|
||||
@@ -36,6 +36,7 @@ option('audiorate', type : 'feature', value : 'auto')
|
||||
option('audioresample', type : 'feature', value : 'auto')
|
||||
option('audiotestsrc', type : 'feature', value : 'auto')
|
||||
option('compositor', type : 'feature', value : 'auto')
|
||||
+option('drm', type : 'feature', value : 'auto')
|
||||
option('encoding', type : 'feature', value : 'auto')
|
||||
option('gio', type : 'feature', value : 'auto')
|
||||
option('gio-typefinder', type : 'feature', value : 'auto')
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}/:"
|
||||
|
||||
SRC_URI:append = " \
|
||||
file://0001-allocators-Add-a-DRM-Dumb-Allocator.patch \
|
||||
"
|
||||
|
||||
PACKAGECONFIG ?= " \
|
||||
${GSTREAMER_ORC} \
|
||||
${PACKAGECONFIG_GL} \
|
||||
${@bb.utils.filter('DISTRO_FEATURES', 'alsa x11', d)} \
|
||||
jpeg ogg pango png theora vorbis \
|
||||
${@bb.utils.contains('DISTRO_FEATURES', 'wayland', 'wayland egl', '', d)} \
|
||||
encoding \
|
||||
"
|
||||
|
||||
PACKAGECONFIG[encoding] = "-Dencoding=enabled,-Dencoding=disabled,"
|
||||
|
||||
#enable hardware convert/scale in playbin (gstsubtitleoverlay.c, gstplaysinkvideoconvert.c, gstplaysink.c) & gstencodebin (gstencodebin.c)
|
||||
#disable software convert/scale/rate in gstencodebin (gstencodebin.c)
|
||||
#HW_TRANSFORM_CONFIG = 'CFLAGS="-DCOLORSPACE=\\\\\\"autovideoconvert\\\\\\" \
|
||||
# -DCOLORSPACE_SUBT=\\\\\\"videoconvert\\\\\\" \
|
||||
# -DGST_PLAYBIN_DEFAULT_FLAGS=0x00000017 \
|
||||
# -DCOLORSPACE2=\\\\\\"identity\\\\\\" \
|
||||
# -DVIDEOSCALE=\\\\\\"identity\\\\\\" \
|
||||
# -DVIDEORATE=\\\\\\"identity\\\\\\" "'
|
||||
|
||||
#CACHED_CONFIGUREVARS += "${@bb.utils.contains('DISTRO_FEATURES', 'hwdecode', '${HW_TRANSFORM_CONFIG}', '', d)}"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}/:"
|
||||
|
||||
PACKAGECONFIG ?= " \
|
||||
${GSTREAMER_ORC} \
|
||||
${PACKAGECONFIG_SOUP} \
|
||||
${@bb.utils.filter('DISTRO_FEATURES', 'pulseaudio x11', d)} \
|
||||
bz2 cairo flac gdk-pixbuf gudev jpeg lame libpng mpg123 speex taglib v4l2 \
|
||||
libv4l2 \
|
||||
${@bb.utils.contains_any('DISTRO_FEATURES', '${GTK3DISTROFEATURES}', 'gtk', '', d)} \
|
||||
"
|
||||
|
||||
EXTRA_OEMESON += " \
|
||||
-Dv4l2-probe=enabled \
|
||||
-Dv4l2-libv4l2=enabled \
|
||||
"
|
||||
|
||||
# remove qt5 for the moment
|
||||
PACKAGECONFIG:remove = " qt5"
|
||||
@@ -0,0 +1,68 @@
|
||||
From c590304b77a723b9b69f3d2d2f777dc27ac4901c Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
|
||||
Date: Wed, 15 Feb 2023 13:10:25 -0500
|
||||
Subject: [PATCH] basesink: Add GST_BASE_SINK_FLOW_DROPPED return value
|
||||
|
||||
This new flow return value can be used in ::render virtual method
|
||||
to signal that a frame is not being rendered.
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
||||
---
|
||||
libs/gst/base/gstbasesink.c | 8 ++++++++
|
||||
libs/gst/base/gstbasesink.h | 14 ++++++++++++++
|
||||
2 files changed, 22 insertions(+)
|
||||
|
||||
diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c
|
||||
index 294d946..a3abcc7 100644
|
||||
--- a/libs/gst/base/gstbasesink.c
|
||||
+++ b/libs/gst/base/gstbasesink.c
|
||||
@@ -3950,6 +3950,11 @@ again:
|
||||
|
||||
if (bclass->render)
|
||||
ret = bclass->render (basesink, GST_BUFFER_CAST (obj));
|
||||
+
|
||||
+ if (ret == GST_BASE_SINK_FLOW_DROPPED) {
|
||||
+ ret = GST_FLOW_OK;
|
||||
+ goto dropped;
|
||||
+ }
|
||||
} else {
|
||||
GstBufferList *buffer_list = GST_BUFFER_LIST_CAST (obj);
|
||||
|
||||
@@ -3959,6 +3964,9 @@ again:
|
||||
/* Set the first buffer and buffer list to be included in last sample */
|
||||
gst_base_sink_set_last_buffer (basesink, sync_buf);
|
||||
gst_base_sink_set_last_buffer_list (basesink, buffer_list);
|
||||
+
|
||||
+ /* Not currently supported */
|
||||
+ g_assert (ret != GST_BASE_SINK_FLOW_DROPPED);
|
||||
}
|
||||
|
||||
if (ret == GST_FLOW_STEP)
|
||||
diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h
|
||||
index 8edae03..2cf799a 100644
|
||||
--- a/libs/gst/base/gstbasesink.h
|
||||
+++ b/libs/gst/base/gstbasesink.h
|
||||
@@ -58,6 +58,20 @@ G_BEGIN_DECLS
|
||||
#define GST_BASE_SINK_PREROLL_SIGNAL(obj) g_cond_signal (GST_BASE_SINK_GET_PREROLL_COND (obj));
|
||||
#define GST_BASE_SINK_PREROLL_BROADCAST(obj) g_cond_broadcast (GST_BASE_SINK_GET_PREROLL_COND (obj));
|
||||
|
||||
+/**
|
||||
+ * GST_BASE_SINK_FLOW_DROPPED:
|
||||
+ *
|
||||
+ * A #GstFlowReturn that can be returned from
|
||||
+ * #GstBaseSinkClass::render to indicate that the output buffer was not
|
||||
+ * rendered.
|
||||
+ *
|
||||
+ * Note that this is currently not support for #GstBaseSinkClass::render_list
|
||||
+ * virtual method.
|
||||
+ *
|
||||
+ * Since: 1.24
|
||||
+ */
|
||||
+#define GST_BASE_SINK_FLOW_DROPPED GST_FLOW_CUSTOM_SUCCESS
|
||||
+
|
||||
typedef struct _GstBaseSink GstBaseSink;
|
||||
typedef struct _GstBaseSinkClass GstBaseSinkClass;
|
||||
typedef struct _GstBaseSinkPrivate GstBaseSinkPrivate;
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
|
||||
|
||||
SRC_URI:append = " \
|
||||
file://0001-basesink-Add-GST_BASE_SINK_FLOW_DROPPED-return-value.patch \
|
||||
"
|
||||
Reference in New Issue
Block a user