stm-st-stm32mp: gstreamer: sync gstreamer recipes with v1.22.12

This commit removes all outdated gstreamer recipes and synchronizes it with the
latest v1.22.12 from the meta-st-openstlinux layer, based on the
openstlinux-6.6-yocto-scarthgap-mpu-v24.11.06 tag for Yocto 5.0 (scarthgap).

https://onedigi.atlassian.net/browse/DEL-9381

Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
This commit is contained in:
Arturo Buzarra 2024-11-28 16:47:24 +01:00
parent 9c502ca5b8
commit 0b12b51044
102 changed files with 15382 additions and 3330 deletions

View File

@ -1,37 +0,0 @@
From a01f2526663eee1d98f2e133d076a5dcb556d1ea Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
Date: Tue, 26 Apr 2022 11:30:31 +0200
Subject: [PATCH] gstreamer1.0-libav: disable decoder direct rendering by
default
DMA-buf 0-copy path and direct-rendering mode are not yet compatible
because of stride and offset issues.
Nevertheless performances are better than with direct-rendering enabled
and virtual memory path.
This fix is required to reach 30fps on display driver side
with 30fps VGA video content.
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/libav/gstavviddec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ext/libav/gstavviddec.c b/ext/libav/gstavviddec.c
index f5197fb..fde599b 100644
--- a/ext/libav/gstavviddec.c
+++ b/ext/libav/gstavviddec.c
@@ -41,7 +41,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
#define DEFAULT_LOWRES 0
#define DEFAULT_SKIPFRAME 0
-#define DEFAULT_DIRECT_RENDERING TRUE
+#define DEFAULT_DIRECT_RENDERING FALSE
#define DEFAULT_MAX_THREADS 0
#define DEFAULT_OUTPUT_CORRUPT TRUE
#define REQUIRED_POOL_MAX_BUFFERS 32
--
2.25.1

View File

@ -1,3 +0,0 @@
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
SRC_URI:append = " file://0001-gstreamer1.0-libav-disable-decoder-direct-rendering-.patch "

View File

@ -0,0 +1,490 @@
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>
Upstream-Status: Backport
---
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

View File

@ -0,0 +1,50 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,33 +0,0 @@
From a69cd4d027f3b86fd19a87d8139e08614587885c Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Mon, 26 Nov 2018 17:38:13 +0100
Subject: [PATCH 02/14] waylandsink: fix error when mmapping dmabuf buffers
Linux Kernel 4.10 DRM/KMS requires DRM_RDWR rights
in addition to DRM_CLOEXEC (see drmPrimeHandleToFD())
in order to mmap in RD/WR.
Upstream-Status: Inappropriate [DEY specific]
Change-Id: I9c26642a47e6f71b56c0a4ad4714a5b85d814e5f
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/wayland/waylandpool.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c
index 70e40b4..9b20884 100644
--- a/ext/wayland/waylandpool.c
+++ b/ext/wayland/waylandpool.c
@@ -470,7 +470,7 @@ create_dumb (int drm_fd, uint32_t width, uint32_t height, int format,
*stride = create_arg.pitch;
- ret = drmPrimeHandleToFD (drm_fd, create_arg.handle, DRM_CLOEXEC, prime_fd);
+ ret = drmPrimeHandleToFD (drm_fd, create_arg.handle, DRM_CLOEXEC | DRM_RDWR, prime_fd);
if (ret) {
struct drm_mode_destroy_dumb destroy_arg;
--
2.25.1

View File

@ -0,0 +1,157 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,36 +0,0 @@
From 754625fd6a60fbc529416ba88ff06f542523937a Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Thu, 6 Dec 2018 18:08:15 +0100
Subject: [PATCH 03/14] waylandsink: fix wrong width when creating dmabuf dumb
buffers
Unaligned width is given in argument of create_dumb(), fix this.
Upstream-Status: Inappropriate [DEY specific]
Change-Id: Ifc57aa24331f58f588aae480baa2099a47d5f31b
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/wayland/waylandpool.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c
index 9b20884..6e98143 100644
--- a/ext/wayland/waylandpool.c
+++ b/ext/wayland/waylandpool.c
@@ -537,10 +537,9 @@ gst_buffer_add_wayland_meta (GstBuffer * buffer, GstWaylandBufferPool * self)
buf_height = (size / buf_width) * 8 / get_format_bpp (format);
if ((buf_width * buf_height * get_format_bpp (format)) / 8 < size)
GST_ERROR_OBJECT (self, "Not allocating enough memory");
-
ret =
- create_dumb (self->fd, width, buf_height, format, &prime_fd,
- &dumb_stride);
+ create_dumb (self->fd, buf_width, buf_height, format, &prime_fd,
+ &dumb_stride);
if (ret || prime_fd == -1) {
return NULL;
--
2.25.1

View File

@ -0,0 +1,40 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,46 +0,0 @@
From f1e46e02aeac410a4bf1faae5a7dac62c0dfbe1d Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Wed, 12 Dec 2018 11:39:33 +0100
Subject: [PATCH 04/14] waylandsink: do not hardcode dmabuf bufferpool info
size
Read pool config to get the maximum number of buffers
for info size pool allocation.
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/wayland/waylandpool.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c
index 6e98143..1ba1f85 100644
--- a/ext/wayland/waylandpool.c
+++ b/ext/wayland/waylandpool.c
@@ -357,11 +357,21 @@ gst_wayland_buffer_pool_start (GstBufferPool * pool)
int fd;
char filename[1024];
static int init = 0;
+ GstStructure *config;
+ guint config_max_buf;
GST_DEBUG_OBJECT (self, "Initializing wayland buffer pool");
+ /* get max size of pool */
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_get_params (config, NULL, NULL,
+ NULL, &config_max_buf);
+
+ if (config_max_buf == 0)
+ config_max_buf = 32;
+
/* configure */
- size = GST_VIDEO_INFO_SIZE (&self->info) * 15;
+ size = GST_VIDEO_INFO_SIZE (&self->info) * config_max_buf;
/* allocate shm pool */
snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
--
2.25.1

View File

@ -0,0 +1,51 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,45 +0,0 @@
From 837247993dd5399c0faa95950ab62bd1a1f7d6cb Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Thu, 6 Dec 2018 18:08:59 +0100
Subject: [PATCH 05/14] waylandsink: increase max buffers to 32 to enable
dmabuf with libav decoders
libav software decoders requires max buffers in pool config to be
at least 32, otherwise this pool is rejected.
Upstream-Status: Inappropriate [DEY specific]
Change-Id: If1a54ee8c1a9f320fd91537e8e2082c4a7a78700
---
ext/wayland/gstwaylandsink.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index 20df1bf..8b807da 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -52,6 +52,9 @@
#include <gst/wayland/wayland.h>
#include <gst/video/videooverlay.h>
+#define CONFIG_DMABUF_MIN_BUFFERS 2
+#define CONFIG_DMABUF_MAX_BUFFERS 32
+
/* signals */
enum
{
@@ -574,8 +577,9 @@ gst_wayland_create_dmabuf_pool (GstWaylandSink * sink, GstCaps * caps)
}
structure = gst_buffer_pool_get_config (pool);
- gst_buffer_pool_config_set_params (structure, caps, info.size, 2, 0);
- gst_buffer_pool_config_set_allocator (structure, NULL, &params);
+ gst_buffer_pool_config_set_params (structure, caps, size,
+ CONFIG_DMABUF_MIN_BUFFERS, CONFIG_DMABUF_MAX_BUFFERS);
+
alloc = gst_dmabuf_allocator_new ();
gst_buffer_pool_config_set_allocator (structure, alloc, NULL);
if (!gst_buffer_pool_set_config (pool, structure)) {
--
2.25.1

View File

@ -0,0 +1,349 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,46 +0,0 @@
From 36a3da1477d9dd5c23b0c47fd45e61a8c0316600 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Thu, 6 Dec 2018 18:09:20 +0100
Subject: [PATCH 06/14] waylandsink: always select dmabuf buffer pool
Force usage of dmabuf buffer pool by default, ie
even if video/x-raw(memory:DMABuf) is not set in caps.
This allows 0-copy path with software downstream elements
(use of dmabuf buffers mmapped memory directly instead
of copying).
Upstream-Status: Inappropriate [DEY specific]
Change-Id: Icb6e8ff272c562e829bb3ff91150e7d77b25dfd1
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/wayland/gstwaylandsink.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index 8b807da..40edff7 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -610,9 +610,17 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
format = GST_VIDEO_INFO_FORMAT (&sink->video_info);
sink->video_info_changed = TRUE;
- use_dmabuf = gst_caps_features_contains (gst_caps_get_features (caps, 0),
- GST_CAPS_FEATURE_MEMORY_DMABUF);
+ /* Force usage of dmabuf buffer pool by default, ie
+ * even if video/x-raw(memory:DMABuf) is not set in caps.
+ * This allows 0-copy path with software downstream elements
+ * (use of dmabuf buffers mmapped memory directly instead
+ * of copying)
+ */
+ /* use_dmabuf = gst_caps_features_contains (gst_caps_get_features (caps, 0),
+ GST_CAPS_FEATURE_MEMORY_DMABUF); */
+ use_dmabuf = TRUE;
+ /* validate the format base on the memory type */
if (use_dmabuf) {
if (!gst_wl_display_check_format_for_dmabuf (sink->display, format))
goto unsupported_format;
--
2.25.1

View File

@ -0,0 +1,31 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,36 +0,0 @@
From 15464502cf5851e29fa5da9c6e1547655865de21 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Mon, 10 Dec 2018 17:36:27 +0100
Subject: [PATCH 07/14] waylandsink: do not destroy pool twice
Fix segfault in wayland client due to pool
destroy being called with null pool...
This problem was encountered with GStreamer-1.14.
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/wayland/waylandpool.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c
index 1ba1f85..17a94f1 100644
--- a/ext/wayland/waylandpool.c
+++ b/ext/wayland/waylandpool.c
@@ -417,7 +417,12 @@ gst_wayland_buffer_pool_stop (GstBufferPool * pool)
GST_DEBUG_OBJECT (self, "Stopping wayland buffer pool");
+ /* already stopped... */
+ if (!self->wl_pool)
+ return FALSE;
+
munmap (self->data, self->size);
+
wl_shm_pool_destroy (self->wl_pool);
self->wl_pool = NULL;
--
2.25.1

View File

@ -0,0 +1,174 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,28 +0,0 @@
From cf2dfe7a376d10a3d7815d29ffc1c9efb4d4f19e Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 21 May 2018 14:26:47 +0200
Subject: [PATCH 09/14] waylandsink: Uprank to secondary
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Christophe Priouzeau <christophe.priouzeau@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 b97570e..0dc1f0d 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -126,7 +126,7 @@ G_DEFINE_TYPE_WITH_CODE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK,
gst_wayland_sink_videooverlay_init)
G_IMPLEMENT_INTERFACE (GST_TYPE_WAYLAND_VIDEO,
gst_wayland_sink_waylandvideo_init));
-GST_ELEMENT_REGISTER_DEFINE (waylandsink, "waylandsink", GST_RANK_MARGINAL,
+GST_ELEMENT_REGISTER_DEFINE (waylandsink, "waylandsink", GST_RANK_SECONDARY+1,
GST_TYPE_WAYLAND_SINK);
/* A tiny GstVideoBufferPool subclass that modify the options to remove
--
2.25.1

View File

@ -0,0 +1,93 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,43 +0,0 @@
From 9eb8fcc53467a575dc3fba3bbeae26ed8752e639 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Mon, 11 Feb 2019 16:00:02 +0100
Subject: [PATCH 10/14] waylandsink: set video alignment to 32 bytes
Display subsystem requires at least 32 bytes alignment.
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/wayland/waylandpool.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c
index 17a94f1..e04a459 100644
--- a/ext/wayland/waylandpool.c
+++ b/ext/wayland/waylandpool.c
@@ -635,6 +635,7 @@ gst_wayland_buffer_pool_new (GstWlDisplay * display)
GstWaylandBufferPool *pool;
GstStructure *s;
GstVideoAlignment align;
+ guint i;
g_return_val_if_fail (GST_IS_WL_DISPLAY (display), NULL);
pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL);
@@ -645,8 +646,12 @@ gst_wayland_buffer_pool_new (GstWlDisplay * display)
s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
gst_buffer_pool_config_add_option (s, GST_BUFFER_POOL_OPTION_VIDEO_META);
gst_buffer_pool_config_add_option (s, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
- /* reset alignment */
+
+ /* display subsystem requires at least 32 bytes alignment */
gst_video_alignment_reset (&align);
+ for (i = 0; i < GST_VIDEO_MAX_PLANES; i++)
+ align.stride_align[i] = 31;
+
gst_buffer_pool_config_set_video_alignment (s, &align);
gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), s);
--
2.25.1

View File

@ -0,0 +1,268 @@
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>
Upstream-Status: Backport
---
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

View File

@ -0,0 +1,412 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,41 +0,0 @@
From e46e02a4745e20b139a5834d235fe2eeb992be14 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Fri, 22 Mar 2019 15:40:03 +0100
Subject: [PATCH 11/14] waylandsink: fallback to shm if display does not
support dmabuf
Fallback to shm if display does not support dmabuf.
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/wayland/gstwaylandsink.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index 0dc1f0d..e4952cb 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -618,15 +618,11 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
*/
/* use_dmabuf = gst_caps_features_contains (gst_caps_get_features (caps, 0),
GST_CAPS_FEATURE_MEMORY_DMABUF); */
- use_dmabuf = TRUE;
+ use_dmabuf = gst_wl_display_check_format_for_dmabuf (sink->display, format);
- /* validate the format base on the memory type */
- if (use_dmabuf) {
- if (!gst_wl_display_check_format_for_dmabuf (sink->display, format))
+ if (!use_dmabuf)
+ if (!gst_wl_display_check_format_for_shm (sink->display, format))
goto unsupported_format;
- } else if (!gst_wl_display_check_format_for_shm (sink->display, format)) {
- goto unsupported_format;
- }
/* create a new pool for the new caps */
if (sink->pool)
--
2.25.1

View File

@ -0,0 +1,58 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,58 +0,0 @@
From 105576bd522f3a751fda51ea35da2147b1adcfe7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
Date: Fri, 4 Oct 2019 09:47:43 +0200
Subject: [PATCH 12/14] waylandsink: XDG protocol does not work in fullscreen
Using new XDG protocol, it turns out to be not working when enabling
fullscreen support.
This patch avoids to over commit surface during configuration and takes
into account render region when provided within wayland callback.
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
---
ext/wayland/wlwindow.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/ext/wayland/wlwindow.c b/ext/wayland/wlwindow.c
index 66df0fc..cc5de26 100644
--- a/ext/wayland/wlwindow.c
+++ b/ext/wayland/wlwindow.c
@@ -325,10 +325,18 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info,
/* render_rectangle is already set via toplevel_configure in
* xdg_shell fullscreen mode */
if (!(display->xdg_wm_base && fullscreen)) {
+ gint width, height;
+
/* set the initial size to be the same as the reported video size */
- gint width =
- gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
- gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height);
+ if ( window->render_rectangle.w == 0 || window->render_rectangle.h == 0) {
+ width =
+ gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
+ height = info->height;
+ } else {
+ width = window->render_rectangle.w;
+ height = window->render_rectangle.h;
+ }
+ gst_wl_window_set_render_rectangle (window, 0, 0, width, height);
}
return window;
@@ -567,7 +575,10 @@ gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y,
gst_wl_window_resize_video_surface (window, TRUE);
}
- wl_surface_commit (window->area_surface_wrapper);
+ if (window->xdg_surface && window->configured) {
+ wl_surface_damage (window->area_surface_wrapper, 0, 0, w, h);
+ wl_surface_commit (window->area_surface_wrapper);
+ }
if (window->video_width != 0)
wl_subsurface_set_desync (window->video_subsurface);
--
2.25.1

View File

