Merge pull request #7043 from HiassofT/le11-ffmpeg-5.1.2

ffmpeg: update to 5.1.2
This commit is contained in:
CvH 2023-03-05 21:40:29 +01:00 committed by GitHub
commit 341c3dbd4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 30966 additions and 71882 deletions

View File

@ -3,14 +3,14 @@
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
PKG_NAME="ffmpeg"
PKG_VERSION="4.4.1"
PKG_SHA256="eadbad9e9ab30b25f5520fbfde99fae4a92a1ae3c0257a8d68569a4651e30e02"
PKG_VERSION="5.1.2"
PKG_SHA256="619e706d662c8420859832ddc259cd4d4096a48a2ce1eefd052db9e440eef3dc"
PKG_LICENSE="GPL-3.0-only"
PKG_SITE="https://ffmpeg.org"
PKG_URL="http://ffmpeg.org/releases/ffmpeg-${PKG_VERSION}.tar.xz"
PKG_DEPENDS_TARGET="toolchain zlib bzip2 openssl speex"
PKG_LONGDESC="FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video."
PKG_PATCH_DIRS="kodi libreelec"
PKG_PATCH_DIRS="libreelec"
case "${PROJECT}" in
Amlogic)
@ -18,14 +18,17 @@ case "${PROJECT}" in
PKG_FFMPEG_BRANCH="dev/4.4/rpi_import_1"
PKG_SHA256="3b42cbffd15d95d59e402475fcdb1aaac9ae6a8404a521b95d1fe79c6b2baad4"
PKG_URL="https://github.com/jc-kynesim/rpi-ffmpeg/archive/${PKG_VERSION}.tar.gz"
PKG_PATCH_DIRS="libreelec dav1d"
;;
RPi)
PKG_FFMPEG_RPI="--disable-mmal --disable-rpi --enable-sand"
PKG_FFMPEG_RPI="--disable-mmal --enable-sand"
PKG_PATCH_DIRS+=" rpi"
;;
*)
PKG_PATCH_DIRS+=" v4l2-request v4l2-drmprime"
case "${PROJECT}" in
Allwinner|Rockchip)
PKG_PATCH_DIRS+=" vf-deinterlace-v4l2m2m"
esac
;;
esac
@ -48,14 +51,8 @@ if [ "${V4L2_SUPPORT}" = "yes" ]; then
PKG_NEED_UNPACK+=" $(get_pkg_directory libdrm)"
PKG_FFMPEG_V4L2="--enable-v4l2_m2m --enable-libdrm"
if [ "${PROJECT}" = "Allwinner" -o "${PROJECT}" = "Rockchip" -o "${DEVICE}" = "iMX8" ]; then
if [ "${PROJECT}" = "Allwinner" -o "${PROJECT}" = "Rockchip" -o "${DEVICE}" = "iMX8" -o "${DEVICE}" = "RPi4" ]; then
PKG_V4L2_REQUEST="yes"
elif [ "${PROJECT}" = "RPi" -a "${DEVICE}" = "RPi4" ]; then
PKG_V4L2_REQUEST="yes"
PKG_FFMPEG_HWACCEL="--disable-hwaccel=h264_v4l2request \
--disable-hwaccel=mpeg2_v4l2request \
--disable-hwaccel=vp8_v4l2request \
--disable-hwaccel=vp9_v4l2request"
else
PKG_V4L2_REQUEST="no"
fi

View File

