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:
parent
9c502ca5b8
commit
0b12b51044
|
|
@ -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
|
||||
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
|
||||
|
||||
SRC_URI:append = " file://0001-gstreamer1.0-libav-disable-decoder-direct-rendering-.patch "
|
||||
|
|
@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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, ¶ms);
|
||||
+ 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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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, ¶ms_listener, &data);
|
||||
zwp_linux_buffer_params_v1_create (params, width, height, format, flags);
|
||||
--
|
||||
2.25.1
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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, ¶ms_listener, &data);
|
||||
zwp_linux_buffer_params_v1_create (params, width, height, format, flags);
|
||||
--
|
||||
2.25.1
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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} \
|
||||
|
|
@ -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
Loading…
Reference in New Issue