@ -1,99 +0,0 @@
From e14996eb9c0332aeda6390db207380dd0267e7c2 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Wed, 25 Sep 2019 16:01:49 +0200
Subject: [PATCH 13/14] waylandsink: silently drop erroneous frame
Do not stop playback when erroneous frame is received at show_frame():
- test file descriptors validity, to not let throw erroneous
file descriptor to wayland backend (which may crash on fatal error)
- if file descriptors are not valid, do not fall into general
"GST_ELEMENT_ERROR" nor return FLOW_ERROR.
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/wayland/gstwaylandsink.c | 6 +++---
ext/wayland/wllinuxdmabuf.c | 14 ++++++++++++++
ext/wayland/wlshmallocator.c | 10 ++++++++++
3 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index e4952cb..cf355d3 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -1025,9 +1025,9 @@ activate_failed:
}
src_map_failed:
{
- GST_ELEMENT_ERROR (sink, RESOURCE, READ,
- ("Video memory can not be read from userspace."), (NULL));
- ret = GST_FLOW_ERROR;
+ /* Silently drop in case of erroneous buffer */
+ GST_ERROR_OBJECT (sink, "Video memory can not be read from userspace,"
+ "dropping buffer %p", buffer);
goto done;
}
dst_map_failed:
diff --git a/ext/wayland/wllinuxdmabuf.c b/ext/wayland/wllinuxdmabuf.c
index 96487d1..36815b5 100644
--- a/ext/wayland/wllinuxdmabuf.c
+++ b/ext/wayland/wllinuxdmabuf.c
@@ -28,6 +28,8 @@
#include "wllinuxdmabuf.h"
#include "wlvideoformat.h"
+#include <unistd.h>
+
GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
#define GST_CAT_DEFAULT gstwayland_debug
@@ -110,6 +112,18 @@ gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf,
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);
+ gint dup_fd = dup (fd);
+
+ /* Test if file descriptor is valid */
+ if (dup_fd < 0) {
+ GST_ERROR_OBJECT (display, "zwp_linux_dmabuf: dup failed for fd=%d (err=%d) buffer=%p",
+ fd, dup_fd, buf);
+ zwp_linux_buffer_params_v1_destroy (params);
+ data.wbuf = NULL;
+ goto out;
+ }
+ close(dup_fd);
+
zwp_linux_buffer_params_v1_add (params, fd, i, m->offset + skip,
stride, 0, 0);
} else {
diff --git a/ext/wayland/wlshmallocator.c b/ext/wayland/wlshmallocator.c
index 0a82a35..8659c2f 100644
--- a/ext/wayland/wlshmallocator.c
+++ b/ext/wayland/wlshmallocator.c
@@ -212,12 +212,22 @@ gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
enum wl_shm_format format;
struct wl_shm_pool *wl_pool;
struct wl_buffer *wbuffer;
+ gint fd = gst_fd_memory_get_fd (mem);
+ gint dup_fd = dup(fd);
if (!gst_wl_shm_validate_video_info (info)) {
GST_DEBUG_OBJECT (display, "Unsupported strides and offsets.");
return NULL;
}
+ /* Test if file descriptor is valid */
+ if (dup_fd < 0) {
+ GST_ERROR_OBJECT (display, "wl_shm_memory: dup failed for fd=%d (err=%d) mem=%p",
+ fd, dup_fd, mem);
+ return NULL;
+ }
+ close(dup_fd);
+
width = GST_VIDEO_INFO_WIDTH (info);
height = GST_VIDEO_INFO_HEIGHT (info);
stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
--
2.25.1

View File

@ -0,0 +1,27 @@
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>
Upstream-Status: Pending
---
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

View File

@ -1,29 +0,0 @@
From 678d91a743bb35e202211abc6db495fbf8d75601 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Tue, 18 Feb 2020 13:33:21 +0100
Subject: [PATCH 14/14] waylandsink add waylandpool on meson build
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Christophe Priouzeau <christophe.priouzeau@st.com>
---
ext/wayland/meson.build | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ext/wayland/meson.build b/ext/wayland/meson.build
index a3ffb70..66dd148 100644
--- a/ext/wayland/meson.build
+++ b/ext/wayland/meson.build
@@ -5,7 +5,8 @@ wl_sources = [
'wldisplay.c',
'wlwindow.c',
'wlvideoformat.c',
- 'wllinuxdmabuf.c'
+ 'wllinuxdmabuf.c',
+ 'waylandpool.c'
]
libdrm_dep = dependency('libdrm', version: '>= 2.4.55', required:get_option('wayland'))
--
2.25.1

View File

@ -0,0 +1,27 @@
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>
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,26 @@
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>
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,29 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,53 +0,0 @@
From 2eb1cc3d1af83020cfbce5193b1a273078257668 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Tue, 11 Oct 2022 12:26:15 +0200
Subject: [PATCH] waylandsink: fix shm pool wrongly selected with some
GStreamer elements
With some GStreamer elements, and depending on their position in
pipeline, propose_allocation() may be called right before set_caps(),
leading to use sink->use_dmabuf while not being set.
Fix this by checking for dmabuf format also in propose_allocation()
instead of relying on sink->use_dmabuf.
Example of pipeline which underline the problem:
gst-launch-1.0 filesrc location=<png> ! pngdec ! videoconvert ! imagefreeze ! waylandsink
Problem is not reproduced with this pipeline:
gst-launch-1.0 filesrc location=<png> ! pngdec ! imagefreeze ! videoconvert ! waylandsink
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
ext/wayland/gstwaylandsink.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index 1f68546..3bbb736 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -688,8 +688,20 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
GstAllocator *alloc;
GstCaps *pcaps;
guint config_min_buf, config_max_buf;
+ gboolean use_dmabuf;
+ GstVideoFormat format;
+
+ format = GST_VIDEO_INFO_FORMAT (&sink->video_info);
- if (!sink->use_dmabuf)
+ /* Force usage of dmabuf buffer pool by default, ie
+ * even if video/x-raw(memory:DMABuf) is not set in caps.
+ * This allows 0-copy path with software downstream elements
+ * (use of dmabuf buffers mmapped memory directly instead
+ * of copying)
+ */
+ use_dmabuf = gst_wl_display_check_format_for_dmabuf (sink->display, format);
+
+ if (!use_dmabuf)
return gst_wayland_sink_propose_shm_allocation(bsink, query);
/*
--
2.25.1

View File

@ -0,0 +1,26 @@
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
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,66 @@
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>
Upstream-Status: Submitted
---
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

View File

@ -0,0 +1,651 @@
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.
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,131 @@
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.
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,813 @@
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.
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,77 @@
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.
Upstream-Status: Pending
---
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

View File

@ -18,20 +18,19 @@ 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...
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
Upstream-Status: Submitted
---
ext/wayland/gstwaylandsink.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index 40edff7..b97570e 100644
index a5fb0cd..d98c53f 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -774,10 +774,29 @@ render_last_buffer (GstWaylandSink * sink, gboolean redraw)
wlbuffer = gst_buffer_get_wl_buffer (sink->display, sink->last_buffer);
surface = gst_wl_window_get_wl_surface (sink->window);
@@ -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
@ -51,14 +50,14 @@ index 40edff7..b97570e 100644
+ * being currently rendered by display subsystem...
+ */
+#if 0
sink->redraw_pending = TRUE;
self->redraw_pending = TRUE;
callback = wl_surface_frame (surface);
sink->callback = callback;
wl_callback_add_listener (callback, &frame_callback_listener, sink);
self->callback = callback;
wl_callback_add_listener (callback, &frame_callback_listener, self);
+#endif
if (G_UNLIKELY (sink->video_info_changed && !redraw)) {
info = &sink->video_info;
if (G_UNLIKELY (self->video_info_changed && !redraw)) {
info = &self->video_info;
--
2.25.1

View File

@ -0,0 +1,107 @@
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>
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,63 @@
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>
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,63 @@
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>
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,35 @@
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>
Upstream-Status: Pending
---
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

View File

@ -0,0 +1,53 @@
From f6bf17e24601a6e5ba91d147a2532b9ce03f984c Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Mon, 11 Sep 2023 14:12:12 +0200
Subject: [PATCH 2/5] waylandsink: Fix rendering of unaligned content
Non 16 pixels aligned YUV content is displayed with a stride
effect with waylandsink/gtkwaylandsink.
Fix this by forcing 16 pixels alignment of width when creating
zwp linux dmabuf wayland plane.
This should not have any effect because of well aligned stride/offset
but it does... so align width as a temporary workaround till problem
is fully understood.
To reproduce issue:
export WAYLAND_DEBUG=1
gst-launch-1.0 videotestsrc ! video/x-raw, format=NV12, width=306, height=480 ! waylandsink drm-device=/dev/dri/card0 2>&1 | grep zwp
[3956691.525] -> zwp_linux_buffer_params_v1@21.add(fd 19, 0, 0, 384, 0, 0)
[3956691.555] -> zwp_linux_buffer_params_v1@21.add(fd 20, 1, 184320, 384, 0, 0)
[3956691.580] -> zwp_linux_buffer_params_v1@21.create(306, 480, 842094158, 0)
-------------------------------------------------------^^^
=> bad rendering with stride effect
With this fix:
[ 48713.010] -> zwp_linux_buffer_params_v1@21.add(fd 19, 0, 0, 384, 0, 0)
[ 48713.039] -> zwp_linux_buffer_params_v1@21.add(fd 20, 1, 184320, 384, 0, 0)
[ 48713.065] -> zwp_linux_buffer_params_v1@21.create(320, 480, 842094158, 0)
-------------------------------------------------------^^^
=> rendering is correct
Signed-off-by: Hugues Fruchet <hugues.fruchet@foss.st.com>
Upstream-Status: Pending
---
gst-libs/gst/wayland/gstwllinuxdmabuf.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/gst-libs/gst/wayland/gstwllinuxdmabuf.c b/gst-libs/gst/wayland/gstwllinuxdmabuf.c
index deb5d32..2fbe57e 100644
--- a/gst-libs/gst/wayland/gstwllinuxdmabuf.c
+++ b/gst-libs/gst/wayland/gstwllinuxdmabuf.c
@@ -154,6 +154,9 @@ gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf,
}
}
+ //FIXME, otherwise stride effect with non 16-pixels aligned videos
+ width = GST_ROUND_UP_16(width);
+
/* Request buffer creation */
zwp_linux_buffer_params_v1_add_listener (params, &params_listener, &data);
zwp_linux_buffer_params_v1_create (params, width, height, format, flags);
--
2.25.1

View File

@ -0,0 +1,25 @@
From 86e5e19f3f9af7cf5c7d6f875e799aaf0eb40b92 Mon Sep 17 00:00:00 2001
From: Michael Grzeschik <m.grzeschik@pengutronix.de>
Date: Thu, 2 Mar 2023 09:18:49 +0100
Subject: [PATCH 1/4] v4l2codecs: add NV12M format to gstv4l2format
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2format.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/sys/v4l2codecs/gstv4l2format.c b/sys/v4l2codecs/gstv4l2format.c
index 64c47e1..bc20d68 100644
--- a/sys/v4l2codecs/gstv4l2format.c
+++ b/sys/v4l2codecs/gstv4l2format.c
@@ -33,6 +33,7 @@ struct FormatEntry
static struct FormatEntry format_map[] = {
{V4L2_PIX_FMT_NV12, 1, GST_VIDEO_FORMAT_NV12, 8, 420},
+ {V4L2_PIX_FMT_NV12M, 1, GST_VIDEO_FORMAT_NV12, 8, 420},
{V4L2_PIX_FMT_YUYV, 1, GST_VIDEO_FORMAT_YUY2, 8, 422},
{V4L2_PIX_FMT_SUNXI_TILED_NV12, 1, GST_VIDEO_FORMAT_NV12_32L32, 8, 422},
{V4L2_PIX_FMT_NV12_4L4, 1, GST_VIDEO_FORMAT_NV12_4L4, 8, 420},
--
2.25.1

View File

@ -0,0 +1,52 @@
From a68f43ffe7be63cb2dd5839b493547249211ad0a Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Mon, 18 Sep 2023 13:28:32 +0200
Subject: [PATCH 2/4] v4l2codecs: fix gst_v4l2_encoder_set_src_fmt() call
Set source format regarding state->vinfo and call it
right before setting sink format.
Fixes issues when encoding from YUY2 and I420 formats.
Signed-off-by: Hugues Fruchet <hugues.fruchet@foss.st.com>
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codecvp8enc.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.c b/sys/v4l2codecs/gstv4l2codecvp8enc.c
index 71c7dd2..2d476b3 100644
--- a/sys/v4l2codecs/gstv4l2codecvp8enc.c
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.c
@@ -285,6 +285,14 @@ gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * encoder,
gst_v4l2_codec_vp8_enc_reset_allocation (self);
+ if (!gst_v4l2_encoder_set_src_fmt (self->encoder, &state->info,
+ 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;
+ }
+
if (!gst_v4l2_encoder_select_sink_format (self->encoder, &state->info,
&self->vinfo)) {
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
@@ -295,14 +303,6 @@ gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * 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);
--
2.25.1

View File

@ -0,0 +1,51 @@
From af0ac2c50aa14d1a0cb8aad8aa3820ee70acd7a5 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Tue, 10 Oct 2023 15:48:35 +0200
Subject: [PATCH 3/4] v4l2codecs: add support of encoding from RGB
Add support of encoding from RGB in 16 bits and 32 bits formats:
- RGB16
- BGRx
- RGBx
- xBGR
- xRGB
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2format.c | 7 +++++++
sys/v4l2codecs/gstv4l2format.h | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/sys/v4l2codecs/gstv4l2format.c b/sys/v4l2codecs/gstv4l2format.c
index bc20d68..604876e 100644
--- a/sys/v4l2codecs/gstv4l2format.c
+++ b/sys/v4l2codecs/gstv4l2format.c
@@ -40,6 +40,13 @@ static struct FormatEntry format_map[] = {
{V4L2_PIX_FMT_MM21, 2, GST_VIDEO_FORMAT_NV12_16L32S, 8, 420},
{V4L2_PIX_FMT_YUV420M, 3, GST_VIDEO_FORMAT_I420, 8, 420},
{V4L2_PIX_FMT_P010, 1, GST_VIDEO_FORMAT_P010_10LE, 16, 420},
+ {V4L2_PIX_FMT_RGB565, 1, GST_VIDEO_FORMAT_RGB16, 16, 0},
+ {V4L2_PIX_FMT_XBGR32, 1, GST_VIDEO_FORMAT_BGRx, 32, 0},
+ {V4L2_PIX_FMT_BGR32, 1, GST_VIDEO_FORMAT_BGRx, 32, 0},
+ {V4L2_PIX_FMT_RGBX32, 1, GST_VIDEO_FORMAT_RGBx, 32, 0},
+ {V4L2_PIX_FMT_BGRX32, 1, GST_VIDEO_FORMAT_xBGR, 32, 0},
+ {V4L2_PIX_FMT_XRGB32, 1, GST_VIDEO_FORMAT_xRGB, 32, 0},
+ {V4L2_PIX_FMT_RGB32, 1, GST_VIDEO_FORMAT_xRGB, 32, 0},
{0,}
};
diff --git a/sys/v4l2codecs/gstv4l2format.h b/sys/v4l2codecs/gstv4l2format.h
index b579248..dd1e1ea 100644
--- a/sys/v4l2codecs/gstv4l2format.h
+++ b/sys/v4l2codecs/gstv4l2format.h
@@ -24,7 +24,7 @@
#include <gst/video/video.h>
#include "linux/videodev2.h"
-#define GST_V4L2_DEFAULT_VIDEO_FORMATS "{ NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420, P010_10LE}"
+#define GST_V4L2_DEFAULT_VIDEO_FORMATS "{ NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420, P010_10LE, RGB16, BGRx, RGBx, xBGR, xRGB}"
gboolean gst_v4l2_format_to_video_info (struct v4l2_format * fmt,
GstVideoInfo * out_info);
--
2.25.1

View File

@ -0,0 +1,193 @@
From 7edfb2c56b58498589000824021d9a4a11f97439 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Wed, 18 Oct 2023 17:45:46 +0200
Subject: [PATCH 4/4] v4l2codecs: add colorimetry support at sink pad
Forward sink pad colorimetry informations to V4L2.
This is needed to precisely configure the matrix
used by encoder for RGB to YUV conversion.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2encoder.c | 152 ++++++++++++++++++++++++++++++++
1 file changed, 152 insertions(+)
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index eabb74a..b9e529f 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -387,6 +387,11 @@ gst_v4l2_encoder_select_sink_format (GstV4l2Encoder * self, GstVideoInfo * in,
guint32 pix_fmt;
gint width = in->width;
gint height = in->height;
+ GstVideoInfo info = *in;
+ enum v4l2_colorspace colorspace = 0;
+ enum v4l2_quantization range = 0;
+ enum v4l2_ycbcr_encoding matrix = 0;
+ enum v4l2_xfer_func transfer = 0;
ret = ioctl (self->video_fd, VIDIOC_G_FMT, &fmt);
if (ret < 0) {
@@ -400,6 +405,149 @@ gst_v4l2_encoder_select_sink_format (GstV4l2Encoder * self, GstVideoInfo * in,
return FALSE;
}
+ /* We first pick the main colorspace from the primaries */
+ switch (info.colorimetry.primaries) {
+ case GST_VIDEO_COLOR_PRIMARIES_BT709:
+ /* There is two colorspaces using these primaries, use the range to
+ * differentiate */
+ if (info.colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235)
+ colorspace = V4L2_COLORSPACE_REC709;
+ else
+ colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ case GST_VIDEO_COLOR_PRIMARIES_BT2020:
+ colorspace = V4L2_COLORSPACE_BT2020;
+ break;
+ case GST_VIDEO_COLOR_PRIMARIES_BT470M:
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
+ colorspace = V4L2_COLORSPACE_SMPTE170M;
+ break;
+ case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
+ colorspace = V4L2_COLORSPACE_SMPTE240M;
+ break;
+
+ case GST_VIDEO_COLOR_PRIMARIES_FILM:
+ case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
+ /* We don't know, we will guess */
+ break;
+
+ default:
+ GST_WARNING_OBJECT (self,
+ "Unknown colorimetry primaries %d", info.colorimetry.primaries);
+ break;
+ }
+
+ switch (info.colorimetry.range) {
+ case GST_VIDEO_COLOR_RANGE_0_255:
+ range = V4L2_QUANTIZATION_FULL_RANGE;
+ break;
+ case GST_VIDEO_COLOR_RANGE_16_235:
+ range = V4L2_QUANTIZATION_LIM_RANGE;
+ break;
+ case GST_VIDEO_COLOR_RANGE_UNKNOWN:
+ /* We let the driver pick a default one */
+ break;
+ default:
+ GST_WARNING_OBJECT (self,
+ "Unknown colorimetry range %d", info.colorimetry.range);
+ break;
+ }
+
+ switch (info.colorimetry.matrix) {
+ case GST_VIDEO_COLOR_MATRIX_RGB:
+ /* Unspecified, leave to default */
+ break;
+ /* FCC is about the same as BT601 with less digit */
+ case GST_VIDEO_COLOR_MATRIX_FCC:
+ case GST_VIDEO_COLOR_MATRIX_BT601:
+ matrix = V4L2_YCBCR_ENC_601;
+ break;
+ case GST_VIDEO_COLOR_MATRIX_BT709:
+ matrix = V4L2_YCBCR_ENC_709;
+ break;
+ case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
+ matrix = V4L2_YCBCR_ENC_SMPTE240M;
+ break;
+ case GST_VIDEO_COLOR_MATRIX_BT2020:
+ matrix = V4L2_YCBCR_ENC_BT2020;
+ break;
+ case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
+ /* We let the driver pick a default one */
+ break;
+ default:
+ GST_WARNING_OBJECT (self,
+ "Unknown colorimetry matrix %d", info.colorimetry.matrix);
+ break;
+ }
+
+ switch (info.colorimetry.transfer) {
+ case GST_VIDEO_TRANSFER_GAMMA18:
+ case GST_VIDEO_TRANSFER_GAMMA20:
+ case GST_VIDEO_TRANSFER_GAMMA22:
+ case GST_VIDEO_TRANSFER_GAMMA28:
+ GST_WARNING_OBJECT (self,
+ "GAMMA 18, 20, 22, 28 transfer functions not supported");
+ /* fallthrough */
+ case GST_VIDEO_TRANSFER_GAMMA10:
+ transfer = V4L2_XFER_FUNC_NONE;
+ break;
+ case GST_VIDEO_TRANSFER_SMPTE2084:
+ transfer = V4L2_XFER_FUNC_SMPTE2084;
+ break;
+ case GST_VIDEO_TRANSFER_BT601:
+ case GST_VIDEO_TRANSFER_BT2020_12:
+ case GST_VIDEO_TRANSFER_BT2020_10:
+ case GST_VIDEO_TRANSFER_BT709:
+ transfer = V4L2_XFER_FUNC_709;
+ break;
+ case GST_VIDEO_TRANSFER_SMPTE240M:
+ transfer = V4L2_XFER_FUNC_SMPTE240M;
+ break;
+ case GST_VIDEO_TRANSFER_SRGB:
+ transfer = V4L2_XFER_FUNC_SRGB;
+ break;
+ case GST_VIDEO_TRANSFER_LOG100:
+ case GST_VIDEO_TRANSFER_LOG316:
+ GST_WARNING_OBJECT (self,
+ "LOG 100, 316 transfer functions not supported");
+ /* FIXME No known sensible default, maybe AdobeRGB ? */
+ break;
+ case GST_VIDEO_TRANSFER_UNKNOWN:
+ /* We let the driver pick a default one */
+ break;
+ default:
+ GST_WARNING_OBJECT (self,
+ "Unknown colorimetry transfer %d", info.colorimetry.transfer);
+ break;
+ }
+
+ if (colorspace == 0) {
+ /* Try to guess colorspace according to pixelformat and size */
+ if (GST_VIDEO_INFO_IS_YUV (&info)) {
+ if (range == V4L2_QUANTIZATION_FULL_RANGE
+ && matrix == V4L2_YCBCR_ENC_601 && transfer == 0) {
+ /* Full range BT.601 YCbCr encoding with unknown primaries and transfer
+ * function most likely is JPEG */
+ colorspace = V4L2_COLORSPACE_JPEG;
+ transfer = V4L2_XFER_FUNC_SRGB;
+ } else {
+ /* SD streams likely use SMPTE170M and HD streams REC709 */
+ if (width <= 720 && GST_VIDEO_INFO_HEIGHT (&info) <= 576)
+ colorspace = V4L2_COLORSPACE_SMPTE170M;
+ else
+ colorspace = V4L2_COLORSPACE_REC709;
+ }
+ } else if (GST_VIDEO_INFO_IS_RGB (&info)) {
+ colorspace = V4L2_COLORSPACE_SRGB;
+ transfer = V4L2_XFER_FUNC_NONE;
+ }
+ }
+
if (pix_fmt != fmt.fmt.pix_mp.pixelformat
|| fmt.fmt.pix_mp.width != width || fmt.fmt.pix_mp.height != height) {
GST_DEBUG_OBJECT (self,
@@ -408,6 +556,10 @@ gst_v4l2_encoder_select_sink_format (GstV4l2Encoder * self, GstVideoInfo * in,
fmt.fmt.pix_mp.pixelformat = pix_fmt;
fmt.fmt.pix_mp.width = width;
fmt.fmt.pix_mp.height = height;
+ fmt.fmt.pix_mp.colorspace = colorspace;
+ fmt.fmt.pix_mp.quantization = range;
+ fmt.fmt.pix_mp.ycbcr_enc = matrix;
+ fmt.fmt.pix_mp.xfer_func = transfer;
ret = ioctl (self->video_fd, VIDIOC_S_FMT, &fmt);
if (ret < 0) {
GST_ERROR_OBJECT (self, "VIDIOC_S_FMT failed: %s", g_strerror (errno));
--
2.25.1

View File

@ -0,0 +1,29 @@
From e68bd1ef1e283d37c584c6bedfcdc8e82159bcbf Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Tue, 21 Nov 2023 10:51:47 +0100
Subject: [PATCH 40/68] Revert "v4l2codecs: fix support of unaligned videos"
This reverts commit cfd4935254b0d438ea60d350c0c3521b435aee84.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2encoder.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index b9e529f..26d79c1 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -567,10 +567,6 @@ 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

View File

@ -0,0 +1,210 @@
From 97575d37f6f584211553f5637b8b517762acb408 Mon Sep 17 00:00:00 2001
From: Seungha Yang <seungha@centricular.com>
Date: Thu, 11 May 2023 04:53:24 +0900
Subject: [PATCH 41/68] h264parser: Define level enum values
... and stop duplicating it
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4595>
Upstream-Status: Backport
---
gst-libs/gst/codecparsers/gsth264parser.h | 31 +++++++++++++++++++++++
gst-libs/gst/codecs/gsth264decoder.c | 30 +++-------------------
gst/codectimestamper/gsth264timestamper.c | 30 +++-------------------
gst/videoparsers/gsth264parse.c | 24 ------------------
4 files changed, 37 insertions(+), 78 deletions(-)
diff --git a/gst-libs/gst/codecparsers/gsth264parser.h b/gst-libs/gst/codecparsers/gsth264parser.h
index eb99b6a..f18a1f0 100644
--- a/gst-libs/gst/codecparsers/gsth264parser.h
+++ b/gst-libs/gst/codecparsers/gsth264parser.h
@@ -352,6 +352,37 @@ typedef enum
GST_H264_CT_TYPE_UNKNOWN = 2,
} GstCtType;
+/**
+ * GstH264Level:
+ *
+ * H.264 level
+ *
+ * Since: 1.24
+ */
+typedef enum
+{
+ GST_H264_LEVEL_L1 = 10,
+ GST_H264_LEVEL_L1B = 9,
+ GST_H264_LEVEL_L1_1 = 11,
+ GST_H264_LEVEL_L1_2 = 12,
+ GST_H264_LEVEL_L1_3 = 13,
+ GST_H264_LEVEL_L2_0 = 20,
+ GST_H264_LEVEL_L2_1 = 21,
+ GST_H264_LEVEL_L2_2 = 22,
+ GST_H264_LEVEL_L3 = 30,
+ GST_H264_LEVEL_L3_1 = 31,
+ GST_H264_LEVEL_L3_2 = 32,
+ GST_H264_LEVEL_L4 = 40,
+ GST_H264_LEVEL_L4_1 = 41,
+ GST_H264_LEVEL_L4_2 = 42,
+ GST_H264_LEVEL_L5 = 50,
+ GST_H264_LEVEL_L5_1 = 51,
+ GST_H264_LEVEL_L5_2 = 52,
+ GST_H264_LEVEL_L6 = 60,
+ GST_H264_LEVEL_L6_1 = 61,
+ GST_H264_LEVEL_L6_2 = 62,
+} GstH264Level;
+
typedef struct _GstH264NalParser GstH264NalParser;
typedef struct _GstH264NalUnit GstH264NalUnit;
diff --git a/gst-libs/gst/codecs/gsth264decoder.c b/gst-libs/gst/codecs/gsth264decoder.c
index fc7d3a1..576e77c 100644
--- a/gst-libs/gst/codecs/gsth264decoder.c
+++ b/gst-libs/gst/codecs/gsth264decoder.c
@@ -2220,33 +2220,9 @@ gst_h264_decoder_get_max_num_reorder_frames (GstH264Decoder * self,
return max_dpb_size;
}
-typedef enum
-{
- GST_H264_LEVEL_L1 = 10,
- GST_H264_LEVEL_L1B = 9,
- GST_H264_LEVEL_L1_1 = 11,
- GST_H264_LEVEL_L1_2 = 12,
- GST_H264_LEVEL_L1_3 = 13,
- GST_H264_LEVEL_L2_0 = 20,
- GST_H264_LEVEL_L2_1 = 21,
- GST_H264_LEVEL_L2_2 = 22,
- GST_H264_LEVEL_L3 = 30,
- GST_H264_LEVEL_L3_1 = 31,
- GST_H264_LEVEL_L3_2 = 32,
- GST_H264_LEVEL_L4 = 40,
- GST_H264_LEVEL_L4_1 = 41,
- GST_H264_LEVEL_L4_2 = 42,
- GST_H264_LEVEL_L5 = 50,
- GST_H264_LEVEL_L5_1 = 51,
- GST_H264_LEVEL_L5_2 = 52,
- GST_H264_LEVEL_L6 = 60,
- GST_H264_LEVEL_L6_1 = 61,
- GST_H264_LEVEL_L6_2 = 62,
-} GstH264DecoderLevel;
-
typedef struct
{
- GstH264DecoderLevel level;
+ GstH264Level level;
guint32 max_mbps;
guint32 max_fs;
@@ -2278,7 +2254,7 @@ static const LevelLimits level_limits_map[] = {
};
static gint
-h264_level_to_max_dpb_mbs (GstH264DecoderLevel level)
+h264_level_to_max_dpb_mbs (GstH264Level level)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (level_limits_map); i++) {
@@ -2397,7 +2373,7 @@ gst_h264_decoder_process_sps (GstH264Decoder * self, GstH264SPS * sps)
level = 9;
}
- max_dpb_mbs = h264_level_to_max_dpb_mbs ((GstH264DecoderLevel) level);
+ max_dpb_mbs = h264_level_to_max_dpb_mbs ((GstH264Level) level);
if (!max_dpb_mbs)
return GST_FLOW_ERROR;
diff --git a/gst/codectimestamper/gsth264timestamper.c b/gst/codectimestamper/gsth264timestamper.c
index d4f136d..8e73dc2 100644
--- a/gst/codectimestamper/gsth264timestamper.c
+++ b/gst/codectimestamper/gsth264timestamper.c
@@ -194,33 +194,9 @@ gst_h264_timestamper_set_caps (GstCodecTimestamper * timestamper,
return TRUE;
}
-typedef enum
-{
- GST_H264_LEVEL_L1 = 10,
- GST_H264_LEVEL_L1B = 9,
- GST_H264_LEVEL_L1_1 = 11,
- GST_H264_LEVEL_L1_2 = 12,
- GST_H264_LEVEL_L1_3 = 13,
- GST_H264_LEVEL_L2_0 = 20,
- GST_H264_LEVEL_L2_1 = 21,
- GST_H264_LEVEL_L2_2 = 22,
- GST_H264_LEVEL_L3 = 30,
- GST_H264_LEVEL_L3_1 = 31,
- GST_H264_LEVEL_L3_2 = 32,
- GST_H264_LEVEL_L4 = 40,
- GST_H264_LEVEL_L4_1 = 41,
- GST_H264_LEVEL_L4_2 = 42,
- GST_H264_LEVEL_L5 = 50,
- GST_H264_LEVEL_L5_1 = 51,
- GST_H264_LEVEL_L5_2 = 52,
- GST_H264_LEVEL_L6 = 60,
- GST_H264_LEVEL_L6_1 = 61,
- GST_H264_LEVEL_L6_2 = 62,
-} GstH264DecoderLevel;
-
typedef struct
{
- GstH264DecoderLevel level;
+ GstH264Level level;
guint32 max_mbps;
guint32 max_fs;
@@ -252,7 +228,7 @@ static const LevelLimits level_limits_map[] = {
};
static guint
-h264_level_to_max_dpb_mbs (GstH264DecoderLevel level)
+h264_level_to_max_dpb_mbs (GstH264Level level)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (level_limits_map); i++) {
@@ -283,7 +259,7 @@ gst_h264_timestamper_process_sps (GstH264Timestamper * self, GstH264SPS * sps)
level = 9;
}
- max_dpb_mbs = h264_level_to_max_dpb_mbs ((GstH264DecoderLevel) level);
+ max_dpb_mbs = h264_level_to_max_dpb_mbs ((GstH264Level) level);
if (sps->vui_parameters_present_flag
&& sps->vui_parameters.bitstream_restriction_flag) {
max_dpb_frames = MAX (1, sps->vui_parameters.max_dec_frame_buffering);
diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c
index 8bb47f9..f8b22df 100644
--- a/gst/videoparsers/gsth264parse.c
+++ b/gst/videoparsers/gsth264parse.c
@@ -2040,30 +2040,6 @@ get_level_string (GstH264SPS * sps)
}
}
-typedef enum
-{
- GST_H264_LEVEL_L1 = 10,
- GST_H264_LEVEL_L1B = 9,
- GST_H264_LEVEL_L1_1 = 11,
- GST_H264_LEVEL_L1_2 = 12,
- GST_H264_LEVEL_L1_3 = 13,
- GST_H264_LEVEL_L2_0 = 20,
- GST_H264_LEVEL_L2_1 = 21,
- GST_H264_LEVEL_L2_2 = 22,
- GST_H264_LEVEL_L3 = 30,
- GST_H264_LEVEL_L3_1 = 31,
- GST_H264_LEVEL_L3_2 = 32,
- GST_H264_LEVEL_L4 = 40,
- GST_H264_LEVEL_L4_1 = 41,
- GST_H264_LEVEL_L4_2 = 42,
- GST_H264_LEVEL_L5 = 50,
- GST_H264_LEVEL_L5_1 = 51,
- GST_H264_LEVEL_L5_2 = 52,
- GST_H264_LEVEL_L6 = 60,
- GST_H264_LEVEL_L6_1 = 61,
- GST_H264_LEVEL_L6_2 = 62,
-} GstH264Level;
-
typedef struct
{
GstH264Level level;
--
2.25.1

View File

@ -0,0 +1,71 @@
From 98729dcc40b5e1fa407559ee74c8e98a38d9ecac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= <scerveau@igalia.com>
Date: Wed, 31 May 2023 14:51:34 +0200
Subject: [PATCH 42/68] codecparsers: keep naming consistency in GST_H264_LEVEL
GST_H264_LEVEL_2 should be used instead of GST_H264_LEVEL_2_0
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4737>
Upstream-Status: Backport
---
gst-libs/gst/codecparsers/gsth264parser.h | 2 +-
gst-libs/gst/codecs/gsth264decoder.c | 2 +-
gst/codectimestamper/gsth264timestamper.c | 2 +-
gst/videoparsers/gsth264parse.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/gst-libs/gst/codecparsers/gsth264parser.h b/gst-libs/gst/codecparsers/gsth264parser.h
index f18a1f0..e9e79e6 100644
--- a/gst-libs/gst/codecparsers/gsth264parser.h
+++ b/gst-libs/gst/codecparsers/gsth264parser.h
@@ -366,7 +366,7 @@ typedef enum
GST_H264_LEVEL_L1_1 = 11,
GST_H264_LEVEL_L1_2 = 12,
GST_H264_LEVEL_L1_3 = 13,
- GST_H264_LEVEL_L2_0 = 20,
+ GST_H264_LEVEL_L2 = 20,
GST_H264_LEVEL_L2_1 = 21,
GST_H264_LEVEL_L2_2 = 22,
GST_H264_LEVEL_L3 = 30,
diff --git a/gst-libs/gst/codecs/gsth264decoder.c b/gst-libs/gst/codecs/gsth264decoder.c
index 576e77c..a62751b 100644
--- a/gst-libs/gst/codecs/gsth264decoder.c
+++ b/gst-libs/gst/codecs/gsth264decoder.c
@@ -2236,7 +2236,7 @@ static const LevelLimits level_limits_map[] = {
{GST_H264_LEVEL_L1_1, 3000, 396, 900, 192},
{GST_H264_LEVEL_L1_2, 6000, 396, 2376, 384},
{GST_H264_LEVEL_L1_3, 11800, 396, 2376, 768},
- {GST_H264_LEVEL_L2_0, 11880, 396, 2376, 2000},
+ {GST_H264_LEVEL_L2, 11880, 396, 2376, 2000},
{GST_H264_LEVEL_L2_1, 19800, 792, 4752, 4000},
{GST_H264_LEVEL_L2_2, 20250, 1620, 8100, 4000},
{GST_H264_LEVEL_L3, 40500, 1620, 8100, 10000},
diff --git a/gst/codectimestamper/gsth264timestamper.c b/gst/codectimestamper/gsth264timestamper.c
index 8e73dc2..4200187 100644
--- a/gst/codectimestamper/gsth264timestamper.c
+++ b/gst/codectimestamper/gsth264timestamper.c
@@ -210,7 +210,7 @@ static const LevelLimits level_limits_map[] = {
{GST_H264_LEVEL_L1_1, 3000, 396, 900, 192},
{GST_H264_LEVEL_L1_2, 6000, 396, 2376, 384},
{GST_H264_LEVEL_L1_3, 11800, 396, 2376, 768},
- {GST_H264_LEVEL_L2_0, 11880, 396, 2376, 2000},
+ {GST_H264_LEVEL_L2, 11880, 396, 2376, 2000},
{GST_H264_LEVEL_L2_1, 19800, 792, 4752, 4000},
{GST_H264_LEVEL_L2_2, 20250, 1620, 8100, 4000},
{GST_H264_LEVEL_L3, 40500, 1620, 8100, 10000},
diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c
index f8b22df..0ce77a5 100644
--- a/gst/videoparsers/gsth264parse.c
+++ b/gst/videoparsers/gsth264parse.c
@@ -2052,7 +2052,7 @@ static const GstH264LevelLimit level_limits_map[] = {
{GST_H264_LEVEL_L1_1, 768000},
{GST_H264_LEVEL_L1_2, 1536000},
{GST_H264_LEVEL_L1_3, 3041280},
- {GST_H264_LEVEL_L2_0, 3041280},
+ {GST_H264_LEVEL_L2, 3041280},
{GST_H264_LEVEL_L2_1, 5068800},
{GST_H264_LEVEL_L2_2, 5184000},
{GST_H264_LEVEL_L3, 10368000},
--
2.25.1

View File

@ -0,0 +1,34 @@
From 9d989a3eb0f1d38e73013f3e866f30e5b5606ddd Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Thu, 2 Nov 2023 10:38:51 -0400
Subject: [PATCH 43/68] v4l2codecs: encoder: No need to set num_planes of plane
size
This is going to be filled by the driver.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2encoder.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index 26d79c1..0938bb1 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -622,12 +622,11 @@ gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoInfo * info,
GST_DEBUG_OBJECT (self,
"Trying to use peer format: %" GST_FOURCC_FORMAT " %ix%i",
GST_FOURCC_ARGS (pix_fmt), width, height);
+
fmt.fmt.pix_mp.pixelformat = pix_fmt;
fmt.fmt.pix_mp.width = width;
fmt.fmt.pix_mp.height = height;
- fmt.fmt.pix_mp.num_planes = 1;
- fmt.fmt.pix_mp.plane_fmt[0].sizeimage =
- GST_ROUND_UP_16 (width) * GST_ROUND_UP_16 (height) * 3 / 2;
+
ret = ioctl (self->video_fd, VIDIOC_S_FMT, &fmt);
if (ret < 0) {
GST_ERROR_OBJECT (self, "VIDIOC_S_FMT failed: %s", g_strerror (errno));
--
2.25.1

View File

@ -0,0 +1,26 @@
From 99b66f0a6014d9f9beab8a4d17d39388738d3ce3 Mon Sep 17 00:00:00 2001
From: Michael Grzeschik <m.grzeschik@pengutronix.de>
Date: Thu, 2 Mar 2023 09:18:49 +0100
Subject: [PATCH 44/68] v4l2codecs: add NV12M format to gstv4l2format
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2format.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sys/v4l2codecs/gstv4l2format.c b/sys/v4l2codecs/gstv4l2format.c
index 604876e..bbfdee2 100644
--- a/sys/v4l2codecs/gstv4l2format.c
+++ b/sys/v4l2codecs/gstv4l2format.c
@@ -33,7 +33,7 @@ struct FormatEntry
static struct FormatEntry format_map[] = {
{V4L2_PIX_FMT_NV12, 1, GST_VIDEO_FORMAT_NV12, 8, 420},
- {V4L2_PIX_FMT_NV12M, 1, GST_VIDEO_FORMAT_NV12, 8, 420},
+ {V4L2_PIX_FMT_NV12M, 2, GST_VIDEO_FORMAT_NV12, 8, 420},
{V4L2_PIX_FMT_YUYV, 1, GST_VIDEO_FORMAT_YUY2, 8, 422},
{V4L2_PIX_FMT_SUNXI_TILED_NV12, 1, GST_VIDEO_FORMAT_NV12_32L32, 8, 422},
{V4L2_PIX_FMT_NV12_4L4, 1, GST_VIDEO_FORMAT_NV12_4L4, 8, 420},
--
2.25.1

View File

@ -0,0 +1,124 @@
From 205b58f87337b9cfba33b63224ec968f0ac7d6a2 Mon Sep 17 00:00:00 2001
From: Michael Grzeschik <m.grzeschik@pengutronix.de>
Date: Tue, 21 Feb 2023 01:57:50 +0100
Subject: [PATCH 45/68] v4l2codecs: Add V4L2 H264 stateless encode uAPI
Upstream-Status: Pending
---
sys/v4l2codecs/linux/v4l2-controls.h | 85 ++++++++++++++++++++++++++++
sys/v4l2codecs/linux/videodev2.h | 3 +
2 files changed, 88 insertions(+)
diff --git a/sys/v4l2codecs/linux/v4l2-controls.h b/sys/v4l2codecs/linux/v4l2-controls.h
index 8838a5d..9c83596 100644
--- a/sys/v4l2codecs/linux/v4l2-controls.h
+++ b/sys/v4l2codecs/linux/v4l2-controls.h
@@ -1615,6 +1615,91 @@ struct v4l2_ctrl_h264_decode_params {
__u32 flags;
};
+#define V4L2_H264_NAL_CODED_SLICE_NON_IDR_PIC 1
+#define V4L2_H264_NAL_CODED_SLICE_IDR_PIC 5
+
+#define V4L2_CID_STATELESS_H264_ENCODE_PARAMS (V4L2_CID_CODEC_STATELESS_BASE + 8)
+
+/**
+ * struct v4l2_ctrl_h264_encode_params
+ * @slice_type: selects slice type. Set to one of V4L2_H264_SLICE_TYPE_{}
+ * @pic_parameter_set_id: identifies the picture parameter set that is referred to
+ * in the slice header. The value shall be in the range of 0 to 255, inclusive.
+ * @frame_num: an identifier for pictures.
+ * @idr_pic_id: identifies an IDR picture.
+ * @cabac_init_idc: index for determining the initialization table used in the
+ * initialization process for context variables. The value of cabac_init_idc
+ * shall be in the range of 0 to 2, inclusive.
+ * @disable_deblocking_filter_idc: specifies whether the operation of the
+ * deblocking filter shall be disabled across some block edges of the slice and
+ * specifies for which edges the filtering is disabled.
+ * @slice_alpha_c0_offset_div2: offset used in accessing the alpha and tC0
+ * deblocking filter tables for filtering operations controlled by the macroblocks
+ * within the slice.
+ * @slice_beta_offset_div2: offset used in accessing the beta deblocking filter
+ * table for filtering operations controlled by the macroblocks within the slice.
+ * @slice_size_mb_rows: number of macroblock rows in a slice.
+ * @pic_init_qp_minus26: initial value minus 26 of luma qp for each slice.
+ * @chroma_qp_index_offset: offset that shall be added to qp luma for addressing the
+ * table of qp chroma values for the Cb chroma component.
+ * @flags: combination of V4L2_H264_SLICE_FLAG_{} flags.
+ */
+struct v4l2_ctrl_h264_encode_params {
+ /* Slice parameters */
+
+ __u8 slice_type;
+ __u8 pic_parameter_set_id;
+ __u16 frame_num;
+ __u16 idr_pic_id;
+ __u8 cabac_init_idc;
+ __u8 disable_deblocking_filter_idc;
+ __s8 slice_alpha_c0_offset_div2;
+ __s8 slice_beta_offset_div2;
+
+ __s32 slice_size_mb_rows;
+
+ /* PPS parameters */
+
+ __s8 pic_init_qp_minus26;
+ __s8 chroma_qp_index_offset;
+
+ __u32 flags; /* V4L2_H264_ENCODE_FLAG_ */
+
+ /* Nal parameters */
+ __u8 nal_reference_idc; // 2 bit
+ __u8 nalu_type; // 5 bit
+
+ /* Reference */
+
+ __u64 reference_ts;
+};
+
+#define V4L2_H264_ENCODE_FLAG_ENTROPY_CABAC 0x01
+#define V4L2_H264_ENCODE_FLAG_TRANSFORM_8X8_MODE 0x02
+#define V4L2_H264_ENCODE_FLAG_CONSTRAINED_INTRA_PRED 0x04
+#define V4L2_H264_ENCODE_FLAG_MARK_LONGTERM 0x08
+
+#define V4L2_CID_STATELESS_H264_ENCODE_RC (V4L2_CID_CODEC_STATELESS_BASE + 9)
+
+/**
+ * struct v4l2_ctrl_h264_encode_rc
+ *
+ * @qp: quantization parameter for the currently encoded slice
+ *
+ * TODO: other fields likely not needed
+ */
+struct v4l2_ctrl_h264_encode_rc {
+ __u32 qp;
+ __u32 qp_min;
+ __u32 qp_max;
+ __s32 mad_qp_delta;
+ __u32 mad_threshold;
+
+ __u32 cp_distance_mbs;
+ __u32 cp_target[10];
+ __s32 cp_target_error[6];
+ __s32 cp_qp_delta[7];
+};
/* Stateless FWHT control, used by the vicodec driver */
diff --git a/sys/v4l2codecs/linux/videodev2.h b/sys/v4l2codecs/linux/videodev2.h
index 687ac85..efaa797 100644
--- a/sys/v4l2codecs/linux/videodev2.h
+++ b/sys/v4l2codecs/linux/videodev2.h
@@ -1794,6 +1794,9 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_H264_SLICE_PARAMS = 0x0203,
V4L2_CTRL_TYPE_H264_DECODE_PARAMS = 0x0204,
V4L2_CTRL_TYPE_H264_PRED_WEIGHTS = 0x0205,
+ V4L2_CTRL_TYPE_H264_ENCODE_PARAMS = 0x0206,
+ V4L2_CTRL_TYPE_H264_ENCODE_RC = 0x0207,
+ V4L2_CTRL_TYPE_H264_ENCODE_FEEDBACK = 0x0208,
V4L2_CTRL_TYPE_FWHT_PARAMS = 0x0220,
--
2.25.1

View File

@ -0,0 +1,645 @@
From dfe8a89861ce2ea180c67b916afa6b91fc6fca9c Mon Sep 17 00:00:00 2001
From: Michael Grzeschik <m.grzeschik@pengutronix.de>
Date: Mon, 20 Feb 2023 23:39:33 +0100
Subject: [PATCH 46/68] codecs: Add base class for stateless h264 encoder
Add stateless h264 encoder base class and h264 frame structure.
Upstream-Status: Pending
---
gst-libs/gst/codecs/gsth264encoder.c | 352 +++++++++++++++++++++++++++
gst-libs/gst/codecs/gsth264encoder.h | 81 ++++++
gst-libs/gst/codecs/gsth264frame.c | 66 +++++
gst-libs/gst/codecs/gsth264frame.h | 70 ++++++
gst-libs/gst/codecs/meson.build | 5 +
5 files changed, 574 insertions(+)
create mode 100644 gst-libs/gst/codecs/gsth264encoder.c
create mode 100644 gst-libs/gst/codecs/gsth264encoder.h
create mode 100644 gst-libs/gst/codecs/gsth264frame.c
create mode 100644 gst-libs/gst/codecs/gsth264frame.h
diff --git a/gst-libs/gst/codecs/gsth264encoder.c b/gst-libs/gst/codecs/gsth264encoder.c
new file mode 100644
index 0000000..b024939
--- /dev/null
+++ b/gst-libs/gst/codecs/gsth264encoder.c
@@ -0,0 +1,352 @@
+/* GStreamer
+ * Copyright (C) 2023 Michael Grzeschik <m.grzeschik@pengutronix.de>
+ *
+ * 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 "gsth264encoder.h"
+
+#include <gst/codecparsers/gsth264bitwriter.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/base/base.h>
+
+GST_DEBUG_CATEGORY (gst_h264_encoder_debug);
+#define GST_CAT_DEFAULT gst_h264_encoder_debug
+
+#define H264ENC_DEFAULT_KEYFRAME_INTERVAL 30
+
+#define H264_MAX_QUALITY 63
+#define H264_MIN_QUALITY 0
+
+#define H264_DEFAULT_BITRATE 100000
+
+enum
+{
+ PROP_0,
+ PROP_KEYFRAME_INTERVAL,
+ PROP_MAX_QUALITY,
+ PROP_MIN_QUALITY,
+ PROP_BITRATE,
+};
+
+struct _GstH264EncoderPrivate
+{
+ 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_h264_encoder_parent_class
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstH264Encoder, gst_h264_encoder,
+ GST_TYPE_VIDEO_ENCODER,
+ G_ADD_PRIVATE (GstH264Encoder);
+ GST_DEBUG_CATEGORY_INIT (gst_h264_encoder_debug, "h264encoder", 0,
+ "H264 Video Encoder"));
+
+static void
+gst_h264_encoder_init (GstH264Encoder * self)
+{
+ self->priv = gst_h264_encoder_get_instance_private (self);
+}
+
+static void
+gst_h264_encoder_finalize (GObject * object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_h264_encoder_start (GstVideoEncoder * encoder)
+{
+ GstH264Encoder *self = GST_H264_ENCODER (encoder);
+ GstH264EncoderPrivate *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_h264_encoder_stop (GstVideoEncoder * encoder)
+{
+ return TRUE;
+}
+
+static gboolean
+gst_h264_encoder_set_format (GstVideoEncoder * encoder,
+ GstVideoCodecState * state)
+{
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_h264_encoder_set_quality (GstH264Encoder * self, GstH264Frame * h264_frame)
+{
+ GstH264EncoderPrivate *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;
+
+ h264_frame->quality = qp;
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_h264_encoder_set_frame_type (GstH264Encoder * self, GstH264Frame * h264_frame)
+{
+ GstH264EncoderPrivate *priv = self->priv;
+ GstVideoCodecFrame *frame = h264_frame->frame;
+
+ if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
+ h264_frame->type = GstH264Keyframe;
+ 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");
+ h264_frame->type = GstH264Keyframe;
+ return GST_FLOW_OK;
+ }
+
+ /* Generate a interframe */
+ GST_DEBUG_OBJECT (self, "Generate a interframe");
+ h264_frame->type = GstH264Inter;
+ return GST_FLOW_OK;
+}
+
+static void
+gst_h264_encoder_mark_frame (GstH264Encoder * self, GstH264Frame * h264_frame)
+{
+ GstVideoCodecFrame *frame = h264_frame->frame;
+ GstH264EncoderPrivate *priv = self->priv;
+
+ switch (h264_frame->type) {
+ case GstH264Keyframe:
+ priv->last_keyframe = frame->system_frame_number;
+ break;
+ }
+
+ priv->current_quality = h264_frame->quality;
+ priv->used_bytes += gst_buffer_get_size (frame->output_buffer);
+ priv->nb_frames++;
+}
+
+static GstFlowReturn
+gst_h264_encoder_handle_frame (GstVideoEncoder * encoder,
+ GstVideoCodecFrame * frame)
+{
+ GstH264Encoder *self = GST_H264_ENCODER (encoder);
+ GstH264EncoderClass *klass = GST_H264_ENCODER_GET_CLASS (self);
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstH264Frame *h264_frame = gst_h264_frame_new (frame);
+
+ ret = gst_h264_encoder_set_frame_type (self, h264_frame);
+ if (ret != GST_FLOW_OK)
+ return ret;
+
+ ret = gst_h264_encoder_set_quality (self, h264_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, h264_frame);
+ if (ret == GST_FLOW_OK)
+ gst_h264_encoder_mark_frame (self, h264_frame);
+ }
+
+ gst_h264_frame_unref (h264_frame);
+
+ return ret;
+}
+
+static void
+gst_h264_encoder_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstH264Encoder *self = GST_H264_ENCODER (object);
+ GstH264EncoderPrivate *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_h264_encoder_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstH264Encoder *self = GST_H264_ENCODER (object);
+ GstH264EncoderPrivate *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_h264_encoder_class_init (GstH264EncoderClass * klass)
+{
+ GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = GST_DEBUG_FUNCPTR (gst_h264_encoder_finalize);
+ object_class->get_property = gst_h264_encoder_get_property;
+ object_class->set_property = gst_h264_encoder_set_property;
+
+ encoder_class->start = GST_DEBUG_FUNCPTR (gst_h264_encoder_start);
+ encoder_class->stop = GST_DEBUG_FUNCPTR (gst_h264_encoder_stop);
+ encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_h264_encoder_set_format);
+ encoder_class->handle_frame =
+ GST_DEBUG_FUNCPTR (gst_h264_encoder_handle_frame);
+
+ /**
+ * GstH264Encoder: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, H264ENC_DEFAULT_KEYFRAME_INTERVAL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+ /**
+ * GstH264Encoder: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)",
+ H264_MIN_QUALITY, H264_MAX_QUALITY, H264_MAX_QUALITY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+ /**
+ * GstH264Encoder: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)",
+ H264_MIN_QUALITY, H264_MAX_QUALITY, H264_MIN_QUALITY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+ /**
+ * GstH264Encoder: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, H264_DEFAULT_BITRATE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+}
diff --git a/gst-libs/gst/codecs/gsth264encoder.h b/gst-libs/gst/codecs/gsth264encoder.h
new file mode 100644
index 0000000..49f9fd3
--- /dev/null
+++ b/gst-libs/gst/codecs/gsth264encoder.h
@@ -0,0 +1,81 @@
+/* GStreamer
+ * Copyright (C) 2023 Michael Grzeschik <m.grzeschik@pengutronix.de>
+ *
+ * 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_H264_ENCODER_H__
+#define __GST_H264_ENCODER_H__
+
+#include <gst/codecs/codecs-prelude.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideoencoder.h>
+
+#include "gsth264frame.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_H264_ENCODER (gst_h264_encoder_get_type())
+#define GST_H264_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_H264_ENCODER,GstH264Encoder))
+#define GST_H264_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_H264_ENCODER,GstH264EncoderClass))
+#define GST_H264_ENCODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_H264_ENCODER,GstH264EncoderClass))
+#define GST_IS_H264_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_H264_ENCODER))
+#define GST_IS_H264_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_H264_ENCODER))
+#define GST_H264_ENCODER_CAST(obj) ((GstH264Encoder*)obj)
+typedef struct _GstH264Encoder GstH264Encoder;
+typedef struct _GstH264EncoderClass GstH264EncoderClass;
+typedef struct _GstH264EncoderPrivate GstH264EncoderPrivate;
+
+/**
+ * GstH264Encoder:
+ *
+ * The opaque #GstH264Encoder data structure.
+ */
+struct _GstH264Encoder
+{
+ /*< private > */
+ GstVideoEncoder parent;
+
+ /*< private > */
+ GstH264EncoderPrivate *priv;
+ gpointer padding[GST_PADDING_LARGE];
+};
+
+/**
+ * GstH264EncoderClass:
+ */
+struct _GstH264EncoderClass
+{
+ GstVideoEncoderClass parent_class;
+
+ /**
+ * GstH264EncoderClass::encode_frame:
+ * @encoder: a #GstH264Encoder
+ * @frame: a #GstH264Frame
+ *
+ * Provide the frame to be encoded with the encode parameters (to be defined)
+ */
+ GstFlowReturn (*encode_frame) (GstH264Encoder * encoder,
+ GstH264Frame * frame);
+ /*< private > */
+ gpointer padding[GST_PADDING_LARGE];
+};
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstH264Encoder, gst_object_unref)
+ GST_CODECS_API GType gst_h264_encoder_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_H264_ENCODER_H__ */
diff --git a/gst-libs/gst/codecs/gsth264frame.c b/gst-libs/gst/codecs/gsth264frame.c
new file mode 100644
index 0000000..81420d7
--- /dev/null
+++ b/gst-libs/gst/codecs/gsth264frame.c
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) 2023 Michael Grzeschik <m.grzeschik@pengutronix.de>
+ *
+ * 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 "gsth264frame.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_h264_encoder_debug);
+#define GST_CAT_DEFAULT gst_h264_encoder_debug
+
+GST_DEFINE_MINI_OBJECT_TYPE (GstH264Frame, gst_h264_frame);
+
+static void
+_gst_h264_frame_free (GstH264Frame * frame)
+{
+ GST_TRACE ("Free frame %p", frame);
+
+ gst_video_codec_frame_unref (frame->frame);
+
+ g_free (frame);
+}
+
+/**
+ * gst_h264_frame_new:
+ *
+ * Create new #GstH264Frame
+ *
+ * Returns: a new #GstH264Frame
+ */
+GstH264Frame *
+gst_h264_frame_new (GstVideoCodecFrame * f)
+{
+ GstH264Frame *frame;
+
+ if (!f)
+ return NULL;
+
+ frame = g_new0 (GstH264Frame, 1);
+
+ gst_mini_object_init (GST_MINI_OBJECT_CAST (frame), 0,
+ GST_TYPE_H264_FRAME, NULL, NULL,
+ (GstMiniObjectFreeFunction) _gst_h264_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/gsth264frame.h b/gst-libs/gst/codecs/gsth264frame.h
new file mode 100644
index 0000000..3c90d53
--- /dev/null
+++ b/gst-libs/gst/codecs/gsth264frame.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) 2023 Michael Grzeschik <m.grzeschik@pengutronix.de>
+ *
+ * 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_H264_FRAME_H__
+#define __GTS_H264_FRAME_H__
+
+#include <gst/codecs/codecs-prelude.h>
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_H264_FRAME (gst_h264_frame_get_type())
+#define GST_IS_H264_FRAME(obj) (GST_IS_MINI_OBJECT_TYPE(obj, GST_TYPE_H264_FRAME))
+#define GST_H264_FRAME(obj) ((GstH264Frame *)obj)
+#define GST_H264_FRAME_CAST(obj) (GST_H264_FRAME(obj))
+
+typedef struct _GstH264Frame GstH264Frame;
+
+enum
+{
+ GstH264Keyframe,
+ GstH264Inter,
+};
+
+struct _GstH264Frame
+{
+ GstMiniObject parent;
+ gint type;
+ gint quality;
+
+ GstVideoCodecFrame *frame;
+};
+
+GST_CODECS_API
+GType gst_h264_frame_get_type (void);
+
+GST_CODECS_API
+GstH264Frame * gst_h264_frame_new (GstVideoCodecFrame *f);
+
+static inline GstH264Frame *
+gst_h264_frame_ref (GstH264Frame * frame)
+{
+ return (GstH264Frame *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (frame));
+}
+
+static inline void
+gst_h264_frame_unref (GstH264Frame * frame)
+{
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (frame));
+}
+
+G_END_DECLS
+
+#endif /* __GTS_H264_FRAME_H__ */
diff --git a/gst-libs/gst/codecs/meson.build b/gst-libs/gst/codecs/meson.build
index 458d90d..3ea3bdc 100644
--- a/gst-libs/gst/codecs/meson.build
+++ b/gst-libs/gst/codecs/meson.build
@@ -14,6 +14,8 @@ codecs_sources = files(
'gstvp9statefulparser.c',
'gstvp8encoder.c',
'gstvp8frame.c',
+ 'gsth264encoder.c',
+ 'gsth264frame.c',
)
codecs_headers = files(
@@ -32,6 +34,8 @@ codecs_headers = files(
'gstvp9statefulparser.h',
'gstvp8encoder.h',
'gstvp8frame.h',
+ 'gsth264encoder.h',
+ 'gsth264frame.h',
)
cp_args = [
@@ -71,6 +75,7 @@ if build_gir
'--c-include=gst/codecs/gstvp8decoder.h',
'--c-include=gst/codecs/gstmpeg2decoder.h',
'--c-include=gst/codecs/gstvp8encoder.h',
+ '--c-include=gst/codecs/gsth264encoder.h',
],
'dependencies' : [gstvideo_dep, gstcodecparsers_dep]
}
--
2.25.1

View File

@ -0,0 +1,61 @@
From e9b9898be9c2cbf007b5e6580d4f90c93163502b Mon Sep 17 00:00:00 2001
From: Michael Grzeschik <m.grzeschik@pengutronix.de>
Date: Tue, 21 Feb 2023 02:10:52 +0100
Subject: [PATCH 47/68] v4l2codecs: encoder: Add h264 code to v4l2 encoder
class
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2encoder.c | 25 +++++++++++++++++++++++++
sys/v4l2codecs/gstv4l2encoder.h | 2 ++
2 files changed, 27 insertions(+)
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index 0938bb1..cded8bf 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -1366,3 +1366,28 @@ gst_v4l2_codec_vp8_enc_get_qp_range (GstV4l2Encoder * self,
return TRUE;
}
+
+gboolean
+gst_v4l2_codec_h264_enc_get_qp_range (GstV4l2Encoder * self,
+ guint * qp_min, guint * qp_max)
+{
+ gint ret;
+ struct v4l2_query_ext_ctrl control = {
+ .id = V4L2_CID_STATELESS_H264_ENCODE_RC,
+ };
+
+ *qp_max = 127;
+ *qp_min = 0;
+
+ ret = ioctl (self->video_fd, VIDIOC_QUERY_EXT_CTRL, &control);
+ if (ret < 0) {
+ GST_DEBUG_OBJECT (self, "unable to retrieve encoder qp, use default");
+ return FALSE;
+ }
+
+ *qp_max = control.maximum;
+ *qp_min = control.minimum;
+ GST_DEBUG_OBJECT (self, "encoder qp min %d qp max %d", *qp_min, *qp_max);
+
+ return TRUE;
+}
diff --git a/sys/v4l2codecs/gstv4l2encoder.h b/sys/v4l2codecs/gstv4l2encoder.h
index 9acb0e3..e7f44ba 100644
--- a/sys/v4l2codecs/gstv4l2encoder.h
+++ b/sys/v4l2codecs/gstv4l2encoder.h
@@ -134,6 +134,8 @@ gboolean gst_v4l2_encoder_request_failed (GstV4l2Request * request);
gboolean gst_v4l2_codec_vp8_enc_get_qp_range (GstV4l2Encoder * self, guint * qp_min, guint * qp_max);
+gboolean gst_v4l2_codec_h264_enc_get_qp_range (GstV4l2Encoder * self, guint * qp_min, guint * qp_max);
+
G_END_DECLS
#endif /* __GST_V4L2_ENCODER_H__ */
--
2.25.1

View File

@ -0,0 +1,40 @@
From fd4de5d5f6b5b16777cdd89b3b29861926c5d915 Mon Sep 17 00:00:00 2001
From: Michael Grzeschik <m.grzeschik@pengutronix.de>
Date: Mon, 20 Feb 2023 23:45:33 +0100
Subject: [PATCH 49/68] v4l2codecs: Register V4L2 stateless H264 encoder
If a v4l2 stateless VP8 encoder is detected register the matching
element.
Upstream-Status: Pending
---
sys/v4l2codecs/plugin.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/sys/v4l2codecs/plugin.c b/sys/v4l2codecs/plugin.c
index 7867474..bd052dc 100644
--- a/sys/v4l2codecs/plugin.c
+++ b/sys/v4l2codecs/plugin.c
@@ -24,6 +24,7 @@
#include "gstv4l2codecdevice.h"
#include "gstv4l2codech264dec.h"
+#include "gstv4l2codech264enc.h"
#include "gstv4l2codech265dec.h"
#include "gstv4l2codecmpeg2dec.h"
#include "gstv4l2codecvp8dec.h"
@@ -113,6 +114,12 @@ register_video_encoder (GstPlugin * plugin, GstV4l2CodecDevice * device)
gst_v4l2_codec_vp8_enc_register (plugin, encoder, device,
GST_RANK_PRIMARY + 1);
break;
+ case V4L2_PIX_FMT_H264_SLICE:
+ GST_INFO_OBJECT (encoder, "Registering %s as H264 Encoder",
+ device->name);
+ gst_v4l2_codec_h264_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));
--
2.25.1

View File

@ -0,0 +1,83 @@
From d89ede36298dd4985548c64ef177454b31e3c576 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Wed, 1 Nov 2023 10:16:27 -0400
Subject: [PATCH 50/68] v4l2codecs: encoders: Implement propose allocation
For now, do not offer any pool since our buffer pool implementation is
not complete. But at least advertise GstVideoMeta support in order to
avoid upstream element having to normalize the strides.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 15 +++++++++++++++
sys/v4l2codecs/gstv4l2codecvp8enc.c | 15 +++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 9f1b994..070c51a 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -265,6 +265,19 @@ gst_v4l2_codec_h264_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
return result;
}
+static gboolean
+gst_v4l2_codec_h264_enc_propose_allocation (GstVideoEncoder * encoder,
+ GstQuery * query)
+{
+ GstV4l2CodecH264Enc *self = GST_V4L2_CODEC_H264_ENC (encoder);
+
+ gst_query_add_allocation_pool (query, NULL, self->vinfo.size, 2, 0);
+ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+ return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
+ query);
+}
+
static gboolean
gst_v4l2_codec_h264_enc_buffers_allocation (GstVideoEncoder * encoder)
{
@@ -1078,6 +1091,8 @@ gst_v4l2_codec_h264_enc_subclass_init (GstV4l2CodecH264EncClass * klass,
encoder_class->sink_event =
GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_enc_sink_event);
encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_enc_getcaps);
+ encoder_class->propose_allocation =
+ GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_enc_propose_allocation);
h264encoder_class->encode_frame =
GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_enc_encode_frame);
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.c b/sys/v4l2codecs/gstv4l2codecvp8enc.c
index 2d476b3..24e8540 100644
--- a/sys/v4l2codecs/gstv4l2codecvp8enc.c
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.c
@@ -235,6 +235,19 @@ gst_v4l2_codec_vp8_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
return result;
}
+static gboolean
+gst_v4l2_codec_vp8_enc_propose_allocation (GstVideoEncoder * encoder,
+ GstQuery * query)
+{
+ GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
+
+ gst_query_add_allocation_pool (query, NULL, self->vinfo.size, 2, 0);
+ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+ return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
+ query);
+}
+
static gboolean
gst_v4l2_codec_vp8_enc_buffers_allocation (GstVideoEncoder * encoder)
{
@@ -689,6 +702,8 @@ gst_v4l2_codec_vp8_enc_subclass_init (GstV4l2CodecVp8EncClass * klass,
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);
+ encoder_class->propose_allocation =
+ GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_propose_allocation);
vp8encoder_class->encode_frame =
GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_enc_encode_frame);
--
2.25.1