@ -1,124 +0,0 @@
From 7ee17ec7e46afef0e0af20af196292ec75f50b62 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Sat, 26 Jun 2021 17:24:15 -0300
Subject: [PATCH] avcodec/libdav1d: don't repeatedly parse the same sequence
header
Look at the event flag that signals a new sequence header was found
in the bitstream on supported libdav1d versions for this purpose.
Signed-off-by: James Almer <jamrial@gmail.com>
---
libavcodec/libdav1d.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index 6370ae1fbf02..c39df418d515 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -33,6 +33,9 @@
#include "decode.h"
#include "internal.h"
+#define FF_DAV1D_VERSION_AT_LEAST(x,y) \
+ (DAV1D_API_VERSION_MAJOR > (x) || DAV1D_API_VERSION_MAJOR == (x) && DAV1D_API_VERSION_MINOR >= (y))
+
typedef struct Libdav1dContext {
AVClass *class;
Dav1dContext *c;
From d873b5fffc8292242549c4c026023e370e15c05b Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 20 Sep 2021 22:30:35 -0300
Subject: [PATCH] avcodec/libdav1d: pass auto threads value to libdav1d
libdav1d 1.0.0 will be the first version supporting Dav1dSettings.n_threads == 0.
Signed-off-by: James Almer <jamrial@gmail.com>
---
libavcodec/libdav1d.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index 4711337f39a7..e4fdaf722907 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -207,7 +207,11 @@ static av_cold int libdav1d_init(AVCodecContext *c)
{
Libdav1dContext *dav1d = c->priv_data;
Dav1dSettings s;
+#if FF_DAV1D_VERSION_AT_LEAST(6,0)
+ int threads = c->thread_count;
+#else
int threads = (c->thread_count ? c->thread_count : av_cpu_count()) * 3 / 2;
+#endif
int res;
av_log(c, AV_LOG_INFO, "libdav1d %s\n", dav1d_version());
From e204846ec16c1ab34c7f3a681734cf5190433018 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Fri, 3 Sep 2021 13:50:32 -0300
Subject: [PATCH] avcodec/libdav1d: fix compilation after recent libdav1d API
changes
They were done in preparation for an upcoming 1.0 release.
Keep supporting previous releases for the time being.
Reviewed-by: BBB
Signed-off-by: James Almer <jamrial@gmail.com>
---
libavcodec/libdav1d.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index 51e0980f6edb..4711337f39a7 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -228,6 +228,15 @@ static av_cold int libdav1d_init(AVCodecContext *c)
if (dav1d->operating_point >= 0)
s.operating_point = dav1d->operating_point;
+#if FF_DAV1D_VERSION_AT_LEAST(6,0)
+ if (dav1d->frame_threads || dav1d->tile_threads)
+ s.n_threads = FFMAX(dav1d->frame_threads, dav1d->tile_threads);
+ else
+ s.n_threads = FFMIN(threads, DAV1D_MAX_THREADS);
+ s.max_frame_delay = (c->flags & AV_CODEC_FLAG_LOW_DELAY) ? 1 : s.n_threads;
+ av_log(c, AV_LOG_DEBUG, "Using %d threads, %d max_frame_delay\n",
+ s.n_threads, s.max_frame_delay);
+#else
s.n_tile_threads = dav1d->tile_threads
? dav1d->tile_threads
: FFMIN(floor(sqrt(threads)), DAV1D_MAX_TILE_THREADS);
@@ -236,6 +245,7 @@ static av_cold int libdav1d_init(AVCodecContext *c)
: FFMIN(ceil(threads / s.n_tile_threads), DAV1D_MAX_FRAME_THREADS);
av_log(c, AV_LOG_DEBUG, "Using %d frame threads, %d tile threads\n",
s.n_frame_threads, s.n_tile_threads);
+#endif
res = libdav1d_parse_extradata(c);
if (res < 0)
@@ -519,11 +529,18 @@ static av_cold int libdav1d_close(AVCodecContext *c)
return 0;
}
+#ifndef DAV1D_MAX_FRAME_THREADS
+#define DAV1D_MAX_FRAME_THREADS DAV1D_MAX_THREADS
+#endif
+#ifndef DAV1D_MAX_TILE_THREADS
+#define DAV1D_MAX_TILE_THREADS DAV1D_MAX_THREADS
+#endif
+
#define OFFSET(x) offsetof(Libdav1dContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption libdav1d_options[] = {
- { "tilethreads", "Tile threads", OFFSET(tile_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_TILE_THREADS, VD },
- { "framethreads", "Frame threads", OFFSET(frame_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_FRAME_THREADS, VD },
+ { "tilethreads", "Tile threads", OFFSET(tile_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_TILE_THREADS, VD | AV_OPT_FLAG_DEPRECATED },
+ { "framethreads", "Frame threads", OFFSET(frame_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_FRAME_THREADS, VD | AV_OPT_FLAG_DEPRECATED },
{ "filmgrain", "Apply Film Grain", OFFSET(apply_grain), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VD | AV_OPT_FLAG_DEPRECATED },
{ "oppoint", "Select an operating point of the scalable bitstream", OFFSET(operating_point), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 31, VD },
{ "alllayers", "Output all spatial layers", OFFSET(all_layers), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VD },

View File

@ -1,44 +0,0 @@
From 1d23e125b6f76e74b754560c3b6931507cacddce Mon Sep 17 00:00:00 2001
From: Timo Rothenpieler <timo@rothenpieler.org>
Date: Tue, 7 Sep 2021 19:35:31 +0200
Subject: [PATCH] configure: account for openssl3 license change
---
configure | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/configure b/configure
index c87a010387..ed7345b2c1 100755
--- a/configure
+++ b/configure
@@ -1765,7 +1765,6 @@ EXTERNAL_LIBRARY_GPL_LIST="
EXTERNAL_LIBRARY_NONFREE_LIST="
decklink
libfdk_aac
- openssl
libtls
"
@@ -1857,6 +1856,7 @@ EXTERNAL_LIBRARY_LIST="
mediacodec
openal
opengl
+ openssl
pocketsphinx
vapoursynth
"
@@ -6572,7 +6572,10 @@ enabled omx_rpi && { test_code cc OMX_Core.h OMX_IndexConfigBrcmVideoR
die "ERROR: OpenMAX IL headers from raspberrypi/firmware not found"; } &&
enable omx
enabled omx && require_headers OMX_Core.h
-enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl ||
+enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" openssl/ssl.h OPENSSL_init_ssl &&
+ { enabled gplv3 || ! enabled gpl || enabled nonfree || die "ERROR: OpenSSL >=3.0.0 requires --enable-version3"; }; } ||
+ { enabled gpl && ! enabled nonfree && die "ERROR: OpenSSL <3.0.0 is incompatible with the gpl"; } ||
+ check_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl ||
check_pkg_config openssl openssl openssl/ssl.h SSL_library_init ||
check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto ||
check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto ||
--
2.34.1

View File

@ -1,880 +0,0 @@
From 5180cdc317139414eedcb49627d240519435b104 Mon Sep 17 00:00:00 2001
From: marc <mhocking@ubuntu-desktop.(none)>
Date: Mon, 18 Feb 2013 17:18:18 +0000
Subject: [PATCH 01/15] dxva-h264: Fix an AMD driver issue with playback of
streams that don't start with an I-Frame
---
libavcodec/dxva2_h264.c | 8 ++++++++
libavcodec/h264_slice.c | 1 +
libavcodec/h264dec.c | 1 +
libavcodec/h264dec.h | 2 ++
4 files changed, 12 insertions(+)
diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c
index 5b23b28f12..c0a8d80f3b 100644
--- a/libavcodec/dxva2_h264.c
+++ b/libavcodec/dxva2_h264.c
@@ -504,6 +504,14 @@ static int dxva2_h264_end_frame(AVCodecContext *avctx)
if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
return -1;
+
+ // Wait for an I-frame before start decoding. Workaround for ATI UVD and UVD+ GPUs
+ if (!h->got_first_iframe) {
+ if (!(ctx_pic->pp.wBitFields & (1 << 15)))
+ return -1;
+ h->got_first_iframe = 1;
+ }
+
ret = ff_dxva2_common_end_frame(avctx, h->cur_pic_ptr->f,
&ctx_pic->pp, sizeof(ctx_pic->pp),
&ctx_pic->qm, sizeof(ctx_pic->qm),
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 7c69016338..0b415ada6f 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -942,6 +942,7 @@ static int h264_slice_header_init(H264Context *h)
h->first_field = 0;
h->prev_interlaced_frame = 1;
+ h->got_first_iframe = 0;
init_scan_tables(h);
ret = ff_h264_alloc_tables(h);
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index 485f47d36e..1705046e29 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -442,6 +442,7 @@ void ff_h264_flush_change(H264Context *h)
h->next_outputed_poc = INT_MIN;
h->prev_interlaced_frame = 1;
+ h->got_first_iframe = 0;
idr(h);
h->poc.prev_frame_num = -1;
diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
index b3677cdbb9..b7b19ba4f1 100644
--- a/libavcodec/h264dec.h
+++ b/libavcodec/h264dec.h
@@ -540,6 +540,8 @@ typedef struct H264Context {
* slices) anymore */
int setup_finished;
+ int got_first_iframe;
+
int cur_chroma_format_idc;
int cur_bit_depth_luma;
int16_t slice_row[MAX_SLICES]; ///< to detect when MAX_SLICES is too low
From 02731d93b4c725f13bf3b3217b48db3be18e0bce Mon Sep 17 00:00:00 2001
From: Rechi <Rechi@users.noreply.github.com>
Date: Tue, 21 Nov 2017 08:16:53 +0100
Subject: [PATCH 02/15] use Kodi as extra version
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 7e9d8b08c3..882a3cb31b 100644
--- a/Makefile
+++ b/Makefile
@@ -130,7 +130,7 @@ GIT_LOG = $(SRC_PATH)/.git/logs/HEAD
.version: M=@
libavutil/ffversion.h .version:
- $(M)$(VERSION_SH) $(SRC_PATH) libavutil/ffversion.h $(EXTRA_VERSION)
+ $(M)$(VERSION_SH) $(SRC_PATH) libavutil/ffversion.h Kodi
$(Q)touch .version
# force version.sh to run whenever version might have changed
From 1ec811b6f330f60ec7a522cc60e98bd8ae30c766 Mon Sep 17 00:00:00 2001
From: Rechi <Rechi@users.noreply.github.com>
Date: Tue, 21 Nov 2017 08:16:53 +0100
Subject: [PATCH 03/15] common.mak: never ignore an error if strip doesn't
succeed
---
ffbuild/common.mak | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ffbuild/common.mak b/ffbuild/common.mak
index 164a43932d..2ab5dd0dfd 100644
--- a/ffbuild/common.mak
+++ b/ffbuild/common.mak
@@ -87,7 +87,7 @@ COMPILE_MSA = $(call COMPILE,CC,MSAFLAGS)
%.o: %.asm
$(COMPILE_X86ASM)
- -$(if $(ASMSTRIPFLAGS), $(STRIP) $(ASMSTRIPFLAGS) $@)
+ $(if $(STRIP), $(if $(ASMSTRIPFLAGS), $(STRIP) $(ASMSTRIPFLAGS) $@))
%.o: %.rc
$(WINDRES) $(IFLAGS) $(foreach ARG,$(CC_DEPFLAGS),--preprocessor-arg "$(ARG)") -o $@ $<
From 29b9dec3de00f69339e6a5fed79b2d8ce2b3c105 Mon Sep 17 00:00:00 2001
From: wsnipex <wsnipex@a1.net>
Date: Tue, 21 Nov 2017 08:16:53 +0100
Subject: [PATCH 04/15] only check for a git rev if the src tree is in a git
repo
fixes the version string when building from the kodi depends src tree
---
ffbuild/version.sh | 2 ++
1 file changed, 2 insertions(+)
diff --git a/ffbuild/version.sh b/ffbuild/version.sh
index edc4dd33c5..239a138ca7 100755
--- a/ffbuild/version.sh
+++ b/ffbuild/version.sh
@@ -2,6 +2,7 @@
# Usage: version.sh <ffmpeg-root-dir> <output-version.h> <extra-version>
+if [ -d $1/.git ]; then # only check for a git rev, if the src tree is in a git repo
# check for git short hash
if ! test "$revision"; then
if (cd "$1" && grep git RELEASE 2> /dev/null >/dev/null) ; then
@@ -27,6 +28,7 @@ if [ -z "$revision" ]; then
git_hash="${srcdir##*-}";;
esac
fi
+fi
# no revision number found
test "$revision" || revision=$(cd "$1" && cat RELEASE 2> /dev/null)
From d2e9030c8a0d55426e13d1007e163c48f2533819 Mon Sep 17 00:00:00 2001
From: Anton Fedchin <afedchin at ruswizards.com>
Date: Fri, 11 Jan 2019 10:47:43 +0100
Subject: [PATCH 05/15] after 153b36f there is a possibility to crash when
trying to get index of a surface which points to nirvana.
it may occurs when a stream starts with non i-frame.
---
libavcodec/dxva2.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c
index b57ea21941..542bc2f18d 100644
--- a/libavcodec/dxva2.c
+++ b/libavcodec/dxva2.c
@@ -777,16 +777,18 @@ unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx,
#if CONFIG_D3D11VA
if (avctx->pix_fmt == AV_PIX_FMT_D3D11)
return (intptr_t)frame->data[1];
- if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
+ if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD && surface) {
D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
ID3D11VideoDecoderOutputView_GetDesc((ID3D11VideoDecoderOutputView*) surface, &viewDesc);
return viewDesc.Texture2D.ArraySlice;
}
#endif
#if CONFIG_DXVA2
- for (i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++) {
- if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD && ctx->dxva2.surface[i] == surface)
- return i;
+ if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
+ for (i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++) {
+ if (ctx->dxva2.surface[i] == surface)
+ return i;
+ }
}
#endif
From 916223c0a47091272c9d0b6035f187310908ff37 Mon Sep 17 00:00:00 2001
From: Rainer Hochecker <fernetmenta@online.de>
Date: Sat, 26 Jan 2019 19:48:35 +0100
Subject: [PATCH 06/15] avcodec/vaapi_h264: skip decode if pic has no slices
This fixes / workarounds https://bugs.freedesktop.org/show_bug.cgi?id=105368.
It was hit frequently when watching h264 channels received via DVB-X.
Corresponding kodi bug: https://github.com/xbmc/xbmc/issues/15704
---
libavcodec/vaapi_h264.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c
index 9332aa6f31..d4494beebf 100644
--- a/libavcodec/vaapi_h264.c
+++ b/libavcodec/vaapi_h264.c
@@ -314,6 +314,11 @@ static int vaapi_h264_end_frame(AVCodecContext *avctx)
H264SliceContext *sl = &h->slice_ctx[0];
int ret;
+ if (pic->nb_slices == 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto finish;
+ }
+
ret = ff_vaapi_decode_issue(avctx, pic);
if (ret < 0)
goto finish;
From b211c09d17ef86d7b38d1bfe9814a01e9040bf03 Mon Sep 17 00:00:00 2001
From: Fei Wang <fei.w.wang@intel.com>
Date: Tue, 12 Oct 2021 16:23:56 +0800
Subject: [PATCH 07/15] cbs_av1: fix incorrect data type
Since order_hint_bits_minus_1 range is 0~7, cur_frame_hint can be
most 128. And similar return value for cbs_av1_get_relative_dist.
So if plus them and use int8_t for the result may lose its precision.
Signed-off-by: Fei Wang <fei.w.wang@intel.com>
(cherry picked from commit e7ff5722b1abae4284e79da707e71ff82b409699)
(cherry picked from commit 8aab15a91d6e8ca726580e969ff71828ad63baaa)
---
libavcodec/cbs_av1_syntax_template.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libavcodec/cbs_av1_syntax_template.c b/libavcodec/cbs_av1_syntax_template.c
index 6fe6e9a4f3..d98d3d42de 100644
--- a/libavcodec/cbs_av1_syntax_template.c
+++ b/libavcodec/cbs_av1_syntax_template.c
@@ -355,7 +355,7 @@ static int FUNC(set_frame_refs)(CodedBitstreamContext *ctx, RWContext *rw,
AV1_REF_FRAME_ALTREF2, AV1_REF_FRAME_ALTREF
};
int8_t ref_frame_idx[AV1_REFS_PER_FRAME], used_frame[AV1_NUM_REF_FRAMES];
- int8_t shifted_order_hints[AV1_NUM_REF_FRAMES];
+ int16_t shifted_order_hints[AV1_NUM_REF_FRAMES];
int cur_frame_hint, latest_order_hint, earliest_order_hint, ref;
int i, j;
From 2db5def80f1913a00410d6f16ae3730de567c3b8 Mon Sep 17 00:00:00 2001
From: Fei Wang <fei.w.wang@intel.com>
Date: Tue, 12 Oct 2021 16:23:57 +0800
Subject: [PATCH 08/15] avcodec/av1: extend some definitions in spec section 3
Signed-off-by: Fei Wang <fei.w.wang@intel.com>
(cherry picked from commit 75de7fe26218cb37fff9d5afa7b5b2b8bee4a9a8)
(cherry picked from commit 2f459697445df67cc61c9a6c2930fdf3f830e629)
---
libavcodec/av1.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/libavcodec/av1.h b/libavcodec/av1.h
index 0f99ae4829..951a18ecb2 100644
--- a/libavcodec/av1.h
+++ b/libavcodec/av1.h
@@ -114,6 +114,13 @@ enum {
AV1_WARP_MODEL_TRANSLATION = 1,
AV1_WARP_MODEL_ROTZOOM = 2,
AV1_WARP_MODEL_AFFINE = 3,
+ AV1_WARP_PARAM_REDUCE_BITS = 6,
+
+ AV1_DIV_LUT_BITS = 8,
+ AV1_DIV_LUT_PREC_BITS = 14,
+ AV1_DIV_LUT_NUM = 257,
+
+ AV1_MAX_LOOP_FILTER = 63,
};
From ddc3058a3e7b7c44a3911fb356f932853565b3d0 Mon Sep 17 00:00:00 2001
From: Fei Wang <fei.w.wang@intel.com>
Date: Tue, 12 Oct 2021 16:23:58 +0800
Subject: [PATCH 09/15] avcodec/av1dec: support setup shear process
Defined in spec 7.11.3.6/7.11.3.7.
Signed-off-by: Fei Wang <fei.w.wang@intel.com>
(cherry picked from commit de7475b111679120b3b089fe543224f50882287c)
(cherry picked from commit 481d3930d90d52587ad76d277cbd2f9cb3109079)
---
libavcodec/av1dec.c | 98 +++++++++++++++++++++++++++++++++++++++++++++
libavcodec/av1dec.h | 1 +
2 files changed, 99 insertions(+)
diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
index a75d6744d3..a3301f454f 100644
--- a/libavcodec/av1dec.c
+++ b/libavcodec/av1dec.c
@@ -28,6 +28,34 @@
#include "internal.h"
#include "profiles.h"
+/**< same with Div_Lut defined in spec 7.11.3.7 */
+static const uint16_t div_lut[AV1_DIV_LUT_NUM] = {
+ 16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768,
+ 15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142,
+ 15087, 15033, 14980, 14926, 14873, 14821, 14769, 14717, 14665, 14614, 14564,
+ 14513, 14463, 14413, 14364, 14315, 14266, 14218, 14170, 14122, 14075, 14028,
+ 13981, 13935, 13888, 13843, 13797, 13752, 13707, 13662, 13618, 13574, 13530,
+ 13487, 13443, 13400, 13358, 13315, 13273, 13231, 13190, 13148, 13107, 13066,
+ 13026, 12985, 12945, 12906, 12866, 12827, 12788, 12749, 12710, 12672, 12633,
+ 12596, 12558, 12520, 12483, 12446, 12409, 12373, 12336, 12300, 12264, 12228,
+ 12193, 12157, 12122, 12087, 12053, 12018, 11984, 11950, 11916, 11882, 11848,
+ 11815, 11782, 11749, 11716, 11683, 11651, 11619, 11586, 11555, 11523, 11491,
+ 11460, 11429, 11398, 11367, 11336, 11305, 11275, 11245, 11215, 11185, 11155,
+ 11125, 11096, 11067, 11038, 11009, 10980, 10951, 10923, 10894, 10866, 10838,
+ 10810, 10782, 10755, 10727, 10700, 10673, 10645, 10618, 10592, 10565, 10538,
+ 10512, 10486, 10460, 10434, 10408, 10382, 10356, 10331, 10305, 10280, 10255,
+ 10230, 10205, 10180, 10156, 10131, 10107, 10082, 10058, 10034, 10010, 9986,
+ 9963, 9939, 9916, 9892, 9869, 9846, 9823, 9800, 9777, 9754, 9732,
+ 9709, 9687, 9664, 9642, 9620, 9598, 9576, 9554, 9533, 9511, 9489,
+ 9468, 9447, 9425, 9404, 9383, 9362, 9341, 9321, 9300, 9279, 9259,
+ 9239, 9218, 9198, 9178, 9158, 9138, 9118, 9098, 9079, 9059, 9039,
+ 9020, 9001, 8981, 8962, 8943, 8924, 8905, 8886, 8867, 8849, 8830,
+ 8812, 8793, 8775, 8756, 8738, 8720, 8702, 8684, 8666, 8648, 8630,
+ 8613, 8595, 8577, 8560, 8542, 8525, 8508, 8490, 8473, 8456, 8439,
+ 8422, 8405, 8389, 8372, 8355, 8339, 8322, 8306, 8289, 8273, 8257,
+ 8240, 8224, 8208, 8192
+};
+
static uint32_t inverse_recenter(int r, uint32_t v)
{
if (v > 2 * r)
@@ -97,6 +125,70 @@ static void read_global_param(AV1DecContext *s, int type, int ref, int idx)
-mx, mx + 1, r) << prec_diff) + round;
}
+static uint64_t round_two(uint64_t x, uint16_t n)
+{
+ if (n == 0)
+ return x;
+ return ((x + ((uint64_t)1 << (n - 1))) >> n);
+}
+
+static int64_t round_two_signed(int64_t x, uint16_t n)
+{
+ return ((x<0) ? -((int64_t)round_two(-x, n)) : (int64_t)round_two(x, n));
+}
+
+/**
+ * Resolve divisor process.
+ * see spec 7.11.3.7
+ */
+static int16_t resolve_divisor(uint32_t d, uint16_t *shift)
+{
+ int32_t e, f;
+
+ *shift = av_log2(d);
+ e = d - (1 << (*shift));
+ if (*shift > AV1_DIV_LUT_BITS)
+ f = round_two(e, *shift - AV1_DIV_LUT_BITS);
+ else
+ f = e << (AV1_DIV_LUT_BITS - (*shift));
+
+ *shift += AV1_DIV_LUT_PREC_BITS;
+
+ return div_lut[f];
+}
+
+/**
+ * check if global motion params is valid.
+ * see spec 7.11.3.6
+ */
+static uint8_t get_shear_params_valid(AV1DecContext *s, int idx)
+{
+ int16_t alpha, beta, gamma, delta, divf, divs;
+ int64_t v, w;
+ int32_t *param = &s->cur_frame.gm_params[idx][0];
+ if (param[2] < 0)
+ return 0;
+
+ alpha = av_clip_int16(param[2] - (1 << AV1_WARPEDMODEL_PREC_BITS));
+ beta = av_clip_int16(param[3]);
+ divf = resolve_divisor(abs(param[2]), &divs);
+ v = (int64_t)param[4] * (1 << AV1_WARPEDMODEL_PREC_BITS);
+ w = (int64_t)param[3] * param[4];
+ gamma = av_clip_int16((int)round_two_signed((v * divf), divs));
+ delta = av_clip_int16(param[5] - (int)round_two_signed((w * divf), divs) - (1 << AV1_WARPEDMODEL_PREC_BITS));
+
+ alpha = round_two_signed(alpha, AV1_WARP_PARAM_REDUCE_BITS) << AV1_WARP_PARAM_REDUCE_BITS;
+ beta = round_two_signed(beta, AV1_WARP_PARAM_REDUCE_BITS) << AV1_WARP_PARAM_REDUCE_BITS;
+ gamma = round_two_signed(gamma, AV1_WARP_PARAM_REDUCE_BITS) << AV1_WARP_PARAM_REDUCE_BITS;
+ delta = round_two_signed(delta, AV1_WARP_PARAM_REDUCE_BITS) << AV1_WARP_PARAM_REDUCE_BITS;
+
+ if ((4 * abs(alpha) + 7 * abs(beta)) >= (1 << AV1_WARPEDMODEL_PREC_BITS) ||
+ (4 * abs(gamma) + 4 * abs(delta)) >= (1 << AV1_WARPEDMODEL_PREC_BITS))
+ return 0;
+
+ return 1;
+}
+
/**
* update gm type/params, since cbs already implemented part of this funcation,
* so we don't need to full implement spec.
@@ -144,6 +236,9 @@ static void global_motion_params(AV1DecContext *s)
read_global_param(s, type, ref, 0);
read_global_param(s, type, ref, 1);
}
+ if (type <= AV1_WARP_MODEL_AFFINE) {
+ s->cur_frame.gm_invalid[ref] = !get_shear_params_valid(s, ref);
+ }
}
}
@@ -509,6 +604,9 @@ static int av1_frame_ref(AVCodecContext *avctx, AV1Frame *dst, const AV1Frame *s
dst->spatial_id = src->spatial_id;
dst->temporal_id = src->temporal_id;
+ memcpy(dst->gm_invalid,
+ src->gm_invalid,
+ AV1_NUM_REF_FRAMES * sizeof(uint8_t));
memcpy(dst->gm_type,
src->gm_type,
AV1_NUM_REF_FRAMES * sizeof(uint8_t));
diff --git a/libavcodec/av1dec.h b/libavcodec/av1dec.h
index 248a68750f..4e140588b9 100644
--- a/libavcodec/av1dec.h
+++ b/libavcodec/av1dec.h
@@ -42,6 +42,7 @@ typedef struct AV1Frame {
int temporal_id;
int spatial_id;
+ uint8_t gm_invalid[AV1_NUM_REF_FRAMES];
uint8_t gm_type[AV1_NUM_REF_FRAMES];
int32_t gm_params[AV1_NUM_REF_FRAMES][6];
From ad58733c84c131216e04ceb39d0dff64bfac5a2c Mon Sep 17 00:00:00 2001
From: Fei Wang <fei.w.wang@intel.com>
Date: Tue, 12 Oct 2021 16:23:59 +0800
Subject: [PATCH 10/15] avcodec/av1_vaapi: add gm params valid check
Signed-off-by: Fei Wang <fei.w.wang@intel.com>
(cherry picked from commit 0d0ea70e7bdd85def85d526480d728740a371744)
(cherry picked from commit 8b9a48b7aa3c14103f975035bb18601b13ed1707)
---
libavcodec/vaapi_av1.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libavcodec/vaapi_av1.c b/libavcodec/vaapi_av1.c
index 16b7e35747..f577447be4 100644
--- a/libavcodec/vaapi_av1.c
+++ b/libavcodec/vaapi_av1.c
@@ -213,7 +213,8 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx,
frame_header->height_in_sbs_minus_1[i];
}
for (int i = AV1_REF_FRAME_LAST; i <= AV1_REF_FRAME_ALTREF; i++) {
- pic_param.wm[i - 1].wmtype = s->cur_frame.gm_type[i];
+ pic_param.wm[i - 1].invalid = s->cur_frame.gm_invalid[i];
+ pic_param.wm[i - 1].wmtype = s->cur_frame.gm_type[i];
for (int j = 0; j < 6; j++)
pic_param.wm[i - 1].wmmat[j] = s->cur_frame.gm_params[i][j];
}
From fd1acddbee3686c97c2c38cc4befea38794eb44d Mon Sep 17 00:00:00 2001
From: Tong Wu <tong1.wu@intel.com>
Date: Tue, 12 Oct 2021 16:24:00 +0800
Subject: [PATCH 11/15] avcodec/dxva2_av1: fix global motion params
Defined in spec 5.9.24/5.9.25. Since function void
global_motion_params(AV1DecContext *s) already updates
gm type/params, the wminvalid parameter only need to get
the value from cur_frame.gm_invalid.
Signed-off-by: Tong Wu <tong1.wu@intel.com>
(cherry picked from commit 4e7a7d75e3c21a6af03c4cd52ffc50270664e58a)
(cherry picked from commit 03f5a57b9364d7ce789589594450fdf714a23e70)
---
libavcodec/dxva2_av1.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libavcodec/dxva2_av1.c b/libavcodec/dxva2_av1.c
index c30b57799c..8a912bf6c1 100644
--- a/libavcodec/dxva2_av1.c
+++ b/libavcodec/dxva2_av1.c
@@ -139,7 +139,7 @@ static int fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *c
pp->frame_refs[i].Index = ref_frame->buf[0] ? ref_idx : 0xFF;
/* Global Motion */
- pp->frame_refs[i].wminvalid = (h->cur_frame.gm_type[AV1_REF_FRAME_LAST + i] == AV1_WARP_MODEL_IDENTITY);
+ pp->frame_refs[i].wminvalid = h->cur_frame.gm_invalid[AV1_REF_FRAME_LAST + i];
pp->frame_refs[i].wmtype = h->cur_frame.gm_type[AV1_REF_FRAME_LAST + i];
for (j = 0; j < 6; ++j) {
pp->frame_refs[i].wmmat[j] = h->cur_frame.gm_params[AV1_REF_FRAME_LAST + i][j];
From 06181d3fd98d040ad2e1cb297896b3ba9235a9b4 Mon Sep 17 00:00:00 2001
From: Fei Wang <fei.w.wang@intel.com>
Date: Tue, 12 Oct 2021 16:24:01 +0800
Subject: [PATCH 12/15] avcodec/vaapi: increase av1 decode pool size
For film grain clip, vaapi_av1 decoder will cache additional 8
surfaces that will be used to store frames which apply film grain.
So increase the pool size by plus 8 to avoid leak of surface.
Signed-off-by: Fei Wang <fei.w.wang@intel.com>
(cherry picked from commit 53403158cc19b9e5baeff6af9317f14d1a20d0cb)
(cherry picked from commit 5774a0524c0851293a36acf3f3586e7c39a64b4a)
---
libavcodec/vaapi_decode.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
index 57a0eb4e6e..032e8531f2 100644
--- a/libavcodec/vaapi_decode.c
+++ b/libavcodec/vaapi_decode.c
@@ -577,10 +577,10 @@ static int vaapi_decode_make_config(AVCodecContext *avctx,
switch (avctx->codec_id) {
case AV_CODEC_ID_H264:
case AV_CODEC_ID_HEVC:
+ case AV_CODEC_ID_AV1:
frames->initial_pool_size += 16;
break;
case AV_CODEC_ID_VP9:
- case AV_CODEC_ID_AV1:
frames->initial_pool_size += 8;
break;
case AV_CODEC_ID_VP8:
From 1d82fef4ddc4e5512219c8c0e2e93fe351d1f65a Mon Sep 17 00:00:00 2001
From: Fei Wang <fei.w.wang@intel.com>
Date: Tue, 12 Oct 2021 16:24:02 +0800
Subject: [PATCH 13/15] avcodec/av1_vaapi: setting 2 output surface for film
grain
VAAPI needs 2 output surface for film grain frame. One used for
reference and the other used for applying film grain and pushing
to downstream.
Signed-off-by: Fei Wang <fei.w.wang@intel.com>
(cherry picked from commit 7871144cf801bc8b9e3b00319dd7c3c3d91dd3fa)
(cherry picked from commit 5962698d25f148d6b89dc4e526fffc5db2295f1e)
---
libavcodec/vaapi_av1.c | 115 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 108 insertions(+), 7 deletions(-)
diff --git a/libavcodec/vaapi_av1.c b/libavcodec/vaapi_av1.c
index f577447be4..26476c7738 100644
--- a/libavcodec/vaapi_av1.c
+++ b/libavcodec/vaapi_av1.c
@@ -21,8 +21,28 @@
#include "libavutil/pixdesc.h"
#include "hwconfig.h"
#include "vaapi_decode.h"
+#include "internal.h"
#include "av1dec.h"
+typedef struct VAAPIAV1FrameRef {
+ ThreadFrame frame;
+ int valid;
+} VAAPIAV1FrameRef;
+
+typedef struct VAAPIAV1DecContext {
+ VAAPIDecodeContext base;
+
+ /**
+ * For film grain case, VAAPI generate 2 output for each frame,
+ * current_frame will not apply film grain, and will be used for
+ * references for next frames. Maintain the reference list without
+ * applying film grain here. And current_display_picture will be
+ * used to apply film grain and push to downstream.
+ */
+ VAAPIAV1FrameRef ref_tab[AV1_NUM_REF_FRAMES];
+ ThreadFrame tmp_frame;
+} VAAPIAV1DecContext;
+
static VASurfaceID vaapi_av1_surface_id(AV1Frame *vf)
{
if (vf)
@@ -49,6 +69,48 @@ static int8_t vaapi_av1_get_bit_depth_idx(AVCodecContext *avctx)
return bit_depth == 8 ? 0 : bit_depth == 10 ? 1 : 2;
}
+static int vaapi_av1_decode_init(AVCodecContext *avctx)
+{
+ VAAPIAV1DecContext *ctx = avctx->internal->hwaccel_priv_data;
+
+ ctx->tmp_frame.f = av_frame_alloc();
+ if (!ctx->tmp_frame.f) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to allocate frame.\n");
+ return AVERROR(ENOMEM);
+ }
+
+ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->ref_tab); i++) {
+ ctx->ref_tab[i].frame.f = av_frame_alloc();
+ if (!ctx->ref_tab[i].frame.f) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to allocate reference table frame %d.\n", i);
+ return AVERROR(ENOMEM);
+ }
+ ctx->ref_tab[i].valid = 0;
+ }
+
+ return ff_vaapi_decode_init(avctx);
+}
+
+static int vaapi_av1_decode_uninit(AVCodecContext *avctx)
+{
+ VAAPIAV1DecContext *ctx = avctx->internal->hwaccel_priv_data;
+
+ if (ctx->tmp_frame.f->buf[0])
+ ff_thread_release_buffer(avctx, &ctx->tmp_frame);
+ av_frame_free(&ctx->tmp_frame.f);
+
+ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->ref_tab); i++) {
+ if (ctx->ref_tab[i].frame.f->buf[0])
+ ff_thread_release_buffer(avctx, &ctx->ref_tab[i].frame);
+ av_frame_free(&ctx->ref_tab[i].frame.f);
+ }
+
+ return ff_vaapi_decode_uninit(avctx);
+}
+
+
static int vaapi_av1_start_frame(AVCodecContext *avctx,
av_unused const uint8_t *buffer,
av_unused uint32_t size)
@@ -58,18 +120,28 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx,
const AV1RawFrameHeader *frame_header = s->raw_frame_header;
const AV1RawFilmGrainParams *film_grain = &s->cur_frame.film_grain;
VAAPIDecodePicture *pic = s->cur_frame.hwaccel_picture_private;
+ VAAPIAV1DecContext *ctx = avctx->internal->hwaccel_priv_data;
VADecPictureParameterBufferAV1 pic_param;
int8_t bit_depth_idx;
int err = 0;
int apply_grain = !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) && film_grain->apply_grain;
uint8_t remap_lr_type[4] = {AV1_RESTORE_NONE, AV1_RESTORE_SWITCHABLE, AV1_RESTORE_WIENER, AV1_RESTORE_SGRPROJ};
- pic->output_surface = vaapi_av1_surface_id(&s->cur_frame);
-
bit_depth_idx = vaapi_av1_get_bit_depth_idx(avctx);
if (bit_depth_idx < 0)
goto fail;
+ if (apply_grain) {
+ if (ctx->tmp_frame.f->buf[0])
+ ff_thread_release_buffer(avctx, &ctx->tmp_frame);
+ err = ff_thread_get_buffer(avctx, &ctx->tmp_frame, AV_GET_BUFFER_FLAG_REF);
+ if (err < 0)
+ goto fail;
+ pic->output_surface = ff_vaapi_get_surface_id(ctx->tmp_frame.f);
+ } else {
+ pic->output_surface = vaapi_av1_surface_id(&s->cur_frame);
+ }
+
memset(&pic_param, 0, sizeof(VADecPictureParameterBufferAV1));
pic_param = (VADecPictureParameterBufferAV1) {
.profile = seq->seq_profile,
@@ -77,6 +149,7 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx,
.bit_depth_idx = bit_depth_idx,
.current_frame = pic->output_surface,
.current_display_picture = pic->output_surface,
+ .current_display_picture = vaapi_av1_surface_id(&s->cur_frame),
.frame_width_minus1 = frame_header->frame_width_minus_1,
.frame_height_minus1 = frame_header->frame_height_minus_1,
.primary_ref_frame = frame_header->primary_ref_frame,
@@ -185,7 +258,9 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx,
if (pic_param.pic_info_fields.bits.frame_type == AV1_FRAME_KEY)
pic_param.ref_frame_map[i] = VA_INVALID_ID;
else
- pic_param.ref_frame_map[i] = vaapi_av1_surface_id(&s->ref[i]);
+ pic_param.ref_frame_map[i] = ctx->ref_tab[i].valid ?
+ ff_vaapi_get_surface_id(ctx->ref_tab[i].frame.f) :
+ vaapi_av1_surface_id(&s->ref[i]);
}
for (int i = 0; i < AV1_REFS_PER_FRAME; i++) {
pic_param.ref_frame_idx[i] = frame_header->ref_frame_idx[i];
@@ -264,8 +339,34 @@ fail:
static int vaapi_av1_end_frame(AVCodecContext *avctx)
{
const AV1DecContext *s = avctx->priv_data;
+ const AV1RawFrameHeader *header = s->raw_frame_header;
+ const AV1RawFilmGrainParams *film_grain = &s->cur_frame.film_grain;
VAAPIDecodePicture *pic = s->cur_frame.hwaccel_picture_private;
- return ff_vaapi_decode_issue(avctx, pic);
+ VAAPIAV1DecContext *ctx = avctx->internal->hwaccel_priv_data;
+
+ int apply_grain = !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) && film_grain->apply_grain;
+ int ret;
+ ret = ff_vaapi_decode_issue(avctx, pic);
+ if (ret < 0)
+ return ret;
+
+ for (int i = 0; i < AV1_NUM_REF_FRAMES; i++) {
+ if (header->refresh_frame_flags & (1 << i)) {
+ if (ctx->ref_tab[i].frame.f->buf[0])
+ ff_thread_release_buffer(avctx, &ctx->ref_tab[i].frame);
+
+ if (apply_grain) {
+ ret = ff_thread_ref_frame(&ctx->ref_tab[i].frame, &ctx->tmp_frame);
+ if (ret < 0)
+ return ret;
+ ctx->ref_tab[i].valid = 1;
+ } else {
+ ctx->ref_tab[i].valid = 0;
+ }
+ }
+ }
+
+ return 0;
}
static int vaapi_av1_decode_slice(AVCodecContext *avctx,
@@ -312,9 +413,9 @@ const AVHWAccel ff_av1_vaapi_hwaccel = {
.end_frame = vaapi_av1_end_frame,
.decode_slice = vaapi_av1_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
- .init = ff_vaapi_decode_init,
- .uninit = ff_vaapi_decode_uninit,
+ .init = vaapi_av1_decode_init,
+ .uninit = vaapi_av1_decode_uninit,
.frame_params = ff_vaapi_common_frame_params,
- .priv_data_size = sizeof(VAAPIDecodeContext),
+ .priv_data_size = sizeof(VAAPIAV1DecContext),
.caps_internal = HWACCEL_CAP_ASYNC_SAFE,
};
From be18092cec1867b5e30525e023f49c5e7547931b Mon Sep 17 00:00:00 2001
From: Fei Wang <fei.w.wang@intel.com>
Date: Tue, 12 Oct 2021 16:24:03 +0800
Subject: [PATCH 14/15] avcodec/av1_vaapi: enable segmentation features
Signed-off-by: Fei Wang <fei.w.wang@intel.com>
(cherry picked from commit dc94f2eaaf0ae623d7dc02e1273c829015c025a3)
(cherry picked from commit 582fb329a483774f0345cbfebc3a12f0ad8f5bba)
---
libavcodec/vaapi_av1.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/libavcodec/vaapi_av1.c b/libavcodec/vaapi_av1.c
index 26476c7738..c57d1b898a 100644
--- a/libavcodec/vaapi_av1.c
+++ b/libavcodec/vaapi_av1.c
@@ -126,6 +126,9 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx,
int err = 0;
int apply_grain = !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) && film_grain->apply_grain;
uint8_t remap_lr_type[4] = {AV1_RESTORE_NONE, AV1_RESTORE_SWITCHABLE, AV1_RESTORE_WIENER, AV1_RESTORE_SGRPROJ};
+ uint8_t segmentation_feature_signed[AV1_SEG_LVL_MAX] = {1, 1, 1, 1, 1, 0, 0, 0};
+ uint8_t segmentation_feature_max[AV1_SEG_LVL_MAX] = {255, AV1_MAX_LOOP_FILTER,
+ AV1_MAX_LOOP_FILTER, AV1_MAX_LOOP_FILTER, AV1_MAX_LOOP_FILTER, 7 , 0 , 0 };
bit_depth_idx = vaapi_av1_get_bit_depth_idx(avctx);
if (bit_depth_idx < 0)
@@ -293,6 +296,17 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx,
for (int j = 0; j < 6; j++)
pic_param.wm[i - 1].wmmat[j] = s->cur_frame.gm_params[i][j];
}
+ for (int i = 0; i < AV1_MAX_SEGMENTS; i++) {
+ for (int j = 0; j < AV1_SEG_LVL_MAX; j++) {
+ pic_param.seg_info.feature_mask[i] |= (frame_header->feature_enabled[i][j] << j);
+ if (segmentation_feature_signed[j])
+ pic_param.seg_info.feature_data[i][j] = av_clip(frame_header->feature_value[i][j],
+ -segmentation_feature_max[j], segmentation_feature_max[j]);
+ else
+ pic_param.seg_info.feature_data[i][j] = av_clip(frame_header->feature_value[i][j],
+ 0, segmentation_feature_max[j]);
+ }
+ }
if (apply_grain) {
for (int i = 0; i < film_grain->num_y_points; i++) {
pic_param.film_grain_info.point_y_value[i] =
From 293e067b0c0f592628ee0de71769ed2e9c3d07f2 Mon Sep 17 00:00:00 2001
From: Fei Wang <fei.w.wang@intel.com>
Date: Tue, 12 Oct 2021 16:24:04 +0800
Subject: [PATCH 15/15] avcodec/av1_vaapi: improve decode quality
- quantizer delta and matrix level specific.
- support loop filter delta.
- support use superres.
Signed-off-by: Fei Wang <fei.w.wang@intel.com>
(cherry picked from commit 84c73102d933c9b7f64f504196c91edddad99618)
(cherry picked from commit 2c887141b8318b7d4b198461bbb8d94ac662a96c)
---
libavcodec/vaapi_av1.c | 68 +++++++++++++++++++++++++-----------------
1 file changed, 41 insertions(+), 27 deletions(-)
diff --git a/libavcodec/vaapi_av1.c b/libavcodec/vaapi_av1.c
index c57d1b898a..5985493b8d 100644
--- a/libavcodec/vaapi_av1.c
+++ b/libavcodec/vaapi_av1.c
@@ -147,27 +147,35 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx,
memset(&pic_param, 0, sizeof(VADecPictureParameterBufferAV1));
pic_param = (VADecPictureParameterBufferAV1) {
- .profile = seq->seq_profile,
- .order_hint_bits_minus_1 = seq->order_hint_bits_minus_1,
- .bit_depth_idx = bit_depth_idx,
- .current_frame = pic->output_surface,
- .current_display_picture = pic->output_surface,
- .current_display_picture = vaapi_av1_surface_id(&s->cur_frame),
- .frame_width_minus1 = frame_header->frame_width_minus_1,
- .frame_height_minus1 = frame_header->frame_height_minus_1,
- .primary_ref_frame = frame_header->primary_ref_frame,
- .order_hint = frame_header->order_hint,
- .tile_cols = frame_header->tile_cols,
- .tile_rows = frame_header->tile_rows,
- .context_update_tile_id = frame_header->context_update_tile_id,
- .interp_filter = frame_header->interpolation_filter,
- .filter_level[0] = frame_header->loop_filter_level[0],
- .filter_level[1] = frame_header->loop_filter_level[1],
- .filter_level_u = frame_header->loop_filter_level[2],
- .filter_level_v = frame_header->loop_filter_level[3],
- .base_qindex = frame_header->base_q_idx,
- .cdef_damping_minus_3 = frame_header->cdef_damping_minus_3,
- .cdef_bits = frame_header->cdef_bits,
+ .profile = seq->seq_profile,
+ .order_hint_bits_minus_1 = seq->order_hint_bits_minus_1,
+ .bit_depth_idx = bit_depth_idx,
+ .matrix_coefficients = seq->color_config.matrix_coefficients,
+ .current_frame = pic->output_surface,
+ .current_display_picture = vaapi_av1_surface_id(&s->cur_frame),
+ .frame_width_minus1 = frame_header->frame_width_minus_1,
+ .frame_height_minus1 = frame_header->frame_height_minus_1,
+ .primary_ref_frame = frame_header->primary_ref_frame,
+ .order_hint = frame_header->order_hint,
+ .tile_cols = frame_header->tile_cols,
+ .tile_rows = frame_header->tile_rows,
+ .context_update_tile_id = frame_header->context_update_tile_id,
+ .superres_scale_denominator = frame_header->use_superres ?
+ frame_header->coded_denom + AV1_SUPERRES_DENOM_MIN :
+ AV1_SUPERRES_NUM,
+ .interp_filter = frame_header->interpolation_filter,
+ .filter_level[0] = frame_header->loop_filter_level[0],
+ .filter_level[1] = frame_header->loop_filter_level[1],
+ .filter_level_u = frame_header->loop_filter_level[2],
+ .filter_level_v = frame_header->loop_filter_level[3],
+ .base_qindex = frame_header->base_q_idx,
+ .y_dc_delta_q = frame_header->delta_q_y_dc,
+ .u_dc_delta_q = frame_header->delta_q_u_dc,
+ .u_ac_delta_q = frame_header->delta_q_u_ac,
+ .v_dc_delta_q = frame_header->delta_q_v_dc,
+ .v_ac_delta_q = frame_header->delta_q_v_ac,
+ .cdef_damping_minus_3 = frame_header->cdef_damping_minus_3,
+ .cdef_bits = frame_header->cdef_bits,
.seq_info_fields.fields = {
.still_picture = seq->still_picture,
.use_128x128_superblock = seq->use_128x128_superblock,
@@ -238,12 +246,15 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx,
.mode_ref_delta_update = frame_header->loop_filter_delta_update,
},
.mode_control_fields.bits = {
- .delta_q_present_flag = frame_header->delta_q_present,
- .log2_delta_q_res = frame_header->delta_q_res,
- .tx_mode = frame_header->tx_mode,
- .reference_select = frame_header->reference_select,
- .reduced_tx_set_used = frame_header->reduced_tx_set,
- .skip_mode_present = frame_header->skip_mode_present,
+ .delta_q_present_flag = frame_header->delta_q_present,
+ .log2_delta_q_res = frame_header->delta_q_res,
+ .delta_lf_present_flag = frame_header->delta_lf_present,
+ .log2_delta_lf_res = frame_header->delta_lf_res,
+ .delta_lf_multi = frame_header->delta_lf_multi,
+ .tx_mode = frame_header->tx_mode,
+ .reference_select = frame_header->reference_select,
+ .reduced_tx_set_used = frame_header->reduced_tx_set,
+ .skip_mode_present = frame_header->skip_mode_present,
},
.loop_restoration_fields.bits = {
.yframe_restoration_type = remap_lr_type[frame_header->lr_type[0]],
@@ -254,6 +265,9 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx,
},
.qmatrix_fields.bits = {
.using_qmatrix = frame_header->using_qmatrix,
+ .qm_y = frame_header->qm_y,
+ .qm_u = frame_header->qm_u,
+ .qm_v = frame_header->qm_v,
}
};

View File

@ -1,4 +1,4 @@
From 8f7c8a0f9e28641880d72996b9452e0a9da1288c Mon Sep 17 00:00:00 2001
From 3c53cf80b0de8af387694a464bdce294988d0fa5 Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Wed, 10 Apr 2019 13:39:21 -0700
Subject: [PATCH 1/2] libavcodec/libdav1d: add libdav1d_get_format method to
@ -18,10 +18,10 @@ decoding is properly activated.
1 file changed, 11 insertions(+)
diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index 3c2a68b7e0..68996426cc 100644
index 0a46cf2264..1f4e708bcf 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -58,6 +58,16 @@ static const enum AVPixelFormat pix_fmt_rgb[3] = {
@@ -66,6 +66,16 @@ static const enum AVPixelFormat pix_fmt_rgb[3] = {
AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
};
@ -38,16 +38,16 @@ index 3c2a68b7e0..68996426cc 100644
static void libdav1d_log_callback(void *opaque, const char *fmt, va_list vl)
{
AVCodecContext *c = opaque;
@@ -264,6 +274,7 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame)
c->profile = p->seq_hdr->profile;
c->level = ((p->seq_hdr->operating_points[0].major_level - 2) << 2)
| p->seq_hdr->operating_points[0].minor_level;
@@ -390,6 +400,7 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame)
if (res < 0)
goto fail;
+ frame->format = c->pix_fmt = libdav1d_get_format(c, p);
frame->width = p->p.w;
frame->height = p->p.h;
if (c->width != p->p.w || c->height != p->p.h) {
From 635cf67be3d37159c96e75f00399b3e232372251 Mon Sep 17 00:00:00 2001
From 3af25a2cae2ad3152e2969eefd9f13c9bb183969 Mon Sep 17 00:00:00 2001
From: chewitt <github@chrishewitt.net>
Date: Sun, 11 Aug 2019 07:08:19 +0000
Subject: [PATCH 2/2] add long-term yuv2rgb logging patch
@ -57,7 +57,7 @@ Subject: [PATCH 2/2] add long-term yuv2rgb logging patch
1 file changed, 4 deletions(-)
diff --git a/libswscale/yuv2rgb.c b/libswscale/yuv2rgb.c
index 6a3956e8e2..d6f9aea166 100644
index 6ee483d12a..c22161741b 100644
--- a/libswscale/yuv2rgb.c
+++ b/libswscale/yuv2rgb.c
@@ -688,10 +688,6 @@ SwsFunc ff_yuv2rgb_get_func_ptr(SwsContext *c)

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
From 1e73397d52d69378ebac5a390da508cd16d7d97e Mon Sep 17 00:00:00 2001
From c4be609d822229be09cd9dd6f64cad716b0a48ce Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Tue, 24 Apr 2018 23:00:23 -0700
Subject: [PATCH 1/9] libavcodec: v4l2m2m: output AVDRMFrameDescriptor
@ -42,7 +42,7 @@ V5:
5 files changed, 213 insertions(+), 12 deletions(-)
diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
index 4b2679eb38..cbd3e5680d 100644
index 3f5471067a..07662b5fc3 100644
--- a/libavcodec/v4l2_buffers.c
+++ b/libavcodec/v4l2_buffers.c
@@ -21,6 +21,7 @@
@ -53,15 +53,15 @@ index 4b2679eb38..cbd3e5680d 100644
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -30,6 +31,7 @@
@@ -29,6 +30,7 @@
#include <poll.h>
#include "libavcodec/avcodec.h"
#include "libavcodec/internal.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/hwcontext.h"
#include "v4l2_context.h"
#include "v4l2_buffers.h"
#include "v4l2_m2m.h"
@@ -210,7 +212,79 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf)
@@ -209,7 +211,79 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf)
return AVCOL_TRC_UNSPECIFIED;
}
@ -142,7 +142,7 @@ index 4b2679eb38..cbd3e5680d 100644
{
V4L2Buffer* avbuf = opaque;
V4L2m2mContext *s = buf_to_m2mctx(avbuf);
@@ -234,6 +308,36 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused)
@@ -233,6 +307,36 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused)
}
}
@ -179,7 +179,7 @@ index 4b2679eb38..cbd3e5680d 100644
static int v4l2_buf_increase_ref(V4L2Buffer *in)
{
V4L2m2mContext *s = buf_to_m2mctx(in);
@@ -254,6 +358,24 @@ static int v4l2_buf_increase_ref(V4L2Buffer *in)
@@ -253,6 +357,24 @@ static int v4l2_buf_increase_ref(V4L2Buffer *in)
return 0;
}
@ -204,7 +204,7 @@ index 4b2679eb38..cbd3e5680d 100644
static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf)
{
int ret;
@@ -303,13 +425,24 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
@@ -302,13 +424,24 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
frame->format = avbuf->context->av_pix_fmt;
@ -233,7 +233,7 @@ index 4b2679eb38..cbd3e5680d 100644
}
/* fixup special cases */
@@ -543,9 +676,6 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
@@ -542,9 +675,6 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
avbuf->status = V4L2BUF_AVAILABLE;
@ -243,7 +243,7 @@ index 4b2679eb38..cbd3e5680d 100644
if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
avbuf->buf.m.planes = avbuf->planes;
avbuf->buf.length = avbuf->num_planes;
@@ -555,6 +685,15 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
@@ -554,6 +684,15 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
avbuf->buf.length = avbuf->planes[0].length;
}
@ -260,18 +260,18 @@ index 4b2679eb38..cbd3e5680d 100644
}
diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h
index 8dbc7fc104..037e667997 100644
index 3d2ff1b9a5..b82c990dcc 100644
--- a/libavcodec/v4l2_buffers.h
+++ b/libavcodec/v4l2_buffers.h
@@ -27,6 +27,7 @@
#include <stdatomic.h>
#include <linux/videodev2.h>
@@ -30,6 +30,7 @@
#include "libavutil/buffer.h"
#include "libavutil/frame.h"
+#include "libavutil/hwcontext_drm.h"
#include "avcodec.h"
#include "packet.h"
enum V4L2Buffer_status {
@@ -42,6 +43,9 @@ typedef struct V4L2Buffer {
@@ -45,6 +46,9 @@ typedef struct V4L2Buffer {
/* each buffer needs to have a reference to its context */
struct V4L2Context *context;
@ -282,10 +282,10 @@ index 8dbc7fc104..037e667997 100644
* of how many context-refs we are holding. */
AVBufferRef *context_ref;
diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
index ff1ea8e57b..e9e8c27a54 100644
index e891649f92..4de23e687c 100644
--- a/libavcodec/v4l2_context.c
+++ b/libavcodec/v4l2_context.c
@@ -455,22 +455,54 @@ static int v4l2_release_buffers(V4L2Context* ctx)
@@ -441,22 +441,54 @@ static int v4l2_release_buffers(V4L2Context* ctx)
struct v4l2_requestbuffers req = {
.memory = V4L2_MEMORY_MMAP,
.type = ctx->type,
@ -359,7 +359,7 @@ index b67b216331..0fbd19a013 100644
typedef struct V4L2m2mPriv {
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index ab07c0a24a..6bc7442702 100644
index 8a51dec3fa..d916a3b726 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -23,6 +23,9 @@
@ -373,8 +373,8 @@ index ab07c0a24a..6bc7442702 100644
#include "libavutil/pixdesc.h"
#include "libavutil/opt.h"
@@ -30,6 +33,9 @@
#include "codec_internal.h"
#include "libavcodec/decode.h"
#include "libavcodec/internal.h"
+#include "libavcodec/hwaccels.h"
+#include "libavcodec/internal.h"
@ -382,7 +382,7 @@ index ab07c0a24a..6bc7442702 100644
#include "v4l2_context.h"
#include "v4l2_m2m.h"
#include "v4l2_fmt.h"
@@ -201,6 +207,15 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
@@ -205,6 +211,15 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
capture->av_codec_id = AV_CODEC_ID_RAWVIDEO;
capture->av_pix_fmt = avctx->pix_fmt;
@ -398,7 +398,7 @@ index ab07c0a24a..6bc7442702 100644
s->avctx = avctx;
ret = ff_v4l2_m2m_codec_init(priv);
if (ret) {
@@ -226,6 +241,11 @@ static const AVOption options[] = {
@@ -230,6 +245,11 @@ static const AVOption options[] = {
{ NULL},
};
@ -410,18 +410,18 @@ index ab07c0a24a..6bc7442702 100644
#define M2MDEC_CLASS(NAME) \
static const AVClass v4l2_m2m_ ## NAME ## _dec_class = { \
.class_name = #NAME "_v4l2m2m_decoder", \
@@ -249,6 +269,9 @@ static const AVOption options[] = {
@@ -253,6 +273,9 @@ static const AVOption options[] = {
.bsfs = bsf_name, \
.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
.p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
.caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_CLEANUP, \
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
+ .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
+ AV_PIX_FMT_NONE}, \
+ .hw_configs = v4l2_m2m_hw_configs, \
.wrapper_name = "v4l2m2m", \
.p.wrapper_name = "v4l2m2m", \
}
From deb0ba531401f069dc6e4dcf235dfc08bca6577c Mon Sep 17 00:00:00 2001
From bb47b0e2ce4dda5ddeb4568d2b0260ec950d68cd Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Thu, 16 Aug 2018 21:09:40 -0700
Subject: [PATCH 2/9] libavcodec: v4l2m2m: depends on libdrm
@ -432,10 +432,10 @@ Subject: [PATCH 2/9] libavcodec: v4l2m2m: depends on libdrm
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/configure b/configure
index 4ba72bf84b..efb065905c 100755
index ba5793b2ff..1872046e0e 100755
--- a/configure
+++ b/configure
@@ -3438,6 +3438,7 @@ sndio_indev_deps="sndio"
@@ -3539,6 +3539,7 @@ sndio_indev_deps="sndio"
sndio_outdev_deps="sndio"
v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h"
v4l2_indev_suggest="libv4l2"
@ -444,7 +444,7 @@ index 4ba72bf84b..efb065905c 100755
v4l2_outdev_suggest="libv4l2"
vfwcap_indev_deps="vfw32 vfwcap_defines"
diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
index cbd3e5680d..bebe2c1796 100644
index 07662b5fc3..d41558527c 100644
--- a/libavcodec/v4l2_buffers.c
+++ b/libavcodec/v4l2_buffers.c
@@ -21,7 +21,7 @@
@ -457,7 +457,7 @@ index cbd3e5680d..bebe2c1796 100644
#include <sys/ioctl.h>
#include <sys/mman.h>
From f89fad11f53110cd6968c83e89bafb0c449f34ec Mon Sep 17 00:00:00 2001
From a362c4ec155e5e38c7a1ed3d3c57054ba09d9945 Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Thu, 16 Aug 2018 21:10:13 -0700
Subject: [PATCH 3/9] libavcodec: v4l2m2m: set format_modifier to
@ -468,10 +468,10 @@ Subject: [PATCH 3/9] libavcodec: v4l2m2m: set format_modifier to
1 file changed, 2 insertions(+)
diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
index bebe2c1796..12037d5d66 100644
index d41558527c..95c8a1e409 100644
--- a/libavcodec/v4l2_buffers.c
+++ b/libavcodec/v4l2_buffers.c
@@ -328,10 +328,12 @@ static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
@@ -327,10 +327,12 @@ static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
/* drm frame */
avbuf->drm_frame.objects[i].size = avbuf->buf.m.planes[i].length;
avbuf->drm_frame.objects[i].fd = expbuf.fd;
@ -485,7 +485,7 @@ index bebe2c1796..12037d5d66 100644
}
From d5a37af1a8fe1ed70428e55286126d241986dd0c Mon Sep 17 00:00:00 2001
From d4c8398a40baae35c79c1baf7e99306edda53e1a Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Thu, 16 Aug 2018 21:10:53 -0700
Subject: [PATCH 4/9] libavcodec: v4l2m2m: only mmap the buffer when it is
@ -496,10 +496,10 @@ Subject: [PATCH 4/9] libavcodec: v4l2m2m: only mmap the buffer when it is
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
index 12037d5d66..1adf518ab9 100644
index 95c8a1e409..0a65f32cb2 100644
--- a/libavcodec/v4l2_buffers.c
+++ b/libavcodec/v4l2_buffers.c
@@ -662,14 +662,22 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
@@ -661,14 +661,22 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
avbuf->plane_info[i].length = avbuf->buf.m.planes[i].length;
@ -529,7 +529,7 @@ index 12037d5d66..1adf518ab9 100644
if (avbuf->plane_info[i].mm_addr == MAP_FAILED)
From d0be699166cdc413a5dc3e1c087433ac7cf142e7 Mon Sep 17 00:00:00 2001
From 5c468fefad99503d2fe53e5a83ef29a409f0abaa Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Thu, 16 Aug 2018 21:11:38 -0700
Subject: [PATCH 5/9] libavcodec: v4l2m2m: allow using software pixel formats
@ -539,10 +539,10 @@ Subject: [PATCH 5/9] libavcodec: v4l2m2m: allow using software pixel formats
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index 6bc7442702..4b9baf833c 100644
index d916a3b726..7787a2c185 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -213,8 +213,16 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
@@ -217,8 +217,16 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
* - the DRM frame format is passed in the DRM frame descriptor layer.
* check the v4l2_get_drm_frame function.
*/
@ -560,16 +560,16 @@ index 6bc7442702..4b9baf833c 100644
s->avctx = avctx;
ret = ff_v4l2_m2m_codec_init(priv);
@@ -270,6 +278,7 @@ static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = {
.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
@@ -274,6 +282,7 @@ static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = {
.p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
.caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_CLEANUP, \
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
.p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
+ AV_PIX_FMT_NV12, \
AV_PIX_FMT_NONE}, \
.hw_configs = v4l2_m2m_hw_configs, \
.wrapper_name = "v4l2m2m", \
.p.wrapper_name = "v4l2m2m", \
From c4736742883eb2a1965ac65a5c75d5409e3c85a0 Mon Sep 17 00:00:00 2001
From dd923e56e054df2f1bb275cef039b82e94fcbcb6 Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Mon, 24 Sep 2018 13:39:31 -0700
Subject: [PATCH 6/9] libavcodec: v4l2m2m: implement hwcontext
@ -582,10 +582,10 @@ Subject: [PATCH 6/9] libavcodec: v4l2m2m: implement hwcontext
4 files changed, 37 insertions(+)
diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
index 1adf518ab9..6e2a544394 100644
index 0a65f32cb2..a040d418d9 100644
--- a/libavcodec/v4l2_buffers.c
+++ b/libavcodec/v4l2_buffers.c
@@ -435,6 +435,7 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
@@ -434,6 +434,7 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
frame->data[0] = (uint8_t *) v4l2_get_drm_frame(avbuf);
frame->format = AV_PIX_FMT_DRM_PRIME;
@ -593,7 +593,7 @@ index 1adf518ab9..6e2a544394 100644
} else {
/* 1. get references to the actual data */
for (i = 0; i < avbuf->num_planes; i++) {
@@ -635,6 +636,27 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
@@ -634,6 +635,27 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
avbuf->buf.type = ctx->type;
avbuf->buf.index = index;
@ -622,10 +622,10 @@ index 1adf518ab9..6e2a544394 100644
avbuf->buf.length = VIDEO_MAX_PLANES;
avbuf->buf.m.planes = avbuf->planes;
diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h
index 22a9532444..e804e94131 100644
index 6f7460c89a..02fbb6eec3 100644
--- a/libavcodec/v4l2_context.h
+++ b/libavcodec/v4l2_context.h
@@ -92,6 +92,8 @@ typedef struct V4L2Context {
@@ -93,6 +93,8 @@ typedef struct V4L2Context {
*/
int done;
@ -648,7 +648,7 @@ index 0fbd19a013..adf5997bb5 100644
int output_drm;
} V4L2m2mContext;
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index 4b9baf833c..6c23693137 100644
index 7787a2c185..9aca68e48c 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -35,6 +35,7 @@
@ -659,7 +659,7 @@ index 4b9baf833c..6c23693137 100644
#include "v4l2_context.h"
#include "v4l2_m2m.h"
@@ -224,6 +225,16 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
@@ -228,6 +229,16 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
break;
}
@ -677,7 +677,7 @@ index 4b9baf833c..6c23693137 100644
ret = ff_v4l2_m2m_codec_init(priv);
if (ret) {
From 0b15c77718900bf60c91217ed1492390022ad6db Mon Sep 17 00:00:00 2001
From 32ca7163c62887aa4b4032bbd5858a03bf3e145e Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Mon, 4 May 2020 13:01:29 -0700
Subject: [PATCH 7/9] libavcodec: v4l2m2m: allow lower minimum buffer values
@ -705,10 +705,10 @@ index adf5997bb5..1082b9dad2 100644
typedef struct V4L2m2mContext {
char devname[PATH_MAX];
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index 6c23693137..e323c37052 100644
index 9aca68e48c..7afc81180d 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -256,7 +256,7 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx)
@@ -260,7 +260,7 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx)
static const AVOption options[] = {
V4L_M2M_DEFAULT_OPTS,
{ "num_capture_buffers", "Number of buffers in the capture context",
@ -718,7 +718,7 @@ index 6c23693137..e323c37052 100644
};
From acc86933e5fe3a13aae44cf84c48bab6c717e49b Mon Sep 17 00:00:00 2001
From 199d87bed11be1665913b88d7cae9417f48afa37 Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Wed, 6 May 2020 11:12:58 -0700
Subject: [PATCH 8/9] libavcodec: v4l2m2m: add option to specify pixel format
@ -731,10 +731,10 @@ Subject: [PATCH 8/9] libavcodec: v4l2m2m: add option to specify pixel format
3 files changed, 12 insertions(+)
diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
index e9e8c27a54..a97b70e836 100644
index 4de23e687c..49ef4a684f 100644
--- a/libavcodec/v4l2_context.c
+++ b/libavcodec/v4l2_context.c
@@ -531,6 +531,8 @@ static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfm
@@ -517,6 +517,8 @@ static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfm
static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p)
{
@ -743,7 +743,7 @@ index e9e8c27a54..a97b70e836 100644
enum AVPixelFormat pixfmt = ctx->av_pix_fmt;
struct v4l2_fmtdesc fdesc;
int ret;
@@ -549,6 +551,13 @@ static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p)
@@ -535,6 +537,13 @@ static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p)
if (ret)
return AVERROR(EINVAL);
@ -778,10 +778,10 @@ index 1082b9dad2..943a8923c4 100644
/**
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index e323c37052..363e998142 100644
index 7afc81180d..de89d0ff18 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -257,6 +257,7 @@ static const AVOption options[] = {
@@ -261,6 +261,7 @@ static const AVOption options[] = {
V4L_M2M_DEFAULT_OPTS,
{ "num_capture_buffers", "Number of buffers in the capture context",
OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 2, INT_MAX, FLAGS },
@ -790,7 +790,7 @@ index e323c37052..363e998142 100644
};
From 909ca6380d9112cc0111266da02a4a8e1e5abc1e Mon Sep 17 00:00:00 2001
From 38c65aab679c04e4dd5a58f889844e68e34c80ab Mon Sep 17 00:00:00 2001
From: Lukas Rusak <lorusak@gmail.com>
Date: Mon, 24 Sep 2018 13:39:56 -0700
Subject: [PATCH 9/9] libavcodec: v4l2m2m: implement flush
@ -800,10 +800,10 @@ Subject: [PATCH 9/9] libavcodec: v4l2m2m: implement flush
1 file changed, 36 insertions(+)
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index 363e998142..52ec67cb59 100644
index de89d0ff18..3278627553 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -250,6 +250,41 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx)
@@ -254,6 +254,41 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx)
return ff_v4l2_m2m_codec_end(avctx->priv_data);
}
@ -815,6 +815,11 @@ index 363e998142..52ec67cb59 100644
+ V4L2Context* capture = &s->capture;
+ int ret, i;
+
+ struct v4l2_decoder_cmd cmd = {
+ .cmd = V4L2_DEC_CMD_START,
+ .flags = 0,
+ };
+
+ ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMOFF);
+ if (ret < 0)
+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s error: %d\n", output->name, ret);
@ -828,11 +833,6 @@ index 363e998142..52ec67cb59 100644
+ output->buffers[i].status = V4L2BUF_AVAILABLE;
+ }
+
+ struct v4l2_decoder_cmd cmd = {
+ .cmd = V4L2_DEC_CMD_START,
+ .flags = 0,
+ };
+
+ ret = ioctl(s->fd, VIDIOC_DECODER_CMD, &cmd);
+ if (ret < 0)
+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_DECODER_CMD start error: %d\n", errno);
@ -845,11 +845,11 @@ index 363e998142..52ec67cb59 100644
#define OFFSET(x) offsetof(V4L2m2mPriv, x)
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
@@ -286,6 +321,7 @@ static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = {
@@ -290,6 +325,7 @@ static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = {
.init = v4l2_decode_init, \
.receive_frame = v4l2_receive_frame, \
FF_CODEC_RECEIVE_FRAME_CB(v4l2_receive_frame), \
.close = v4l2_decode_close, \
+ .flush = v4l2_decode_flush, \
.bsfs = bsf_name, \
.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
.p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
.caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_CLEANUP, \

View File

@ -1,20 +1,21 @@
From 39069d9cc03a42cd497dd6b9756116ff4b684a5d Mon Sep 17 00:00:00 2001
From d14859b090dc3b2e1bd761698b947b0b55e4d831 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 3 Dec 2019 21:01:18 +0100
Subject: [PATCH] WIP deint filter
Subject: [PATCH] Add V4L2 m2m deinterlace filter
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/vf_deinterlace_v4l2m2m.c | 879 +++++++++++++++++++++++++++
3 files changed, 881 insertions(+)
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/vf_deinterlace_v4l2m2m.c | 1009 ++++++++++++++++++++++++++
3 files changed, 1011 insertions(+)
create mode 100644 libavfilter/vf_deinterlace_v4l2m2m.c
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 512354065305..625fd29f9313 100644
index 30cc329fb6..2fe6ab223e 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -218,6 +218,7 @@ OBJS-$(CONFIG_DEFLATE_FILTER) += vf_neighbor.o
@@ -254,6 +254,7 @@ OBJS-$(CONFIG_DEFLATE_FILTER) += vf_neighbor.o
OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o
OBJS-$(CONFIG_DEINTERLACE_QSV_FILTER) += vf_deinterlace_qsv.o
OBJS-$(CONFIG_DEINTERLACE_VAAPI_FILTER) += vf_deinterlace_vaapi.o vaapi_vpp.o
@ -23,23 +24,23 @@ index 512354065305..625fd29f9313 100644
OBJS-$(CONFIG_DELOGO_FILTER) += vf_delogo.o
OBJS-$(CONFIG_DENOISE_VAAPI_FILTER) += vf_misc_vaapi.o vaapi_vpp.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 1183e4026751..fe5a2e8c02e8 100644
index 5ebacfde27..4b74bac3c8 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -204,6 +204,7 @@ extern AVFilter ff_vf_dedot;
extern AVFilter ff_vf_deflate;
extern AVFilter ff_vf_deflicker;
extern AVFilter ff_vf_deinterlace_qsv;
+extern AVFilter ff_vf_deinterlace_v4l2m2m;
extern AVFilter ff_vf_deinterlace_vaapi;
extern AVFilter ff_vf_dejudder;
extern AVFilter ff_vf_delogo;
@@ -234,6 +234,7 @@ extern const AVFilter ff_vf_dedot;
extern const AVFilter ff_vf_deflate;
extern const AVFilter ff_vf_deflicker;
extern const AVFilter ff_vf_deinterlace_qsv;
+extern const AVFilter ff_vf_deinterlace_v4l2m2m;
extern const AVFilter ff_vf_deinterlace_vaapi;
extern const AVFilter ff_vf_dejudder;
extern const AVFilter ff_vf_delogo;
diff --git a/libavfilter/vf_deinterlace_v4l2m2m.c b/libavfilter/vf_deinterlace_v4l2m2m.c
new file mode 100644
index 000000000000..1029e5b620fd
index 0000000000..ff5ed500a9
--- /dev/null
+++ b/libavfilter/vf_deinterlace_v4l2m2m.c
@@ -0,0 +1,879 @@
@@ -0,0 +1,1009 @@
+/*
+ * This file is part of FFmpeg.
+ *
@ -127,12 +128,21 @@ index 000000000000..1029e5b620fd
+ int height;
+ int orig_width;
+ int orig_height;
+ uint64_t drm_in_format;
+ uint64_t drm_out_format;
+
+ atomic_uint refcount;
+
+ AVBufferRef *hw_frames_ctx;
+
+ int frame_count;
+ AVFrame *frames[2];
+ /*
+ * TODO: check if its really neccessary to hold this
+ * ref, it's only used for freeing av_frame on decoding
+ * end/abort
+ */
+ AVFrame *cur_in_frame;
+ AVFrame *prev_in_frame;
+ unsigned int field_order;
+
+ V4L2Queue output;
+ V4L2Queue capture;
@ -144,6 +154,76 @@ index 000000000000..1029e5b620fd
+ DeintV4L2M2MContextShared *shared;
+} DeintV4L2M2MContext;
+
+static inline uint32_t v4l2_pix_fmt_from_drm_format(uint64_t drm_format)
+{
+ switch(drm_format) {
+#if defined(V4L2_PIX_FMT_SUNXI_TILED_NV12) && defined(DRM_FORMAT_MOD_ALLWINNER_TILED)
+ case DRM_FORMAT_MOD_ALLWINNER_TILED:
+ return V4L2_PIX_FMT_SUNXI_TILED_NV12;
+#endif
+ case DRM_FORMAT_NV12:
+ return V4L2_PIX_FMT_NV12;
+#if defined(V4L2_PIX_FMT_NV15) && defined(DRM_FORMAT_NV15)
+ case DRM_FORMAT_NV15:
+ return V4L2_PIX_FMT_NV15;
+#endif
+ case DRM_FORMAT_NV16:
+ return V4L2_PIX_FMT_NV16;
+#if defined(V4L2_PIX_FMT_NV20) && defined(DRM_FORMAT_NV20)
+ case DRM_FORMAT_NV20:
+ return V4L2_PIX_FMT_NV20;
+#endif
+ case DRM_FORMAT_NV21:
+ return V4L2_PIX_FMT_NV21;
+ case DRM_FORMAT_NV61:
+ return V4L2_PIX_FMT_NV61;
+ default:
+ av_log(NULL, AV_LOG_WARNING, "%s unknown drm format 0x%llx using default v4l2_pix_fmt 0x%x\n",
+ __func__ , drm_format, V4L2_PIX_FMT_NV12);
+ return V4L2_PIX_FMT_NV12;
+ }
+}
+
+static inline uint64_t drm_format_from_v4l2_pix_fmt(uint32_t v4l2_pix_fmt)
+{
+ switch(v4l2_pix_fmt) {
+ case V4L2_PIX_FMT_NV12:
+ return DRM_FORMAT_NV12;
+#if defined(V4L2_PIX_FMT_NV15) && defined(DRM_FORMAT_NV15)
+ case V4L2_PIX_FMT_NV15:
+ return DRM_FORMAT_NV15;
+#endif
+ case V4L2_PIX_FMT_NV16:
+ return DRM_FORMAT_NV16;
+#if defined(V4L2_PIX_FMT_NV20) && defined(DRM_FORMAT_NV20)
+ case V4L2_PIX_FMT_NV20:
+ return DRM_FORMAT_NV20;
+#endif
+ case V4L2_PIX_FMT_NV21:
+ return DRM_FORMAT_NV21;
+ case V4L2_PIX_FMT_NV61:
+ return DRM_FORMAT_NV61;
+#if defined(V4L2_PIX_FMT_SUNXI_TILED_NV12) && defined(DRM_FORMAT_MOD_ALLWINNER_TILED)
+ case V4L2_PIX_FMT_SUNXI_TILED_NV12:
+ return DRM_FORMAT_MOD_ALLWINNER_TILED;
+#endif
+ default:
+ av_log(NULL, AV_LOG_WARNING, "%s unknown v4l2_pix_fmt format 0x%x using default drm_format 0x%x\n",
+ __func__ , v4l2_pix_fmt, DRM_FORMAT_NV12);
+ return DRM_FORMAT_NV12;
+ }
+}
+
+static inline uint64_t drm_format_modifier(uint64_t drm_format)
+{
+#ifdef DRM_FORMAT_MOD_ALLWINNER_TILED
+ if (drm_format == DRM_FORMAT_MOD_ALLWINNER_TILED)
+ return DRM_FORMAT_MOD_ALLWINNER_TILED;
+#endif
+ return DRM_FORMAT_MOD_LINEAR;
+
+}
+
+static int deint_v4l2m2m_prepare_context(DeintV4L2M2MContextShared *ctx)
+{
+ struct v4l2_capability cap;
@ -174,11 +254,12 @@ index 000000000000..1029e5b620fd
+ return AVERROR(EINVAL);
+}
+
+static int deint_v4l2m2m_try_format(V4L2Queue *queue)
+static int deint_v4l2m2m_try_format(V4L2Queue *queue, uint64_t drm_format)
+{
+ struct v4l2_format *fmt = &queue->format;
+ DeintV4L2M2MContextShared *ctx = queue->ctx;
+ int ret, field;
+ uint32_t v4l2_pix_fmt = v4l2_pix_fmt_from_drm_format(drm_format);
+
+ ret = ioctl(ctx->fd, VIDIOC_G_FMT, fmt);
+ if (ret)
@ -190,12 +271,12 @@ index 000000000000..1029e5b620fd
+ field = V4L2_FIELD_NONE;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+ fmt->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
+ fmt->fmt.pix_mp.pixelformat = v4l2_pix_fmt;
+ fmt->fmt.pix_mp.field = field;
+ fmt->fmt.pix_mp.width = ctx->width;
+ fmt->fmt.pix_mp.height = ctx->height;
+ } else {
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
+ fmt->fmt.pix.pixelformat = v4l2_pix_fmt;
+ fmt->fmt.pix.field = field;
+ fmt->fmt.pix.width = ctx->width;
+ fmt->fmt.pix.height = ctx->height;
@ -206,14 +287,14 @@ index 000000000000..1029e5b620fd
+ return AVERROR(EINVAL);
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+ if (fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12 ||
+ if (fmt->fmt.pix_mp.pixelformat != v4l2_pix_fmt ||
+ fmt->fmt.pix_mp.field != field) {
+ av_log(NULL, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type);
+
+ return AVERROR(EINVAL);
+ }
+ } else {
+ if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_NV12 ||
+ if (fmt->fmt.pix.pixelformat != v4l2_pix_fmt ||
+ fmt->fmt.pix.field != field) {
+ av_log(NULL, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type);
+
@ -223,19 +304,21 @@ index 000000000000..1029e5b620fd
+
+ return 0;
+}
+
+static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t field, int width, int height)
+static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t field, int width, int height, uint64_t drm_format)
+{
+ struct v4l2_format *fmt = &queue->format;
+ DeintV4L2M2MContextShared *ctx = queue->ctx;
+ int ret;
+ uint32_t v4l2_pix_fmt = v4l2_pix_fmt_from_drm_format(drm_format);
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+ fmt->fmt.pix_mp.pixelformat = v4l2_pix_fmt;
+ fmt->fmt.pix_mp.field = field;
+ fmt->fmt.pix_mp.width = width;
+ fmt->fmt.pix_mp.height = height;
+ /* TODO: bytesperline and imagesize */
+ } else {
+ fmt->fmt.pix.pixelformat = v4l2_pix_fmt;
+ fmt->fmt.pix.field = field;
+ fmt->fmt.pix.width = width;
+ fmt->fmt.pix.height = height;
@ -247,6 +330,18 @@ index 000000000000..1029e5b620fd
+ if (ret)
+ av_log(NULL, AV_LOG_ERROR, "VIDIOC_S_FMT failed: %d\n", ret);
+
+ else if (!V4L2_TYPE_IS_OUTPUT(queue->format.type)) {
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type) && fmt->fmt.pix_mp.pixelformat != v4l2_pix_fmt) {
+ ctx->drm_out_format = drm_format_from_v4l2_pix_fmt(fmt->fmt.pix_mp.pixelformat);
+ av_log(NULL, AV_LOG_DEBUG, "%s driver updated v4l2_pixfmt from: %x to %x, so now using %llx as drm output format\n",
+ __func__, v4l2_pix_fmt, fmt->fmt.pix_mp.pixelformat, ctx->drm_out_format);
+ } else if (fmt->fmt.pix.pixelformat != v4l2_pix_fmt) {
+ ctx->drm_out_format = drm_format_from_v4l2_pix_fmt(fmt->fmt.pix.pixelformat);
+ av_log(NULL, AV_LOG_DEBUG, "%s driver updated v4l2_pixfmt from: %x to %x, so now using %llx as drm output format\n",
+ __func__, v4l2_pix_fmt, fmt->fmt.pix.pixelformat, ctx->drm_out_format);
+ }
+ }
+
+ return ret;
+}
+
@ -262,11 +357,11 @@ index 000000000000..1029e5b620fd
+ if (ret)
+ goto fail;
+
+ ret = deint_v4l2m2m_try_format(&ctx->capture);
+ ret = deint_v4l2m2m_try_format(&ctx->capture, ctx->drm_out_format);
+ if (ret)
+ goto fail;
+
+ ret = deint_v4l2m2m_try_format(&ctx->output);
+ ret = deint_v4l2m2m_try_format(&ctx->output, ctx->drm_in_format);
+ if (ret)
+ goto fail;
+
@ -329,7 +424,7 @@ index 000000000000..1029e5b620fd
+ return 0;
+}
+
+static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
+static int v4l2_buffer_export_drm(V4L2Buffer* avbuf, uint64_t drm_format)
+{
+ struct v4l2_exportbuffer expbuf;
+ int i, ret;
@ -351,12 +446,12 @@ index 000000000000..1029e5b620fd
+ /* drm frame */
+ avbuf->drm_frame.objects[i].size = avbuf->buffer.m.planes[i].length;
+ avbuf->drm_frame.objects[i].fd = expbuf.fd;
+ avbuf->drm_frame.objects[i].format_modifier = DRM_FORMAT_MOD_LINEAR;
+ avbuf->drm_frame.objects[i].format_modifier = drm_format_modifier(drm_format);
+ } else {
+ /* drm frame */
+ avbuf->drm_frame.objects[0].size = avbuf->buffer.length;
+ avbuf->drm_frame.objects[0].fd = expbuf.fd;
+ avbuf->drm_frame.objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
+ avbuf->drm_frame.objects[0].format_modifier = drm_format_modifier(drm_format);
+ }
+ }
+
@ -441,7 +536,7 @@ index 000000000000..1029e5b620fd
+ if (ret)
+ goto fail;
+
+ ret = v4l2_buffer_export_drm(buf);
+ ret = v4l2_buffer_export_drm(buf, ctx->drm_out_format);
+ if (ret)
+ goto fail;
+ }
@ -599,8 +694,11 @@ index 000000000000..1029e5b620fd
+ close(capture->buffers[i].fd);
+ }
+
+ for (i = 0; i < ctx->frame_count; i++)
+ av_frame_free(&ctx->frames[i]);
+ if (ctx->cur_in_frame)
+ av_frame_free(&ctx->cur_in_frame);
+
+ if (ctx->prev_in_frame)
+ av_frame_free(&ctx->prev_in_frame);
+
+ av_buffer_unref(&ctx->hw_frames_ctx);
+
@ -630,7 +728,7 @@ index 000000000000..1029e5b620fd
+ deint_v4l2m2m_destroy_context(ctx);
+}
+
+static uint8_t *v4l2_get_drm_frame(V4L2Buffer *avbuf, int height)
+static uint8_t *v4l2_get_drm_frame(V4L2Buffer *avbuf, int height, uint64_t drm_format)
+{
+ AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame;
+ AVDRMLayerDescriptor *layer;
@ -648,7 +746,7 @@ index 000000000000..1029e5b620fd
+ layer->planes[i].pitch = avbuf->plane_info[i].bytesperline;
+ }
+
+ layer->format = DRM_FORMAT_NV12;
+ layer->format = drm_format;
+
+ if (avbuf->num_planes == 1) {
+ layer->nb_planes = 2;
@ -680,7 +778,7 @@ index 000000000000..1029e5b620fd
+
+ atomic_fetch_add(&ctx->refcount, 1);
+
+ frame->data[0] = (uint8_t *)v4l2_get_drm_frame(avbuf, ctx->orig_height);
+ frame->data[0] = (uint8_t *)v4l2_get_drm_frame(avbuf, ctx->orig_height, ctx->drm_out_format);
+ frame->format = AV_PIX_FMT_DRM_PRIME;
+ frame->hw_frames_ctx = av_buffer_ref(ctx->hw_frames_ctx);
+ frame->height = ctx->height;
@ -694,49 +792,79 @@ index 000000000000..1029e5b620fd
+ return 0;
+}
+
+static int deint_v4l2m2m_dequeue(AVFilterContext *avctx, AVFrame *input_frame, int field)
+static int deint_v4l2m2m_dequeue(AVFilterContext *avctx, AVFrame *input_frame)
+{
+ DeintV4L2M2MContext *priv = avctx->priv;
+ DeintV4L2M2MContextShared *ctx = priv->shared;
+ AVFilterLink *outlink = avctx->outputs[0];
+ AVFrame *output_frame;
+ AVFrame *output_frame_1, *output_frame_2;
+ int64_t first_pts = AV_NOPTS_VALUE;
+ int err;
+
+ output_frame = av_frame_alloc();
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64" (field %d)\n",
+ input_frame->pts, ctx->field_order);
+
+ if (!output_frame)
+ output_frame_1 = av_frame_alloc();
+ if (!output_frame_1)
+ return AVERROR(ENOMEM);
+
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame, 500);
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame_1, 500);
+ if (err < 0) {
+ av_log(priv, AV_LOG_ERROR, "no frame (field %d)\n", field);
+ goto fail;
+ av_log(priv, AV_LOG_ERROR, "no 1st frame (field %d)\n", ctx->field_order);
+ goto fail_out1;
+ }
+
+ err = av_frame_copy_props(output_frame, input_frame);
+ err = av_frame_copy_props(output_frame_1, input_frame);
+ if (err < 0)
+ goto fail;
+ goto fail_out1;
+
+ output_frame->interlaced_frame = 0;
+ output_frame_1->interlaced_frame = 0;
+
+ if (field == 0) {
+ output_frame->pts *= 2;
+ } else {
+ int64_t cur_pts = ctx->frames[0]->pts;
+ int64_t next_pts = ctx->frames[1]->pts;
+
+ if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) {
+ output_frame->pts = next_pts + cur_pts;
+ } else {
+ output_frame->pts = AV_NOPTS_VALUE;
+ }
+ output_frame_2 = av_frame_alloc();
+ if (!output_frame_2) {
+ err = AVERROR(ENOMEM);
+ goto fail_out1;
+ }
+ av_log(priv, AV_LOG_DEBUG, "pts: %"PRId64" (field %d)\n", output_frame->pts, field);
+
+ return ff_filter_frame(outlink, output_frame);
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame_2, 500);
+ if (err < 0) {
+ av_log(priv, AV_LOG_ERROR, "no 2nd frame (field %d)\n", ctx->field_order);
+ goto fail_out2;
+ }
+
+fail:
+ av_frame_free(&output_frame);
+ err = av_frame_copy_props(output_frame_2, input_frame);
+ if (err < 0)
+ goto fail_out2;
+
+ output_frame_2->interlaced_frame = 0;
+
+ if (ctx->prev_in_frame && ctx->prev_in_frame->pts != AV_NOPTS_VALUE
+ && input_frame->pts != AV_NOPTS_VALUE) {
+ first_pts = (ctx->prev_in_frame->pts + input_frame->pts) / 2;
+ av_log(priv, AV_LOG_DEBUG, "calculated first pts %"PRId64"\n", first_pts);
+ }
+
+ output_frame_1->pts = first_pts;
+
+ err = ff_filter_frame(outlink, output_frame_1);
+ if (err < 0) {
+ av_frame_free(&output_frame_2);
+ return err;
+ }
+ err = ff_filter_frame(outlink, output_frame_2);
+
+ if (err < 0)
+ return err;
+
+ av_log(priv, AV_LOG_DEBUG, "1st frame pts: %"PRId64" 2nd frame pts: %"PRId64" first pts: %"PRId64" (field %d)\n",
+ output_frame_1->pts, output_frame_2->pts, first_pts, ctx->field_order);
+
+ return 0;
+
+fail_out2:
+ av_frame_free(&output_frame_2);
+fail_out1:
+ av_frame_free(&output_frame_1);
+ return err;
+}
+
@ -791,24 +919,32 @@ index 000000000000..1029e5b620fd
+ V4L2Queue *output = &ctx->output;
+ int ret;
+
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64"\n", in->pts);
+ if (!ctx->frame_count) {
+ AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)in->data[0];
+ unsigned int field;
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64" field :%d interlaced: %d\n",
+ in->pts, in->top_field_first, in->interlaced_frame);
+
+ ctx->cur_in_frame = in;
+
+ if (ctx->field_order == V4L2_FIELD_ANY) {
+ AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)in->data[0];
+ ctx->orig_width = drm_desc->layers[0].planes[0].pitch;
+ ctx->orig_height = drm_desc->layers[0].planes[1].offset / ctx->orig_width;
+ ctx->drm_in_format = drm_desc->layers->format;
+ ctx->drm_out_format = drm_desc->layers->format;
+
+ if (in->top_field_first)
+ field = V4L2_FIELD_INTERLACED_TB;
+ if (in->top_field_first)
+ ctx->field_order = V4L2_FIELD_INTERLACED_TB;
+ else
+ field = V4L2_FIELD_INTERLACED_BT;
+ ctx->field_order = V4L2_FIELD_INTERLACED_BT;
+
+ ret = deint_v4l2m2m_set_format(output, field, ctx->orig_width, ctx->orig_height);
+ ret = deint_v4l2m2m_set_format(output, ctx->field_order,
+ ctx->orig_width, ctx->orig_height,
+ ctx->drm_in_format);
+ if (ret)
+ return ret;
+
+ ret = deint_v4l2m2m_set_format(capture, V4L2_FIELD_NONE, ctx->orig_width, ctx->orig_height);
+ ret = deint_v4l2m2m_set_format(capture, V4L2_FIELD_NONE,
+ ctx->orig_width, ctx->orig_height,
+ ctx->drm_out_format);
+ if (ret)
+ return ret;
+
@ -829,27 +965,19 @@ index 000000000000..1029e5b620fd
+ return ret;
+ }
+
+ if (ctx->frame_count < 2) {
+ ctx->frames[ctx->frame_count++] = in;
+ } else {
+ av_frame_free(&ctx->frames[0]);
+ ctx->frames[0] = ctx->frames[1];
+ ctx->frames[1] = in;
+ }
+
+ ret = deint_v4l2m2m_enqueue(output, in);
+ if (ret)
+ return ret;
+
+ if (ctx->frame_count == 2) {
+ ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 0);
+ if (ret)
+ return ret;
+ ret = deint_v4l2m2m_dequeue(avctx, in);
+ if (ret)
+ return ret;
+
+ ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 1);
+ if (ret)
+ return ret;
+ }
+ if (ctx->prev_in_frame)
+ av_frame_free(&ctx->prev_in_frame);
+
+ ctx->prev_in_frame = in;
+ ctx->cur_in_frame = NULL;
+
+ return 0;
+}
@ -870,6 +998,11 @@ index 000000000000..1029e5b620fd
+ ctx->capture.ctx = ctx;
+ ctx->capture.num_buffers = 6;
+ ctx->done = 0;
+ ctx->field_order = V4L2_FIELD_ANY;
+ ctx->cur_in_frame = NULL;
+ ctx->prev_in_frame = NULL;
+ ctx->drm_in_format = DRM_FORMAT_NV12;
+ ctx->drm_out_format = DRM_FORMAT_NV12;
+ atomic_init(&ctx->refcount, 1);
+
+ return 0;
@ -896,7 +1029,6 @@ index 000000000000..1029e5b620fd
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = deint_v4l2m2m_filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad deint_v4l2m2m_outputs[] = {
@ -905,7 +1037,6 @@ index 000000000000..1029e5b620fd
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = deint_v4l2m2m_config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_deinterlace_v4l2m2m = {
@ -914,11 +1045,8 @@ index 000000000000..1029e5b620fd
+ .priv_size = sizeof(DeintV4L2M2MContext),
+ .init = &deint_v4l2m2m_init,
+ .uninit = &deint_v4l2m2m_uninit,
+ .query_formats = &deint_v4l2m2m_query_formats,
+ .inputs = deint_v4l2m2m_inputs,
+ .outputs = deint_v4l2m2m_outputs,
+ FILTER_QUERY_FUNC(&deint_v4l2m2m_query_formats),
+ FILTER_INPUTS(deint_v4l2m2m_inputs),
+ FILTER_OUTPUTS(deint_v4l2m2m_outputs),
+ .priv_class = &deinterlace_v4l2m2m_class,
+};
--
2.29.2

View File

@ -1,924 +0,0 @@
From 39069d9cc03a42cd497dd6b9756116ff4b684a5d Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 3 Dec 2019 21:01:18 +0100
Subject: [PATCH] WIP deint filter
---
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/vf_deinterlace_v4l2m2m.c | 879 +++++++++++++++++++++++++++
3 files changed, 881 insertions(+)
create mode 100644 libavfilter/vf_deinterlace_v4l2m2m.c
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 512354065305..625fd29f9313 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -218,6 +218,7 @@ OBJS-$(CONFIG_DEFLATE_FILTER) += vf_neighbor.o
OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o
OBJS-$(CONFIG_DEINTERLACE_QSV_FILTER) += vf_deinterlace_qsv.o
OBJS-$(CONFIG_DEINTERLACE_VAAPI_FILTER) += vf_deinterlace_vaapi.o vaapi_vpp.o
+OBJS-$(CONFIG_DEINTERLACE_V4L2M2M_FILTER) += vf_deinterlace_v4l2m2m.o
OBJS-$(CONFIG_DEJUDDER_FILTER) += vf_dejudder.o
OBJS-$(CONFIG_DELOGO_FILTER) += vf_delogo.o
OBJS-$(CONFIG_DENOISE_VAAPI_FILTER) += vf_misc_vaapi.o vaapi_vpp.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 1183e4026751..fe5a2e8c02e8 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -204,6 +204,7 @@ extern AVFilter ff_vf_dedot;
extern AVFilter ff_vf_deflate;
extern AVFilter ff_vf_deflicker;
extern AVFilter ff_vf_deinterlace_qsv;
+extern AVFilter ff_vf_deinterlace_v4l2m2m;
extern AVFilter ff_vf_deinterlace_vaapi;
extern AVFilter ff_vf_dejudder;
extern AVFilter ff_vf_delogo;
diff --git a/libavfilter/vf_deinterlace_v4l2m2m.c b/libavfilter/vf_deinterlace_v4l2m2m.c
new file mode 100644
index 000000000000..1029e5b620fd
--- /dev/null
+++ b/libavfilter/vf_deinterlace_v4l2m2m.c
@@ -0,0 +1,879 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * deinterlace video filter - V4L2 M2M
+ */
+
+#include <drm_fourcc.h>
+
+#include <linux/videodev2.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdatomic.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/common.h"
+#include "libavutil/hwcontext.h"
+#include "libavutil/hwcontext_drm.h"
+#include "libavutil/internal.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/time.h"
+
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct V4L2Queue V4L2Queue;
+typedef struct DeintV4L2M2MContextShared DeintV4L2M2MContextShared;
+
+typedef struct V4L2PlaneInfo {
+ int bytesperline;
+ size_t length;
+} V4L2PlaneInfo;
+
+typedef struct V4L2Buffer {
+ int enqueued;
+ int reenqueue;
+ int fd;
+ struct v4l2_buffer buffer;
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ int num_planes;
+ V4L2PlaneInfo plane_info[VIDEO_MAX_PLANES];
+ AVDRMFrameDescriptor drm_frame;
+ V4L2Queue *q;
+} V4L2Buffer;
+
+typedef struct V4L2Queue {
+ struct v4l2_format format;
+ int num_buffers;
+ V4L2Buffer *buffers;
+ DeintV4L2M2MContextShared *ctx;
+} V4L2Queue;
+
+typedef struct DeintV4L2M2MContextShared {
+ int fd;
+ int done;
+ int width;
+ int height;
+ int orig_width;
+ int orig_height;
+ atomic_uint refcount;
+
+ AVBufferRef *hw_frames_ctx;
+
+ int frame_count;
+ AVFrame *frames[2];
+
+ V4L2Queue output;
+ V4L2Queue capture;
+} DeintV4L2M2MContextShared;
+
+typedef struct DeintV4L2M2MContext {
+ const AVClass *class;
+
+ DeintV4L2M2MContextShared *shared;
+} DeintV4L2M2MContext;
+
+static int deint_v4l2m2m_prepare_context(DeintV4L2M2MContextShared *ctx)
+{
+ struct v4l2_capability cap;
+ int ret;
+
+ memset(&cap, 0, sizeof(cap));
+ ret = ioctl(ctx->fd, VIDIOC_QUERYCAP, &cap);
+ if (ret < 0)
+ return ret;
+
+ if (!(cap.capabilities & V4L2_CAP_STREAMING))
+ return AVERROR(EINVAL);
+
+ if (cap.capabilities & V4L2_CAP_VIDEO_M2M) {
+ ctx->capture.format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ctx->output.format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+ return 0;
+ }
+
+ if (cap.capabilities & V4L2_CAP_VIDEO_M2M_MPLANE) {
+ ctx->capture.format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ctx->output.format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+ return 0;
+ }
+
+ return AVERROR(EINVAL);
+}
+
+static int deint_v4l2m2m_try_format(V4L2Queue *queue)
+{
+ struct v4l2_format *fmt = &queue->format;
+ DeintV4L2M2MContextShared *ctx = queue->ctx;
+ int ret, field;
+
+ ret = ioctl(ctx->fd, VIDIOC_G_FMT, fmt);
+ if (ret)
+ av_log(NULL, AV_LOG_ERROR, "VIDIOC_G_FMT failed: %d\n", ret);
+
+ if (V4L2_TYPE_IS_OUTPUT(fmt->type))
+ field = V4L2_FIELD_INTERLACED_TB;
+ else
+ field = V4L2_FIELD_NONE;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+ fmt->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
+ fmt->fmt.pix_mp.field = field;
+ fmt->fmt.pix_mp.width = ctx->width;
+ fmt->fmt.pix_mp.height = ctx->height;
+ } else {
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
+ fmt->fmt.pix.field = field;
+ fmt->fmt.pix.width = ctx->width;
+ fmt->fmt.pix.height = ctx->height;
+ }
+
+ ret = ioctl(ctx->fd, VIDIOC_TRY_FMT, fmt);
+ if (ret)
+ return AVERROR(EINVAL);
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+ if (fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12 ||
+ fmt->fmt.pix_mp.field != field) {
+ av_log(NULL, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type);
+
+ return AVERROR(EINVAL);
+ }
+ } else {
+ if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_NV12 ||
+ fmt->fmt.pix.field != field) {
+ av_log(NULL, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type);
+
+ return AVERROR(EINVAL);
+ }
+ }
+
+ return 0;
+}
+
+static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t field, int width, int height)
+{
+ struct v4l2_format *fmt = &queue->format;
+ DeintV4L2M2MContextShared *ctx = queue->ctx;
+ int ret;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+ fmt->fmt.pix_mp.field = field;
+ fmt->fmt.pix_mp.width = width;
+ fmt->fmt.pix_mp.height = height;
+ /* TODO: bytesperline and imagesize */
+ } else {
+ fmt->fmt.pix.field = field;
+ fmt->fmt.pix.width = width;
+ fmt->fmt.pix.height = height;
+ fmt->fmt.pix.sizeimage = 0;
+ fmt->fmt.pix.bytesperline = 0;
+ }
+
+ ret = ioctl(ctx->fd, VIDIOC_S_FMT, fmt);
+ if (ret)
+ av_log(NULL, AV_LOG_ERROR, "VIDIOC_S_FMT failed: %d\n", ret);
+
+ return ret;
+}
+
+static int deint_v4l2m2m_probe_device(DeintV4L2M2MContextShared *ctx, char *node)
+{
+ int ret;
+
+ ctx->fd = open(node, O_RDWR | O_NONBLOCK, 0);
+ if (ctx->fd < 0)
+ return AVERROR(errno);
+
+ ret = deint_v4l2m2m_prepare_context(ctx);
+ if (ret)
+ goto fail;
+
+ ret = deint_v4l2m2m_try_format(&ctx->capture);
+ if (ret)
+ goto fail;
+
+ ret = deint_v4l2m2m_try_format(&ctx->output);
+ if (ret)
+ goto fail;
+
+ return 0;
+
+fail:
+ close(ctx->fd);
+ ctx->fd = -1;
+
+ return ret;
+}
+
+static int deint_v4l2m2m_find_device(DeintV4L2M2MContextShared *ctx)
+{
+ int ret = AVERROR(EINVAL);
+ struct dirent *entry;
+ char node[PATH_MAX];
+ DIR *dirp;
+
+ dirp = opendir("/dev");
+ if (!dirp)
+ return AVERROR(errno);
+
+ for (entry = readdir(dirp); entry; entry = readdir(dirp)) {
+
+ if (strncmp(entry->d_name, "video", 5))
+ continue;
+
+ snprintf(node, sizeof(node), "/dev/%s", entry->d_name);
+ av_log(NULL, AV_LOG_DEBUG, "probing device %s\n", node);
+ ret = deint_v4l2m2m_probe_device(ctx, node);
+ if (!ret)
+ break;
+ }
+
+ closedir(dirp);
+
+ if (ret) {
+ av_log(NULL, AV_LOG_ERROR, "Could not find a valid device\n");
+ ctx->fd = -1;
+
+ return ret;
+ }
+
+ av_log(NULL, AV_LOG_INFO, "Using device %s\n", node);
+
+ return 0;
+}
+
+static int deint_v4l2m2m_enqueue_buffer(V4L2Buffer *buf)
+{
+ int ret;
+
+ ret = ioctl(buf->q->ctx->fd, VIDIOC_QBUF, &buf->buffer);
+ if (ret < 0)
+ return AVERROR(errno);
+
+ buf->enqueued = 1;
+
+ return 0;
+}
+
+static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
+{
+ struct v4l2_exportbuffer expbuf;
+ int i, ret;
+
+ for (i = 0; i < avbuf->num_planes; i++) {
+ memset(&expbuf, 0, sizeof(expbuf));
+
+ expbuf.index = avbuf->buffer.index;
+ expbuf.type = avbuf->buffer.type;
+ expbuf.plane = i;
+
+ ret = ioctl(avbuf->q->ctx->fd, VIDIOC_EXPBUF, &expbuf);
+ if (ret < 0)
+ return AVERROR(errno);
+
+ avbuf->fd = expbuf.fd;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->buffer.type)) {
+ /* drm frame */
+ avbuf->drm_frame.objects[i].size = avbuf->buffer.m.planes[i].length;
+ avbuf->drm_frame.objects[i].fd = expbuf.fd;
+ avbuf->drm_frame.objects[i].format_modifier = DRM_FORMAT_MOD_LINEAR;
+ } else {
+ /* drm frame */
+ avbuf->drm_frame.objects[0].size = avbuf->buffer.length;
+ avbuf->drm_frame.objects[0].fd = expbuf.fd;
+ avbuf->drm_frame.objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
+ }
+ }
+
+ return 0;
+}
+
+static int deint_v4l2m2m_allocate_buffers(V4L2Queue *queue)
+{
+ struct v4l2_format *fmt = &queue->format;
+ DeintV4L2M2MContextShared *ctx = queue->ctx;
+ struct v4l2_requestbuffers req;
+ int ret, i, j, multiplanar;
+ uint32_t memory;
+
+ memory = V4L2_TYPE_IS_OUTPUT(fmt->type) ?
+ V4L2_MEMORY_DMABUF : V4L2_MEMORY_MMAP;
+
+ multiplanar = V4L2_TYPE_IS_MULTIPLANAR(fmt->type);
+
+ memset(&req, 0, sizeof(req));
+ req.count = queue->num_buffers;
+ req.memory = memory;
+ req.type = fmt->type;
+
+ ret = ioctl(ctx->fd, VIDIOC_REQBUFS, &req);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "VIDIOC_REQBUFS failed: %s\n", strerror(errno));
+
+ return AVERROR(errno);
+ }
+
+ queue->num_buffers = req.count;
+ queue->buffers = av_mallocz(queue->num_buffers * sizeof(V4L2Buffer));
+ if (!queue->buffers) {
+ av_log(NULL, AV_LOG_ERROR, "malloc enomem\n");
+
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i < queue->num_buffers; i++) {
+ V4L2Buffer *buf = &queue->buffers[i];
+
+ buf->enqueued = 0;
+ buf->fd = -1;
+ buf->q = queue;
+
+ buf->buffer.type = fmt->type;
+ buf->buffer.memory = memory;
+ buf->buffer.index = i;
+
+ if (multiplanar) {
+ buf->buffer.length = VIDEO_MAX_PLANES;
+ buf->buffer.m.planes = buf->planes;
+ }
+
+ ret = ioctl(ctx->fd, VIDIOC_QUERYBUF, &buf->buffer);
+ if (ret < 0) {
+ ret = AVERROR(errno);
+
+ goto fail;
+ }
+
+ if (multiplanar)
+ buf->num_planes = buf->buffer.length;
+ else
+ buf->num_planes = 1;
+
+ for (j = 0; j < buf->num_planes; j++) {
+ V4L2PlaneInfo *info = &buf->plane_info[j];
+
+ if (multiplanar) {
+ info->bytesperline = fmt->fmt.pix_mp.plane_fmt[j].bytesperline;
+ info->length = buf->buffer.m.planes[j].length;
+ } else {
+ info->bytesperline = fmt->fmt.pix.bytesperline;
+ info->length = buf->buffer.length;
+ }
+ }
+
+ if (!V4L2_TYPE_IS_OUTPUT(fmt->type)) {
+ ret = deint_v4l2m2m_enqueue_buffer(buf);
+ if (ret)
+ goto fail;
+
+ ret = v4l2_buffer_export_drm(buf);
+ if (ret)
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ for (i = 0; i < queue->num_buffers; i++)
+ if (queue->buffers[i].fd >= 0)
+ close(queue->buffers[i].fd);
+ av_free(queue->buffers);
+ queue->buffers = NULL;
+
+ return ret;
+}
+
+static int deint_v4l2m2m_streamon(V4L2Queue *queue)
+{
+ int type = queue->format.type;
+ int ret;
+
+ ret = ioctl(queue->ctx->fd, VIDIOC_STREAMON, &type);
+ if (ret < 0)
+ return AVERROR(errno);
+
+ return 0;
+}
+
+static int deint_v4l2m2m_streamoff(V4L2Queue *queue)
+{
+ int type = queue->format.type;
+ int ret;
+
+ ret = ioctl(queue->ctx->fd, VIDIOC_STREAMOFF, &type);
+ if (ret < 0)
+ return AVERROR(errno);
+
+ return 0;
+}
+
+static V4L2Buffer* deint_v4l2m2m_dequeue_buffer(V4L2Queue *queue, int timeout)
+{
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ DeintV4L2M2MContextShared *ctx = queue->ctx;
+ struct v4l2_buffer buf = { 0 };
+ V4L2Buffer* avbuf = NULL;
+ struct pollfd pfd;
+ short events;
+ int ret;
+
+ if (V4L2_TYPE_IS_OUTPUT(queue->format.type))
+ events = POLLOUT | POLLWRNORM;
+ else
+ events = POLLIN | POLLRDNORM;
+
+ pfd.events = events;
+ pfd.fd = ctx->fd;
+
+ for (;;) {
+ ret = poll(&pfd, 1, timeout);
+ if (ret > 0)
+ break;
+ if (errno == EINTR)
+ continue;
+ return NULL;
+ }
+
+ if (pfd.revents & POLLERR)
+ return NULL;
+
+ if (pfd.revents & events) {
+ memset(&buf, 0, sizeof(buf));
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.type = queue->format.type;
+ if (V4L2_TYPE_IS_MULTIPLANAR(queue->format.type)) {
+ memset(planes, 0, sizeof(planes));
+ buf.length = VIDEO_MAX_PLANES;
+ buf.m.planes = planes;
+ }
+
+ ret = ioctl(ctx->fd, VIDIOC_DQBUF, &buf);
+ if (ret) {
+ if (errno != EAGAIN)
+ av_log(NULL, AV_LOG_DEBUG, "VIDIOC_DQBUF, errno (%s)\n",
+ av_err2str(AVERROR(errno)));
+ return NULL;
+ }
+
+ avbuf = &queue->buffers[buf.index];
+ avbuf->enqueued = 0;
+ avbuf->buffer = buf;
+ if (V4L2_TYPE_IS_MULTIPLANAR(queue->format.type)) {
+ memcpy(avbuf->planes, planes, sizeof(planes));
+ avbuf->buffer.m.planes = avbuf->planes;
+ }
+
+ return avbuf;
+ }
+
+ return NULL;
+}
+
+static V4L2Buffer *deint_v4l2m2m_find_free_buf(V4L2Queue *queue)
+{
+ int i;
+
+ for (i = 0; i < queue->num_buffers; i++)
+ if (!queue->buffers[i].enqueued)
+ return &queue->buffers[i];
+
+ return NULL;
+}
+
+static int deint_v4l2m2m_enqueue(V4L2Queue *queue, const AVFrame* frame)
+{
+ AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)frame->data[0];
+ V4L2Buffer *buf;
+ int i;
+
+ if (V4L2_TYPE_IS_OUTPUT(queue->format.type))
+ while (deint_v4l2m2m_dequeue_buffer(queue, 0));
+
+ buf = deint_v4l2m2m_find_free_buf(queue);
+ if (!buf)
+ return AVERROR(ENOMEM);
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(buf->buffer.type))
+ for (i = 0; i < drm_desc->nb_objects; i++)
+ buf->buffer.m.planes[i].m.fd = drm_desc->objects[i].fd;
+ else
+ buf->buffer.m.fd = drm_desc->objects[0].fd;
+
+ return deint_v4l2m2m_enqueue_buffer(buf);
+}
+
+static void deint_v4l2m2m_destroy_context(DeintV4L2M2MContextShared *ctx)
+{
+ if (atomic_fetch_sub(&ctx->refcount, 1) == 1) {
+ V4L2Queue *capture = &ctx->capture;
+ V4L2Queue *output = &ctx->output;
+ int i;
+
+ av_log(NULL, AV_LOG_DEBUG, "%s - destroying context\n", __func__);
+
+ if (ctx->fd >= 0) {
+ deint_v4l2m2m_streamoff(capture);
+ deint_v4l2m2m_streamoff(output);
+ }
+
+ if (capture->buffers)
+ for (i = 0; i < capture->num_buffers; i++) {
+ capture->buffers[i].q = NULL;
+ if (capture->buffers[i].fd >= 0)
+ close(capture->buffers[i].fd);
+ }
+
+ for (i = 0; i < ctx->frame_count; i++)
+ av_frame_free(&ctx->frames[i]);
+
+ av_buffer_unref(&ctx->hw_frames_ctx);
+
+ if (capture->buffers)
+ av_free(capture->buffers);
+
+ if (output->buffers)
+ av_free(output->buffers);
+
+ if (ctx->fd >= 0) {
+ close(ctx->fd);
+ ctx->fd = -1;
+ }
+
+ av_free(ctx);
+ }
+}
+
+static void v4l2_free_buffer(void *opaque, uint8_t *unused)
+{
+ V4L2Buffer *buf = opaque;
+ DeintV4L2M2MContextShared *ctx = buf->q->ctx;
+
+ if (!ctx->done)
+ deint_v4l2m2m_enqueue_buffer(buf);
+
+ deint_v4l2m2m_destroy_context(ctx);
+}
+
+static uint8_t *v4l2_get_drm_frame(V4L2Buffer *avbuf, int height)
+{
+ AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame;
+ AVDRMLayerDescriptor *layer;
+
+ /* fill the DRM frame descriptor */
+ drm_desc->nb_objects = avbuf->num_planes;
+ drm_desc->nb_layers = 1;
+
+ layer = &drm_desc->layers[0];
+ layer->nb_planes = avbuf->num_planes;
+
+ for (int i = 0; i < avbuf->num_planes; i++) {
+ layer->planes[i].object_index = i;
+ layer->planes[i].offset = 0;
+ layer->planes[i].pitch = avbuf->plane_info[i].bytesperline;
+ }
+
+ layer->format = DRM_FORMAT_NV12;
+
+ if (avbuf->num_planes == 1) {
+ layer->nb_planes = 2;
+
+ layer->planes[1].object_index = 0;
+ layer->planes[1].offset = avbuf->plane_info[0].bytesperline * height;
+ layer->planes[1].pitch = avbuf->plane_info[0].bytesperline;
+ }
+
+ return (uint8_t *)drm_desc;
+}
+
+static int deint_v4l2m2m_dequeue_frame(V4L2Queue *queue, AVFrame* frame, int timeout)
+{
+ DeintV4L2M2MContextShared *ctx = queue->ctx;
+ V4L2Buffer* avbuf;
+
+ avbuf = deint_v4l2m2m_dequeue_buffer(queue, timeout);
+ if (!avbuf) {
+ av_log(NULL, AV_LOG_ERROR, "dequeueing failed\n");
+ return AVERROR(EINVAL);
+ }
+
+ frame->buf[0] = av_buffer_create((uint8_t *) &avbuf->drm_frame,
+ sizeof(avbuf->drm_frame), v4l2_free_buffer,
+ avbuf, AV_BUFFER_FLAG_READONLY);
+ if (!frame->buf[0])
+ return AVERROR(ENOMEM);
+
+ atomic_fetch_add(&ctx->refcount, 1);
+
+ frame->data[0] = (uint8_t *)v4l2_get_drm_frame(avbuf, ctx->orig_height);
+ frame->format = AV_PIX_FMT_DRM_PRIME;
+ frame->hw_frames_ctx = av_buffer_ref(ctx->hw_frames_ctx);
+ frame->height = ctx->height;
+ frame->width = ctx->width;
+
+ if (avbuf->buffer.flags & V4L2_BUF_FLAG_ERROR) {
+ av_log(NULL, AV_LOG_ERROR, "driver decode error\n");
+ frame->decode_error_flags |= FF_DECODE_ERROR_INVALID_BITSTREAM;
+ }
+
+ return 0;
+}
+
+static int deint_v4l2m2m_dequeue(AVFilterContext *avctx, AVFrame *input_frame, int field)
+{
+ DeintV4L2M2MContext *priv = avctx->priv;
+ DeintV4L2M2MContextShared *ctx = priv->shared;
+ AVFilterLink *outlink = avctx->outputs[0];
+ AVFrame *output_frame;
+ int err;
+
+ output_frame = av_frame_alloc();
+
+ if (!output_frame)
+ return AVERROR(ENOMEM);
+
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame, 500);
+ if (err < 0) {
+ av_log(priv, AV_LOG_ERROR, "no frame (field %d)\n", field);
+ goto fail;
+ }
+
+ err = av_frame_copy_props(output_frame, input_frame);
+ if (err < 0)
+ goto fail;
+
+ output_frame->interlaced_frame = 0;
+
+ if (field == 0) {
+ output_frame->pts *= 2;
+ } else {
+ int64_t cur_pts = ctx->frames[0]->pts;
+ int64_t next_pts = ctx->frames[1]->pts;
+
+ if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) {
+ output_frame->pts = next_pts + cur_pts;
+ } else {
+ output_frame->pts = AV_NOPTS_VALUE;
+ }
+ }
+ av_log(priv, AV_LOG_DEBUG, "pts: %"PRId64" (field %d)\n", output_frame->pts, field);
+
+ return ff_filter_frame(outlink, output_frame);
+
+fail:
+ av_frame_free(&output_frame);
+ return err;
+}
+
+static int deint_v4l2m2m_config_props(AVFilterLink *outlink)
+{
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ AVFilterContext *avctx = outlink->src;
+ DeintV4L2M2MContext *priv = avctx->priv;
+ DeintV4L2M2MContextShared *ctx = priv->shared;
+ int ret;
+
+ ctx->height = avctx->inputs[0]->h;
+ ctx->width = avctx->inputs[0]->w;
+
+ outlink->frame_rate = av_mul_q(inlink->frame_rate,
+ (AVRational){ 2, 1 });
+ outlink->time_base = av_mul_q(inlink->time_base,
+ (AVRational){ 1, 2 });
+
+ ret = deint_v4l2m2m_find_device(ctx);
+ if (ret)
+ return ret;
+
+ if (!inlink->hw_frames_ctx) {
+ av_log(priv, AV_LOG_ERROR, "No hw context provided on input\n");
+ return AVERROR(EINVAL);
+ }
+
+ ctx->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
+ if (!ctx->hw_frames_ctx)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static int deint_v4l2m2m_query_formats(AVFilterContext *avctx)
+{
+ static const enum AVPixelFormat pixel_formats[] = {
+ AV_PIX_FMT_DRM_PRIME,
+ AV_PIX_FMT_NONE,
+ };
+
+ return ff_set_common_formats(avctx, ff_make_format_list(pixel_formats));
+}
+
+static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in)
+{
+ AVFilterContext *avctx = link->dst;
+ DeintV4L2M2MContext *priv = avctx->priv;
+ DeintV4L2M2MContextShared *ctx = priv->shared;
+ V4L2Queue *capture = &ctx->capture;
+ V4L2Queue *output = &ctx->output;
+ int ret;
+
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64"\n", in->pts);
+ if (!ctx->frame_count) {
+ AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)in->data[0];
+ unsigned int field;
+
+ ctx->orig_width = drm_desc->layers[0].planes[0].pitch;
+ ctx->orig_height = drm_desc->layers[0].planes[1].offset / ctx->orig_width;
+
+ if (in->top_field_first)
+ field = V4L2_FIELD_INTERLACED_TB;
+ else
+ field = V4L2_FIELD_INTERLACED_BT;
+
+ ret = deint_v4l2m2m_set_format(output, field, ctx->orig_width, ctx->orig_height);
+ if (ret)
+ return ret;
+
+ ret = deint_v4l2m2m_set_format(capture, V4L2_FIELD_NONE, ctx->orig_width, ctx->orig_height);
+ if (ret)
+ return ret;
+
+ ret = deint_v4l2m2m_allocate_buffers(capture);
+ if (ret)
+ return ret;
+
+ ret = deint_v4l2m2m_streamon(capture);
+ if (ret)
+ return ret;
+
+ ret = deint_v4l2m2m_allocate_buffers(output);
+ if (ret)
+ return ret;
+
+ ret = deint_v4l2m2m_streamon(output);
+ if (ret)
+ return ret;
+ }
+
+ if (ctx->frame_count < 2) {
+ ctx->frames[ctx->frame_count++] = in;
+ } else {
+ av_frame_free(&ctx->frames[0]);
+ ctx->frames[0] = ctx->frames[1];
+ ctx->frames[1] = in;
+ }
+
+ ret = deint_v4l2m2m_enqueue(output, in);
+ if (ret)
+ return ret;
+
+ if (ctx->frame_count == 2) {
+ ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 0);
+ if (ret)
+ return ret;
+
+ ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static av_cold int deint_v4l2m2m_init(AVFilterContext *avctx)
+{
+ DeintV4L2M2MContext *priv = avctx->priv;
+ DeintV4L2M2MContextShared *ctx;
+
+ ctx = av_mallocz(sizeof(DeintV4L2M2MContextShared));
+ if (!ctx)
+ return AVERROR(ENOMEM);
+
+ priv->shared = ctx;
+ ctx->fd = -1;
+ ctx->output.ctx = ctx;
+ ctx->output.num_buffers = 6;
+ ctx->capture.ctx = ctx;
+ ctx->capture.num_buffers = 6;
+ ctx->done = 0;
+ atomic_init(&ctx->refcount, 1);
+
+ return 0;
+}
+
+static void deint_v4l2m2m_uninit(AVFilterContext *avctx)
+{
+ DeintV4L2M2MContext *priv = avctx->priv;
+ DeintV4L2M2MContextShared *ctx = priv->shared;
+
+ ctx->done = 1;
+ deint_v4l2m2m_destroy_context(ctx);
+}
+
+static const AVOption deinterlace_v4l2m2m_options[] = {
+ { NULL },
+};
+
+AVFILTER_DEFINE_CLASS(deinterlace_v4l2m2m);
+
+static const AVFilterPad deint_v4l2m2m_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = deint_v4l2m2m_filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad deint_v4l2m2m_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = deint_v4l2m2m_config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_deinterlace_v4l2m2m = {
+ .name = "deinterlace_v4l2m2m",
+ .description = NULL_IF_CONFIG_SMALL("V4L2 M2M deinterlacer"),
+ .priv_size = sizeof(DeintV4L2M2MContext),
+ .init = &deint_v4l2m2m_init,
+ .uninit = &deint_v4l2m2m_uninit,
+ .query_formats = &deint_v4l2m2m_query_formats,
+ .inputs = deint_v4l2m2m_inputs,
+ .outputs = deint_v4l2m2m_outputs,
+ .priv_class = &deinterlace_v4l2m2m_class,
+};
--
2.29.2

View File

@ -1,230 +0,0 @@
From 6bea46839ba23bffaa093bb9ed805d571aaa66ea Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Wed, 30 Sep 2020 21:11:34 +0200
Subject: [PATCH] libavfilter: v4l2deinterlace: dequeue both destination
buffers on time
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
libavfilter/vf_deinterlace_v4l2m2m.c | 140 +++++++++++++++++----------
1 file changed, 88 insertions(+), 52 deletions(-)
diff --git a/libavfilter/vf_deinterlace_v4l2m2m.c b/libavfilter/vf_deinterlace_v4l2m2m.c
index 1029e5b620fd..72d28333ffa7 100644
--- a/libavfilter/vf_deinterlace_v4l2m2m.c
+++ b/libavfilter/vf_deinterlace_v4l2m2m.c
@@ -89,8 +89,14 @@ typedef struct DeintV4L2M2MContextShared {
AVBufferRef *hw_frames_ctx;
- int frame_count;
- AVFrame *frames[2];
+ /*
+ * TODO: check if its really neccessary to hold this
+ * ref, it's only used for freeing av_frame on decoding
+ * end/abort
+ */
+ AVFrame *cur_in_frame;
+ AVFrame *prev_in_frame;
+ unsigned int field_order;
V4L2Queue output;
V4L2Queue capture;
@@ -557,8 +563,11 @@ static void deint_v4l2m2m_destroy_context(DeintV4L2M2MContextShared *ctx)
close(capture->buffers[i].fd);
}
- for (i = 0; i < ctx->frame_count; i++)
- av_frame_free(&ctx->frames[i]);
+ if (ctx->cur_in_frame)
+ av_frame_free(&ctx->cur_in_frame);
+
+ if (ctx->prev_in_frame)
+ av_frame_free(&ctx->prev_in_frame);
av_buffer_unref(&ctx->hw_frames_ctx);
@@ -652,49 +661,79 @@ static int deint_v4l2m2m_dequeue_frame(V4L2Queue *queue, AVFrame* frame, int tim
return 0;
}
-static int deint_v4l2m2m_dequeue(AVFilterContext *avctx, AVFrame *input_frame, int field)
+static int deint_v4l2m2m_dequeue(AVFilterContext *avctx, AVFrame *input_frame)
{
DeintV4L2M2MContext *priv = avctx->priv;
DeintV4L2M2MContextShared *ctx = priv->shared;
AVFilterLink *outlink = avctx->outputs[0];
- AVFrame *output_frame;
+ AVFrame *output_frame_1, *output_frame_2;
+ int64_t first_pts = AV_NOPTS_VALUE;
int err;
- output_frame = av_frame_alloc();
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64" (field %d)\n",
+ input_frame->pts, ctx->field_order);
- if (!output_frame)
+ output_frame_1 = av_frame_alloc();
+ if (!output_frame_1)
return AVERROR(ENOMEM);
- err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame, 500);
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame_1, 500);
if (err < 0) {
- av_log(priv, AV_LOG_ERROR, "no frame (field %d)\n", field);
- goto fail;
+ av_log(priv, AV_LOG_ERROR, "no 1st frame (field %d)\n", ctx->field_order);
+ goto fail_out1;
}
- err = av_frame_copy_props(output_frame, input_frame);
+ err = av_frame_copy_props(output_frame_1, input_frame);
if (err < 0)
- goto fail;
+ goto fail_out1;
- output_frame->interlaced_frame = 0;
+ output_frame_1->interlaced_frame = 0;
- if (field == 0) {
- output_frame->pts *= 2;
- } else {
- int64_t cur_pts = ctx->frames[0]->pts;
- int64_t next_pts = ctx->frames[1]->pts;
+ output_frame_2 = av_frame_alloc();
+ if (!output_frame_2) {
+ err = AVERROR(ENOMEM);
+ goto fail_out1;
+ }
+
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame_2, 500);
+ if (err < 0) {
+ av_log(priv, AV_LOG_ERROR, "no 2nd frame (field %d)\n", ctx->field_order);
+ goto fail_out2;
+ }
+
+ err = av_frame_copy_props(output_frame_2, input_frame);
+ if (err < 0)
+ goto fail_out2;
+
+ output_frame_2->interlaced_frame = 0;
- if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) {
- output_frame->pts = next_pts + cur_pts;
- } else {
- output_frame->pts = AV_NOPTS_VALUE;
- }
+ if (ctx->prev_in_frame && ctx->prev_in_frame->pts != AV_NOPTS_VALUE
+ && input_frame->pts != AV_NOPTS_VALUE) {
+ first_pts = (ctx->prev_in_frame->pts + input_frame->pts) / 2;
+ av_log(priv, AV_LOG_DEBUG, "calculated first pts %"PRId64"\n", first_pts);
}
- av_log(priv, AV_LOG_DEBUG, "pts: %"PRId64" (field %d)\n", output_frame->pts, field);
- return ff_filter_frame(outlink, output_frame);
+ output_frame_1->pts = first_pts;
+
+ err = ff_filter_frame(outlink, output_frame_1);
+ if (err < 0) {
+ av_frame_free(&output_frame_2);
+ return err;
+ }
+ err = ff_filter_frame(outlink, output_frame_2);
+
+ if (err < 0)
+ return err;
+
+ av_log(priv, AV_LOG_DEBUG, "1st frame pts: %"PRId64" 2nd frame pts: %"PRId64" first pts: %"PRId64" (field %d)\n",
+ output_frame_1->pts, output_frame_2->pts, first_pts, ctx->field_order);
+
+ return 0;
-fail:
- av_frame_free(&output_frame);
+fail_out2:
+ av_frame_free(&output_frame_2);
+fail_out1:
+ av_frame_free(&output_frame_1);
return err;
}
@@ -749,20 +788,22 @@ static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in)
V4L2Queue *output = &ctx->output;
int ret;
- av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64"\n", in->pts);
- if (!ctx->frame_count) {
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64" field :%d interlaced: %d\n",
+ in->pts, in->top_field_first, in->interlaced_frame);
+
+ ctx->cur_in_frame = in;
+
+ if (ctx->field_order == V4L2_FIELD_ANY) {
AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)in->data[0];
- unsigned int field;
-
ctx->orig_width = drm_desc->layers[0].planes[0].pitch;
ctx->orig_height = drm_desc->layers[0].planes[1].offset / ctx->orig_width;
- if (in->top_field_first)
- field = V4L2_FIELD_INTERLACED_TB;
+ if (in->top_field_first)
+ ctx->field_order = V4L2_FIELD_INTERLACED_TB;
else
- field = V4L2_FIELD_INTERLACED_BT;
+ ctx->field_order = V4L2_FIELD_INTERLACED_BT;
- ret = deint_v4l2m2m_set_format(output, field, ctx->orig_width, ctx->orig_height);
+ ret = deint_v4l2m2m_set_format(output, ctx->field_order, ctx->orig_width, ctx->orig_height);
if (ret)
return ret;
@@ -787,27 +828,19 @@ static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in)
return ret;
}
- if (ctx->frame_count < 2) {
- ctx->frames[ctx->frame_count++] = in;
- } else {
- av_frame_free(&ctx->frames[0]);
- ctx->frames[0] = ctx->frames[1];
- ctx->frames[1] = in;
- }
-
ret = deint_v4l2m2m_enqueue(output, in);
if (ret)
return ret;
- if (ctx->frame_count == 2) {
- ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 0);
- if (ret)
- return ret;
+ ret = deint_v4l2m2m_dequeue(avctx, in);
+ if (ret)
+ return ret;
- ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 1);
- if (ret)
- return ret;
- }
+ if (ctx->prev_in_frame)
+ av_frame_free(&ctx->prev_in_frame);
+
+ ctx->prev_in_frame = in;
+ ctx->cur_in_frame = NULL;
return 0;
}
@@ -828,6 +861,9 @@ static av_cold int deint_v4l2m2m_init(AVFilterContext *avctx)
ctx->capture.ctx = ctx;
ctx->capture.num_buffers = 6;
ctx->done = 0;
+ ctx->field_order = V4L2_FIELD_ANY;
+ ctx->cur_in_frame = NULL;
+ ctx->prev_in_frame = NULL;
atomic_init(&ctx->refcount, 1);
return 0;
--
2.29.2