View File

@ -0,0 +1,71 @@
From 7ea1579a4df24d7a2d4bbb1ded764ca47000e299 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Wed, 1 Nov 2023 11:49:45 -0400
Subject: [PATCH 51/68] v4l2codecs: format: Allow matching planar format
variants
This is to allow matching formats that simply have different numbrer of
planes like NV12 and NV12M. This avoids the spurious S_FMT when this is
the only difference reported by the driver.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2encoder.c | 2 +-
sys/v4l2codecs/gstv4l2format.c | 20 ++++++++++++++++++++
sys/v4l2codecs/gstv4l2format.h | 2 ++
3 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index cded8bf..0886d15 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -617,7 +617,7 @@ gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoInfo * info,
return FALSE;
}
- if (pix_fmt != fmt.fmt.pix_mp.pixelformat
+ if (!gst_v4l2_format_equivalent (pix_fmt, fmt.fmt.pix_mp.pixelformat)
|| fmt.fmt.pix_mp.width != width || fmt.fmt.pix_mp.height != height) {
GST_DEBUG_OBJECT (self,
"Trying to use peer format: %" GST_FOURCC_FORMAT " %ix%i",
diff --git a/sys/v4l2codecs/gstv4l2format.c b/sys/v4l2codecs/gstv4l2format.c
index bbfdee2..e029d7d 100644
--- a/sys/v4l2codecs/gstv4l2format.c
+++ b/sys/v4l2codecs/gstv4l2format.c
@@ -209,3 +209,23 @@ gst_v4l2_format_from_video_format (GstVideoFormat format, guint32 * out_pix_fmt)
*out_pix_fmt = entry->v4l2_pix_fmt;
return TRUE;
}
+
+gboolean
+gst_v4l2_format_equivalent (guint32 pix_fmt_a, guint32 pix_fmt_b)
+{
+ struct FormatEntry *entry_a, *entry_b;
+
+ if (pix_fmt_a == pix_fmt_b)
+ return TRUE;
+
+ entry_a = lookup_v4l2_fmt (pix_fmt_a);
+ entry_b = lookup_v4l2_fmt (pix_fmt_b);
+
+ if (!entry_a || !entry_b)
+ return FALSE;
+
+ if (entry_a->gst_fmt == entry_b->gst_fmt)
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/sys/v4l2codecs/gstv4l2format.h b/sys/v4l2codecs/gstv4l2format.h
index dd1e1ea..1f634ee 100644
--- a/sys/v4l2codecs/gstv4l2format.h
+++ b/sys/v4l2codecs/gstv4l2format.h
@@ -35,4 +35,6 @@ gboolean gst_v4l2_format_to_video_format (guint32 pix_fmt,
gboolean gst_v4l2_format_from_video_format (GstVideoFormat format,
guint32 * out_pix_fmt);
+gboolean gst_v4l2_format_equivalent (guint32 pix_fmt_a, guint32 pix_fmt_b);
+
#endif /* __GST_V4L2_FORMAT_H__ */
--
2.25.1

View File

@ -0,0 +1,38 @@
From 2bf76dc97e65611bcbc5bb82a264ae6a88df8903 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Thu, 2 Nov 2023 10:39:34 -0400
Subject: [PATCH 52/68] v4l2codecs: encoder: Save the sink format
Save the V4L2 sink format that has been selected. The information
enclosed will be used to validate buffer importation.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2encoder.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index 0886d15..a9e0939 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -77,8 +77,9 @@ struct _GstV4l2Encoder
GstQueueArray *pending_requests;
guint version;
- enum v4l2_buf_type src_buf_type;
enum v4l2_buf_type sink_buf_type;
+ struct v4l2_format sink_fmt;
+ enum v4l2_buf_type src_buf_type;
gboolean mplane;
/* properties */
@@ -575,6 +576,7 @@ gst_v4l2_encoder_select_sink_format (GstV4l2Encoder * self, GstVideoInfo * in,
GST_INFO_OBJECT (self, "Selected sink format %s %ix%i",
gst_video_format_to_string (out->finfo->format), out->width, out->height);
+ self->sink_fmt = fmt;
return TRUE;
}
--
2.25.1

View File

@ -0,0 +1,29 @@
From 98d79a4ea5acc38550b1cead1dc0e876c710273f Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Thu, 2 Nov 2023 10:41:18 -0400
Subject: [PATCH 53/68] v4l2codecs: format: Prefer mplane variants
If we have the choice, prefer the mplane variant of the pixel formats
since it allows importing the single plane variant.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2format.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sys/v4l2codecs/gstv4l2format.c b/sys/v4l2codecs/gstv4l2format.c
index e029d7d..7af79f9 100644
--- a/sys/v4l2codecs/gstv4l2format.c
+++ b/sys/v4l2codecs/gstv4l2format.c
@@ -32,8 +32,8 @@ struct FormatEntry
};
static struct FormatEntry format_map[] = {
- {V4L2_PIX_FMT_NV12, 1, GST_VIDEO_FORMAT_NV12, 8, 420},
{V4L2_PIX_FMT_NV12M, 2, GST_VIDEO_FORMAT_NV12, 8, 420},
+ {V4L2_PIX_FMT_NV12, 1, GST_VIDEO_FORMAT_NV12, 8, 420},
{V4L2_PIX_FMT_YUYV, 1, GST_VIDEO_FORMAT_YUY2, 8, 422},
{V4L2_PIX_FMT_SUNXI_TILED_NV12, 1, GST_VIDEO_FORMAT_NV12_32L32, 8, 422},
{V4L2_PIX_FMT_NV12_4L4, 1, GST_VIDEO_FORMAT_NV12_4L4, 8, 420},
--
2.25.1

View File

@ -0,0 +1,517 @@
From c7ebabfc115055d62b47910cb136ea2abe6b5428 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Tue, 31 Oct 2023 16:24:33 -0400
Subject: [PATCH 54/68] v4l2codecs: encoder: Implement zero-copy support
In this implementation we switch encoders to always run in memory type
V4L2_MEMORY_DMABUF. To alllow fallback, we allocated 4 frame using
V4L2_MEMORY_MMAP at setup time and detach the dmabuf from the driver. If
upstream provides dmabuf, we try importating that, and if that fails, we
make a copy and continue.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codecallocator.c | 14 +-
sys/v4l2codecs/gstv4l2codech264enc.c | 35 +++--
sys/v4l2codecs/gstv4l2codecvp8enc.c | 21 ++-
sys/v4l2codecs/gstv4l2encoder.c | 198 ++++++++++++++++++++++---
sys/v4l2codecs/gstv4l2encoder.h | 8 +-
5 files changed, 228 insertions(+), 48 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codecallocator.c b/sys/v4l2codecs/gstv4l2codecallocator.c
index e0fb371..fd77347 100644
--- a/sys/v4l2codecs/gstv4l2codecallocator.c
+++ b/sys/v4l2codecs/gstv4l2codecallocator.c
@@ -245,7 +245,8 @@ gst_v4l2_codec_encoder_allocator_prepare (GstV4l2CodecAllocator * self)
gint ret;
guint i;
- ret = gst_v4l2_encoder_request_buffers (encoder, direction, self->pool_size);
+ ret = gst_v4l2_encoder_request_buffers (encoder, direction, self->pool_size,
+ V4L2_MEMORY_MMAP);
if (ret < self->pool_size) {
if (ret >= 0)
GST_ERROR_OBJECT (self,
@@ -261,10 +262,16 @@ gst_v4l2_codec_encoder_allocator_prepare (GstV4l2CodecAllocator * self)
g_queue_push_tail (&self->pool, buf);
}
+ if (direction == GST_PAD_SINK) {
+ gst_v4l2_codec_allocator_detach (self);
+ gst_v4l2_encoder_request_buffers (encoder, direction,
+ VIDEO_MAX_FRAME, V4L2_MEMORY_DMABUF);
+ }
+
return TRUE;
failed:
- gst_v4l2_encoder_request_buffers (encoder, direction, 0);
+ gst_v4l2_encoder_request_buffers (encoder, direction, 0, V4L2_MEMORY_MMAP);
return FALSE;
}
@@ -446,7 +453,8 @@ gst_v4l2_codec_allocator_detach (GstV4l2CodecAllocator * self)
gst_v4l2_decoder_request_buffers (self->decoder, self->direction, 0);
}
if (self->encoder) {
- gst_v4l2_encoder_request_buffers (self->encoder, self->direction, 0);
+ gst_v4l2_encoder_request_buffers (self->encoder, self->direction, 0,
+ V4L2_MEMORY_MMAP);
}
}
GST_OBJECT_UNLOCK (self);
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 070c51a..e7a6e07 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -270,8 +270,16 @@ gst_v4l2_codec_h264_enc_propose_allocation (GstVideoEncoder * encoder,
GstQuery * query)
{
GstV4l2CodecH264Enc *self = GST_V4L2_CODEC_H264_ENC (encoder);
+ GstV4l2CodecPool *pool = NULL;
+ gboolean need_pool;
- gst_query_add_allocation_pool (query, NULL, self->vinfo.size, 2, 0);
+ gst_query_parse_allocation (query, NULL, &need_pool);
+
+ if (need_pool)
+ pool = gst_v4l2_codec_pool_new (self->sink_allocator, &self->vinfo);
+
+ gst_query_add_allocation_pool (query, GST_BUFFER_POOL (pool),
+ self->vinfo.size, 2, 0);
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
@@ -964,12 +972,6 @@ gst_v4l2_codec_h264_enc_encode_frame (GstH264Encoder * encoder,
goto done;
}
- if (!gst_v4l2_codec_h264_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);
@@ -991,13 +993,22 @@ gst_v4l2_codec_h264_enc_encode_frame (GstH264Encoder * encoder,
}
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_codec_h264_enc_copy_input_buffer (self, frame)) {
+ GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT,
+ ("Failed to allocate/copy input buffer."), (NULL));
+ goto done;
+ }
+
+ gst_v4l2_encoder_request_replace_pic_buf (request, frame->input_buffer);
+
+ 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, &flags))
- {
+ 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;
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.c b/sys/v4l2codecs/gstv4l2codecvp8enc.c
index 24e8540..5990c73 100644
--- a/sys/v4l2codecs/gstv4l2codecvp8enc.c
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.c
@@ -580,11 +580,6 @@ gst_v4l2_codec_vp8_enc_encode_frame (GstVp8Encoder * encoder,
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);
@@ -605,9 +600,19 @@ gst_v4l2_codec_vp8_enc_encode_frame (GstVp8Encoder * encoder,
}
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_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;
+ }
+
+ gst_v4l2_encoder_request_replace_pic_buf (request, frame->input_buffer);
+
+ 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, &flags)) {
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index a9e0939..85f0457 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -66,6 +66,12 @@ struct _GstV4l2Request
gboolean sub_request;
};
+struct BufState
+{
+ gboolean queued;
+ gint dmabuf_fd;
+};
+
struct _GstV4l2Encoder
{
GstObject parent;
@@ -82,6 +88,9 @@ struct _GstV4l2Encoder
enum v4l2_buf_type src_buf_type;
gboolean mplane;
+ /* Rember which FD was used with which index */
+ struct BufState buffer_state[VIDEO_MAX_FRAME];
+
/* properties */
gchar *media_device;
gchar *video_device;
@@ -106,6 +115,67 @@ direction_to_buffer_type (GstV4l2Encoder * self, GstPadDirection direction)
return self->sink_buf_type;
}
+static void
+buffer_state_init (GstV4l2Encoder * self)
+{
+ gint i;
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ self->buffer_state[i].dmabuf_fd = -1;
+}
+
+static void
+buffer_state_streamoff (GstV4l2Encoder * self)
+{
+ gint i;
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ self->buffer_state[i].queued = FALSE;
+}
+
+static gint
+buffer_state_find_buffer (GstV4l2Encoder * self, gint dmabuf_fd)
+{
+ gint outstanding_index = -1;
+ gint i;
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (self->buffer_state[i].queued)
+ continue;
+
+ if (outstanding_index == -1)
+ outstanding_index = i;
+
+ if (self->buffer_state[i].dmabuf_fd == dmabuf_fd)
+ break;
+ }
+
+ if (i == VIDEO_MAX_FRAME) {
+ if (outstanding_index == -1) {
+ return -1;
+ }
+
+ i = outstanding_index;
+ }
+
+ return i;
+}
+
+static void
+buffer_state_queue (GstV4l2Encoder * self, gint index, gint dmabuf_fd)
+{
+ g_assert (!self->buffer_state[index].queued);
+
+ self->buffer_state[index].queued = TRUE;
+ self->buffer_state[index].dmabuf_fd = dmabuf_fd;
+}
+
+static void
+buffer_state_dequeue (GstV4l2Encoder * self, gint index)
+{
+ self->buffer_state[index].queued = FALSE;
+}
+
static void
gst_v4l2_encoder_finalize (GObject * obj)
{
@@ -126,6 +196,8 @@ gst_v4l2_encoder_init (GstV4l2Encoder * self)
{
self->request_pool = gst_queue_array_new (16);
self->pending_requests = gst_queue_array_new (16);
+
+ buffer_state_init (self);
}
static void
@@ -268,6 +340,8 @@ gst_v4l2_encoder_streamoff (GstV4l2Encoder * self, GstPadDirection direction)
pending_req->pending = FALSE;
gst_v4l2_encoder_request_unref (pending_req);
}
+ } else {
+ buffer_state_streamoff (self);
}
ret = ioctl (self->video_fd, VIDIOC_STREAMOFF, &type);
@@ -619,8 +693,8 @@ gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoInfo * info,
return FALSE;
}
- if (!gst_v4l2_format_equivalent (pix_fmt, fmt.fmt.pix_mp.pixelformat)
- || fmt.fmt.pix_mp.width != width || fmt.fmt.pix_mp.height != height) {
+ if (pix_fmt != fmt.fmt.pix_mp.pixelformat || fmt.fmt.pix_mp.width != width
+ || fmt.fmt.pix_mp.height != height) {
GST_DEBUG_OBJECT (self,
"Trying to use peer format: %" GST_FOURCC_FORMAT " %ix%i",
GST_FOURCC_ARGS (pix_fmt), width, height);
@@ -628,6 +702,7 @@ gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoInfo * info,
fmt.fmt.pix_mp.pixelformat = pix_fmt;
fmt.fmt.pix_mp.width = width;
fmt.fmt.pix_mp.height = height;
+ fmt.fmt.pix_mp.plane_fmt[0].sizeimage = 4 * 1024 * 1024;//FIXME
ret = ioctl (self->video_fd, VIDIOC_S_FMT, &fmt);
if (ret < 0) {
@@ -648,12 +723,12 @@ gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoInfo * info,
gint
gst_v4l2_encoder_request_buffers (GstV4l2Encoder * self,
- GstPadDirection direction, guint num_buffers)
+ GstPadDirection direction, guint num_buffers, guint mem_type)
{
gint ret;
struct v4l2_requestbuffers reqbufs = {
.count = num_buffers,
- .memory = V4L2_MEMORY_MMAP,
+ .memory = mem_type,
.type = direction_to_buffer_type (self, direction),
};
@@ -779,38 +854,104 @@ gst_v4l2_encoder_queue_src_buffer (GstV4l2Encoder * self,
return TRUE;
}
+static gboolean
+gst_v4l2_encoder_import_buffer (GstV4l2Encoder * self, GstBuffer * buffer,
+ struct v4l2_buffer *v4l2_buffer)
+{
+ GstVideoMeta *vmeta = NULL;
+ gint i;
+
+ if (!self->mplane) {
+ GST_INFO_OBJECT (self,
+ "zero copy is only support on MPLANE drivers implementation.");
+ return FALSE;
+ }
+
+ vmeta = gst_buffer_get_video_meta (buffer);
+ if (!vmeta) {
+ GST_INFO_OBJECT (self, "a GstVideoMeta is required for zero copy.");
+ return FALSE;
+ }
+
+ if (self->sink_fmt.fmt.pix_mp.num_planes != vmeta->n_planes) {
+ GST_INFO_OBJECT (self,
+ "planar format into single plane is not support in zero copy.");
+ return FALSE;
+ }
+
+ for (i = 0; i < vmeta->n_planes; i++) {
+ struct v4l2_plane *planes = v4l2_buffer->m.planes;
+ struct v4l2_plane_pix_format *plane_fmt =
+ self->sink_fmt.fmt.pix_mp.plane_fmt;
+ gsize size, offset, maxsize;
+ guint length, mem_idx;
+ gsize mem_skip;
+ GstMemory *mem;
+
+ if (vmeta->stride[i] != plane_fmt[i].bytesperline) {
+ GST_INFO_OBJECT (self,
+ "Stride miss-match at plane %i: got %i but expect %u",
+ i, vmeta->stride[i], plane_fmt[i].bytesperline);
+ return FALSE;
+ }
+
+ if (!gst_buffer_find_memory (buffer, vmeta->offset[i], 1, &mem_idx,
+ &length, &mem_skip)) {
+ GST_INFO_OBJECT (self, "no memory found for plane %i at offset %"
+ G_GSIZE_FORMAT ".", i, vmeta->offset[i]);
+ return FALSE;
+ }
+
+ mem = gst_buffer_peek_memory (buffer, mem_idx);
+ if (!gst_is_dmabuf_memory (mem)) {
+ GST_INFO_OBJECT (self, "cannot import non-dmabuf memory");
+ return FALSE;
+ }
+
+ size = gst_memory_get_sizes (mem, &offset, &maxsize);
+
+ /* *INDENT-OFF* */
+ planes[i] = (struct v4l2_plane) {
+ .bytesused = offset + size,
+ .length = offset + maxsize,
+ .data_offset = offset + mem_skip,
+ .m.fd = gst_dmabuf_memory_get_fd (mem),
+ };
+ /* *INDENT-ON* */
+ }
+
+ v4l2_buffer->length = vmeta->n_planes;
+ v4l2_buffer->index = buffer_state_find_buffer (self,
+ v4l2_buffer->m.planes[0].m.fd);
+
+ if (v4l2_buffer->index < 0) {
+ GST_INFO_OBJECT (self, "no more free buffer to queue the picture.");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static gboolean
gst_v4l2_encoder_queue_sink_buffer (GstV4l2Encoder * self,
GstV4l2Request * request, GstBuffer * buffer, guint32 frame_num,
guint flags)
{
- gint i, ret;
+ gint ret;
struct v4l2_plane planes[GST_VIDEO_MAX_PLANES];
struct v4l2_buffer buf = {
.type = self->sink_buf_type,
- .memory = V4L2_MEMORY_MMAP,
- .index = gst_v4l2_codec_buffer_get_index (buffer),
+ .memory = V4L2_MEMORY_DMABUF,
.timestamp.tv_usec = frame_num,
.request_fd = request->fd,
.flags = V4L2_BUF_FLAG_REQUEST_FD | flags,
+ .m.planes = planes,
};
GST_TRACE_OBJECT (self, "Queuing bitstream buffer %i", buf.index);
- if (self->mplane) {
- buf.length = gst_buffer_n_memory (buffer);
- buf.m.planes = planes;
- for (i = 0; i < buf.length; i++) {
- GstMemory *mem = gst_buffer_peek_memory (buffer, i);
- /* *INDENT-OFF* */
- planes[i] = (struct v4l2_plane) {
- .bytesused = gst_memory_get_sizes (mem, NULL, NULL),
- };
- /* *INDENT-ON* */
- }
- } else {
- buf.bytesused = gst_buffer_get_size (buffer);
- }
+ if (!gst_v4l2_encoder_import_buffer (self, buffer, &buf))
+ return FALSE;
ret = ioctl (self->video_fd, VIDIOC_QBUF, &buf);
if (ret < 0) {
@@ -818,6 +959,9 @@ gst_v4l2_encoder_queue_sink_buffer (GstV4l2Encoder * self,
return FALSE;
}
+ buffer_state_queue (self, buf.index,
+ gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (buffer, 0)));
+
return TRUE;
}
@@ -828,7 +972,7 @@ gst_v4l2_encoder_dequeue_sink (GstV4l2Encoder * self)
struct v4l2_plane planes[GST_VIDEO_MAX_PLANES] = { {0} };
struct v4l2_buffer buf = {
.type = self->sink_buf_type,
- .memory = V4L2_MEMORY_MMAP,
+ .memory = V4L2_MEMORY_DMABUF,
};
if (self->mplane) {
@@ -843,6 +987,7 @@ gst_v4l2_encoder_dequeue_sink (GstV4l2Encoder * self)
}
GST_TRACE_OBJECT (self, "Dequeued picture buffer %i", buf.index);
+ buffer_state_dequeue (self, buf.index);
return TRUE;
}
@@ -1256,7 +1401,7 @@ gst_v4l2_encoder_request_queue (GstV4l2Request * request, guint flags)
if (!gst_v4l2_encoder_queue_sink_buffer (encoder, request,
request->pic_buf, request->frame_num, flags)) {
- GST_ERROR_OBJECT (encoder, "Driver did not accept the picture buffer.");
+ GST_INFO_OBJECT (encoder, "Driver did not accept the picture buffer.");
return FALSE;
}
@@ -1344,6 +1489,13 @@ gst_v4l2_encoder_request_set_done (GstV4l2Request * request,
return ret;
}
+void
+gst_v4l2_encoder_request_replace_pic_buf (GstV4l2Request * request,
+ GstBuffer * pic_buf)
+{
+ gst_buffer_replace (&request->pic_buf, pic_buf);
+}
+
gboolean
gst_v4l2_codec_vp8_enc_get_qp_range (GstV4l2Encoder * self,
guint * qp_min, guint * qp_max)
diff --git a/sys/v4l2codecs/gstv4l2encoder.h b/sys/v4l2codecs/gstv4l2encoder.h
index e7f44ba..09016e1 100644
--- a/sys/v4l2codecs/gstv4l2encoder.h
+++ b/sys/v4l2codecs/gstv4l2encoder.h
@@ -64,7 +64,8 @@ gboolean gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoI
gint gst_v4l2_encoder_request_buffers (GstV4l2Encoder * self,
GstPadDirection direction,
- guint num_buffers);
+ guint num_buffers,
+ guint mem_type);
gboolean gst_v4l2_encoder_export_buffer (GstV4l2Encoder * self,
GstPadDirection directon,
@@ -130,12 +131,15 @@ gboolean gst_v4l2_encoder_request_queue (GstV4l2Request * request,
gint gst_v4l2_encoder_request_set_done (GstV4l2Request * request, guint32 * bytesused, guint32 * flags);
-gboolean gst_v4l2_encoder_request_failed (GstV4l2Request * request);
+void gst_v4l2_encoder_request_replace_pic_buf (GstV4l2Request * request,
+ GstBuffer * pic_buf);
gboolean gst_v4l2_codec_vp8_enc_get_qp_range (GstV4l2Encoder * self, guint * qp_min, guint * qp_max);
gboolean gst_v4l2_codec_h264_enc_get_qp_range (GstV4l2Encoder * self, guint * qp_min, guint * qp_max);
+gboolean gst_v4l2_encoder_uses_zero_copy (GstV4l2Encoder * self);
+
G_END_DECLS
#endif /* __GST_V4L2_ENCODER_H__ */
--
2.25.1

View File

@ -0,0 +1,27 @@
From 3029b0bd479ee17c15aca93b4c6e2fdad44c7824 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Wed, 15 Nov 2023 11:30:58 -0500
Subject: [PATCH 55/68] codecs: h264enc: Fix indentation
Upstream-Status: Pending
---
gst-libs/gst/codecs/gsth264encoder.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gst-libs/gst/codecs/gsth264encoder.c b/gst-libs/gst/codecs/gsth264encoder.c
index b024939..5769446 100644
--- a/gst-libs/gst/codecs/gsth264encoder.c
+++ b/gst-libs/gst/codecs/gsth264encoder.c
@@ -147,7 +147,8 @@ gst_h264_encoder_set_quality (GstH264Encoder * self, GstH264Frame * h264_frame)
}
static GstFlowReturn
-gst_h264_encoder_set_frame_type (GstH264Encoder * self, GstH264Frame * h264_frame)
+gst_h264_encoder_set_frame_type (GstH264Encoder * self,
+ GstH264Frame * h264_frame)
{
GstH264EncoderPrivate *priv = self->priv;
GstVideoCodecFrame *frame = h264_frame->frame;
--
2.25.1

View File

@ -0,0 +1,362 @@
From e3f07a8e64dcd406b6665a7bce125efdf603efb9 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Wed, 15 Nov 2023 11:31:14 -0500
Subject: [PATCH 56/68] v4l2codecs: h264enc: Fix indentation
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 157 ++++++++++++---------------
1 file changed, 69 insertions(+), 88 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index e7a6e07..6bf249a 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -45,12 +45,11 @@ enum
#define GST_PAD_SINK_FORMATS "{NV12, YUY2, I420}"
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_PAD_SINK_FORMATS)
- ", colorimetry= {bt601,bt709,bt601-full-range,bt709-full-range}"
- )
- );
+GST_STATIC_PAD_TEMPLATE (GST_VIDEO_ENCODER_SINK_NAME,
+ GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_PAD_SINK_FORMATS)
+ ", colorimetry= {bt601,bt709,bt601-full-range,bt709-full-range}")
+ );
static GstStaticPadTemplate src_template =
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_ENCODER_SRC_NAME,
@@ -157,13 +156,7 @@ gst_v4l2_codec_h264_enc_api_check (GstV4l2Encoder * encoder)
}, {
SET_ID (V4L2_CID_STATELESS_H264_ENCODE_RC),
.size = sizeof(struct v4l2_ctrl_h264_encode_rc),
- // }, {
- // SET_ID (V4L2_CID_STATELESS_H264_SPS),
- // .size = sizeof(struct v4l2_ctrl_h264_sps),
- // }, {
- // SET_ID (V4L2_CID_STATELESS_H264_PPS),
- // .size = sizeof(struct v4l2_ctrl_h264_pps),
- },
+ }
};
#undef SET_ID
/* *INDENT-ON* */
@@ -324,7 +317,7 @@ gst_v4l2_codec_h264_enc_buffers_allocation (GstVideoEncoder * encoder)
static gboolean
gst_v4l2_codec_h264_enc_set_codec_data (GstVideoEncoder * encoder,
- GstBuffer *codec_data, guint *data_size)
+ GstBuffer * codec_data, guint * data_size)
{
GstV4l2CodecH264Enc *self = GST_V4L2_CODEC_H264_ENC (encoder);
@@ -362,7 +355,7 @@ gst_v4l2_codec_h264_enc_set_codec_data (GstVideoEncoder * encoder,
}
static guint8
-get_sps_aspect_ratio_idc(guint par_n, guint par_d)
+get_sps_aspect_ratio_idc (guint par_n, guint par_d)
{
if (par_n == 1 && par_d == 1)
return 1;
@@ -397,7 +390,7 @@ get_sps_aspect_ratio_idc(guint par_n, guint par_d)
else if (par_n == 2 && par_d == 1)
return 16;
else
- return 0; // Extended_SAR for custom ratios
+ return 0; // Extended_SAR for custom ratios
}
/* Begin of code taken from VA plugin */
@@ -412,9 +405,9 @@ typedef struct
int MaxCPB;
int MinCr;
} GstVaH264LevelLimits;
-/* *INDENT-OFF* */
static const GstVaH264LevelLimits _va_h264_level_limits[] = {
+ /* *INDENT-OFF* */
/* level idc MaxMBPS MaxFS MaxDpbMbs MaxBR MaxCPB MinCr */
{"1", GST_H264_LEVEL_L1, 1485, 99, 396, 64, 175, 2},
{"1b", GST_H264_LEVEL_L1B, 1485, 99, 396, 128, 350, 2},
@@ -436,32 +429,33 @@ static const GstVaH264LevelLimits _va_h264_level_limits[] = {
{"6", GST_H264_LEVEL_L6, 4177920, 139264, 696320, 240000, 240000, 2},
{"6.1", GST_H264_LEVEL_L6_1, 8355840, 139264, 696320, 480000, 480000, 2},
{"6.2", GST_H264_LEVEL_L6_2, 16711680, 139264, 696320, 800000, 800000, 2},
+ /* *INDENT-ON* */
};
-/* *INDENT-ON* */
+
/* Enf of code taken from VA Plugin */
// Recursive function to find the greatest common divisor
static gint
-gcd(int a, int b)
+gcd (int a, int b)
{
if (b == 0)
return a;
- return gcd(b, a % b);
+ return gcd (b, a % b);
}
static gint
-find_time_scale_multiplier(int fps_d)
+find_time_scale_multiplier (int fps_d)
{
guint base_value = 1000;
- return (fps_d * base_value) / gcd(fps_d, base_value);
+ return (fps_d * base_value) / gcd (fps_d, base_value);
}
static void
-gst_v4l2_codec_h264_enc_init_sps_pps(GstV4l2CodecH264Enc *self,
+gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
GstVideoCodecState * state)
{
- memset(&self->sps, 0, sizeof(self->sps));
- memset(&self->sps, 0, sizeof(self->pps));
+ memset (&self->sps, 0, sizeof (self->sps));
+ memset (&self->sps, 0, sizeof (self->pps));
/* SPS */
self->sps.profile_idc = 66;
@@ -470,7 +464,7 @@ gst_v4l2_codec_h264_enc_init_sps_pps(GstV4l2CodecH264Enc *self,
// sps.seq_parameter_set_id = 0; // TODO: Set it properly
- self->sps.chroma_format_idc = 1; /* YUV 4:2:0 */
+ self->sps.chroma_format_idc = 1; /* YUV 4:2:0 */
self->sps.pic_width_in_mbs_minus1 = self->width_mbs - 1;
self->sps.pic_height_in_map_units_minus1 = self->height_mbs - 1;
@@ -492,114 +486,100 @@ gst_v4l2_codec_h264_enc_init_sps_pps(GstV4l2CodecH264Enc *self,
// Calculate lowest acceptable level
GstStructure *structure;
gint fps_n, fps_d;
- structure = gst_caps_get_structure(state->caps, 0);
- gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d);
- gint n_levels = sizeof(_va_h264_level_limits) / sizeof(_va_h264_level_limits[0]);
+ structure = gst_caps_get_structure (state->caps, 0);
+ gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
+ gint n_levels =
+ sizeof (_va_h264_level_limits) / sizeof (_va_h264_level_limits[0]);
GValue bitrate = G_VALUE_INIT;
- g_object_get_property(G_OBJECT(&self->parent), "bitrate", &bitrate);
- self->targeted_bitrate = g_value_get_uint64(&bitrate);
+ g_object_get_property (G_OBJECT (&self->parent), "bitrate", &bitrate);
+ self->targeted_bitrate = g_value_get_uint64 (&bitrate);
int MaxBR = self->targeted_bitrate;
int FS = self->width * self->height / 256;
- int MBPS = FS * fps_n / fps_d; // Assuming each macroblock is 16x16
+ int MBPS = FS * fps_n / fps_d; // Assuming each macroblock is 16x16
int DpbMbs = FS;
int CPB = MaxBR;
int CR = fps_n / fps_d;
gint lowest_level = 0;
- for (; lowest_level < n_levels; ++lowest_level)
- {
+ for (; lowest_level < n_levels; ++lowest_level) {
const GstVaH264LevelLimits *level = &_va_h264_level_limits[lowest_level];
- if (MBPS <= level->MaxMBPS && FS <= level->MaxFS && DpbMbs <= level->MaxDpbMbs &&
- MaxBR <= level->MaxBR && CPB <= level->MaxCPB && CR >= level->MinCr)
- {
+ if (MBPS <= level->MaxMBPS && FS <= level->MaxFS
+ && DpbMbs <= level->MaxDpbMbs && MaxBR <= level->MaxBR
+ && CPB <= level->MaxCPB && CR >= level->MinCr) {
break;
}
}
self->sps.level_idc = _va_h264_level_limits[lowest_level].idc;
- if (self->sps.level_idc == GST_H264_LEVEL_L1B)
- {
+ if (self->sps.level_idc == GST_H264_LEVEL_L1B) {
self->sps.constraint_set3_flag = 1;
}
- GST_DEBUG_OBJECT(self, "width:%d height:%d targeted_bitrate:%ld",
- self->height, self->height, self->targeted_bitrate);
- GST_DEBUG_OBJECT(self, "MBPS=%d,FS=%d,DpbMbs=%d,MaxBR=%d,CPB=%d,CR=%d",
- MBPS, FS, DpbMbs, MaxBR, CPB, CR);
- GST_DEBUG_OBJECT(self, "level_idc: %d", self->sps.level_idc);
+ GST_DEBUG_OBJECT (self, "width:%d height:%d targeted_bitrate:%ld",
+ self->height, self->height, self->targeted_bitrate);
+ GST_DEBUG_OBJECT (self, "MBPS=%d,FS=%d,DpbMbs=%d,MaxBR=%d,CPB=%d,CR=%d",
+ MBPS, FS, DpbMbs, MaxBR, CPB, CR);
+ GST_DEBUG_OBJECT (self, "level_idc: %d", self->sps.level_idc);
/* Crop unaligned videos */
- if (self->width & 15 || self->height & 15)
- {
- static const guint SubWidthC[] = {1, 2, 2, 1};
- static const guint SubHeightC[] = {1, 2, 1, 1};
+ if (self->width & 15 || self->height & 15) {
+ static const guint SubWidthC[] = { 1, 2, 2, 1 };
+ static const guint SubHeightC[] = { 1, 2, 1, 1 };
const guint CropUnitX = SubWidthC[self->sps.chroma_format_idc];
const guint CropUnitY = SubHeightC[self->sps.chroma_format_idc] *
- (2 - self->sps.frame_mbs_only_flag);
+ (2 - self->sps.frame_mbs_only_flag);
self->sps.frame_cropping_flag = 1;
self->sps.frame_crop_left_offset = 0;
self->sps.frame_crop_right_offset = (16 * self->width_mbs -
- self->width) /
- CropUnitX;
+ self->width) / CropUnitX;
self->sps.frame_crop_top_offset = 0;
self->sps.frame_crop_bottom_offset = (16 * self->height_mbs -
- self->height) /
- CropUnitY;
+ self->height) / CropUnitY;
}
-
-
// set colorimetry
const gchar *colorimetry;
- colorimetry = gst_structure_get_string(structure, "colorimetry");
+ colorimetry = gst_structure_get_string (structure, "colorimetry");
- if (colorimetry)
- {
+ if (colorimetry) {
self->sps.vui_parameters_present_flag = 1;
self->sps.vui_parameters.colour_description_present_flag = 1;
- if ((strcmp(colorimetry, "bt709") == 0) ||
- (strcmp(colorimetry, "bt709-full-range") == 0))
- {
+ if ((strcmp (colorimetry, "bt709") == 0) ||
+ (strcmp (colorimetry, "bt709-full-range") == 0)) {
self->sps.vui_parameters.colour_primaries = 1;
self->sps.vui_parameters.transfer_characteristics = 1;
self->sps.vui_parameters.matrix_coefficients = 1;
- if (strcmp(colorimetry, "bt709-full-range") == 0)
- {
+ if (strcmp (colorimetry, "bt709-full-range") == 0) {
self->sps.vui_parameters.video_full_range_flag = 1;
}
- }
- else if ((strcmp(colorimetry, "bt601") == 0) ||
- (strcmp(colorimetry, "bt601-full-range") == 0))
- {
+ } else if ((strcmp (colorimetry, "bt601") == 0) ||
+ (strcmp (colorimetry, "bt601-full-range") == 0)) {
self->sps.vui_parameters.colour_primaries = 6;
self->sps.vui_parameters.transfer_characteristics = 6;
self->sps.vui_parameters.matrix_coefficients = 6;
- if (strcmp(colorimetry, "bt601-full-range") == 0)
- {
+ if (strcmp (colorimetry, "bt601-full-range") == 0) {
self->sps.vui_parameters.video_full_range_flag = 1;
}
}
}
-
// set aspect ratio
gint par_n, par_d;
- if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &par_n, &par_d))
- {
+ if (gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_n,
+ &par_d)) {
self->sps.vui_parameters.aspect_ratio_info_present_flag = 1;
- self->sps.vui_parameters.aspect_ratio_idc = get_sps_aspect_ratio_idc(par_n, par_d);
- if (self->sps.vui_parameters.aspect_ratio_idc == 255)
- {
+ self->sps.vui_parameters.aspect_ratio_idc =
+ get_sps_aspect_ratio_idc (par_n, par_d);
+ if (self->sps.vui_parameters.aspect_ratio_idc == 255) {
self->sps.vui_parameters.sar_width = par_n;
self->sps.vui_parameters.sar_height = par_d;
}
}
-
// set Frame rate
- if (gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d))
- {
+ if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) {
self->sps.vui_parameters.timing_info_present_flag = 1;
self->sps.vui_parameters.fixed_frame_rate_flag = 1; // Only supports fixed frame rate for now
- gint multiplier = find_time_scale_multiplier(fps_d);
+ gint multiplier = find_time_scale_multiplier (fps_d);
gint time_scale = fps_n * multiplier;
self->sps.vui_parameters.time_scale = time_scale;
- self->sps.vui_parameters.num_units_in_tick = time_scale / (2 * fps_n / fps_d );
+ self->sps.vui_parameters.num_units_in_tick =
+ time_scale / (2 * fps_n / fps_d);
}
/* PPS */
@@ -665,8 +645,8 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
gst_video_codec_state_unref (self->output_state);
caps = gst_caps_new_simple ("video/x-h264",
- "stream-format", G_TYPE_STRING, "byte-stream",
- "alignment", G_TYPE_STRING, "nal", NULL);
+ "stream-format", G_TYPE_STRING, "byte-stream",
+ "alignment", G_TYPE_STRING, "nal", NULL);
self->output_state =
gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
@@ -690,7 +670,7 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
gst_v4l2_codec_h264_enc_get_qp_range (self->encoder, &self->qp_min,
&self->qp_max);
- gst_v4l2_codec_h264_enc_init_sps_pps(self, state);
+ gst_v4l2_codec_h264_enc_init_sps_pps (self, state);
return TRUE;
}
@@ -882,7 +862,8 @@ gst_v4l2_codec_h264_enc_fill_encode_params (GstH264Encoder * encoder,
self->encode_params.nalu_type = V4L2_H264_NAL_CODED_SLICE_NON_IDR_PIC;
self->encode_params.reference_ts = self->reference_timestamp;
self->encode_params.frame_num++;
- self->encode_params.frame_num %= (1 << (self->sps.log2_max_frame_num_minus4 + 4));
+ self->encode_params.frame_num %=
+ (1 << (self->sps.log2_max_frame_num_minus4 + 4));
self->encode_params.nalu_type = 1;
self->encode_params.nal_reference_idc = 2;
break;
@@ -906,7 +887,7 @@ gst_v4l2_codec_h264_enc_fill_encode_rc (GstH264Encoder * encoder,
//h264_rate_control_step(encoder);
- self->encode_rc.qp = self->pps.pic_init_qp_minus26 + 26;//encoder->rc.qp;
+ self->encode_rc.qp = self->pps.pic_init_qp_minus26 + 26; //encoder->rc.qp;
self->encode_rc.qp_min = self->qp_min;
self->encode_rc.qp_max = self->qp_max;
}
@@ -949,8 +930,8 @@ gst_v4l2_codec_h264_enc_encode_frame (GstH264Encoder * encoder,
gst_buffer_resize (codec_data, 0, data_size);
}
- /* *INDENT-OFF* */
struct v4l2_ext_control control[] = {
+ /* *INDENT-OFF* */
{
.id = V4L2_CID_STATELESS_H264_ENCODE_PARAMS,
.ptr = &self->encode_params,
@@ -960,8 +941,8 @@ gst_v4l2_codec_h264_enc_encode_frame (GstH264Encoder * encoder,
.ptr = &self->encode_rc,
.size = sizeof (self->encode_rc),
},
+ /* *INDENT-ON* */
};
- /* *INDENT-ON* */
GST_DEBUG_OBJECT (self, "encode h264 frame with quality = %d",
h264_frame->quality);
@@ -1008,7 +989,7 @@ gst_v4l2_codec_h264_enc_encode_frame (GstH264Encoder * encoder,
}
}
- if (!gst_v4l2_encoder_request_set_done(request, &bytesused, &flags)) {
+ 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;
--
2.25.1

View File

@ -0,0 +1,351 @@
From 4c2bad1d72ed1d87df1112b9d14dfdfb300ca4f2 Mon Sep 17 00:00:00 2001
From: Denis Shimizu <denis.shimizu@collabora.com>
Date: Tue, 14 Nov 2023 06:11:11 -0300
Subject: [PATCH 57/68] v4l2codecs: h264enc: Cleanup caps, colorimetry,
framerate and style
This is an overall fix of how colorimetry, framerate and caps are
handled, with additionall correction regarding GStreamer coding
standard.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 203 +++++++++++----------------
1 file changed, 84 insertions(+), 119 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 6bf249a..505d4e9 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -42,19 +42,15 @@ enum
PROP_LAST = PROP_0
};
-#define GST_PAD_SINK_FORMATS "{NV12, YUY2, I420}"
-
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_PAD_SINK_FORMATS)
- ", colorimetry= {bt601,bt709,bt601-full-range,bt709-full-range}")
- );
+ 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-h264,alignment=nal,stream-format=byte-stream"));
+ GST_STATIC_CAPS ("video/x-h264,alignment=au,stream-format=byte-stream"));
#define H264ENC_DEFAULT_KEYFRAME_INTERVAL 30
@@ -65,7 +61,7 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_ENCODER_SRC_NAME,
/* Scale factor for bitrate (HRD bit_rate_scale: min = 6) */
#define SX_BITRATE 6
-/* Scale factor for CPB size (HRD cpb_size_scale: min = 4) */
+/* Scale factor for cpb_size (HRD cpb_size_scale: min = 4) */
#define SX_CPB_SIZE 4
/* Maximum sizes for common headers (in bits) */
#define MAX_SPS_HDR_SIZE 16473
@@ -88,8 +84,8 @@ struct _GstV4l2CodecH264Enc
GstVideoInfo vinfo;
gint width;
gint height;
- gint width_mbs;
- gint height_mbs;
+ gint width_in_macroblocks;
+ gint height_in_macroblocks;
guint qp_max, qp_min;
guint64 targeted_bitrate;
@@ -390,7 +386,7 @@ get_sps_aspect_ratio_idc (guint par_n, guint par_d)
else if (par_n == 2 && par_d == 1)
return 16;
else
- return 0; // Extended_SAR for custom ratios
+ return 255; // Extended_SAR for custom ratios
}
/* Begin of code taken from VA plugin */
@@ -398,17 +394,18 @@ typedef struct
{
const char *level;
int idc;
- int MaxMBPS;
- int MaxFS;
- int MaxDpbMbs;
- int MaxBR;
- int MaxCPB;
- int MinCr;
+ int max_macroblocks_per_second;
+ int max_frame_size_in_macroblocks;
+ int max_dpb_macroblocks;
+ int maximum_bitrate;
+ int max_cpb_size;
+ int minimum_compression_ratio;
} GstVaH264LevelLimits;
-static const GstVaH264LevelLimits _va_h264_level_limits[] = {
+static const GstVaH264LevelLimits _h264_level_limits[] = {
/* *INDENT-OFF* */
- /* level idc MaxMBPS MaxFS MaxDpbMbs MaxBR MaxCPB MinCr */
+ /*level, idc, max_macroblocks_per_second, max_frame_size_in_macroblocks,
+ max_dpb_macroblocks, max_bitrate, max_cpb_size, minimum_compression_ratio */
{"1", GST_H264_LEVEL_L1, 1485, 99, 396, 64, 175, 2},
{"1b", GST_H264_LEVEL_L1B, 1485, 99, 396, 128, 350, 2},
{"1.1", GST_H264_LEVEL_L1_1, 3000, 396, 900, 192, 500, 2},
@@ -434,26 +431,14 @@ static const GstVaH264LevelLimits _va_h264_level_limits[] = {
/* Enf of code taken from VA Plugin */
-// Recursive function to find the greatest common divisor
-static gint
-gcd (int a, int b)
-{
- if (b == 0)
- return a;
- return gcd (b, a % b);
-}
-
-static gint
-find_time_scale_multiplier (int fps_d)
-{
- guint base_value = 1000;
- return (fps_d * base_value) / gcd (fps_d, base_value);
-}
-
static void
gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
GstVideoCodecState * state)
{
+ gint maximum_bitrate, frame_size_in_macroblocks,
+ macroblocks_per_second, dpb_macroblocks, cpb_size, compression_ratio,
+ minimum_level_index;
+
memset (&self->sps, 0, sizeof (self->sps));
memset (&self->sps, 0, sizeof (self->pps));
@@ -462,12 +447,10 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
self->sps.constraint_set0_flag = 1;
self->sps.constraint_set1_flag = 0;
-
- // sps.seq_parameter_set_id = 0; // TODO: Set it properly
self->sps.chroma_format_idc = 1; /* YUV 4:2:0 */
- self->sps.pic_width_in_mbs_minus1 = self->width_mbs - 1;
- self->sps.pic_height_in_map_units_minus1 = self->height_mbs - 1;
+ self->sps.pic_width_in_mbs_minus1 = self->width_in_macroblocks - 1;
+ self->sps.pic_height_in_map_units_minus1 = self->height_in_macroblocks - 1;
self->sps.num_ref_frames = 1; // FIXME: rename according to spec, max_num_ref_frames
self->sps.num_ref_frames_in_pic_order_cnt_cycle = 2;
@@ -484,103 +467,92 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
self->sps.frame_mbs_only_flag = 1;
// Calculate lowest acceptable level
- GstStructure *structure;
- gint fps_n, fps_d;
- structure = gst_caps_get_structure (state->caps, 0);
- gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
- gint n_levels =
- sizeof (_va_h264_level_limits) / sizeof (_va_h264_level_limits[0]);
+ gint n_levels = G_N_ELEMENTS (_h264_level_limits);
GValue bitrate = G_VALUE_INIT;
- g_object_get_property (G_OBJECT (&self->parent), "bitrate", &bitrate);
+ g_object_get_property (G_OBJECT (self), "bitrate", &bitrate);
self->targeted_bitrate = g_value_get_uint64 (&bitrate);
- int MaxBR = self->targeted_bitrate;
- int FS = self->width * self->height / 256;
- int MBPS = FS * fps_n / fps_d; // Assuming each macroblock is 16x16
- int DpbMbs = FS;
- int CPB = MaxBR;
- int CR = fps_n / fps_d;
- gint lowest_level = 0;
- for (; lowest_level < n_levels; ++lowest_level) {
- const GstVaH264LevelLimits *level = &_va_h264_level_limits[lowest_level];
- if (MBPS <= level->MaxMBPS && FS <= level->MaxFS
- && DpbMbs <= level->MaxDpbMbs && MaxBR <= level->MaxBR
- && CPB <= level->MaxCPB && CR >= level->MinCr) {
+ maximum_bitrate = self->targeted_bitrate;
+ frame_size_in_macroblocks = self->width * self->height / 256;
+ macroblocks_per_second = frame_size_in_macroblocks * state->info.fps_n / state->info.fps_d; // Assuming each macroblock is 16x16
+ dpb_macroblocks = frame_size_in_macroblocks;
+ cpb_size = maximum_bitrate;
+ compression_ratio = state->info.fps_n / state->info.fps_d;
+ minimum_level_index = 0;
+ for (; minimum_level_index < n_levels; ++minimum_level_index) {
+ const GstVaH264LevelLimits *level =
+ &_h264_level_limits[minimum_level_index];
+ if (macroblocks_per_second <= level->max_macroblocks_per_second
+ && frame_size_in_macroblocks <= level->max_frame_size_in_macroblocks
+ && dpb_macroblocks <= level->max_dpb_macroblocks
+ && maximum_bitrate <= level->maximum_bitrate
+ && cpb_size <= level->max_cpb_size
+ && compression_ratio >= level->minimum_compression_ratio) {
break;
}
}
- self->sps.level_idc = _va_h264_level_limits[lowest_level].idc;
+ self->sps.level_idc = _h264_level_limits[minimum_level_index].idc;
if (self->sps.level_idc == GST_H264_LEVEL_L1B) {
self->sps.constraint_set3_flag = 1;
}
GST_DEBUG_OBJECT (self, "width:%d height:%d targeted_bitrate:%ld",
self->height, self->height, self->targeted_bitrate);
- GST_DEBUG_OBJECT (self, "MBPS=%d,FS=%d,DpbMbs=%d,MaxBR=%d,CPB=%d,CR=%d",
- MBPS, FS, DpbMbs, MaxBR, CPB, CR);
+ GST_DEBUG_OBJECT (self,
+ "macroblocks_per_second=%d,frame_size_in_macroblocks=%d,dpb_macroblocks=%d,maximum_bitrate=%d,cpb_size=%d,compression_ratio=%d",
+ macroblocks_per_second, frame_size_in_macroblocks, dpb_macroblocks,
+ maximum_bitrate, cpb_size, compression_ratio);
GST_DEBUG_OBJECT (self, "level_idc: %d", self->sps.level_idc);
/* Crop unaligned videos */
if (self->width & 15 || self->height & 15) {
- static const guint SubWidthC[] = { 1, 2, 2, 1 };
- static const guint SubHeightC[] = { 1, 2, 1, 1 };
- const guint CropUnitX = SubWidthC[self->sps.chroma_format_idc];
- const guint CropUnitY = SubHeightC[self->sps.chroma_format_idc] *
- (2 - self->sps.frame_mbs_only_flag);
+ static const guint chroma_subsampling_width[] = { 1, 2, 2, 1 };
+ static const guint chroma_subsampling_height[] = { 1, 2, 1, 1 };
+ const guint crop_unit_x =
+ chroma_subsampling_width[self->sps.chroma_format_idc];
+ const guint crop_unit_y =
+ chroma_subsampling_height[self->sps.chroma_format_idc] * (2 -
+ self->sps.frame_mbs_only_flag);
self->sps.frame_cropping_flag = 1;
self->sps.frame_crop_left_offset = 0;
- self->sps.frame_crop_right_offset = (16 * self->width_mbs -
- self->width) / CropUnitX;
+ self->sps.frame_crop_right_offset = (16 * self->width_in_macroblocks -
+ self->width) / crop_unit_x;
self->sps.frame_crop_top_offset = 0;
- self->sps.frame_crop_bottom_offset = (16 * self->height_mbs -
- self->height) / CropUnitY;
+ self->sps.frame_crop_bottom_offset = (16 * self->height_in_macroblocks -
+ self->height) / crop_unit_y;
}
// set colorimetry
- const gchar *colorimetry;
- colorimetry = gst_structure_get_string (structure, "colorimetry");
-
- if (colorimetry) {
- self->sps.vui_parameters_present_flag = 1;
+ self->sps.vui_parameters_present_flag = 1;
+ if (state->info.colorimetry.range != GST_VIDEO_COLOR_RANGE_UNKNOWN &&
+ state->info.colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN &&
+ state->info.colorimetry.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
+ state->info.colorimetry.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN) {
+
+ self->sps.vui_parameters.video_signal_type_present_flag = 1;
+ self->sps.vui_parameters.video_format = 5;
self->sps.vui_parameters.colour_description_present_flag = 1;
- if ((strcmp (colorimetry, "bt709") == 0) ||
- (strcmp (colorimetry, "bt709-full-range") == 0)) {
- self->sps.vui_parameters.colour_primaries = 1;
- self->sps.vui_parameters.transfer_characteristics = 1;
- self->sps.vui_parameters.matrix_coefficients = 1;
- if (strcmp (colorimetry, "bt709-full-range") == 0) {
- self->sps.vui_parameters.video_full_range_flag = 1;
- }
- } else if ((strcmp (colorimetry, "bt601") == 0) ||
- (strcmp (colorimetry, "bt601-full-range") == 0)) {
- self->sps.vui_parameters.colour_primaries = 6;
- self->sps.vui_parameters.transfer_characteristics = 6;
- self->sps.vui_parameters.matrix_coefficients = 6;
- if (strcmp (colorimetry, "bt601-full-range") == 0) {
- self->sps.vui_parameters.video_full_range_flag = 1;
- }
+ self->sps.vui_parameters.colour_primaries =
+ gst_video_color_primaries_to_iso (state->info.colorimetry.primaries);
+ self->sps.vui_parameters.transfer_characteristics =
+ gst_video_transfer_function_to_iso (state->info.colorimetry.transfer);
+ self->sps.vui_parameters.matrix_coefficients =
+ gst_video_color_matrix_to_iso (state->info.colorimetry.matrix);
+ if (state->info.colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255) {
+ self->sps.vui_parameters.video_full_range_flag = 1;
}
}
// set aspect ratio
- gint par_n, par_d;
- if (gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_n,
- &par_d)) {
- self->sps.vui_parameters.aspect_ratio_info_present_flag = 1;
- self->sps.vui_parameters.aspect_ratio_idc =
- get_sps_aspect_ratio_idc (par_n, par_d);
- if (self->sps.vui_parameters.aspect_ratio_idc == 255) {
- self->sps.vui_parameters.sar_width = par_n;
- self->sps.vui_parameters.sar_height = par_d;
- }
+ self->sps.vui_parameters.aspect_ratio_info_present_flag = 1;
+ self->sps.vui_parameters.aspect_ratio_idc =
+ get_sps_aspect_ratio_idc (state->info.par_n, state->info.par_d);
+ if (self->sps.vui_parameters.aspect_ratio_idc == 255) {
+ self->sps.vui_parameters.sar_width = state->info.par_n;
+ self->sps.vui_parameters.sar_height = state->info.par_d;
}
// set Frame rate
- if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) {
- self->sps.vui_parameters.timing_info_present_flag = 1;
- self->sps.vui_parameters.fixed_frame_rate_flag = 1; // Only supports fixed frame rate for now
- gint multiplier = find_time_scale_multiplier (fps_d);
- gint time_scale = fps_n * multiplier;
- self->sps.vui_parameters.time_scale = time_scale;
- self->sps.vui_parameters.num_units_in_tick =
- time_scale / (2 * fps_n / fps_d);
- }
+ self->sps.vui_parameters.timing_info_present_flag = 1;
+ self->sps.vui_parameters.fixed_frame_rate_flag = 1; // Only supports fixed frame rate for now
+ self->sps.vui_parameters.num_units_in_tick = state->info.fps_d;
+ self->sps.vui_parameters.time_scale = state->info.fps_n * 2;
/* PPS */
self->pps.id = 0;
@@ -592,11 +564,7 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
self->pps.weighted_bipred_idc = 0;
/* Rate Control */
-
- // h264_rate_control_step(encoder);
-
self->pps.chroma_qp_index_offset = 4;
- // pps.pic_init_qp_minus26 = encoder.rc.qp - 26;
self->pps.pic_init_qp_minus26 = -13;
self->pps.second_chroma_qp_index_offset = self->pps.chroma_qp_index_offset;
self->pps.deblocking_filter_control_present_flag = 1;
@@ -637,8 +605,8 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
self->width = state->info.width;
self->height = state->info.height;
gst_v4l2_codec_h264_enc_buffers_allocation (encoder);
- self->width_mbs = (self->width + 15) / 16;
- self->height_mbs = (self->height + 15) / 16;
+ self->width_in_macroblocks = (self->width + 15) / 16;
+ self->height_in_macroblocks = (self->height + 15) / 16;
self->first_frame = TRUE;
if (self->output_state)
@@ -646,7 +614,7 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
caps = gst_caps_new_simple ("video/x-h264",
"stream-format", G_TYPE_STRING, "byte-stream",
- "alignment", G_TYPE_STRING, "nal", NULL);
+ "alignment", G_TYPE_STRING, "au", NULL);
self->output_state =
gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
@@ -884,9 +852,6 @@ gst_v4l2_codec_h264_enc_fill_encode_rc (GstH264Encoder * encoder,
GstV4l2CodecH264Enc *self = GST_V4L2_CODEC_H264_ENC (encoder);
/* Rate Control */
-
- //h264_rate_control_step(encoder);
-
self->encode_rc.qp = self->pps.pic_init_qp_minus26 + 26; //encoder->rc.qp;
self->encode_rc.qp_min = self->qp_min;
self->encode_rc.qp_max = self->qp_max;
--
2.25.1

View File

@ -0,0 +1,154 @@
From 928f0ed7c027046999f09834fbf2baa139c10d1c Mon Sep 17 00:00:00 2001
From: Denis Shimizu <denis.shimizu@collabora.com>
Date: Wed, 8 Nov 2023 06:58:33 -0300
Subject: [PATCH 58/68] v4l2codecs: h264enc: add CABAC enable/disable control
Add option to enable/disable CABAC. It will change the encoder
parameters and PPS related flag.
Upstream-Status: Pending
---
gst-libs/gst/codecs/gsth264encoder.c | 47 ++++++++++++++++++++++++++++
sys/v4l2codecs/gstv4l2codech264enc.c | 14 ++++++++-
2 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/gst-libs/gst/codecs/gsth264encoder.c b/gst-libs/gst/codecs/gsth264encoder.c
index 5769446..4c35956 100644
--- a/gst-libs/gst/codecs/gsth264encoder.c
+++ b/gst-libs/gst/codecs/gsth264encoder.c
@@ -38,6 +38,8 @@ GST_DEBUG_CATEGORY (gst_h264_encoder_debug);
#define H264_DEFAULT_BITRATE 100000
+#define H264ENC_DEFAULT_CABAC_IDC 0
+
enum
{
PROP_0,
@@ -45,6 +47,8 @@ enum
PROP_MAX_QUALITY,
PROP_MIN_QUALITY,
PROP_BITRATE,
+ PROP_CABAC,
+ PROP_CABAC_INIT_IDC,
};
struct _GstH264EncoderPrivate
@@ -59,6 +63,8 @@ struct _GstH264EncoderPrivate
gint current_quality;
guint64 used_bytes;
guint64 nb_frames;
+ gboolean cabac;
+ guint cabac_init_idc;
};
#define parent_class gst_h264_encoder_parent_class
@@ -247,6 +253,16 @@ gst_h264_encoder_get_property (GObject * object, guint property_id,
g_value_set_uint64 (value, priv->targeted_bitrate);
GST_OBJECT_UNLOCK (self);
break;
+ case PROP_CABAC:
+ GST_OBJECT_LOCK (self);
+ g_value_set_boolean (value, priv->cabac);
+ GST_OBJECT_UNLOCK (self);
+ break;
+ case PROP_CABAC_INIT_IDC:
+ GST_OBJECT_LOCK (self);
+ g_value_set_uint (value, priv->cabac_init_idc);
+ GST_OBJECT_UNLOCK (self);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -281,6 +297,16 @@ gst_h264_encoder_set_property (GObject * object, guint property_id,
priv->targeted_bitrate = g_value_get_uint64 (value);
GST_OBJECT_UNLOCK (self);
break;
+ case PROP_CABAC:
+ GST_OBJECT_LOCK (self);
+ priv->cabac = g_value_get_boolean (value);
+ GST_OBJECT_UNLOCK (self);
+ break;
+ case PROP_CABAC_INIT_IDC:
+ GST_OBJECT_LOCK (self);
+ priv->cabac_init_idc = g_value_get_uint (value);
+ GST_OBJECT_UNLOCK (self);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -350,4 +376,25 @@ gst_h264_encoder_class_init (GstH264EncoderClass * klass)
"Set bitrate target",
0, UINT_MAX, H264_DEFAULT_BITRATE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+ /**
+ * GstH264Encoder:cabac:
+ *
+ *
+ * Since: 1.2x
+ */
+ g_object_class_install_property (object_class, PROP_CABAC,
+ g_param_spec_boolean ("cabac", "CABAC", "Enable use of CABAC over CAVLC",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstH264Encoder:cabac-init-idc:
+ *
+ *
+ * Since: 1.2x
+ */
+ g_object_class_install_property (object_class, PROP_CABAC_INIT_IDC,
+ g_param_spec_uint ("cabac-init-idc", "Initial CABAC table ID",
+ "Set initial CABAC table idc value", 0, 2, H264ENC_DEFAULT_CABAC_IDC,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
}
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 505d4e9..4591af3 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -88,6 +88,8 @@ struct _GstV4l2CodecH264Enc
gint height_in_macroblocks;
guint qp_max, qp_min;
guint64 targeted_bitrate;
+ gboolean cabac;
+ guint cabac_init_idc;
GstV4l2CodecAllocator *sink_allocator;
GstV4l2CodecAllocator *src_allocator;
@@ -568,6 +570,7 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
self->pps.pic_init_qp_minus26 = -13;
self->pps.second_chroma_qp_index_offset = self->pps.chroma_qp_index_offset;
self->pps.deblocking_filter_control_present_flag = 1;
+ self->pps.entropy_coding_mode_flag = self->cabac;
}
static gboolean
@@ -638,6 +641,9 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
gst_v4l2_codec_h264_enc_get_qp_range (self->encoder, &self->qp_min,
&self->qp_max);
+ g_object_get (self, "cabac", &self->cabac, "cabac-init-idc",
+ &self->cabac_init_idc, NULL);
+
gst_v4l2_codec_h264_enc_init_sps_pps (self, state);
return TRUE;
@@ -837,8 +843,14 @@ gst_v4l2_codec_h264_enc_fill_encode_params (GstH264Encoder * encoder,
break;
}
+ if (self->cabac) {
+ self->encode_params.flags |= V4L2_H264_ENCODE_FLAG_ENTROPY_CABAC;
+ } else {
+ self->encode_params.flags &= ~V4L2_H264_ENCODE_FLAG_ENTROPY_CABAC;
+ }
+
self->encode_params.pic_parameter_set_id = 0;
- self->encode_params.cabac_init_idc = 0;
+ self->encode_params.cabac_init_idc = self->cabac_init_idc;
self->encode_params.pic_init_qp_minus26 = self->pps.pic_init_qp_minus26;
self->encode_params.chroma_qp_index_offset = self->pps.chroma_qp_index_offset;
--
2.25.1

View File

@ -0,0 +1,29 @@
From 43ec43c0d889ecabcb06fbc6b334e884ad44a48f Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Wed, 15 Nov 2023 13:19:16 -0500
Subject: [PATCH 59/68] v4l2codecs: h264enc: Don't call virtual negotiate()
directly
This is not meant to be used like this, call
gst_video_encoder_negotiate() instead.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 4591af3..e7ae63a 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -623,7 +623,7 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
caps, state);
- if (GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder)) {
+ if (gst_video_encoder_negotiate (encoder)) {
if (!gst_v4l2_encoder_streamon (self->encoder, GST_PAD_SINK)) {
GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
("Could not enable the encoder driver."),
--
2.25.1

View File

@ -0,0 +1,29 @@
From 5c450c21d66fe2ad1be120ff427c3d2eb1b6e283 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Wed, 15 Nov 2023 15:30:22 -0500
Subject: [PATCH 60/68] v4l2codecs: vp8enc: Don't call virtual negotiate()
directly
This is not meant to be used like this, call
gst_video_encoder_negotiate() instead.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codecvp8enc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.c b/sys/v4l2codecs/gstv4l2codecvp8enc.c
index 5990c73..af84a44 100644
--- a/sys/v4l2codecs/gstv4l2codecvp8enc.c
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.c
@@ -329,7 +329,7 @@ gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * encoder,
gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
caps, state);
- if (GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder)) {
+ if (gst_video_encoder_negotiate (encoder)) {
if (!gst_v4l2_encoder_streamon (self->encoder, GST_PAD_SINK)) {
GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
("Could not enable the encoder driver."),
--
2.25.1

View File

@ -0,0 +1,150 @@
From 9984bd8f4646ce48b4d9b3645ffc67ffcdc75161 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Wed, 15 Nov 2023 15:31:05 -0500
Subject: [PATCH 61/68] v4l2codecs: h264enc: Add profile negotiation
We currently only support main, constrained-baseline and baseline. Some
work on the SPS is needed to generate a valid header for high.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 80 ++++++++++++++++++++++++----
1 file changed, 69 insertions(+), 11 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index e7ae63a..b1617c9 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -47,10 +47,17 @@ 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-h264,alignment=au,stream-format=byte-stream"));
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-h264, "
+ "framerate = (fraction) [0/1, MAX], "
+ "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], "
+ "stream-format = (string) byte-stream, "
+ "alignment = (string) au, "
+ "profile = (string) { main, constrained-baseline, baseline}")
+ );
+
#define H264ENC_DEFAULT_KEYFRAME_INTERVAL 30
@@ -90,6 +97,7 @@ struct _GstV4l2CodecH264Enc
guint64 targeted_bitrate;
gboolean cabac;
guint cabac_init_idc;
+ gchar *profile_name;
GstV4l2CodecAllocator *sink_allocator;
GstV4l2CodecAllocator *src_allocator;
@@ -234,6 +242,8 @@ gst_v4l2_codec_h264_enc_stop (GstVideoEncoder * encoder)
gst_video_codec_state_unref (self->output_state);
self->output_state = NULL;
+ g_clear_pointer (&self->profile_name, g_free);
+
return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (encoder);
}
@@ -445,9 +455,19 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
memset (&self->sps, 0, sizeof (self->pps));
/* SPS */
- self->sps.profile_idc = 66;
- self->sps.constraint_set0_flag = 1;
- self->sps.constraint_set1_flag = 0;
+ if (g_str_equal (self->profile_name, "baseline")) {
+ self->sps.profile_idc = GST_H264_PROFILE_BASELINE;
+ self->sps.constraint_set0_flag = 1;
+ self->sps.constraint_set1_flag = 0;
+ } else if (g_str_equal (self->profile_name, "constrained-baseline")) {
+ self->sps.profile_idc = GST_H264_PROFILE_BASELINE;
+ self->sps.constraint_set0_flag = 1;
+ self->sps.constraint_set1_flag = 1;
+ } else if (g_str_equal (self->profile_name, "main")) {
+ self->sps.profile_idc = GST_H264_PROFILE_MAIN;
+ } else if (g_str_equal (self->profile_name, "high")) {
+ self->sps.profile_idc = GST_H264_PROFILE_HIGH;
+ }
self->sps.chroma_format_idc = 1; /* YUV 4:2:0 */
@@ -573,6 +593,43 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
self->pps.entropy_coding_mode_flag = self->cabac;
}
+static gchar *
+gst_v4l2_codec_h264_enc_decide_profile (GstV4l2CodecH264Enc * self)
+{
+ GstCaps *allowed_caps = NULL;
+ const gchar *profile_name;
+ GstStructure *structure;
+ gchar *ret;
+
+ g_object_get (self, "cabac", &self->cabac, "cabac-init-idc",
+ &self->cabac_init_idc, NULL);
+
+ /* First, check whether the downstream requires a specified profile. */
+ allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
+ if (!allowed_caps)
+ allowed_caps = gst_pad_query_caps (GST_VIDEO_ENCODER_SRC_PAD (self), NULL);
+
+ allowed_caps = gst_caps_make_writable (allowed_caps);
+ allowed_caps = gst_caps_fixate (allowed_caps);
+ structure = gst_caps_get_structure (allowed_caps, 0);
+ profile_name = gst_structure_get_string (structure, "profile");
+
+ if (self->cabac) {
+ if (!g_strstr_len (profile_name, -1, "main")
+ && !g_strstr_len (profile_name, -1, "high")) {
+ GST_WARNING_OBJECT (self,
+ "CABAC is not support by user selected profile '%s'"
+ ", disabling this features", profile_name);
+ self->cabac = FALSE;
+ }
+ }
+
+ ret = g_strdup (profile_name);
+ gst_caps_unref (allowed_caps);
+
+ return ret;
+}
+
static gboolean
gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
GstVideoCodecState * state)
@@ -615,9 +672,13 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
+ g_free (self->profile_name);
+ self->profile_name = gst_v4l2_codec_h264_enc_decide_profile (self);
+
caps = gst_caps_new_simple ("video/x-h264",
"stream-format", G_TYPE_STRING, "byte-stream",
- "alignment", G_TYPE_STRING, "au", NULL);
+ "alignment", G_TYPE_STRING, "au",
+ "profile", G_TYPE_STRING, self->profile_name, NULL);
self->output_state =
gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
@@ -641,9 +702,6 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
gst_v4l2_codec_h264_enc_get_qp_range (self->encoder, &self->qp_min,
&self->qp_max);
- g_object_get (self, "cabac", &self->cabac, "cabac-init-idc",
- &self->cabac_init_idc, NULL);
-
gst_v4l2_codec_h264_enc_init_sps_pps (self, state);
return TRUE;
--
2.25.1

View File

@ -0,0 +1,27 @@
From e3872d514987c3a7eda8e97d2daf6293db06a145 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Wed, 15 Nov 2023 19:13:55 -0500
Subject: [PATCH 62/68] codecs: h264encoder: Fix H.264 QP max value
should be 51 as per spec.
Upstream-Status: Pending
---
gst-libs/gst/codecs/gsth264encoder.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gst-libs/gst/codecs/gsth264encoder.c b/gst-libs/gst/codecs/gsth264encoder.c
index 4c35956..032b57a 100644
--- a/gst-libs/gst/codecs/gsth264encoder.c
+++ b/gst-libs/gst/codecs/gsth264encoder.c
@@ -33,7 +33,7 @@ GST_DEBUG_CATEGORY (gst_h264_encoder_debug);
#define H264ENC_DEFAULT_KEYFRAME_INTERVAL 30
-#define H264_MAX_QUALITY 63
+#define H264_MAX_QUALITY 51
#define H264_MIN_QUALITY 0
#define H264_DEFAULT_BITRATE 100000
--
2.25.1

View File

@ -0,0 +1,142 @@
From 88f6aeb90e1f3138eaa4f1ffd44d34b51dd43192 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Wed, 15 Nov 2023 19:18:18 -0500
Subject: [PATCH 63/68] v4l2codecs: h264dec: Remove dead and broken code
Its not possible with the current uAPI to ask the driver for the QP
range.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 40 +++++-----------------------
sys/v4l2codecs/gstv4l2encoder.c | 25 -----------------
2 files changed, 7 insertions(+), 58 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index b1617c9..967fd4d 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -58,18 +58,6 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
"profile = (string) { main, constrained-baseline, baseline}")
);
-
-#define H264ENC_DEFAULT_KEYFRAME_INTERVAL 30
-
-#define H264_MAX_QUALITY 63
-#define H264_MIN_QUALITY 0
-
-#define H264_DEFAULT_BITRATE 100000
-
-/* Scale factor for bitrate (HRD bit_rate_scale: min = 6) */
-#define SX_BITRATE 6
-/* Scale factor for cpb_size (HRD cpb_size_scale: min = 4) */
-#define SX_CPB_SIZE 4
/* Maximum sizes for common headers (in bits) */
#define MAX_SPS_HDR_SIZE 16473
#define MAX_VUI_PARAMS_SIZE 210
@@ -77,8 +65,6 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
#define MAX_PPS_HDR_SIZE 101
#define MAX_SLICE_HDR_SIZE 397 + 2572 + 6670 + 2402
-#define MAX_GOP_SIZE 1024
-
#define SPS_SIZE 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE + MAX_VUI_PARAMS_SIZE + \
2 * MAX_HRD_PARAMS_SIZE) / 8
#define PPS_SIZE 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8
@@ -93,7 +79,6 @@ struct _GstV4l2CodecH264Enc
gint height;
gint width_in_macroblocks;
gint height_in_macroblocks;
- guint qp_max, qp_min;
guint64 targeted_bitrate;
gboolean cabac;
guint cabac_init_idc;
@@ -699,9 +684,6 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
return FALSE;
}
- gst_v4l2_codec_h264_enc_get_qp_range (self->encoder, &self->qp_min,
- &self->qp_max);
-
gst_v4l2_codec_h264_enc_init_sps_pps (self, state);
return TRUE;
@@ -911,6 +893,7 @@ gst_v4l2_codec_h264_enc_fill_encode_params (GstH264Encoder * encoder,
self->encode_params.cabac_init_idc = self->cabac_init_idc;
self->encode_params.pic_init_qp_minus26 = self->pps.pic_init_qp_minus26;
+
self->encode_params.chroma_qp_index_offset = self->pps.chroma_qp_index_offset;
self->encode_params.disable_deblocking_filter_idc = 0;
}
@@ -922,21 +905,9 @@ gst_v4l2_codec_h264_enc_fill_encode_rc (GstH264Encoder * encoder,
GstV4l2CodecH264Enc *self = GST_V4L2_CODEC_H264_ENC (encoder);
/* Rate Control */
- self->encode_rc.qp = self->pps.pic_init_qp_minus26 + 26; //encoder->rc.qp;
- self->encode_rc.qp_min = self->qp_min;
- self->encode_rc.qp_max = self->qp_max;
-}
-
-static guint
-gst_v4l2_codec_h264_enc_check_qp_range (GstV4l2CodecH264Enc * self,
- GstH264Frame * h264_frame)
-{
- if (h264_frame->quality > self->qp_max)
- return self->qp_max;
- if (h264_frame->quality < self->qp_min)
- return self->qp_min;
-
- return h264_frame->quality;
+ self->encode_rc.qp = h264_frame->quality;
+ self->encode_rc.qp_min = 0;
+ self->encode_rc.qp_max = 51;
}
static GstFlowReturn
@@ -988,6 +959,9 @@ gst_v4l2_codec_h264_enc_encode_frame (GstH264Encoder * encoder,
goto done;
}
+ GST_DEBUG_OBJECT (self, "encode h264 frame with quality = %d",
+ h264_frame->quality);
+
request = gst_v4l2_encoder_alloc_request (self->encoder,
frame->system_frame_number, frame->input_buffer, frame->output_buffer);
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index 85f0457..27f03e9 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -1520,28 +1520,3 @@ gst_v4l2_codec_vp8_enc_get_qp_range (GstV4l2Encoder * self,
return TRUE;
}
-
-gboolean
-gst_v4l2_codec_h264_enc_get_qp_range (GstV4l2Encoder * self,
- guint * qp_min, guint * qp_max)
-{
- gint ret;
- struct v4l2_query_ext_ctrl control = {
- .id = V4L2_CID_STATELESS_H264_ENCODE_RC,
- };
-
- *qp_max = 127;
- *qp_min = 0;
-
- ret = ioctl (self->video_fd, VIDIOC_QUERY_EXT_CTRL, &control);
- if (ret < 0) {
- GST_DEBUG_OBJECT (self, "unable to retrieve encoder qp, use default");
- return FALSE;
- }
-
- *qp_max = control.maximum;
- *qp_min = control.minimum;
- GST_DEBUG_OBJECT (self, "encoder qp min %d qp max %d", *qp_min, *qp_max);
-
- return TRUE;
-}
--
2.25.1

View File

@ -0,0 +1,355 @@
From ab51f9d3d91b8210a4e8d5796eeaba21ccbda6d8 Mon Sep 17 00:00:00 2001
From: Denis Shimizu <denis.shimizu@collabora.com>
Date: Mon, 27 Nov 2023 11:25:54 -0500
Subject: [PATCH 64/68] codecs: Introduce a PID based rate controller
This is a simplistic rate controller using a PID and some boundaries.
This has only been tested for H.264 for now and may need some more work
to support various quantizer scale.
Upstream-Status: Pending
---
gst-libs/gst/codecs/gstratecontroller.c | 241 ++++++++++++++++++++++++
gst-libs/gst/codecs/gstratecontroller.h | 70 +++++++
gst-libs/gst/codecs/meson.build | 1 +
3 files changed, 312 insertions(+)
create mode 100644 gst-libs/gst/codecs/gstratecontroller.c
create mode 100644 gst-libs/gst/codecs/gstratecontroller.h
diff --git a/gst-libs/gst/codecs/gstratecontroller.c b/gst-libs/gst/codecs/gstratecontroller.c
new file mode 100644
index 0000000..42f7d0c
--- /dev/null
+++ b/gst-libs/gst/codecs/gstratecontroller.c
@@ -0,0 +1,241 @@
+/* GStreamer
+ * Copyright (C) 2023 Denis Yuji Shimizu <denis.shimizu@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.
+ */
+
+#include "gstratecontroller.h"
+
+#include <math.h>
+
+#define KP_CONST 0.0001
+#define KI_CONST 0.0000000
+#define KD_CONST 0.0000000
+
+typedef struct
+{
+ gdouble prev_error;
+ gdouble integral;
+} PIDController;
+
+struct _GstRateController
+{
+ GstObject parent;
+
+ PIDController pid;
+ gdouble qp;
+ gsize total_macroblocks;
+ GstClockTime frame_duration;
+
+ /* configuration */
+ gint max_qp;
+ gint min_qp;
+ gint init_qp;
+ gint qp_step;
+ GstRateControlMode mode;
+ gint bitrate;
+};
+
+GType
+gst_rate_control_mode_get_type (void)
+{
+ const static GEnumValue rate_control_modes[] = {
+ {GST_RC_CONSTANT_QP, "cqp", "Constant QP"},
+ {GST_RC_CONSTANT_BITRATE, "cbr", "Constant Bitrate"},
+ {0, NULL, NULL},
+ };
+ static GType rc_mode_type = 0;
+
+ if (g_once_init_enter (&rc_mode_type)) {
+ GType _type = g_enum_register_static ("GstRateControlMode",
+ rate_control_modes);
+ g_once_init_leave (&rc_mode_type, _type);
+ }
+
+ return rc_mode_type;
+}
+
+G_DEFINE_TYPE (GstRateController, gst_rc, G_TYPE_OBJECT);
+
+static void
+gst_rc_init (GstRateController * self)
+{
+}
+
+static void
+gst_rc_class_init (GstRateControllerClass * klass)
+{
+}
+
+GstRateController *
+gst_rc_new (void)
+{
+ return g_object_new (GST_RATE_CONTROLLER_TYPE, NULL);
+}
+
+static gdouble
+pid_control (GstRateController * self, gdouble measured_value,
+ gdouble target_bitrate)
+{
+ PIDController *pid = &self->pid;
+ gdouble error = target_bitrate - measured_value;
+ gdouble derivative = error - pid->prev_error;
+ pid->integral += error;
+ pid->prev_error = error;
+
+ /* Output is inverted, since QP and bitrate are inversely related (higher QP
+ * means lower bitrate) */
+ gdouble output =
+ 0.0 - (KP_CONST * error +
+ KI_CONST * pid->integral + KD_CONST * derivative);
+
+ return output;
+}
+
+void
+gst_rc_record (GstRateController * self, GstRcFrameType frame_type,
+ gsize coded_size, GstClockTime duration)
+{
+ /* If there is no duration, use frame rate */
+ if (!GST_CLOCK_TIME_IS_VALID (duration) || duration == 0)
+ duration = self->frame_duration;
+
+ /* We simply ignore keyframe for now */
+ if (frame_type != GST_RC_KEY_FRAME) {
+ GstClockTime bps =
+ gst_util_uint64_scale (coded_size * 8, GST_SECOND, duration);
+
+ double target_bps_per_macroblock =
+ (gdouble) self->bitrate / self->total_macroblocks;
+ double bps_per_macroblock =
+ gst_guint64_to_gdouble (bps) / self->total_macroblocks;
+
+ gdouble pid_output =
+ pid_control (self, bps_per_macroblock, target_bps_per_macroblock);
+ gdouble qp_increase = CLAMP (pid_output,
+ 0.0 - (gdouble) self->qp_step, (gdouble) self->qp_step);
+ self->qp += qp_increase;
+ }
+}
+
+gint
+gst_rc_get_max_qp (GstRateController * self)
+{
+ return self->max_qp;
+}
+
+gint
+gst_rc_get_min_qp (GstRateController * self)
+{
+ return self->min_qp;
+}
+
+gint
+gst_rc_get_qp_step (GstRateController * self)
+{
+ return self->qp_step;
+}
+
+gint
+gst_rc_get_init_qp (GstRateController * self)
+{
+ return self->init_qp;
+}
+
+GstRateControlMode
+gst_rc_get_mode (GstRateController * self)
+{
+ return self->mode;
+}
+
+gint
+gst_rc_get_bitrate (GstRateController * self)
+{
+ return self->bitrate;
+}
+
+void
+gst_rc_set_format (GstRateController * self, const GstVideoInfo * vinfo)
+{
+ gint width = GST_VIDEO_INFO_WIDTH (vinfo);
+ gint height = GST_VIDEO_INFO_HEIGHT (vinfo);
+ gint fps_n = GST_VIDEO_INFO_FPS_N (vinfo);
+ gint fps_d = GST_VIDEO_INFO_FPS_D (vinfo);
+
+ gint width_in_macroblocks = (width + 15) / 16;
+ gint height_in_macroblocks = (height + 15) / 16;
+
+ self->total_macroblocks = width_in_macroblocks * height_in_macroblocks;
+ self->pid.prev_error = 0;
+ self->pid.integral = 0;
+ self->qp = self->init_qp;
+
+ if (!fps_n || !fps_d) {
+ fps_n = 30;
+ fps_d = 1;
+ }
+
+ self->frame_duration = gst_util_uint64_scale (fps_d, GST_SECOND, fps_n);
+}
+
+void
+gst_rc_set_max_qp (GstRateController * self, gint max_qp)
+{
+ self->max_qp = max_qp;
+}
+
+void
+gst_rc_set_min_qp (GstRateController * self, gint min_qp)
+{
+ self->min_qp = min_qp;
+}
+
+void
+gst_rc_set_qp_step (GstRateController * self, gint qp_step)
+{
+ self->qp_step = qp_step;
+}
+
+void
+gst_rc_set_init_qp (GstRateController * self, gint init_qp)
+{
+ self->init_qp = self->qp = init_qp;
+}
+
+void
+gst_rc_set_mode (GstRateController * self, GstRateControlMode mode)
+{
+ self->mode = mode;
+}
+
+void
+gst_rc_set_bitrate (GstRateController * self, gint bitrate)
+{
+ self->bitrate = bitrate;
+}
+
+gint
+gst_rc_get_qp (GstRateController * self)
+{
+ switch (self->mode) {
+ case GST_RC_CONSTANT_BITRATE:
+ return CLAMP (round (self->qp), self->min_qp, self->max_qp);
+ case GST_RC_CONSTANT_QP:
+ return self->init_qp;
+ }
+
+ g_assert_not_reached ();
+}
diff --git a/gst-libs/gst/codecs/gstratecontroller.h b/gst-libs/gst/codecs/gstratecontroller.h
new file mode 100644
index 0000000..f71cb8e
--- /dev/null
+++ b/gst-libs/gst/codecs/gstratecontroller.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) 2023 Michael Grzeschik <m.grzeschik@pengutronix.de>
+ *
+ * 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/codecs/codecs-prelude.h>
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ GST_RC_CONSTANT_QP,
+ GST_RC_CONSTANT_BITRATE,
+} GstRateControlMode;
+
+typedef enum
+{
+ GST_RC_KEY_FRAME,
+ GST_RC_INTER_FRAME,
+} GstRcFrameType;
+
+GType gst_rate_control_mode_get_type (void);
+
+#define GST_RATE_CONTROLLER_TYPE (gst_rc_get_type())
+G_DECLARE_FINAL_TYPE(GstRateController, gst_rc,
+ GST, RC, GObject);
+
+GstRateController* gst_rc_new (void);
+
+void gst_rc_record (GstRateController * self,
+ GstRcFrameType frame_type,
+ gsize coded_size,
+ GstClockTime duration);
+
+gint gst_rc_get_max_qp (GstRateController *self);
+gint gst_rc_get_min_qp (GstRateController *self);
+gint gst_rc_get_qp_step (GstRateController *self);
+gint gst_rc_get_init_qp (GstRateController *self);
+GstRateControlMode gst_rc_get_mode (GstRateController *self);
+gint gst_rc_get_bitrate (GstRateController *self);
+
+void gst_rc_set_format (GstRateController *self,
+ const GstVideoInfo * vinfo);
+void gst_rc_set_max_qp (GstRateController *self, gint max_qp);
+void gst_rc_set_min_qp (GstRateController *self, gint min_qp);
+void gst_rc_set_qp_step (GstRateController *self, gint qp_step);
+void gst_rc_set_init_qp (GstRateController *self, gint init_qp);
+void gst_rc_set_mode (GstRateController *self, GstRateControlMode mode);
+void gst_rc_set_bitrate (GstRateController *self, gint bitrate);
+
+gint gst_rc_get_qp(GstRateController *self);
+
+G_END_DECLS
diff --git a/gst-libs/gst/codecs/meson.build b/gst-libs/gst/codecs/meson.build
index 3ea3bdc..c04600e 100644
--- a/gst-libs/gst/codecs/meson.build
+++ b/gst-libs/gst/codecs/meson.build
@@ -16,6 +16,7 @@ codecs_sources = files(
'gstvp8frame.c',
'gsth264encoder.c',
'gsth264frame.c',
+ 'gstratecontroller.c',
)
codecs_headers = files(
--
2.25.1

View File

@ -0,0 +1,578 @@
From 8455dc4d016d32559a5da33e6b03d860e33c4800 Mon Sep 17 00:00:00 2001
From: Denis Shimizu <denis.shimizu@collabora.com>
Date: Wed, 15 Nov 2023 16:59:14 -0300
Subject: [PATCH 65/68] codecs: h264encoder: Use the PID base rate controller
This port the h264encoder to use the generic rate controller and adapt
the v4l2codecs accordingly.
Upstream-Status: Pending
---
gst-libs/gst/codecs/gsth264encoder.c | 256 +++++++++++++--------------
gst-libs/gst/codecs/gsth264frame.h | 2 +-
sys/v4l2codecs/gstv4l2codech264enc.c | 27 +--
3 files changed, 143 insertions(+), 142 deletions(-)
diff --git a/gst-libs/gst/codecs/gsth264encoder.c b/gst-libs/gst/codecs/gsth264encoder.c
index 032b57a..f1b0200 100644
--- a/gst-libs/gst/codecs/gsth264encoder.c
+++ b/gst-libs/gst/codecs/gsth264encoder.c
@@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) 2023 Michael Grzeschik <m.grzeschik@pengutronix.de>
+ * Copyright (C) 2023 Denis Shimizu <denis.shimizu@collabora.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -22,47 +23,44 @@
#endif
#include "gsth264encoder.h"
-
+#include "gstratecontroller.h"
#include <gst/codecparsers/gsth264bitwriter.h>
-#include <gst/video/video.h>
#include <gst/video/gstvideometa.h>
-#include <gst/base/base.h>
GST_DEBUG_CATEGORY (gst_h264_encoder_debug);
#define GST_CAT_DEFAULT gst_h264_encoder_debug
-#define H264ENC_DEFAULT_KEYFRAME_INTERVAL 30
-
-#define H264_MAX_QUALITY 51
-#define H264_MIN_QUALITY 0
+#define H264_MAX_QP 51
+#define H264_MIN_QP 0
-#define H264_DEFAULT_BITRATE 100000
-
-#define H264ENC_DEFAULT_CABAC_IDC 0
+#define DEFAULT_KEYFRAME_INTERVAL 30
+#define DEFAULT_MAX_QP 51
+#define DEFAULT_MIN_QP 10
+#define DEFAULT_QP_STEP 4
+#define DEFAULT_QUANTIZER 18
+#define DEFAULT_BITRATE G_MAXUINT
enum
{
PROP_0,
PROP_KEYFRAME_INTERVAL,
- PROP_MAX_QUALITY,
- PROP_MIN_QUALITY,
+ PROP_MAX_QP,
+ PROP_MIN_QP,
+ PROP_QP_STEP,
+ PROP_QUANTIZER,
PROP_BITRATE,
PROP_CABAC,
PROP_CABAC_INIT_IDC,
+ PROP_RATE_CONTROL,
};
struct _GstH264EncoderPrivate
{
- gint keyframe_interval;
-
guint32 last_keyframe;
+ GstRateController *rate_controller;
- guint64 targeted_bitrate;
- gint max_quality;
- gint min_quality;
- gint current_quality;
- guint64 used_bytes;
- guint64 nb_frames;
+ /* properties */
+ gint keyframe_interval;
gboolean cabac;
guint cabac_init_idc;
};
@@ -78,25 +76,22 @@ static void
gst_h264_encoder_init (GstH264Encoder * self)
{
self->priv = gst_h264_encoder_get_instance_private (self);
+ self->priv->rate_controller = gst_rc_new ();
}
static void
gst_h264_encoder_finalize (GObject * object)
{
+ GstH264Encoder *self = GST_H264_ENCODER (object);
+
+ gst_object_unref (self->priv->rate_controller);
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_h264_encoder_start (GstVideoEncoder * encoder)
{
- GstH264Encoder *self = GST_H264_ENCODER (encoder);
- GstH264EncoderPrivate *priv = self->priv;
-
- priv->last_keyframe = 0;
- priv->current_quality = priv->min_quality;
- priv->used_bytes = 0;
- priv->nb_frames = 0;
-
return TRUE;
}
@@ -110,46 +105,12 @@ static gboolean
gst_h264_encoder_set_format (GstVideoEncoder * encoder,
GstVideoCodecState * state)
{
- return TRUE;
-}
-
-static GstFlowReturn
-gst_h264_encoder_set_quality (GstH264Encoder * self, GstH264Frame * h264_frame)
-{
+ GstH264Encoder *self = GST_H264_ENCODER (encoder);
GstH264EncoderPrivate *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;
+ gst_rc_set_format (priv->rate_controller, &state->info);
- h264_frame->quality = qp;
-
- return GST_FLOW_OK;
+ return TRUE;
}
static GstFlowReturn
@@ -183,16 +144,19 @@ gst_h264_encoder_mark_frame (GstH264Encoder * self, GstH264Frame * h264_frame)
{
GstVideoCodecFrame *frame = h264_frame->frame;
GstH264EncoderPrivate *priv = self->priv;
+ GstRcFrameType rc_frame_type = GST_RC_INTER_FRAME;
switch (h264_frame->type) {
case GstH264Keyframe:
priv->last_keyframe = frame->system_frame_number;
+ rc_frame_type = GST_RC_KEY_FRAME;
+ break;
+ default:
break;
}
- priv->current_quality = h264_frame->quality;
- priv->used_bytes += gst_buffer_get_size (frame->output_buffer);
- priv->nb_frames++;
+ gst_rc_record (priv->rate_controller, rc_frame_type,
+ gst_buffer_get_size (frame->output_buffer), frame->duration);
}
static GstFlowReturn
@@ -200,6 +164,7 @@ gst_h264_encoder_handle_frame (GstVideoEncoder * encoder,
GstVideoCodecFrame * frame)
{
GstH264Encoder *self = GST_H264_ENCODER (encoder);
+ GstH264EncoderPrivate *priv = self->priv;
GstH264EncoderClass *klass = GST_H264_ENCODER_GET_CLASS (self);
GstFlowReturn ret = GST_FLOW_OK;
GstH264Frame *h264_frame = gst_h264_frame_new (frame);
@@ -208,12 +173,9 @@ gst_h264_encoder_handle_frame (GstVideoEncoder * encoder,
if (ret != GST_FLOW_OK)
return ret;
- ret = gst_h264_encoder_set_quality (self, h264_frame);
- if (ret != GST_FLOW_OK)
- return ret;
+ h264_frame->qp = gst_rc_get_qp (priv->rate_controller);
- /* TODO: add encoding parameters management here
- * for now just send the frame to encode */
+ /* Send the frame to encode */
if (klass->encode_frame) {
ret = klass->encode_frame (self, h264_frame);
if (ret == GST_FLOW_OK)
@@ -232,41 +194,42 @@ gst_h264_encoder_get_property (GObject * object, guint property_id,
GstH264Encoder *self = GST_H264_ENCODER (object);
GstH264EncoderPrivate *priv = self->priv;
+ GST_OBJECT_LOCK (self);
+
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);
+ case PROP_MAX_QP:
+ g_value_set_int (value, gst_rc_get_max_qp (priv->rate_controller));
+ break;
+ case PROP_MIN_QP:
+ g_value_set_int (value, gst_rc_get_min_qp (priv->rate_controller));
break;
- case PROP_MIN_QUALITY:
- GST_OBJECT_LOCK (self);
- g_value_set_int (value, priv->min_quality);
- GST_OBJECT_UNLOCK (self);
+ case PROP_QP_STEP:
+ g_value_set_int (value, gst_rc_get_qp_step (priv->rate_controller));
+ break;
+ case PROP_QUANTIZER:
+ g_value_set_int (value, gst_rc_get_init_qp (priv->rate_controller));
break;
case PROP_BITRATE:
- GST_OBJECT_LOCK (self);
- g_value_set_uint64 (value, priv->targeted_bitrate);
- GST_OBJECT_UNLOCK (self);
+ g_value_set_uint (value, gst_rc_get_bitrate (priv->rate_controller));
+ break;
+ case PROP_RATE_CONTROL:
+ g_value_set_enum (value, gst_rc_get_mode (priv->rate_controller));
break;
case PROP_CABAC:
- GST_OBJECT_LOCK (self);
g_value_set_boolean (value, priv->cabac);
- GST_OBJECT_UNLOCK (self);
break;
case PROP_CABAC_INIT_IDC:
- GST_OBJECT_LOCK (self);
g_value_set_uint (value, priv->cabac_init_idc);
- GST_OBJECT_UNLOCK (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
+
+ GST_OBJECT_UNLOCK (self);
}
static void
@@ -276,41 +239,42 @@ gst_h264_encoder_set_property (GObject * object, guint property_id,
GstH264Encoder *self = GST_H264_ENCODER (object);
GstH264EncoderPrivate *priv = self->priv;
+ GST_OBJECT_LOCK (self);
+
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);
+ case PROP_MAX_QP:
+ gst_rc_set_max_qp (priv->rate_controller, g_value_get_int (value));
+ break;
+ case PROP_MIN_QP:
+ gst_rc_set_min_qp (priv->rate_controller, g_value_get_int (value));
+ break;
+ case PROP_QP_STEP:
+ gst_rc_set_qp_step (priv->rate_controller, g_value_get_int (value));
break;
- case PROP_MIN_QUALITY:
- GST_OBJECT_LOCK (self);
- priv->min_quality = g_value_get_int (value);
- GST_OBJECT_UNLOCK (self);
+ case PROP_QUANTIZER:
+ gst_rc_set_init_qp (priv->rate_controller, g_value_get_int (value));
break;
case PROP_BITRATE:
- GST_OBJECT_LOCK (self);
- priv->targeted_bitrate = g_value_get_uint64 (value);
- GST_OBJECT_UNLOCK (self);
+ gst_rc_set_bitrate (priv->rate_controller, g_value_get_uint (value));
+ break;
+ case PROP_RATE_CONTROL:
+ gst_rc_set_mode (priv->rate_controller, g_value_get_enum (value));
break;
case PROP_CABAC:
- GST_OBJECT_LOCK (self);
priv->cabac = g_value_get_boolean (value);
- GST_OBJECT_UNLOCK (self);
break;
case PROP_CABAC_INIT_IDC:
- GST_OBJECT_LOCK (self);
priv->cabac_init_idc = g_value_get_uint (value);
- GST_OBJECT_UNLOCK (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
+
+ GST_OBJECT_UNLOCK (self);
}
static void
@@ -332,69 +296,99 @@ gst_h264_encoder_class_init (GstH264EncoderClass * klass)
/**
* GstH264Encoder: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, H264ENC_DEFAULT_KEYFRAME_INTERVAL,
+ "Maximum distance in frames between IDR.",
+ 0, G_MAXINT, DEFAULT_KEYFRAME_INTERVAL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
/**
- * GstH264Encoder:max-quality:
- *
+ * GstH264Encoder:qp-max:
*
* 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)",
- H264_MIN_QUALITY, H264_MAX_QUALITY, H264_MAX_QUALITY,
+ g_object_class_install_property (object_class, PROP_MAX_QP,
+ g_param_spec_int ("qp-max", "Max Quantizer Level",
+ "Set upper qp limit (lower number equates to higher quality but more bits)",
+ H264_MIN_QP, H264_MAX_QP, DEFAULT_MAX_QP,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
/**
- * GstH264Encoder:min-quality:
+ * GstH264Encoder:qp-min:
*
+ * Since: 1.2x
+ */
+ g_object_class_install_property (object_class, PROP_MIN_QP,
+ g_param_spec_int ("qp-min", "Min Quantizer Level",
+ "Set lower qp limit (lower number equates to higher quality but more bits)",
+ H264_MIN_QP, H264_MAX_QP, DEFAULT_MIN_QP,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+ /**
+ * GstH264Encoder:qp-step:
+ *
+ * Since: 1.2x
+ */
+ g_object_class_install_property (object_class, PROP_QP_STEP,
+ g_param_spec_int ("qp-step", "Max QP increase/decrease step",
+ "Set maximum value which qp value can be increase/decrease by the bitrate controller (Valid only with rate-control=cbr)",
+ H264_MIN_QP, H264_MAX_QP, DEFAULT_QP_STEP,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+ /**
+ * GstH264Encoder:quantizer:
*
* 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)",
- H264_MIN_QUALITY, H264_MAX_QUALITY, H264_MIN_QUALITY,
+ g_object_class_install_property (object_class, PROP_QUANTIZER,
+ g_param_spec_int ("quantizer", "Quantizer Level",
+ "Set the qp value (lower number equates to higher quality but more bits, initial value for rate-control=cbr)",
+ H264_MIN_QP, H264_MAX_QP, DEFAULT_QUANTIZER,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
/**
* GstH264Encoder: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, H264_DEFAULT_BITRATE,
+ g_param_spec_uint ("bitrate", "Targeted bitrate",
+ "Set the targeted bitrate (in bit/s)",
+ 0, UINT_MAX, DEFAULT_BITRATE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
/**
* GstH264Encoder:cabac:
- *
+ * Note: Supported only on main profile
*
* Since: 1.2x
*/
g_object_class_install_property (object_class, PROP_CABAC,
- g_param_spec_boolean ("cabac", "CABAC", "Enable use of CABAC over CAVLC",
- FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_param_spec_boolean ("cabac", "CABAC",
+ "Enable Cabac", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstH264Encoder:cabac-init-idc:
- *
+ * Note: Supported only on main profile
*
* Since: 1.2x
*/
g_object_class_install_property (object_class, PROP_CABAC_INIT_IDC,
- g_param_spec_uint ("cabac-init-idc", "Initial CABAC table ID",
- "Set initial CABAC table idc value", 0, 2, H264ENC_DEFAULT_CABAC_IDC,
+ g_param_spec_uint ("cabac-init-idc", "PROP_CABAC_INIT_IDC",
+ "Set Cabac init idc value",
+ 0, 2, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+ /**
+ * GstH264Encoder:rate-control:
+ *
+ * Since: 1.2x
+ */
+ g_object_class_install_property (object_class, PROP_RATE_CONTROL,
+ g_param_spec_enum ("rate-control", "Rate Control Mode",
+ "Select rate control mode", gst_rate_control_mode_get_type (),
+ GST_RC_CONSTANT_QP,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
}
diff --git a/gst-libs/gst/codecs/gsth264frame.h b/gst-libs/gst/codecs/gsth264frame.h
index 3c90d53..3a5a658 100644
--- a/gst-libs/gst/codecs/gsth264frame.h
+++ b/gst-libs/gst/codecs/gsth264frame.h
@@ -42,7 +42,7 @@ struct _GstH264Frame
{
GstMiniObject parent;
gint type;
- gint quality;
+ gint qp;
GstVideoCodecFrame *frame;
};
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 967fd4d..7d52fba 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) 2023 Michael Grzeschik <m.grzeschik@pengutronix.de>
+ * Copyright (C) 2023 Denis Shimizu <denis.shimizu@collabora.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -20,7 +21,6 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-
#include "gstv4l2codecallocator.h"
#include "gstv4l2codech264enc.h"
#include "gstv4l2codecpool.h"
@@ -79,6 +79,7 @@ struct _GstV4l2CodecH264Enc
gint height;
gint width_in_macroblocks;
gint height_in_macroblocks;
+ gint qp_init, qp_max, qp_min;
guint64 targeted_bitrate;
gboolean cabac;
guint cabac_init_idc;
@@ -477,7 +478,7 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
gint n_levels = G_N_ELEMENTS (_h264_level_limits);
GValue bitrate = G_VALUE_INIT;
g_object_get_property (G_OBJECT (self), "bitrate", &bitrate);
- self->targeted_bitrate = g_value_get_uint64 (&bitrate);
+ self->targeted_bitrate = g_value_get_uint (&bitrate);
maximum_bitrate = self->targeted_bitrate;
frame_size_in_macroblocks = self->width * self->height / 256;
macroblocks_per_second = frame_size_in_macroblocks * state->info.fps_n / state->info.fps_d; // Assuming each macroblock is 16x16
@@ -571,8 +572,11 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
self->pps.weighted_bipred_idc = 0;
/* Rate Control */
+ GValue qp_init = G_VALUE_INIT;
+ g_object_get_property (G_OBJECT (self), "quantizer", &qp_init);
+ self->qp_init = g_value_get_int (&qp_init);
self->pps.chroma_qp_index_offset = 4;
- self->pps.pic_init_qp_minus26 = -13;
+ self->pps.pic_init_qp_minus26 = self->qp_init - 26;
self->pps.second_chroma_qp_index_offset = self->pps.chroma_qp_index_offset;
self->pps.deblocking_filter_control_present_flag = 1;
self->pps.entropy_coding_mode_flag = self->cabac;
@@ -649,6 +653,8 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
self->width = state->info.width;
self->height = state->info.height;
+ GST_VIDEO_ENCODER_CLASS (parent_class)->set_format (encoder, state);
+
gst_v4l2_codec_h264_enc_buffers_allocation (encoder);
self->width_in_macroblocks = (self->width + 15) / 16;
self->height_in_macroblocks = (self->height + 15) / 16;
@@ -684,6 +690,9 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
return FALSE;
}
+ g_object_get (self, "cabac", &self->cabac, "cabac-init-idc",
+ &self->cabac_init_idc, NULL);
+
gst_v4l2_codec_h264_enc_init_sps_pps (self, state);
return TRUE;
@@ -905,9 +914,9 @@ gst_v4l2_codec_h264_enc_fill_encode_rc (GstH264Encoder * encoder,
GstV4l2CodecH264Enc *self = GST_V4L2_CODEC_H264_ENC (encoder);
/* Rate Control */
- self->encode_rc.qp = h264_frame->quality;
- self->encode_rc.qp_min = 0;
- self->encode_rc.qp_max = 51;
+ self->encode_rc.qp = h264_frame->qp;
+ self->encode_rc.qp_min = self->qp_min;
+ self->encode_rc.qp_max = self->qp_max;
}
static GstFlowReturn
@@ -950,8 +959,7 @@ gst_v4l2_codec_h264_enc_encode_frame (GstH264Encoder * encoder,
/* *INDENT-ON* */
};
- GST_DEBUG_OBJECT (self, "encode h264 frame with quality = %d",
- h264_frame->quality);
+ GST_DEBUG_OBJECT (self, "encode h264 frame with qp = %d", h264_frame->qp);
if (!gst_v4l2_codec_h264_enc_ensure_output_bitstream (self, frame)) {
GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT,
@@ -959,8 +967,7 @@ gst_v4l2_codec_h264_enc_encode_frame (GstH264Encoder * encoder,
goto done;
}
- GST_DEBUG_OBJECT (self, "encode h264 frame with quality = %d",
- h264_frame->quality);
+ GST_DEBUG_OBJECT (self, "encode h264 frame with qp = %d", h264_frame->qp);
request = gst_v4l2_encoder_alloc_request (self->encoder,
frame->system_frame_number, frame->input_buffer, frame->output_buffer);
--
2.25.1

View File

@ -0,0 +1,286 @@
From 5d051f38c95bb6f2f72588d55696a14939bc5fb5 Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Thu, 30 Nov 2023 10:49:57 -0500
Subject: [PATCH 66/68] v4l2codecs: h264enc: Rewrite profile/level negotiation
This aligns the SPS/PPS with caps and properly negotiate the level.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 213 ++++++++++++++++-----------
1 file changed, 124 insertions(+), 89 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 7d52fba..911ed34 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -80,10 +80,11 @@ struct _GstV4l2CodecH264Enc
gint width_in_macroblocks;
gint height_in_macroblocks;
gint qp_init, qp_max, qp_min;
- guint64 targeted_bitrate;
gboolean cabac;
guint cabac_init_idc;
+
gchar *profile_name;
+ guint level_idc;
GstV4l2CodecAllocator *sink_allocator;
GstV4l2CodecAllocator *src_allocator;
@@ -387,56 +388,10 @@ get_sps_aspect_ratio_idc (guint par_n, guint par_d)
return 255; // Extended_SAR for custom ratios
}
-/* Begin of code taken from VA plugin */
-typedef struct
-{
- const char *level;
- int idc;
- int max_macroblocks_per_second;
- int max_frame_size_in_macroblocks;
- int max_dpb_macroblocks;
- int maximum_bitrate;
- int max_cpb_size;
- int minimum_compression_ratio;
-} GstVaH264LevelLimits;
-
-static const GstVaH264LevelLimits _h264_level_limits[] = {
- /* *INDENT-OFF* */
- /*level, idc, max_macroblocks_per_second, max_frame_size_in_macroblocks,
- max_dpb_macroblocks, max_bitrate, max_cpb_size, minimum_compression_ratio */
- {"1", GST_H264_LEVEL_L1, 1485, 99, 396, 64, 175, 2},
- {"1b", GST_H264_LEVEL_L1B, 1485, 99, 396, 128, 350, 2},
- {"1.1", GST_H264_LEVEL_L1_1, 3000, 396, 900, 192, 500, 2},
- {"1.2", GST_H264_LEVEL_L1_2, 6000, 396, 2376, 384, 1000, 2},
- {"1.3", GST_H264_LEVEL_L1_3, 11880, 396, 2376, 768, 2000, 2},
- {"2", GST_H264_LEVEL_L2, 11880, 396, 2376, 2000, 2000, 2},
- {"2.1", GST_H264_LEVEL_L2_1, 19800, 792, 4752, 4000, 4000, 2},
- {"2.2", GST_H264_LEVEL_L2_2, 20250, 1620, 8100, 4000, 4000, 2},
- {"3", GST_H264_LEVEL_L3, 40500, 1620, 8100, 10000, 10000, 2},
- {"3.1", GST_H264_LEVEL_L3_1, 108000, 3600, 18000, 14000, 14000, 4},
- {"3.2", GST_H264_LEVEL_L3_2, 216000, 5120, 20480, 20000, 20000, 4},
- {"4", GST_H264_LEVEL_L4, 245760, 8192, 32768, 20000, 25000, 4},
- {"4.1", GST_H264_LEVEL_L4_1, 245760, 8192, 32768, 50000, 62500, 2},
- {"4.2", GST_H264_LEVEL_L4_2, 522240, 8704, 34816, 50000, 62500, 2},
- {"5", GST_H264_LEVEL_L5, 589824, 22080, 110400, 135000, 135000, 2},
- {"5.1", GST_H264_LEVEL_L5_1, 983040, 36864, 184320, 240000, 240000, 2},
- {"5.2", GST_H264_LEVEL_L5_2, 2073600, 36864, 184320, 240000, 240000, 2},
- {"6", GST_H264_LEVEL_L6, 4177920, 139264, 696320, 240000, 240000, 2},
- {"6.1", GST_H264_LEVEL_L6_1, 8355840, 139264, 696320, 480000, 480000, 2},
- {"6.2", GST_H264_LEVEL_L6_2, 16711680, 139264, 696320, 800000, 800000, 2},
- /* *INDENT-ON* */
-};
-
-/* Enf of code taken from VA Plugin */
-
static void
gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
GstVideoCodecState * state)
{
- gint maximum_bitrate, frame_size_in_macroblocks,
- macroblocks_per_second, dpb_macroblocks, cpb_size, compression_ratio,
- minimum_level_index;
-
memset (&self->sps, 0, sizeof (self->sps));
memset (&self->sps, 0, sizeof (self->pps));
@@ -474,41 +429,10 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
self->sps.direct_8x8_inference_flag = 1;
self->sps.frame_mbs_only_flag = 1;
- // Calculate lowest acceptable level
- gint n_levels = G_N_ELEMENTS (_h264_level_limits);
- GValue bitrate = G_VALUE_INIT;
- g_object_get_property (G_OBJECT (self), "bitrate", &bitrate);
- self->targeted_bitrate = g_value_get_uint (&bitrate);
- maximum_bitrate = self->targeted_bitrate;
- frame_size_in_macroblocks = self->width * self->height / 256;
- macroblocks_per_second = frame_size_in_macroblocks * state->info.fps_n / state->info.fps_d; // Assuming each macroblock is 16x16
- dpb_macroblocks = frame_size_in_macroblocks;
- cpb_size = maximum_bitrate;
- compression_ratio = state->info.fps_n / state->info.fps_d;
- minimum_level_index = 0;
- for (; minimum_level_index < n_levels; ++minimum_level_index) {
- const GstVaH264LevelLimits *level =
- &_h264_level_limits[minimum_level_index];
- if (macroblocks_per_second <= level->max_macroblocks_per_second
- && frame_size_in_macroblocks <= level->max_frame_size_in_macroblocks
- && dpb_macroblocks <= level->max_dpb_macroblocks
- && maximum_bitrate <= level->maximum_bitrate
- && cpb_size <= level->max_cpb_size
- && compression_ratio >= level->minimum_compression_ratio) {
- break;
- }
- }
- self->sps.level_idc = _h264_level_limits[minimum_level_index].idc;
- if (self->sps.level_idc == GST_H264_LEVEL_L1B) {
+ /* Add level specific constraint */
+ self->sps.level_idc = self->level_idc;
+ if (self->sps.level_idc == GST_H264_LEVEL_L1B)
self->sps.constraint_set3_flag = 1;
- }
- GST_DEBUG_OBJECT (self, "width:%d height:%d targeted_bitrate:%ld",
- self->height, self->height, self->targeted_bitrate);
- GST_DEBUG_OBJECT (self,
- "macroblocks_per_second=%d,frame_size_in_macroblocks=%d,dpb_macroblocks=%d,maximum_bitrate=%d,cpb_size=%d,compression_ratio=%d",
- macroblocks_per_second, frame_size_in_macroblocks, dpb_macroblocks,
- maximum_bitrate, cpb_size, compression_ratio);
- GST_DEBUG_OBJECT (self, "level_idc: %d", self->sps.level_idc);
/* Crop unaligned videos */
if (self->width & 15 || self->height & 15) {
@@ -582,13 +506,57 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self,
self->pps.entropy_coding_mode_flag = self->cabac;
}
-static gchar *
-gst_v4l2_codec_h264_enc_decide_profile (GstV4l2CodecH264Enc * self)
+/* Begin of code taken from VA plugin */
+typedef struct
+{
+ const char *level;
+ int idc;
+ int max_mbs_per_second;
+ int max_frame_size_in_mbs;
+ int max_dpb_mbs;
+ int max_bitrate;
+ int max_cpb_size;
+ int minimum_compression_ratio;
+} GstH264LevelLimits;
+
+static const GstH264LevelLimits _h264_level_limits[] = {
+ /* *INDENT-OFF* */
+ // level, idc, mbs, frame, dpb, bitrate, cpb, cr
+ {"1", GST_H264_LEVEL_L1, 1485, 99, 396, 64, 175, 2},
+ {"1b", GST_H264_LEVEL_L1B, 1485, 99, 396, 128, 350, 2},
+ {"1.1", GST_H264_LEVEL_L1_1, 3000, 396, 900, 192, 500, 2},
+ {"1.2", GST_H264_LEVEL_L1_2, 6000, 396, 2376, 384, 1000, 2},
+ {"1.3", GST_H264_LEVEL_L1_3, 11880, 396, 2376, 768, 2000, 2},
+ {"2", GST_H264_LEVEL_L2, 11880, 396, 2376, 2000, 2000, 2},
+ {"2.1", GST_H264_LEVEL_L2_1, 19800, 792, 4752, 4000, 4000, 2},
+ {"2.2", GST_H264_LEVEL_L2_2, 20250, 1620, 8100, 4000, 4000, 2},
+ {"3", GST_H264_LEVEL_L3, 40500, 1620, 8100, 10000, 10000, 2},
+ {"3.1", GST_H264_LEVEL_L3_1, 108000, 3600, 18000, 14000, 14000, 4},
+ {"3.2", GST_H264_LEVEL_L3_2, 216000, 5120, 20480, 20000, 20000, 4},
+ {"4", GST_H264_LEVEL_L4, 245760, 8192, 32768, 20000, 25000, 4},
+ {"4.1", GST_H264_LEVEL_L4_1, 245760, 8192, 32768, 50000, 62500, 2},
+ {"4.2", GST_H264_LEVEL_L4_2, 522240, 8704, 34816, 50000, 62500, 2},
+ {"5", GST_H264_LEVEL_L5, 589824, 22080, 110400, 135000, 135000, 2},
+ {"5.1", GST_H264_LEVEL_L5_1, 983040, 36864, 184320, 240000, 240000, 2},
+ {"5.2", GST_H264_LEVEL_L5_2, 2073600, 36864, 184320, 240000, 240000, 2},
+ {"6", GST_H264_LEVEL_L6, 4177920, 139264, 696320, 240000, 240000, 2},
+ {"6.1", GST_H264_LEVEL_L6_1, 8355840, 139264, 696320, 480000, 480000, 2},
+ {"6.2", GST_H264_LEVEL_L6_2, 16711680, 139264, 696320, 800000, 800000, 2},
+ /* *INDENT-ON* */
+};
+
+/* Enf of code taken from VA Plugin */
+
+static gboolean
+gst_v4l2_codec_h264_enc_decide_profile_and_level (GstV4l2CodecH264Enc * self,
+ GstVideoCodecState * state)
{
GstCaps *allowed_caps = NULL;
const gchar *profile_name;
+ const gchar *level_name;
GstStructure *structure;
- gchar *ret;
+ gint minimum_level_index, caps_level_index;
+ guint bitrate, frame_size_in_mbs, mbs_per_second, dpb_mbs;
g_object_get (self, "cabac", &self->cabac, "cabac-init-idc",
&self->cabac_init_idc, NULL);
@@ -613,10 +581,77 @@ gst_v4l2_codec_h264_enc_decide_profile (GstV4l2CodecH264Enc * self)
}
}
- ret = g_strdup (profile_name);
- gst_caps_unref (allowed_caps);
+ g_free (self->profile_name);
+ self->profile_name = g_strdup (profile_name);
- return ret;
+ /* Calculate lowest acceptable level */
+ g_object_get (self, "bitrate", &bitrate, NULL);
+ if (bitrate == G_MAXUINT)
+ bitrate = 0;
+
+ /* table is in Kb/s, translate that number */
+ bitrate /= 1000;
+
+ frame_size_in_mbs = self->width_in_macroblocks * self->height_in_macroblocks;
+ mbs_per_second = frame_size_in_mbs * state->info.fps_n / state->info.fps_d;
+
+ /* Only one reference is supported at the moment */
+ dpb_mbs = frame_size_in_mbs;
+
+ /* Ignoring CPB as we don't implement HRD */
+
+ for (minimum_level_index = 0;
+ minimum_level_index < G_N_ELEMENTS (_h264_level_limits);
+ minimum_level_index++) {
+ const GstH264LevelLimits *level = &_h264_level_limits[minimum_level_index];
+ if (mbs_per_second <= level->max_mbs_per_second
+ && frame_size_in_mbs <= level->max_frame_size_in_mbs
+ && dpb_mbs <= level->max_dpb_mbs && bitrate <= level->max_bitrate) {
+ break;
+ }
+ }
+
+ if (minimum_level_index >= G_N_ELEMENTS (_h264_level_limits)) {
+ GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported H.264 level."),
+ ("The minimum level required for this stream is not supported."));
+ gst_caps_unref (allowed_caps);
+ return FALSE;
+ }
+
+ level_name = gst_structure_get_string (structure, "level");
+ caps_level_index = 0;
+ if (level_name) {
+ for (; caps_level_index < G_N_ELEMENTS (_h264_level_limits);
+ caps_level_index++) {
+ const GstH264LevelLimits *level = &_h264_level_limits[caps_level_index];
+ if (g_str_equal (level->level, level_name))
+ break;
+ }
+
+ if (caps_level_index >= G_N_ELEMENTS (_h264_level_limits)) {
+ GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
+ ("Unsupported H.264 level '%s'.", level_name),
+ ("The H.264 level provided in caps is not supported."));
+ gst_caps_unref (allowed_caps);
+ return FALSE;
+ }
+
+ if (caps_level_index < minimum_level_index) {
+ GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
+ ("H.264 level '%s' too low. At least '%s' is needed.", level_name,
+ _h264_level_limits[minimum_level_index].level),
+ ("The H.264 level provided in caps is too low."));
+ gst_caps_unref (allowed_caps);
+ return FALSE;
+ }
+
+ self->level_idc = _h264_level_limits[caps_level_index].idc;
+ } else {
+ self->level_idc = _h264_level_limits[minimum_level_index].idc;
+ }
+
+ gst_caps_unref (allowed_caps);
+ return TRUE;
}
static gboolean
@@ -663,8 +698,8 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
- g_free (self->profile_name);
- self->profile_name = gst_v4l2_codec_h264_enc_decide_profile (self);
+ if (!gst_v4l2_codec_h264_enc_decide_profile_and_level (self, state))
+ return FALSE;
caps = gst_caps_new_simple ("video/x-h264",
"stream-format", G_TYPE_STRING, "byte-stream",
--
2.25.1

View File

@ -0,0 +1,86 @@
From 3e690d2af6788e94fad1d92e04bd08da14035c5a Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Tue, 28 Nov 2023 12:28:32 -0500
Subject: [PATCH 67/68] v4l2codecs: h264enc: De-emulate SPS and PPS bitstream
The bit writer does not do de-emulation since its only purpose is to
serve bits to VA for which drivers are mandated to take care of that.
Implement minimal de-emulation method using memmove in a post-processing
fashion.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 37 ++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 911ed34..0a195c8 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -26,6 +26,7 @@
#include "gstv4l2codecpool.h"
#include "gstv4l2format.h"
#include <gst/codecparsers/gsth264bitwriter.h>
+#include <gst/base/gstbytereader.h>
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
@@ -310,6 +311,38 @@ gst_v4l2_codec_h264_enc_buffers_allocation (GstVideoEncoder * encoder)
return TRUE;
}
+static guint
+gst_v4l2_codec_deemulate_nal (guint8 * data, guint size, guint maxsize)
+{
+ GstByteReader br;
+ /* skip initial start code */
+ guint offset = 3;
+
+ gst_byte_reader_init (&br, data, maxsize);
+
+ do {
+ offset = gst_byte_reader_masked_scan_uint32 (&br,
+ 0xfffffc00, 0x00000000, offset, size);
+ if (offset == -1 || offset >= size)
+ break;
+
+ if (size == maxsize)
+ break;
+
+ /* Make 1 byte space after the two leading zeros */
+ offset += 2;
+ memmove (data + offset + 1, data + offset, size - offset);
+
+ /* Write the emulation byte */
+ data[offset] = 0x03;
+
+ size++;
+ offset += 3;
+ } while (TRUE);
+
+ return size;
+}
+
static gboolean
gst_v4l2_codec_h264_enc_set_codec_data (GstVideoEncoder * encoder,
GstBuffer * codec_data, guint * data_size)
@@ -332,6 +365,8 @@ gst_v4l2_codec_h264_enc_set_codec_data (GstVideoEncoder * encoder,
return FALSE;
}
+ size = gst_v4l2_codec_deemulate_nal (data, size, SPS_SIZE);
+
data += size;
*data_size = size;
@@ -342,6 +377,8 @@ gst_v4l2_codec_h264_enc_set_codec_data (GstVideoEncoder * encoder,
return FALSE;
}
+ size = gst_v4l2_codec_deemulate_nal (data, size, PPS_SIZE);
+
*data_size += size;
gst_buffer_unmap (codec_data, &info);
--
2.25.1

View File

@ -0,0 +1,47 @@
From 4d51af92e3bfc5c6093807645244d719150b99e4 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Tue, 21 Nov 2023 10:51:39 +0100
Subject: [PATCH 68/68] v4l2codecs: vp8: fix support of unaligned videos
Fix gst_v4l2_codec_vp8_enc_copy_input_buffer() to support copy of
unaligned video.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codecvp8enc.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.c b/sys/v4l2codecs/gstv4l2codecvp8enc.c
index af84a44..42c2b1b 100644
--- a/sys/v4l2codecs/gstv4l2codecvp8enc.c
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.c
@@ -440,11 +440,11 @@ gst_v4l2_codec_vp8_enc_copy_input_buffer (GstV4l2CodecVp8Enc * self,
{
GstVideoFrame src_frame;
GstVideoFrame dest_frame;
- GstVideoInfo dest_vinfo;
+ GstVideoInfo src_vinfo;
GstBuffer *buffer;
GstFlowReturn flow_ret;
- gst_video_info_set_format (&dest_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo),
+ gst_video_info_set_format (&src_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo),
self->width, self->height);
flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->sink_pool),
@@ -461,11 +461,11 @@ gst_v4l2_codec_vp8_enc_copy_input_buffer (GstV4l2CodecVp8Enc * self,
if (!buffer)
goto fail;
- if (!gst_video_frame_map (&src_frame, &self->vinfo,
+ if (!gst_video_frame_map (&src_frame, &src_vinfo,
frame->input_buffer, GST_MAP_READ))
goto fail;
- if (!gst_video_frame_map (&dest_frame, &dest_vinfo, buffer, GST_MAP_WRITE)) {
+ if (!gst_video_frame_map (&dest_frame, &self->vinfo, buffer, GST_MAP_WRITE)) {
gst_video_frame_unmap (&dest_frame);
goto fail;
}
--
2.25.1

View File

@ -0,0 +1,36 @@
From a6dc255e58014d396a4b42a01c51c18fc383d49f Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
Date: Mon, 18 Dec 2023 17:42:00 +0100
Subject: [PATCH] Force to add math as library dependency
Signed-off-by: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
Upstream-Status: Pending
---
gst-libs/gst/codecs/meson.build | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/gst-libs/gst/codecs/meson.build b/gst-libs/gst/codecs/meson.build
index c04600e..7c4040c 100644
--- a/gst-libs/gst/codecs/meson.build
+++ b/gst-libs/gst/codecs/meson.build
@@ -45,6 +45,8 @@ cp_args = [
'-DG_LOG_DOMAIN="GStreamer-Codecs"'
]
+mathlib = cc.find_library('m', required : false)
+
gstcodecs = library('gstcodecs-' + api_version,
codecs_sources,
c_args : gst_plugins_bad_args + cp_args,
@@ -53,7 +55,7 @@ gstcodecs = library('gstcodecs-' + api_version,
soversion : soversion,
darwin_versions : osxversion,
install : true,
- dependencies : [gstvideo_dep, gstcodecparsers_dep],
+ dependencies : [gstvideo_dep, gstcodecparsers_dep, mathlib],
)
library_def = {'lib': gstcodecs}
--
2.34.1

View File

@ -0,0 +1,248 @@
From 6d9de5b60a9f26822ae28bb9d5fa788a80963ccd Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Tue, 12 Mar 2024 15:27:33 +0100
Subject: [PATCH] v4l2codecs: encoder: add rotation support
Add rotation support based on V4L2_CID_ROTATE control.
90 and 270 degrees rotation requires swap of src width & height
which must be take into account when allocating src pool.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 15 ++++++----
sys/v4l2codecs/gstv4l2codecvp8enc.c | 15 ++++++----
sys/v4l2codecs/gstv4l2encoder.c | 41 ++++++++++++++++++++++++++++
3 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 0a195c8..921302a 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -76,6 +76,7 @@ struct _GstV4l2CodecH264Enc
GstV4l2Encoder *encoder;
GstVideoCodecState *output_state;
GstVideoInfo vinfo;
+ GstVideoInfo sink_info;
gint width;
gint height;
gint width_in_macroblocks;
@@ -276,7 +277,8 @@ gst_v4l2_codec_h264_enc_propose_allocation (GstVideoEncoder * encoder,
}
static gboolean
-gst_v4l2_codec_h264_enc_buffers_allocation (GstVideoEncoder * encoder)
+gst_v4l2_codec_h264_enc_buffers_allocation (GstVideoEncoder * encoder,
+ GstVideoCodecState * state)
{
GstV4l2CodecH264Enc *self = GST_V4L2_CODEC_H264_ENC (encoder);
@@ -306,7 +308,7 @@ gst_v4l2_codec_h264_enc_buffers_allocation (GstVideoEncoder * encoder)
return FALSE;
}
- self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &self->vinfo);
+ self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &state->info);
return TRUE;
}
@@ -705,6 +707,8 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
gst_v4l2_codec_h264_enc_reset_allocation (self);
+ self->sink_info = state->info;
+
if (!gst_v4l2_encoder_set_src_fmt (self->encoder, &state->info,
V4L2_PIX_FMT_H264_SLICE)) {
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported pixel format"),
@@ -713,7 +717,7 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
return FALSE;
}
- if (!gst_v4l2_encoder_select_sink_format (self->encoder, &state->info,
+ if (!gst_v4l2_encoder_select_sink_format (self->encoder, &self->sink_info,
&self->vinfo)) {
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
("Failed to configure H264 encoder"),
@@ -727,7 +731,8 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
self->height = state->info.height;
GST_VIDEO_ENCODER_CLASS (parent_class)->set_format (encoder, state);
- gst_v4l2_codec_h264_enc_buffers_allocation (encoder);
+ gst_v4l2_codec_h264_enc_buffers_allocation (encoder, state);
+
self->width_in_macroblocks = (self->width + 15) / 16;
self->height_in_macroblocks = (self->height + 15) / 16;
self->first_frame = TRUE;
@@ -864,7 +869,7 @@ gst_v4l2_codec_h264_enc_copy_input_buffer (GstV4l2CodecH264Enc * self,
GstFlowReturn flow_ret;
gst_video_info_set_format (&src_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo),
- self->width, self->height);
+ self->sink_info.width, self->sink_info.height);
flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->sink_pool),
&buffer, NULL);
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.c b/sys/v4l2codecs/gstv4l2codecvp8enc.c
index 42c2b1b..4ec141c 100644
--- a/sys/v4l2codecs/gstv4l2codecvp8enc.c
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.c
@@ -72,6 +72,7 @@ struct _GstV4l2CodecVp8Enc
GstV4l2Encoder *encoder;
GstVideoCodecState *output_state;
GstVideoInfo vinfo;
+ GstVideoInfo sink_info;
gint width;
gint height;
guint qp_max, qp_min;
@@ -249,7 +250,8 @@ gst_v4l2_codec_vp8_enc_propose_allocation (GstVideoEncoder * encoder,
}
static gboolean
-gst_v4l2_codec_vp8_enc_buffers_allocation (GstVideoEncoder * encoder)
+gst_v4l2_codec_vp8_enc_buffers_allocation (GstVideoEncoder * encoder,
+ GstVideoCodecState * state)
{
GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
@@ -279,8 +281,7 @@ gst_v4l2_codec_vp8_enc_buffers_allocation (GstVideoEncoder * encoder)
return FALSE;
}
- self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &self->vinfo);
-
+ self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &state->info);
return TRUE;
}
@@ -298,6 +299,8 @@ gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * encoder,
gst_v4l2_codec_vp8_enc_reset_allocation (self);
+ self->sink_info = state->info;
+
if (!gst_v4l2_encoder_set_src_fmt (self->encoder, &state->info,
V4L2_PIX_FMT_VP8_FRAME)) {
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported pixel format"),
@@ -306,7 +309,7 @@ gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * encoder,
return FALSE;
}
- if (!gst_v4l2_encoder_select_sink_format (self->encoder, &state->info,
+ if (!gst_v4l2_encoder_select_sink_format (self->encoder, &self->sink_info,
&self->vinfo)) {
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
("Failed to configure VP8 encoder"),
@@ -318,7 +321,7 @@ gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * encoder,
self->width = state->info.width;
self->height = state->info.height;
- gst_v4l2_codec_vp8_enc_buffers_allocation (encoder);
+ gst_v4l2_codec_vp8_enc_buffers_allocation (encoder, state);
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
@@ -445,7 +448,7 @@ gst_v4l2_codec_vp8_enc_copy_input_buffer (GstV4l2CodecVp8Enc * self,
GstFlowReturn flow_ret;
gst_video_info_set_format (&src_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo),
- self->width, self->height);
+ self->sink_info.width, self->sink_info.height);
flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->sink_pool),
&buffer, NULL);
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index 27f03e9..2532dc3 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -44,6 +44,7 @@ enum
PROP_0,
PROP_MEDIA_DEVICE,
PROP_VIDEO_DEVICE,
+ PROP_ROTATION,
};
struct _GstV4l2Request
@@ -95,6 +96,7 @@ struct _GstV4l2Encoder
gchar *media_device;
gchar *video_device;
guint render_delay;
+ guint rotation;
/* detected features */
gboolean supports_holding_capture;
@@ -687,6 +689,29 @@ gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoInfo * info,
gint width = info->width;
gint height = info->height;
+ /* Apply rotation, this will affect src width/height */
+ if (self->rotation) {
+ struct v4l2_control ctl = { 0, };
+
+ ctl.id = V4L2_CID_ROTATE;
+ ctl.value = self->rotation;
+ ret = ioctl (self->video_fd, VIDIOC_S_CTRL, &ctl);
+ if (ret < 0) {
+ GST_ERROR_OBJECT (self, "VIDIOC_S_CTRL failed: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ if (self->rotation == 90 || self->rotation == 270) {
+ /*
+ * Swap width & height, this will trigger a call
+ * to S_FMT to let driver know the final
+ * rotated resolution
+ */
+ width = info->height;
+ height = info->width;
+ }
+ }
+
ret = ioctl (self->video_fd, VIDIOC_G_FMT, &fmt);
if (ret < 0) {
GST_ERROR_OBJECT (self, "VIDIOC_G_FMT failed: %s", g_strerror (errno));
@@ -718,6 +743,10 @@ gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoInfo * info,
return FALSE;
}
+ /* Stick to driver negotiated resolution */
+ info->width = fmt.fmt.pix_mp.width;
+ info->height = fmt.fmt.pix_mp.height;
+
return TRUE;
}
@@ -1114,6 +1143,12 @@ gst_v4l2_encoder_install_properties (GObjectClass * gobject_class,
g_param_spec_string ("video-device", "Video Device Path",
"Path to the video device node", video_device_path,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_ROTATION,
+ g_param_spec_uint ("rotation", "Rotation",
+ "Set rotation angle in degrees",
+ 0, 270, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
}
void
@@ -1131,6 +1166,9 @@ gst_v4l2_encoder_set_property (GObject * object, guint prop_id,
g_free (self->video_device);
self->video_device = g_value_dup_string (value);
break;
+ case PROP_ROTATION:
+ self->rotation = g_value_get_uint (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1150,6 +1188,9 @@ gst_v4l2_encoder_get_property (GObject * object, guint prop_id,
case PROP_VIDEO_DEVICE:
g_value_set_string (value, self->video_device);
break;
+ case PROP_ROTATION:
+ g_value_set_uint (value, self->rotation);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
--
2.25.1

View File

@ -0,0 +1,252 @@
From 6adaff584bc42f9bdf2e22aa3dab5f3f72626c03 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Wed, 21 Aug 2024 17:35:34 +0200
Subject: [PATCH] v4l2codecs: vp8: add webp image support
Add WebP image decoding support to stateless V4L2 VP8 decoder.
A WebP image is composed of a RIFF header followed by a VP8 chunk.
Upstream-Status: Pending
---
gst-libs/gst/codecs/gstvp8decoder.c | 10 +++
sys/v4l2codecs/gstv4l2codecvp8dec.c | 127 ++++++++++++++++++++++++++-
sys/v4l2codecs/linux/v4l2-controls.h | 1 +
3 files changed, 136 insertions(+), 2 deletions(-)
diff --git a/gst-libs/gst/codecs/gstvp8decoder.c b/gst-libs/gst/codecs/gstvp8decoder.c
index 411f272..9ef51cf 100644
--- a/gst-libs/gst/codecs/gstvp8decoder.c
+++ b/gst-libs/gst/codecs/gstvp8decoder.c
@@ -35,6 +35,8 @@
GST_DEBUG_CATEGORY (gst_vp8_decoder_debug);
#define GST_CAT_DEFAULT gst_vp8_decoder_debug
+#define WEBP_RIFF_HEADER_SIZE 20
+
struct _GstVp8DecoderPrivate
{
gint width;
@@ -376,6 +378,8 @@ gst_vp8_decoder_handle_frame (GstVideoDecoder * decoder,
GstVp8Picture *picture = NULL;
GstFlowReturn ret = GST_FLOW_OK;
GstVp8DecoderOutputFrame output_frame;
+ GstCaps *webp_caps = gst_caps_intersect (gst_caps_new_empty_simple ("image/webp"),
+ self->input_state->caps);
GST_LOG_OBJECT (self,
"handle frame, PTS: %" GST_TIME_FORMAT ", DTS: %"
@@ -388,6 +392,12 @@ gst_vp8_decoder_handle_frame (GstVideoDecoder * decoder,
goto error;
}
+ if (!gst_caps_is_empty (webp_caps)) {
+ /* Drop WebP RIFF header */
+ map.data += WEBP_RIFF_HEADER_SIZE;
+ map.size -= WEBP_RIFF_HEADER_SIZE;
+ }
+
pres = gst_vp8_parser_parse_frame_header (&priv->parser,
&frame_hdr, map.data, map.size);
diff --git a/sys/v4l2codecs/gstv4l2codecvp8dec.c b/sys/v4l2codecs/gstv4l2codecvp8dec.c
index ba63a02..6cc5824 100644
--- a/sys/v4l2codecs/gstv4l2codecvp8dec.c
+++ b/sys/v4l2codecs/gstv4l2codecvp8dec.c
@@ -26,6 +26,8 @@
#include "gstv4l2codecpool.h"
#include "gstv4l2codecvp8dec.h"
#include "gstv4l2format.h"
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstbytereader.h>
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
@@ -45,7 +47,8 @@ enum
static GstStaticPadTemplate sink_template =
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME,
GST_PAD_SINK, GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-vp8")
+ GST_STATIC_CAPS ("video/x-vp8;"
+ "image/webp;")
);
static GstStaticPadTemplate alpha_template =
@@ -80,6 +83,10 @@ struct _GstV4l2CodecVp8Dec
GstMemory *bitstream;
GstMapInfo bitstream_map;
+
+ gboolean saw_header;
+ guint frame_size;
+ gboolean webp;
};
G_DEFINE_ABSTRACT_TYPE (GstV4l2CodecVp8Dec, gst_v4l2_codec_vp8_dec,
@@ -428,7 +435,8 @@ gst_v4l2_codec_vp8_dec_fill_frame_header (GstV4l2CodecVp8Dec * self,
(frame_hdr->show_frame ? V4L2_VP8_FRAME_FLAG_SHOW_FRAME : 0) |
(frame_hdr->mb_no_skip_coeff ? V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF : 0) |
(frame_hdr->sign_bias_golden ? V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN : 0) |
- (frame_hdr->sign_bias_alternate ? V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT : 0),
+ (frame_hdr->sign_bias_alternate ? V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT : 0) |
+ (self->webp ? V4L2_VP8_FRAME_FLAG_WEBP : 0),
};
/* *INDENT-ON* */
@@ -579,6 +587,7 @@ gst_v4l2_codec_vp8_dec_decode_picture (GstVp8Decoder * decoder,
static void
gst_v4l2_codec_vp8_dec_reset_picture (GstV4l2CodecVp8Dec * self)
{
+ self->saw_header = FALSE;
if (self->bitstream) {
if (self->bitstream_map.memory)
gst_memory_unmap (self->bitstream, &self->bitstream_map);
@@ -854,6 +863,7 @@ gst_v4l2_codec_vp8_dec_get_property (GObject * object, guint prop_id,
static void
gst_v4l2_codec_vp8_dec_init (GstV4l2CodecVp8Dec * self)
{
+ self->saw_header = FALSE;
}
static void
@@ -879,6 +889,116 @@ gst_v4l2_codec_vp8_dec_class_init (GstV4l2CodecVp8DecClass * klass)
{
}
+static gboolean
+gst_v4l2_codec_vp8_dec_set_format (GstVideoDecoder * decoder,
+ GstVideoCodecState * state)
+{
+ GstV4l2CodecVp8Dec *self = GST_V4L2_CODEC_VP8_DEC (decoder);
+ GstVp8Decoder *vp8dec = GST_VP8_DECODER (decoder);
+ GstCaps *webp_caps = gst_caps_intersect (gst_caps_new_empty_simple ("image/webp"),
+ state->caps);
+
+ if (vp8dec->input_state)
+ gst_video_codec_state_unref (vp8dec->input_state);
+ vp8dec->input_state = gst_video_codec_state_ref (state);
+
+ if (!gst_caps_is_empty (webp_caps)) {
+ /* WebP requires parsing for right packetization */
+ gst_video_decoder_set_packetized (decoder, FALSE);
+ self->webp = TRUE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Webp image RIFF header
+ *
+ * 52 49 46 46 f6 00 00 00 57 45 42 50 56 50 38 20 RIFF....WEBPVP8
+ * ea 00 00 00 90 09 00 9d 01 2a 30 00 30 00 3e 35 .........*0.0.>5
+ * | \______/ \______/
+ * | | \__VP8 startcode
+ * | \__VP8 frame_tag
+ * |
+ * \__End of WebP RIFF header: 20 bytes, then VP8 chunk
+ *
+ * copied from gstwebpdec.c: gst_webp_dec_parse()
+ */
+static GstFlowReturn
+gst_v4l2_codec_vp8_dec_parse (GstVideoDecoder * decoder,
+ GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
+{
+ gsize toadd = 0;
+ gsize size;
+ gconstpointer data;
+ GstByteReader reader;
+ GstV4l2CodecVp8Dec *self = (GstV4l2CodecVp8Dec *) decoder;
+
+ size = gst_adapter_available (adapter);
+ GST_DEBUG_OBJECT (decoder,
+ "parsing webp image data (%" G_GSIZE_FORMAT " bytes)", size);
+
+ if (at_eos) {
+ GST_DEBUG ("Flushing all data out");
+ toadd = size;
+
+ /* If we have leftover data, throw it away */
+ if (!self->saw_header)
+ goto drop_frame;
+ goto have_full_frame;
+ }
+
+ if (!self->saw_header) {
+ guint32 code;
+
+ if (size < 12)
+ goto need_more_data;
+
+ data = gst_adapter_map (adapter, size);
+ gst_byte_reader_init (&reader, data, size);
+
+ if (!gst_byte_reader_get_uint32_le (&reader, &code))
+ goto error;
+
+ if (code == GST_MAKE_FOURCC ('R', 'I', 'F', 'F')) {
+ if (!gst_byte_reader_get_uint32_le (&reader, &self->frame_size))
+ goto error;
+
+ if (!gst_byte_reader_get_uint32_le (&reader, &code))
+ goto error;
+
+ if (code == GST_MAKE_FOURCC ('W', 'E', 'B', 'P'))
+ self->saw_header = TRUE;
+ }
+ }
+
+ if (!self->saw_header)
+ goto error;
+
+ if (size >= (self->frame_size + 8)) {
+ toadd = self->frame_size + 8;
+ self->saw_header = FALSE;
+
+ goto have_full_frame;
+ }
+
+need_more_data:
+ return GST_VIDEO_DECODER_FLOW_NEED_DATA;
+
+have_full_frame:
+ if (toadd)
+ gst_video_decoder_add_to_frame (decoder, toadd);
+ return gst_video_decoder_have_frame (decoder);
+
+drop_frame:
+ gst_adapter_flush (adapter, size);
+ return GST_FLOW_OK;
+
+error:
+ GST_WARNING("parsing webp GST_FLOW_ERROR");
+ return GST_FLOW_ERROR;
+}
+
static void
gst_v4l2_codec_vp8_dec_subclass_init (GstV4l2CodecVp8DecClass * klass,
GstV4l2CodecDevice * device)
@@ -906,6 +1026,9 @@ gst_v4l2_codec_vp8_dec_subclass_init (GstV4l2CodecVp8DecClass * klass,
decoder_class->open = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_open);
decoder_class->close = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_close);
decoder_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_stop);
+ decoder_class->parse = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_parse);
+ decoder_class->set_format =
+ GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_set_format);
decoder_class->negotiate =
GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_negotiate);
decoder_class->decide_allocation =
diff --git a/sys/v4l2codecs/linux/v4l2-controls.h b/sys/v4l2codecs/linux/v4l2-controls.h
index 7a94437..aaeaa58 100644
--- a/sys/v4l2codecs/linux/v4l2-controls.h
+++ b/sys/v4l2codecs/linux/v4l2-controls.h
@@ -1987,6 +1987,7 @@ struct v4l2_vp8_entropy_coder_state {
#define V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF 0x08
#define V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN 0x10
#define V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT 0x20
+#define V4L2_VP8_FRAME_FLAG_WEBP 0x40
#define V4L2_VP8_FRAME_IS_KEY_FRAME(hdr) \
(!!((hdr)->flags & V4L2_VP8_FRAME_FLAG_KEY_FRAME))
--
2.25.1

View File

@ -0,0 +1,47 @@
From 2331231d12d6865289f2bfc17218e4cb0bc08783 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?=
<vjaquez@igalia.com>
Date: Tue, 19 Dec 2023 13:16:34 +0100
Subject: [PATCH] jpegparse: don't trigger message for failed com marker
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5838>
Upstream-Status: Backport
---
.../gst-plugins-bad/gst/jpegformat/gstjpegparse.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/gst/jpegformat/gstjpegparse.c b/subprojects/gst-plugins-bad/gst/jpegformat/gstjpegparse.c
index 6be24a2879..712ced6efd 100644
--- a/gst/jpegformat/gstjpegparse.c
+++ b/gst/jpegformat/gstjpegparse.c
@@ -569,8 +569,13 @@ get_utf8_from_data (const guint8 * data, guint16 size)
"GST_TAG_ENCODING", NULL
};
const char *str = (gchar *) data;
+ char *ret;
- return gst_tag_freeform_string_to_utf8 (str, size, env_vars);
+ ret = gst_tag_freeform_string_to_utf8 (str, size, env_vars);
+ if (!ret)
+ GST_MEMDUMP ("non-parsed marker data", data, size);
+
+ return ret;
}
/* read comment and post as tag */
@@ -794,10 +799,8 @@ gst_jpeg_parse_handle_frame (GstBaseParse * bparse, GstBaseParseFrame * frame,
parse->state |= GST_JPEG_PARSER_STATE_GOT_SOS;
break;
case GST_JPEG_MARKER_COM:
- if (!gst_jpeg_parse_com (parse, &seg)) {
- GST_ELEMENT_WARNING (parse, STREAM, FORMAT,
- ("Failed to parse com segment"), ("Invalid data"));
- }
+ if (!gst_jpeg_parse_com (parse, &seg))
+ GST_WARNING_OBJECT (parse, "Failed to parse com segment");
break;
case GST_JPEG_MARKER_APP0:
if (!gst_jpeg_parse_app0 (parse, &seg)) {
--
2.25.1

View File

@ -0,0 +1,32 @@
From 0707a1a86ca1fbb09b9788087c9af62343f0cb1c Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Tue, 24 Sep 2024 17:01:10 +0200
Subject: [PATCH] kmsallocator: fix stride with planar formats
This fixes a regression introduced by 37f2d2ac42b4e8033291742b17d304cd46fc66c46c4f52ea20ce27730501348c6e575b8d35580239
Fixes #3801
Upstream-Status: Backport
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7566
---
sys/kms/gstkmsallocator.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sys/kms/gstkmsallocator.c b/sys/kms/gstkmsallocator.c
index 3ec2fdb32d..84359b0782 100644
--- a/sys/kms/gstkmsallocator.c
+++ b/sys/kms/gstkmsallocator.c
@@ -122,7 +122,7 @@ gst_kms_allocator_memory_create (GstKMSAllocator * allocator,
/* Overwrite the video info's stride and offset using the pitch calculcated
* by the kms driver. */
stride = gst_video_format_info_extrapolate_stride (vinfo->finfo, i, pitch);
- GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i) = pitch;
+ GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i) = stride;
GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i) = offs;
/* Note that we cannot negotiate special padding betweem each planes,
--
2.25.1

View File

@ -0,0 +1,29 @@
From c52e3c333b62e85a7a7f43b17aa9c63516b0f3f0 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Thu, 26 Sep 2024 11:33:06 +0200
Subject: [PATCH 1/7] Revert "waylandsink: Fix rendering of unaligned content"
This reverts commit b51049be129e69ed347d36118751dbb6f8c1a36e.
Upstream-Status: Pending
---
gst-libs/gst/wayland/gstwllinuxdmabuf.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/gst-libs/gst/wayland/gstwllinuxdmabuf.c b/gst-libs/gst/wayland/gstwllinuxdmabuf.c
index 2fbe57e..deb5d32 100644
--- a/gst-libs/gst/wayland/gstwllinuxdmabuf.c
+++ b/gst-libs/gst/wayland/gstwllinuxdmabuf.c
@@ -154,9 +154,6 @@ gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf,
}
}
- //FIXME, otherwise stride effect with non 16-pixels aligned videos
- width = GST_ROUND_UP_16(width);
-
/* Request buffer creation */
zwp_linux_buffer_params_v1_add_listener (params, &params_listener, &data);
zwp_linux_buffer_params_v1_create (params, width, height, format, flags);
--
2.25.1

View File

@ -0,0 +1,53 @@
From 50890a27e2333e3471fe37f05371b4959cf2a363 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Tue, 8 Oct 2024 10:51:13 +0200
Subject: [PATCH 2/7] waylandsink: match drm kernel driver alignment
This workaround is needed to render not 128 bytes aligned YUV420
planar content.
For example:
$> gst-launch-1.0 videotestsrc ! video/x-raw, format=I420 ! waylandsink
This workaround may be dropped when switching to DRM modifier
implementation introduced in GStreamer-1.24.
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
Upstream-Status: Pending
---
ext/wayland/gstwaylandsink.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index d98c53f..9254b73 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -692,6 +692,8 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
GstWaylandSink *self = GST_WAYLAND_SINK (bsink);;
gboolean use_dmabuf;
GstVideoFormat format;
+ GstVideoAlignment alignment;
+ guint width;
GST_DEBUG_OBJECT (self, "set caps %" GST_PTR_FORMAT, caps);
@@ -699,6 +701,16 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
if (!gst_video_info_from_caps (&self->video_info, caps))
goto invalid_format;
+ /*
+ * stick to DRM kernel driver alignment (128 bytes) to avoid
+ * any board effects due to size mismatch when switching
+ * later-on with DRM dumb allocated buffers
+ */
+ gst_video_alignment_reset (&alignment);
+ width = GST_VIDEO_INFO_WIDTH (&self->video_info);
+ alignment.padding_right = GST_ROUND_UP_128 (width) - width;
+ gst_video_info_align (&self->video_info, &alignment);
+
format = GST_VIDEO_INFO_FORMAT (&self->video_info);
self->video_info_changed = TRUE;
self->skip_dumb_buffer_copy = FALSE;
--
2.25.1

View File

@ -0,0 +1,53 @@
From 924ff90f6a62112db1eadbcb6808cdbbc6fcfa27 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Tue, 8 Oct 2024 17:55:17 +0200
Subject: [PATCH 3/7] gtkwaylandsink: match drm kernel driver alignment
This workaround is needed to render not 128 bytes aligned YUV420
planar content.
For example:
$> gst-launch-1.0 videotestsrc ! video/x-raw, format=I420 ! gtkwaylandsink
This workaround may be dropped when switching to DRM modifier
implementation introduced in GStreamer-1.24.
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
Upstream-Status: Pending
---
ext/gtk/gstgtkwaylandsink.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
index b55fc3e..1497a11 100644
--- a/ext/gtk/gstgtkwaylandsink.c
+++ b/ext/gtk/gstgtkwaylandsink.c
@@ -949,6 +949,8 @@ gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
gst_gtk_wayland_sink_get_instance_private (self);
gboolean use_dmabuf;
GstVideoFormat format;
+ GstVideoAlignment alignment;
+ guint width;
GST_DEBUG_OBJECT (self, "set caps %" GST_PTR_FORMAT, caps);
@@ -956,6 +958,16 @@ gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
if (!gst_video_info_from_caps (&priv->video_info, caps))
goto invalid_format;
+ /*
+ * stick to DRM kernel driver alignment (128 bytes) to avoid
+ * any board effects due to size mismatch when switching
+ * later-on with DRM dumb allocated buffers
+ */
+ gst_video_alignment_reset (&alignment);
+ width = GST_VIDEO_INFO_WIDTH (&priv->video_info);
+ alignment.padding_right = GST_ROUND_UP_128 (width) - width;
+ gst_video_info_align (&priv->video_info, &alignment);
+
format = GST_VIDEO_INFO_FORMAT (&priv->video_info);
priv->video_info_changed = TRUE;
priv->skip_dumb_buffer_copy = FALSE;
--
2.25.1

View File

@ -0,0 +1,29 @@
From 200e52ab34720d1df1e82a0a51c9ae9c84d20572 Mon Sep 17 00:00:00 2001
From: "Cheah, Vincent Beng Keat" <vincent.beng.keat.cheah@intel.com>
Date: Thu, 27 Jul 2023 15:53:55 +0800
Subject: [PATCH 4/7] waylandsink: Add gst_buffer_pool_config_set_params() to a
pool
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5103>
Upstream-Status: Backport
---
ext/wayland/gstwaylandsink.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index 9254b73..4e6a459 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -768,6 +768,8 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
GstStructure *config;
pool = gst_wl_video_buffer_pool_new ();
config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set_params (config,
+ caps, self->video_info.size, 2, 0);
gst_buffer_pool_config_set_allocator (config,
gst_wl_shm_allocator_get (), NULL);
gst_buffer_pool_set_config (pool, config);
--
2.25.1

View File

@ -0,0 +1,29 @@
From 79e5f04fb120c6b1f9fd9e9227aa98036cb6d25f Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Wed, 9 Oct 2024 12:06:31 +0200
Subject: [PATCH 5/7] gtkwaylandsink: Add gst_buffer_pool_config_set_params()
to a pool
Backport of part of 6e22846301c waylandsink: Add DRM modifiers support
Upstream-Status: Backport
---
ext/gtk/gstgtkwaylandsink.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
index 1497a11..c198954 100644
--- a/ext/gtk/gstgtkwaylandsink.c
+++ b/ext/gtk/gstgtkwaylandsink.c
@@ -1051,6 +1051,8 @@ gst_gtk_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
GstStructure *config;
pool = gst_wl_video_buffer_pool_new ();
config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set_params (config,
+ caps, priv->video_info.size, 2, 0);
gst_buffer_pool_config_set_allocator (config,
gst_wl_shm_allocator_get (), NULL);
gst_buffer_pool_set_config (pool, config);
--
2.25.1

View File

@ -0,0 +1,39 @@
From ec3edddc3a734784ada9f6a98481c80195b90e75 Mon Sep 17 00:00:00 2001
From: Hou Qi <qi.hou@nxp.com>
Date: Wed, 17 Apr 2024 10:58:00 +0900
Subject: [PATCH 6/7] waylandsink: config buffer pool with query size when
propose_allocation
If propose_allocation comes before set_caps, self->video_info
has not been extracted from caps and self->video_info.size is 0.
It causes buffer pool fail to set config . So need to use info
size got from query instead when propose_allocation.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6666>
Upstream-Status: Backport
---
ext/wayland/gstwaylandsink.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index 4e6a459..066f05e 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -764,6 +764,13 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
gst_query_parse_allocation (query, &caps, &need_pool);
+ if (caps == NULL)
+ return FALSE;
+
+ /* extract info from caps */
+ if (!gst_video_info_from_caps (&self->video_info, caps))
+ return FALSE;
+
if (need_pool) {
GstStructure *config;
pool = gst_wl_video_buffer_pool_new ();
--
2.25.1

View File

@ -0,0 +1,35 @@
From 657828bf677e2c49e45aed0da180665c2c238232 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Wed, 9 Oct 2024 12:08:06 +0200
Subject: [PATCH 7/7] gtkwaylandsink: config buffer pool with query size when
propose_allocation
Backport of waylandsink: config buffer pool with query size when propose_allocation
on gtkwaylandsink (was missing upstream).
Upstream-Status: Submitted
---
ext/gtk/gstgtkwaylandsink.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
index c198954..fbe05be 100644
--- a/ext/gtk/gstgtkwaylandsink.c
+++ b/ext/gtk/gstgtkwaylandsink.c
@@ -1047,6 +1047,13 @@ gst_gtk_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
gst_query_parse_allocation (query, &caps, &need_pool);
+ if (caps == NULL)
+ return FALSE;
+
+ /* extract info from caps */
+ if (!gst_video_info_from_caps (&priv->video_info, caps))
+ return FALSE;
+
if (need_pool) {
GstStructure *config;
pool = gst_wl_video_buffer_pool_new ();
--
2.25.1

View File

@ -1,41 +0,0 @@
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
SRC_URI:append = " \
file://0001-waylandsink-add-dmabuf-bufferpool.patch \
file://0002-waylandsink-fix-error-when-mmapping-dmabuf-buffers.patch \
file://0003-waylandsink-fix-wrong-width-when-creating-dmabuf-dum.patch \
file://0004-waylandsink-do-not-hardcode-dmabuf-bufferpool-info-s.patch \
file://0005-waylandsink-increase-max-buffers-to-32-to-enable-dma.patch \
file://0006-waylandsink-always-select-dmabuf-buffer-pool.patch \
file://0007-waylandsink-do-not-destroy-pool-twice.patch \
file://0008-waylandsink-HACK-disable-frame-dropping-while-redraw.patch \
file://0009-waylandsink-Uprank-to-secondary.patch \
file://0010-waylandsink-set-video-alignment-to-32-bytes.patch \
file://0011-waylandsink-fallback-to-shm-if-display-does-not-supp.patch \
file://0012-waylandsink-XDG-protocol-does-not-work-in-fullscreen.patch \
file://0013-waylandsink-silently-drop-erroneous-frame.patch \
file://0014-waylandsink-add-waylandpool-on-meson-build.patch \
\
file://0016-Add-new-gtkwaylandsink-element.patch \
file://0017-waylandsink-fix-shm-pool-wrongly-selected-with-some-.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 \
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
}

View File

@ -0,0 +1,98 @@
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://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://0031-v4l2codecs-fix-support-of-unaligned-videos.patch \
file://0033-waylandsink-Fix-rendering-of-unaligned-content.patch \
file://0035-v4l2codecs-add-NV12M-format-to-gstv4l2format.patch \
file://0036-v4l2codecs-fix-gst_v4l2_encoder_set_src_fmt-call.patch \
file://0037-v4l2codecs-add-support-of-encoding-from-RGB.patch \
file://0038-v4l2codecs-add-colorimetry-support-at-sink-pad.patch \
file://0040-Revert-v4l2codecs-fix-support-of-unaligned-videos.patch \
file://0041-h264parser-Define-level-enum-values.patch \
file://0042-codecparsers-keep-naming-consistency-in-GST_H264_LEV.patch \
file://0043-v4l2codecs-encoder-No-need-to-set-num_planes-of-plan.patch \
file://0044-v4l2codecs-add-NV12M-format-to-gstv4l2format.patch \
file://0045-v4l2codecs-Add-V4L2-H264-stateless-encode-uAPI.patch \
file://0046-codecs-Add-base-class-for-stateless-h264-encoder.patch \
file://0047-v4l2codecs-encoder-Add-h264-code-to-v4l2-encoder-cla.patch \
file://0048-v4l2codecs-Add-V4L2-stateless-H264-encoder.patch \
file://0049-v4l2codecs-Register-V4L2-stateless-H264-encoder.patch \
file://0050-v4l2codecs-encoders-Implement-propose-allocation.patch \
file://0051-v4l2codecs-format-Allow-matching-planar-format-varia.patch \
file://0052-v4l2codecs-encoder-Save-the-sink-format.patch \
file://0053-v4l2codecs-format-Prefer-mplane-variants.patch \
file://0054-v4l2codecs-encoder-Implement-zero-copy-support.patch \
file://0055-codecs-h264enc-Fix-indentation.patch \
file://0056-v4l2codecs-h264enc-Fix-indentation.patch \
file://0057-v4l2codecs-h264enc-Cleanup-caps-colorimetry-framerat.patch \
file://0058-v4l2codecs-h264enc-add-CABAC-enable-disable-control.patch \
file://0059-v4l2codecs-h264enc-Don-t-call-virtual-negotiate-dire.patch \
file://0060-v4l2codecs-vp8enc-Don-t-call-virtual-negotiate-direc.patch \
file://0061-v4l2codecs-h264enc-Add-profile-negotiation.patch \
file://0062-codecs-h264encoder-Fix-H.264-QP-max-value.patch \
file://0063-v4l2codecs-h264dec-Remove-dead-and-broken-code.patch \
file://0064-codecs-Introduce-a-PID-based-rate-controller.patch \
file://0065-codecs-h264encoder-Use-the-PID-base-rate-controller.patch \
file://0066-v4l2codecs-h264enc-Rewrite-profile-level-negotiation.patch \
file://0067-v4l2codecs-h264enc-De-emulate-SPS-and-PPS-bitstream.patch \
file://0068-v4l2codecs-vp8-fix-support-of-unaligned-videos.patch \
file://0069-Force-to-add-math-as-library-dependency.patch \
file://0070-v4l2codecs-sync-to-kernel-v6.6-headers.patch \
file://0070-v4l2codecs-encoder-add-rotation-support.patch \
file://0071-v4l2codecs-vp8-add-webp-image-support.patch \
file://0072-jpegparse-don-t-trigger-message-for-failed-com-marke.patch \
file://0073-kmsallocator-fix-stride-with-planar-formats.patch \
file://0074-Revert-waylandsink-Fix-rendering-of-unaligned-conten.patch \
file://0075-waylandsink-match-drm-kernel-driver-alignment.patch \
file://0076-gtkwaylandsink-match-drm-kernel-driver-alignment.patch \
file://0077-waylandsink-Add-gst_buffer_pool_config_set_params-to.patch \
file://0078-gtkwaylandsink-Add-gst_buffer_pool_config_set_params.patch \
file://0079-waylandsink-config-buffer-pool-with-query-size-when-.patch \
file://0080-gtkwaylandsink-config-buffer-pool-with-query-size-wh.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
}

View File

@ -0,0 +1,955 @@
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>
Upstream-Status: Backport
---
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

View File

@ -1,34 +0,0 @@
From a698ef5806e50b614f49decb4eb2a2b4404f56e5 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Wed, 23 Jan 2019 14:18:28 +0100
Subject: [PATCH 1/2] playbin2: disable any default video processing
Do not enable by default software video processing
to not degrade performances.
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
gst/playback/gstplaybin2.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c
index a2e9ed4..4c0163e 100644
--- a/gst/playback/gstplaybin2.c
+++ b/gst/playback/gstplaybin2.c
@@ -499,9 +499,8 @@ struct _GstPlayBinClass
#define DEFAULT_URI NULL
#define DEFAULT_SUBURI NULL
#define DEFAULT_SOURCE NULL
-#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
- GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_DEINTERLACE | \
- GST_PLAY_FLAG_SOFT_COLORBALANCE
+#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_SOFT_VOLUME
+
#define DEFAULT_N_VIDEO 0
#define DEFAULT_CURRENT_VIDEO -1
#define DEFAULT_N_AUDIO 0
--
2.7.4

View File

@ -0,0 +1,78 @@
From 4e3dc15635d1a3fbd49fca2c5478bd10623fac7d Mon Sep 17 00:00:00 2001
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Date: Mon, 6 Nov 2023 16:35:47 -0500
Subject: [PATCH] DRAFT: video: Allow frame copy from different dimensions
This removes the limitation regarding the frame dimensions when copying.
This leaves it to the implementation to decided if doing so is
acceptable or not. A flag is introduced to allow filling the padding
when a smaller images is copied into a bigger one.
TODO:
- Add filling flag, needed by encoders
- Add some unit tests
Upstream-Status: Backport
---
gst-libs/gst/video/video-frame.c | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/gst-libs/gst/video/video-frame.c b/gst-libs/gst/video/video-frame.c
index bfb57e4..787af67 100644
--- a/gst-libs/gst/video/video-frame.c
+++ b/gst-libs/gst/video/video-frame.c
@@ -319,8 +319,6 @@ gst_video_frame_copy_plane (GstVideoFrame * dest, const GstVideoFrame * src,
finfo = dinfo->finfo;
- g_return_val_if_fail (dinfo->width <= sinfo->width
- && dinfo->height <= sinfo->height, FALSE);
g_return_val_if_fail (finfo->n_planes > plane, FALSE);
sp = src->data[plane];
@@ -333,15 +331,19 @@ gst_video_frame_copy_plane (GstVideoFrame * dest, const GstVideoFrame * src,
}
gst_video_format_info_component (finfo, plane, comp);
- w = GST_VIDEO_FRAME_COMP_WIDTH (dest,
- comp[0]) * GST_VIDEO_FRAME_COMP_PSTRIDE (dest, comp[0]);
+ w = MIN (GST_VIDEO_FRAME_COMP_WIDTH (dest, comp[0]),
+ GST_VIDEO_FRAME_COMP_WIDTH (src, comp[0])) *
+ GST_VIDEO_FRAME_COMP_PSTRIDE (dest, comp[0]);
+
+
/* FIXME: workaround for complex formats like v210, UYVP and IYU1 that have
* pstride == 0 */
if (w == 0)
w = MIN (GST_VIDEO_INFO_PLANE_STRIDE (dinfo, plane),
GST_VIDEO_INFO_PLANE_STRIDE (sinfo, plane));
- h = GST_VIDEO_FRAME_COMP_HEIGHT (dest, comp[0]);
+ h = MIN (GST_VIDEO_FRAME_COMP_HEIGHT (dest, comp[0]),
+ GST_VIDEO_FRAME_COMP_HEIGHT (src, comp[0]));
ss = GST_VIDEO_INFO_PLANE_STRIDE (sinfo, plane);
ds = GST_VIDEO_INFO_PLANE_STRIDE (dinfo, plane);
@@ -409,19 +411,12 @@ gboolean
gst_video_frame_copy (GstVideoFrame * dest, const GstVideoFrame * src)
{
guint i, n_planes;
- const GstVideoInfo *sinfo;
GstVideoInfo *dinfo;
g_return_val_if_fail (dest != NULL, FALSE);
g_return_val_if_fail (src != NULL, FALSE);
- sinfo = &src->info;
dinfo = &dest->info;
-
- g_return_val_if_fail (dinfo->finfo->format == sinfo->finfo->format, FALSE);
- g_return_val_if_fail (dinfo->width <= sinfo->width
- && dinfo->height <= sinfo->height, FALSE);
-
n_planes = dinfo->finfo->n_planes;
for (i = 0; i < n_planes; i++)
--
2.25.1

View File

@ -1,34 +0,0 @@
From 17a847850f31be11c0c98d31cdd4d62856bfa313 Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@st.com>
Date: Wed, 23 Jan 2019 14:16:36 +0100
Subject: [PATCH 2/2] playbin3: disable any default video processing
Do not enable by default software video processing
to not degrade performances.
Upstream-Status: Inappropriate [DEY specific]
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
gst/playback/gstplaybin3.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/gst/playback/gstplaybin3.c b/gst/playback/gstplaybin3.c
index 027766b..9103cb1 100644
--- a/gst/playback/gstplaybin3.c
+++ b/gst/playback/gstplaybin3.c
@@ -520,9 +520,8 @@ struct _GstPlayBin3Class
/* props */
#define DEFAULT_URI NULL
#define DEFAULT_SUBURI NULL
-#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
- GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_DEINTERLACE | \
- GST_PLAY_FLAG_SOFT_COLORBALANCE | GST_PLAY_FLAG_BUFFERING
+#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | \
+ GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_BUFFERING
#define DEFAULT_CURRENT_VIDEO -1
#define DEFAULT_CURRENT_AUDIO -1
#define DEFAULT_CURRENT_TEXT -1
--
2.7.4

View File

@ -1,7 +1,9 @@
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}/:"
SRC_URI:append = " file://0001-playbin2-disable-any-default-video-processing.patch "
SRC_URI:append = " file://0002-playbin3-disable-any-default-video-processing.patch "
SRC_URI:append = " \
file://0001-allocators-Add-a-DRM-Dumb-Allocator.patch \
file://0002-DRAFT-video-Allow-frame-copy-from-different-dimensio.patch \
"
PACKAGECONFIG ?= " \
${GSTREAMER_ORC} \

View File

@ -2,8 +2,9 @@ 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 soup speex taglib v4l2 \
bz2 cairo flac gdk-pixbuf gudev jpeg lame libpng mpg123 speex taglib v4l2 \
libv4l2 \
${@bb.utils.contains_any('DISTRO_FEATURES', '${GTK3DISTROFEATURES}', 'gtk', '', d)} \
"
@ -15,5 +16,3 @@ EXTRA_OEMESON += " \
# remove qt5 for the moment
PACKAGECONFIG:remove = " qt5"
RDEPENDS:${PN}-soup += "libsoup-2.4"

Some files were not shown because too many files have changed in this diff Show More