View File

@ -1,80 +0,0 @@
From 0770ca82391fb60084080b2fd235cc039a3b8314 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sun, 25 Apr 2021 10:40:56 +0000
Subject: [PATCH] v4l2_request: revert changes
---
libavcodec/v4l2_request.c | 10 +++-------
libavcodec/v4l2_request_h264.c | 8 ++++----
2 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/libavcodec/v4l2_request.c b/libavcodec/v4l2_request.c
index 5234b5049b0d..1e513ee5df8d 100644
--- a/libavcodec/v4l2_request.c
+++ b/libavcodec/v4l2_request.c
@@ -142,14 +142,12 @@ static int v4l2_request_queue_buffer(V4L2RequestContext *ctx, int request_fd, V4
.type = buf->buffer.type,
.memory = buf->buffer.memory,
.index = buf->index,
- .timestamp.tv_usec = ctx->timestamp,
+ .timestamp.tv_usec = buf->index + 1,
.bytesused = buf->used,
.request_fd = request_fd,
.flags = ((request_fd >= 0) ? V4L2_BUF_FLAG_REQUEST_FD : 0) | flags,
};
- buf->buffer.timestamp = buffer.timestamp;
-
if (V4L2_TYPE_IS_MULTIPLANAR(buf->buffer.type)) {
planes[0].bytesused = buf->used;
buffer.bytesused = 0;
@@ -239,9 +237,6 @@ static int v4l2_request_queue_decode(AVCodecContext *avctx, AVFrame *frame, stru
av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p used=%u controls=%d index=%d fd=%d request_fd=%d first_slice=%d last_slice=%d\n", __func__, avctx, req->output.used, count, req->capture.index, req->capture.fd, req->request_fd, first_slice, last_slice);
- if (first_slice)
- ctx->timestamp++;
-
ret = v4l2_request_set_controls(ctx, req->request_fd, control, count);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "%s: set controls failed for request %d, %s (%d)\n", __func__, req->request_fd, strerror(errno), errno);
@@ -693,7 +688,6 @@ int ff_v4l2_request_init(AVCodecContext *avctx, uint32_t pixelformat, uint32_t b
ctx->media_fd = -1;
ctx->video_fd = -1;
- ctx->timestamp = 0;
udev = udev_new();
if (!udev) {
@@ -827,6 +821,8 @@ static int v4l2_request_buffer_alloc(AVCodecContext *avctx, V4L2RequestBuffer *b
return ret;
}
+ buf->buffer.timestamp.tv_usec = buf->index + 1;
+
if (V4L2_TYPE_IS_OUTPUT(type)) {
void *addr = mmap(NULL, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED, ctx->video_fd, V4L2_TYPE_IS_MULTIPLANAR(type) ? buf->buffer.m.planes[0].m.mem_offset : buf->buffer.m.offset);
if (addr == MAP_FAILED) {
diff --git a/libavcodec/v4l2_request_h264.c b/libavcodec/v4l2_request_h264.c
index 88da8f0a2db0..a14028336a39 100644
--- a/libavcodec/v4l2_request_h264.c
+++ b/libavcodec/v4l2_request_h264.c
@@ -252,7 +252,7 @@ static int v4l2_request_h264_start_frame(AVCodecContext *avctx,
fill_dpb(&controls->decode_params, h);
- controls->first_slice = !FIELD_PICTURE(h) || h->first_field;
+ controls->first_slice = 1;
controls->num_slices = 0;
return ff_v4l2_request_reset_frame(avctx, h->cur_pic_ptr->f);
@@ -383,8 +383,7 @@ static int v4l2_request_h264_decode_slice(AVCodecContext *avctx, const uint8_t *
static int v4l2_request_h264_end_frame(AVCodecContext *avctx)
{
- const H264Context *h = avctx->priv_data;
- return v4l2_request_h264_queue_decode(avctx, !FIELD_PICTURE(h) || !h->first_field);
+ return v4l2_request_h264_queue_decode(avctx, 1);
}
static int v4l2_request_h264_set_controls(AVCodecContext *avctx)

View File

@ -1,230 +0,0 @@
From 6bea46839ba23bffaa093bb9ed805d571aaa66ea Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Wed, 30 Sep 2020 21:11:34 +0200
Subject: [PATCH] libavfilter: v4l2deinterlace: dequeue both destination
buffers on time
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
libavfilter/vf_deinterlace_v4l2m2m.c | 140 +++++++++++++++++----------
1 file changed, 88 insertions(+), 52 deletions(-)
diff --git a/libavfilter/vf_deinterlace_v4l2m2m.c b/libavfilter/vf_deinterlace_v4l2m2m.c
index 1029e5b620fd..72d28333ffa7 100644
--- a/libavfilter/vf_deinterlace_v4l2m2m.c
+++ b/libavfilter/vf_deinterlace_v4l2m2m.c
@@ -89,8 +89,14 @@ typedef struct DeintV4L2M2MContextShared {
AVBufferRef *hw_frames_ctx;
- int frame_count;
- AVFrame *frames[2];
+ /*
+ * TODO: check if its really neccessary to hold this
+ * ref, it's only used for freeing av_frame on decoding
+ * end/abort
+ */
+ AVFrame *cur_in_frame;
+ AVFrame *prev_in_frame;
+ unsigned int field_order;
V4L2Queue output;
V4L2Queue capture;
@@ -557,8 +563,11 @@ static void deint_v4l2m2m_destroy_context(DeintV4L2M2MContextShared *ctx)
close(capture->buffers[i].fd);
}
- for (i = 0; i < ctx->frame_count; i++)
- av_frame_free(&ctx->frames[i]);
+ if (ctx->cur_in_frame)
+ av_frame_free(&ctx->cur_in_frame);
+
+ if (ctx->prev_in_frame)
+ av_frame_free(&ctx->prev_in_frame);
av_buffer_unref(&ctx->hw_frames_ctx);
@@ -652,49 +661,79 @@ static int deint_v4l2m2m_dequeue_frame(V4L2Queue *queue, AVFrame* frame, int tim
return 0;
}
-static int deint_v4l2m2m_dequeue(AVFilterContext *avctx, AVFrame *input_frame, int field)
+static int deint_v4l2m2m_dequeue(AVFilterContext *avctx, AVFrame *input_frame)
{
DeintV4L2M2MContext *priv = avctx->priv;
DeintV4L2M2MContextShared *ctx = priv->shared;
AVFilterLink *outlink = avctx->outputs[0];
- AVFrame *output_frame;
+ AVFrame *output_frame_1, *output_frame_2;
+ int64_t first_pts = AV_NOPTS_VALUE;
int err;
- output_frame = av_frame_alloc();
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64" (field %d)\n",
+ input_frame->pts, ctx->field_order);
- if (!output_frame)
+ output_frame_1 = av_frame_alloc();
+ if (!output_frame_1)
return AVERROR(ENOMEM);
- err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame, 500);
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame_1, 500);
if (err < 0) {
- av_log(priv, AV_LOG_ERROR, "no frame (field %d)\n", field);
- goto fail;
+ av_log(priv, AV_LOG_ERROR, "no 1st frame (field %d)\n", ctx->field_order);
+ goto fail_out1;
}
- err = av_frame_copy_props(output_frame, input_frame);
+ err = av_frame_copy_props(output_frame_1, input_frame);
if (err < 0)
- goto fail;
+ goto fail_out1;
- output_frame->interlaced_frame = 0;
+ output_frame_1->interlaced_frame = 0;
- if (field == 0) {
- output_frame->pts *= 2;
- } else {
- int64_t cur_pts = ctx->frames[0]->pts;
- int64_t next_pts = ctx->frames[1]->pts;
+ output_frame_2 = av_frame_alloc();
+ if (!output_frame_2) {
+ err = AVERROR(ENOMEM);
+ goto fail_out1;
+ }
+
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame_2, 500);
+ if (err < 0) {
+ av_log(priv, AV_LOG_ERROR, "no 2nd frame (field %d)\n", ctx->field_order);
+ goto fail_out2;
+ }
+
+ err = av_frame_copy_props(output_frame_2, input_frame);
+ if (err < 0)
+ goto fail_out2;
+
+ output_frame_2->interlaced_frame = 0;
- if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) {
- output_frame->pts = next_pts + cur_pts;
- } else {
- output_frame->pts = AV_NOPTS_VALUE;
- }
+ if (ctx->prev_in_frame && ctx->prev_in_frame->pts != AV_NOPTS_VALUE
+ && input_frame->pts != AV_NOPTS_VALUE) {
+ first_pts = (ctx->prev_in_frame->pts + input_frame->pts) / 2;
+ av_log(priv, AV_LOG_DEBUG, "calculated first pts %"PRId64"\n", first_pts);
}
- av_log(priv, AV_LOG_DEBUG, "pts: %"PRId64" (field %d)\n", output_frame->pts, field);
- return ff_filter_frame(outlink, output_frame);
+ output_frame_1->pts = first_pts;
+
+ err = ff_filter_frame(outlink, output_frame_1);
+ if (err < 0) {
+ av_frame_free(&output_frame_2);
+ return err;
+ }
+ err = ff_filter_frame(outlink, output_frame_2);
+
+ if (err < 0)
+ return err;
+
+ av_log(priv, AV_LOG_DEBUG, "1st frame pts: %"PRId64" 2nd frame pts: %"PRId64" first pts: %"PRId64" (field %d)\n",
+ output_frame_1->pts, output_frame_2->pts, first_pts, ctx->field_order);
+
+ return 0;
-fail:
- av_frame_free(&output_frame);
+fail_out2:
+ av_frame_free(&output_frame_2);
+fail_out1:
+ av_frame_free(&output_frame_1);
return err;
}
@@ -749,20 +788,22 @@ static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in)
V4L2Queue *output = &ctx->output;
int ret;
- av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64"\n", in->pts);
- if (!ctx->frame_count) {
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64" field :%d interlaced: %d\n",
+ in->pts, in->top_field_first, in->interlaced_frame);
+
+ ctx->cur_in_frame = in;
+
+ if (ctx->field_order == V4L2_FIELD_ANY) {
AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)in->data[0];
- unsigned int field;
-
ctx->orig_width = drm_desc->layers[0].planes[0].pitch;
ctx->orig_height = drm_desc->layers[0].planes[1].offset / ctx->orig_width;
- if (in->top_field_first)
- field = V4L2_FIELD_INTERLACED_TB;
+ if (in->top_field_first)
+ ctx->field_order = V4L2_FIELD_INTERLACED_TB;
else
- field = V4L2_FIELD_INTERLACED_BT;
+ ctx->field_order = V4L2_FIELD_INTERLACED_BT;
- ret = deint_v4l2m2m_set_format(output, field, ctx->orig_width, ctx->orig_height);
+ ret = deint_v4l2m2m_set_format(output, ctx->field_order, ctx->orig_width, ctx->orig_height);
if (ret)
return ret;
@@ -787,27 +828,19 @@ static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in)
return ret;
}
- if (ctx->frame_count < 2) {
- ctx->frames[ctx->frame_count++] = in;
- } else {
- av_frame_free(&ctx->frames[0]);
- ctx->frames[0] = ctx->frames[1];
- ctx->frames[1] = in;
- }
-
ret = deint_v4l2m2m_enqueue(output, in);
if (ret)
return ret;
- if (ctx->frame_count == 2) {
- ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 0);
- if (ret)
- return ret;
+ ret = deint_v4l2m2m_dequeue(avctx, in);
+ if (ret)
+ return ret;
- ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 1);
- if (ret)
- return ret;
- }
+ if (ctx->prev_in_frame)
+ av_frame_free(&ctx->prev_in_frame);
+
+ ctx->prev_in_frame = in;
+ ctx->cur_in_frame = NULL;
return 0;
}
@@ -828,6 +861,9 @@ static av_cold int deint_v4l2m2m_init(AVFilterContext *avctx)
ctx->capture.ctx = ctx;
ctx->capture.num_buffers = 6;
ctx->done = 0;
+ ctx->field_order = V4L2_FIELD_ANY;
+ ctx->cur_in_frame = NULL;
+ ctx->prev_in_frame = NULL;
atomic_init(&ctx->refcount, 1);
return 0;
--
2.29.2

View File

@ -1,288 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Wed, 15 Sep 2021 00:37:15 +0200
Subject: [PATCH] libavfilter: v4l2deinterlace: support more formats /
automatic output format selection
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
libavfilter/vf_deinterlace_v4l2m2m.c | 120 +++++++++++++++++++++++----
1 file changed, 102 insertions(+), 18 deletions(-)
diff --git a/libavfilter/vf_deinterlace_v4l2m2m.c b/libavfilter/vf_deinterlace_v4l2m2m.c
index d7935d92f9..8161fd9e75 100644
--- a/libavfilter/vf_deinterlace_v4l2m2m.c
+++ b/libavfilter/vf_deinterlace_v4l2m2m.c
@@ -85,6 +85,9 @@ typedef struct DeintV4L2M2MContextShared {
int height;
int orig_width;
int orig_height;
+ uint64_t drm_in_format;
+ uint64_t drm_out_format;
+
atomic_uint refcount;
AVBufferRef *hw_frames_ctx;
@@ -108,6 +111,65 @@ typedef struct DeintV4L2M2MContext {
DeintV4L2M2MContextShared *shared;
} DeintV4L2M2MContext;
+typedef struct drm_v4l2_pix_fmt_mapping {
+ uint64_t drm_format;
+ uint32_t v4l2_pix_fmt;
+};
+
+static struct drm_v4l2_pix_fmt_mapping drm_v4l2_pix_fmt_map[] = {
+ { .drm_format = DRM_FORMAT_NV12, .v4l2_pix_fmt = V4L2_PIX_FMT_NV12 },
+ { .drm_format = DRM_FORMAT_NV21, .v4l2_pix_fmt = V4L2_PIX_FMT_NV21 },
+ { .drm_format = DRM_FORMAT_NV16, .v4l2_pix_fmt = V4L2_PIX_FMT_NV16 },
+ { .drm_format = DRM_FORMAT_NV16, .v4l2_pix_fmt = V4L2_PIX_FMT_NV16 },
+#ifdef DRM_FORMAT_MOD_ALLWINNER_TILED
+ { .drm_format = DRM_FORMAT_MOD_ALLWINNER_TILED, .v4l2_pix_fmt = V4L2_PIX_FMT_SUNXI_TILED_NV12 },
+#endif
+#if defined(V4L2_PIX_FMT_NV15) && defined(DRM_FORMAT_NV15)
+ { .drm_format = DRM_FORMAT_NV15, .v4l2_pix_fmt = V4L2_PIX_FMT_NV15 },
+#endif
+#if defined(V4L2_PIX_FMT_NV20) && defined(DRM_FORMAT_NV20)
+ { .drm_format = DRM_FORMAT_NV20, .v4l2_pix_fmt = V4L2_PIX_FMT_NV20 },
+#endif
+};
+
+static inline uint32_t v4l2_pix_fmt_from_drm_format(uint64_t drm_format)
+{
+ unsigned int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(drm_v4l2_pix_fmt_map); i++) {
+ if (drm_v4l2_pix_fmt_map[i].drm_format == drm_format)
+ return drm_v4l2_pix_fmt_map[i].v4l2_pix_fmt;
+ }
+
+ av_log(NULL, AV_LOG_WARNING, "%s unknown drm format 0x%llx using default v4l2_pix_fmt 0x%x\n",
+ __func__ , drm_format, drm_v4l2_pix_fmt_map[0].v4l2_pix_fmt);
+ return drm_v4l2_pix_fmt_map[0].v4l2_pix_fmt;
+}
+
+static inline uint64_t drm_format_from_v4l2_pix_fmt(uint32_t v4l2_pix_fmt)
+{
+ unsigned int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(drm_v4l2_pix_fmt_map); i++) {
+ if (drm_v4l2_pix_fmt_map[i].v4l2_pix_fmt == v4l2_pix_fmt)
+ return drm_v4l2_pix_fmt_map[i].drm_format;
+ }
+
+ av_log(NULL, AV_LOG_WARNING, "%s unknown v4l2_pix_fmt format 0x%x using default drm_format 0x%llx\n",
+ __func__ , v4l2_pix_fmt, drm_v4l2_pix_fmt_map[0].drm_format);
+ return drm_v4l2_pix_fmt_map[0].drm_format;
+}
+
+static inline uint64_t drm_format_modifier(uint64_t drm_format)
+{
+#ifdef DRM_FORMAT_MOD_ALLWINNER_TILED
+ if (drm_format == DRM_FORMAT_MOD_ALLWINNER_TILED)
+ return DRM_FORMAT_MOD_ALLWINNER_TILED;
+#endif
+ return DRM_FORMAT_MOD_LINEAR;
+
+}
+
static int deint_v4l2m2m_prepare_context(DeintV4L2M2MContextShared *ctx)
{
struct v4l2_capability cap;
@@ -138,11 +200,12 @@ static int deint_v4l2m2m_prepare_context(DeintV4L2M2MContextShared *ctx)
return AVERROR(EINVAL);
}
-static int deint_v4l2m2m_try_format(V4L2Queue *queue)
+static int deint_v4l2m2m_try_format(V4L2Queue *queue, uint64_t drm_format)
{
struct v4l2_format *fmt = &queue->format;
DeintV4L2M2MContextShared *ctx = queue->ctx;
int ret, field;
+ uint32_t v4l2_pix_fmt = v4l2_pix_fmt_from_drm_format(drm_format);
ret = ioctl(ctx->fd, VIDIOC_G_FMT, fmt);
if (ret)
@@ -154,12 +217,12 @@ static int deint_v4l2m2m_try_format(V4L2Queue *queue)
field = V4L2_FIELD_NONE;
if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
- fmt->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
+ fmt->fmt.pix_mp.pixelformat = v4l2_pix_fmt;
fmt->fmt.pix_mp.field = field;
fmt->fmt.pix_mp.width = ctx->width;
fmt->fmt.pix_mp.height = ctx->height;
} else {
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
+ fmt->fmt.pix.pixelformat = v4l2_pix_fmt;
fmt->fmt.pix.field = field;
fmt->fmt.pix.width = ctx->width;
fmt->fmt.pix.height = ctx->height;
@@ -170,14 +233,14 @@ static int deint_v4l2m2m_try_format(V4L2Queue *queue)
return AVERROR(EINVAL);
if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
- if (fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12 ||
+ if (fmt->fmt.pix_mp.pixelformat != v4l2_pix_fmt ||
fmt->fmt.pix_mp.field != field) {
av_log(NULL, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type);
return AVERROR(EINVAL);
}
} else {
- if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_NV12 ||
+ if (fmt->fmt.pix.pixelformat != v4l2_pix_fmt ||
fmt->fmt.pix.field != field) {
av_log(NULL, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type);
@@ -187,19 +250,21 @@ static int deint_v4l2m2m_try_format(V4L2Queue *queue)
return 0;
}
-
-static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t field, int width, int height)
+static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t field, int width, int height, uint64_t drm_format)
{
struct v4l2_format *fmt = &queue->format;
DeintV4L2M2MContextShared *ctx = queue->ctx;
int ret;
+ uint32_t v4l2_pix_fmt = v4l2_pix_fmt_from_drm_format(drm_format);
if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+ fmt->fmt.pix_mp.pixelformat = v4l2_pix_fmt;
fmt->fmt.pix_mp.field = field;
fmt->fmt.pix_mp.width = width;
fmt->fmt.pix_mp.height = height;
/* TODO: bytesperline and imagesize */
} else {
+ fmt->fmt.pix.pixelformat = v4l2_pix_fmt;
fmt->fmt.pix.field = field;
fmt->fmt.pix.width = width;
fmt->fmt.pix.height = height;
@@ -211,6 +276,18 @@ static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t field, int width,
if (ret)
av_log(NULL, AV_LOG_ERROR, "VIDIOC_S_FMT failed: %d\n", ret);
+ else if (!V4L2_TYPE_IS_OUTPUT(queue->format.type)) {
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type) && fmt->fmt.pix_mp.pixelformat != v4l2_pix_fmt) {
+ ctx->drm_out_format = drm_format_from_v4l2_pix_fmt(fmt->fmt.pix_mp.pixelformat);
+ av_log(NULL, AV_LOG_DEBUG, "%s driver updated v4l2_pixfmt from: %x to %x, so now using %llx as drm output format\n",
+ __func__, v4l2_pix_fmt, fmt->fmt.pix_mp.pixelformat, ctx->drm_out_format);
+ } else if (fmt->fmt.pix.pixelformat != v4l2_pix_fmt) {
+ ctx->drm_out_format = drm_format_from_v4l2_pix_fmt(fmt->fmt.pix.pixelformat);
+ av_log(NULL, AV_LOG_DEBUG, "%s driver updated v4l2_pixfmt from: %x to %x, so now using %llx as drm output format\n",
+ __func__, v4l2_pix_fmt, fmt->fmt.pix.pixelformat, ctx->drm_out_format);
+ }
+ }
+
return ret;
}
@@ -226,11 +303,11 @@ static int deint_v4l2m2m_probe_device(DeintV4L2M2MContextShared *ctx, char *node
if (ret)
goto fail;
- ret = deint_v4l2m2m_try_format(&ctx->capture);
+ ret = deint_v4l2m2m_try_format(&ctx->capture, ctx->drm_out_format);
if (ret)
goto fail;
- ret = deint_v4l2m2m_try_format(&ctx->output);
+ ret = deint_v4l2m2m_try_format(&ctx->output, ctx->drm_in_format);
if (ret)
goto fail;
@@ -293,7 +370,7 @@ static int deint_v4l2m2m_enqueue_buffer(V4L2Buffer *buf)
return 0;
}
-static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
+static int v4l2_buffer_export_drm(V4L2Buffer* avbuf, uint64_t drm_format)
{
struct v4l2_exportbuffer expbuf;
int i, ret;
@@ -315,12 +392,12 @@ static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
/* drm frame */
avbuf->drm_frame.objects[i].size = avbuf->buffer.m.planes[i].length;
avbuf->drm_frame.objects[i].fd = expbuf.fd;
- avbuf->drm_frame.objects[i].format_modifier = DRM_FORMAT_MOD_LINEAR;
+ avbuf->drm_frame.objects[i].format_modifier = drm_format_modifier(drm_format);
} else {
/* drm frame */
avbuf->drm_frame.objects[0].size = avbuf->buffer.length;
avbuf->drm_frame.objects[0].fd = expbuf.fd;
- avbuf->drm_frame.objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
+ avbuf->drm_frame.objects[0].format_modifier = drm_format_modifier(drm_format);
}
}
@@ -405,7 +482,7 @@ static int deint_v4l2m2m_allocate_buffers(V4L2Queue *queue)
if (ret)
goto fail;
- ret = v4l2_buffer_export_drm(buf);
+ ret = v4l2_buffer_export_drm(buf, ctx->drm_out_format);
if (ret)
goto fail;
}
@@ -597,7 +674,7 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused)
deint_v4l2m2m_destroy_context(ctx);
}
-static uint8_t *v4l2_get_drm_frame(V4L2Buffer *avbuf, int height)
+static uint8_t *v4l2_get_drm_frame(V4L2Buffer *avbuf, int height, uint64_t drm_format)
{
AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame;
AVDRMLayerDescriptor *layer;
@@ -615,7 +692,7 @@ static uint8_t *v4l2_get_drm_frame(V4L2Buffer *avbuf, int height)
layer->planes[i].pitch = avbuf->plane_info[i].bytesperline;
}
- layer->format = DRM_FORMAT_NV12;
+ layer->format = drm_format;
if (avbuf->num_planes == 1) {
layer->nb_planes = 2;
@@ -647,7 +724,7 @@ static int deint_v4l2m2m_dequeue_frame(V4L2Queue *queue, AVFrame* frame, int tim
atomic_fetch_add(&ctx->refcount, 1);
- frame->data[0] = (uint8_t *)v4l2_get_drm_frame(avbuf, ctx->orig_height);
+ frame->data[0] = (uint8_t *)v4l2_get_drm_frame(avbuf, ctx->orig_height, ctx->drm_out_format);
frame->format = AV_PIX_FMT_DRM_PRIME;
frame->hw_frames_ctx = av_buffer_ref(ctx->hw_frames_ctx);
frame->height = ctx->height;
@@ -797,17 +874,22 @@ static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in)
AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)in->data[0];
ctx->orig_width = drm_desc->layers[0].planes[0].pitch;
ctx->orig_height = drm_desc->layers[0].planes[1].offset / ctx->orig_width;
+ ctx->drm_in_format = drm_desc->layers->format;
+ ctx->drm_out_format = drm_desc->layers->format;
+
if (in->top_field_first)
ctx->field_order = V4L2_FIELD_INTERLACED_TB;
else
ctx->field_order = V4L2_FIELD_INTERLACED_BT;
- ret = deint_v4l2m2m_set_format(output, ctx->field_order, ctx->orig_width, ctx->orig_height);
+ ret = deint_v4l2m2m_set_format(output, ctx->field_order, ctx->orig_width, ctx->orig_height,
+ ctx->drm_in_format);
if (ret)
return ret;
- ret = deint_v4l2m2m_set_format(capture, V4L2_FIELD_NONE, ctx->orig_width, ctx->orig_height);
+ ret = deint_v4l2m2m_set_format(capture, V4L2_FIELD_NONE, ctx->orig_width, ctx->orig_height,
+ ctx->drm_out_format);
if (ret)
return ret;
@@ -864,6 +946,8 @@ static av_cold int deint_v4l2m2m_init(AVFilterContext *avctx)
ctx->field_order = V4L2_FIELD_ANY;
ctx->cur_in_frame = NULL;
ctx->prev_in_frame = NULL;
+ ctx->drm_in_format = drm_v4l2_pix_fmt_map[0].drm_format;
+ ctx->drm_out_format = drm_v4l2_pix_fmt_map[0].drm_format;
atomic_init(&ctx->refcount, 1);
return 0;

View File

@ -2,12 +2,12 @@
# base ffmpeg version
FFMPEG_REPO="git://source.ffmpeg.org/ffmpeg.git"
FFMPEG_VERSION="n4.4.1"
FFMPEG_VERSION="n5.1.2"
KODI_FFMPEG_REPO="https://github.com/xbmc/FFmpeg"
KODI_FFMPEG_VERSION="4.4.1-Nexus-Alpha1"
KODI_FFMPEG_VERSION="5.1.2-Nexus-Alpha3"
ALL_FEATURE_SETS="v4l2-drmprime v4l2-request libreelec rpi kodi"
ALL_FEATURE_SETS="v4l2-drmprime v4l2-request libreelec rpi vf-deinterlace-v4l2m2m"
if [ $# -eq 0 ]; then
echo "usage: $0 all|featureset [githash]"
@ -28,31 +28,17 @@ create_patch() {
PATCH_CREATE_DIFF="no"
case "${FEATURE_SET}" in
v4l2-drmprime)
v4l2-drmprime|v4l2-request|vf-deinterlace-v4l2m2m)
REPO="https://github.com/jernejsk/FFmpeg"
REFSPEC="v4l2-drmprime-v6-4.4.1-Nexus-Alpha1"
BASE_REPO="${KODI_FFMPEG_REPO}"
BASE_VERSION="${KODI_FFMPEG_VERSION}"
;;
v4l2-request)
REPO="https://github.com/jernejsk/FFmpeg"
REFSPEC="v4l2-request-hwaccel-4.4.1-Nexus-Alpha1"
BASE_REPO="${KODI_FFMPEG_REPO}"
BASE_VERSION="${KODI_FFMPEG_VERSION}"
REFSPEC="${FEATURE_SET}-${FFMPEG_VERSION}"
;;
libreelec)
REPO="https://github.com/LibreELEC/FFmpeg"
REFSPEC="4.4-libreelec-misc"
REFSPEC="5.1.2-libreelec-misc"
;;
rpi)
REPO="https://github.com/jc-kynesim/rpi-ffmpeg"
REFSPEC="dev/4.4/rpi_import_1"
PATCH_CREATE_DIFF="yes"
;;
kodi)
REPO="${KODI_FFMPEG_REPO}"
REFSPEC="${KODI_FFMPEG_VERSION}"
REFTYPE="tag"
REFSPEC="dev/5.1.2/rpi_import_1"
;;
*)
echo "illegal feature set ${FEATURE_SET}"