[mixxx/f39] Patch .desktop file to use XWayland instead of Wayland
by Uwe Klotz
commit 1adbe971d2d6e5aa05bf188804edcbd69bdff9dc
Author: Uwe Klotz <uwe.klotz(a)gmail.com>
Date: Tue Nov 21 22:58:33 2023 +0100
Patch .desktop file to use XWayland instead of Wayland
desktop-file-qpa-platform-xcb.patch | 15 +++++++++++++++
mixxx.spec | 1 +
2 files changed, 16 insertions(+)
---
diff --git a/desktop-file-qpa-platform-xcb.patch b/desktop-file-qpa-platform-xcb.patch
new file mode 100644
index 0000000..05955a5
--- /dev/null
+++ b/desktop-file-qpa-platform-xcb.patch
@@ -0,0 +1,15 @@
+--- a/res/linux/org.mixxx.Mixxx.desktop
++++ b/res/linux/org.mixxx.Mixxx.desktop
+@@ -8,7 +8,9 @@ GenericName[fr]=Interface numérique pour DJ
+ Comment=A digital DJ interface
+ Comment[de]=Ein digitales DJ-System
+ Comment[fr]=Une interface numérique pour DJ
+-Exec=sh -c "pasuspender -- mixxx || mixxx"
++# Use XWayland platform plugin (xcb) due to issues with Qt5 on Wayland.
++# See also: <https://github.com/mixxxdj/mixxx/issues/12332>
++Exec=env QT_QPA_PLATFORM=xcb sh -c "pasuspender -- mixxx || mixxx"
+ Terminal=false
+ Icon=mixxx
+ Type=Application
+--
+2.42.0
diff --git a/mixxx.spec b/mixxx.spec
index 1ff831e..d3e0865 100644
--- a/mixxx.spec
+++ b/mixxx.spec
@@ -37,6 +37,7 @@ Source0: https://github.com/mixxxdj/%{name}/archive/%{sources}/%{name}-%{
# as a fragment identifier to the URL to populate SOURCE<n> correctly
Source1: https://github.com/mixxxdj/libkeyfinder/archive/refs/tags/v%{libkeyfinder...
Source2: https://github.com/xsco/libdjinterop/archive/refs/tags/%{libdjinterop_ver...
+Patch0: desktop-file-qpa-platform-xcb.patch
# Build Tools
BuildRequires: desktop-file-utils
1 year
[xtables-addons-kmod] Release 3.25
by Leigh Scott
commit 7610509487b43d7d52806ecf470e6cc51412b1e6
Author: Leigh Scott <leigh123linux(a)gmail.com>
Date: Tue Nov 21 19:21:11 2023 +0000
Release 3.25
el8_fix.patch | 8 ++++----
sources | 2 +-
xtables-addons-kmod.spec | 7 +++++--
3 files changed, 10 insertions(+), 7 deletions(-)
---
diff --git a/el8_fix.patch b/el8_fix.patch
index 2b4f0dd..c42f27f 100644
--- a/el8_fix.patch
+++ b/el8_fix.patch
@@ -1,5 +1,5 @@
---- xtables-addons-3.24/extensions/compat_xtables.h
-+++ xtables-addons-3.24/extensions/compat_xtables.h
+--- xtables-addons-3.25/extensions/compat_xtables.h
++++ xtables-addons-3.25/extensions/compat_xtables.h
@@ -21,7 +21,7 @@
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) || \
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 9) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) || \
@@ -9,8 +9,8 @@
#else
# define ip_route_me_harder(xnet, xsk, xskb, xaddrtype) ip_route_me_harder((xnet), (xskb), (xaddrtype))
# define ip6_route_me_harder(xnet, xsk, xskb) ip6_route_me_harder((xnet), (xskb))
---- xtables-addons-3.24/extensions/xt_ipp2p.c
-+++ xtables-addons-3.24/extensions/xt_ipp2p.c
+--- xtables-addons-3.25/extensions/xt_ipp2p.c
++++ xtables-addons-3.25/extensions/xt_ipp2p.c
@@ -19,7 +19,7 @@ MODULE_AUTHOR("Eicke Friedrich/Klaus Deg
MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic.");
MODULE_LICENSE("GPL");
diff --git a/sources b/sources
index f4745bf..43c2951 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (xtables-addons-3.24.tar.xz) = 08c3b87617e0124aef99a3953fc5e03e8d98be50ce70771e352509ec64263d5256f744489f10f39879630d9dc8d28f3c91173b4739c95bbd8d5ad56e33138eb4
+SHA512 (xtables-addons-3.25.tar.xz) = d027614b36aacd65472e76533ace15a8a97eb1db33ff10226a525c5b4d8232c9732336875abfeac71a3a4351971982e884ede7ffe743b14b391b1eedca56be2d
diff --git a/xtables-addons-kmod.spec b/xtables-addons-kmod.spec
index 2fec86d..ef1667e 100644
--- a/xtables-addons-kmod.spec
+++ b/xtables-addons-kmod.spec
@@ -10,8 +10,8 @@
Name: xtables-addons-kmod
Summary: Kernel module (kmod) for xtables-addons
-Version: 3.24
-Release: 2%{?dist}
+Version: 3.25
+Release: 1%{?dist}
License: GPLv2
URL: https://inai.de/projects/xtables-addons/
Source0: https://inai.de/files/xtables-addons/xtables-addons-%{version}.tar.xz
@@ -62,6 +62,9 @@ done
%{?akmod_install}
%changelog
+* Tue Nov 21 2023 Leigh Scott <leigh123linux(a)gmail.com> - 3.25-1
+- Release 3.25
+
* Wed Aug 02 2023 RPM Fusion Release Engineering <sergiomb(a)rpmfusion.org> - 3.24-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
1 year
[ffmpeg/f38] Add changelog
by Nicolas Chauvet
commit 8c051d4ab23060ae5da11869c676ee47709ed446
Author: Nicolas Chauvet <kwizart(a)gmail.com>
Date: Tue Nov 21 09:24:12 2023 +0100
Add changelog
ffmpeg.spec | 3 +++
1 file changed, 3 insertions(+)
---
diff --git a/ffmpeg.spec b/ffmpeg.spec
index f3c8ade..69cd1c9 100644
--- a/ffmpeg.spec
+++ b/ffmpeg.spec
@@ -547,6 +547,9 @@ strip %{buildroot}%{_libdir}/%{name}/libavcodec.so.*
%changelog
+* Tue Nov 21 2023 Nicolas Chauvet <kwizart(a)gmail.com> - 6.0.1-3
+- Backport AV1 VA-API encode support - Thomas Crider
+
* Wed Nov 15 2023 Leigh Scott <leigh123linux(a)gmail.com> - 6.0.1-2
- Add patch to fix fedora ffmpeg brokenABI change
1 year
[ffmpeg/f38] Add backports to support enhanced RTMP and AV1 encoding through VA-API
by Nicolas Chauvet
commit f8a2895453d2aba9434f946c9a50bc4939ecb1e1
Author: Thomas Crider <gloriouseggroll(a)gmail.com>
Date: Mon Nov 20 19:34:56 2023 -0500
Add backports to support enhanced RTMP and AV1 encoding through VA-API
Accepted in upstream Fedora: https://src.fedoraproject.org/rpms/ffmpeg/c/3739445cffd653a4def4ad145235d...
...-devel-v10-Support-enhanced-flv-in-FFmpeg.patch | 1230 ++++++
ffmpeg-ge-av1-vaapi-encode-support.patch | 3984 ++++++++++++++++++++
ffmpeg.spec | 14 +-
3 files changed, 5225 insertions(+), 3 deletions(-)
---
diff --git a/FFmpeg-devel-v10-Support-enhanced-flv-in-FFmpeg.patch b/FFmpeg-devel-v10-Support-enhanced-flv-in-FFmpeg.patch
new file mode 100644
index 0000000..28ff7bb
--- /dev/null
+++ b/FFmpeg-devel-v10-Support-enhanced-flv-in-FFmpeg.patch
@@ -0,0 +1,1230 @@
+From patchwork Mon May 15 08:31:56 2023
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Steven Liu <lq(a)chinaffmpeg.org>
+X-Patchwork-Id: 41615
+Delivered-To: ffmpegpatchwork2(a)gmail.com
+Received: by 2002:a05:6a20:ba91:b0:105:feb:71f2 with SMTP id
+ fb17csp1443896pzb;
+ Mon, 15 May 2023 01:33:01 -0700 (PDT)
+X-Google-Smtp-Source:
+ ACHHUZ69PgG6fq/KF6IIeKoVV29fkg7cAJfmPD3LnnTmI9YYVAPo/alZm7B+7f+FoOgn9rHdYUo5
+X-Received: by 2002:a17:907:97cb:b0:96a:4654:9a57 with SMTP id
+ js11-20020a17090797cb00b0096a46549a57mr16869758ejc.54.1684139580951;
+ Mon, 15 May 2023 01:33:00 -0700 (PDT)
+ARC-Seal: i=1; a=rsa-sha256; t=1684139580; cv=none;
+ d=google.com; s=arc-20160816;
+ b=iOREUkvWDLqSJl40trM7wg3ufEQ23FOBLjpslXsds5HWyK48b/76lFgQwRfHJbHqbh
+ vc4N6DopB5msRi0VK/pJnDAdtuyQR2tqEgLvbZpHJzjK1zHUKRV5JHlmVhNvQOfYWpMR
+ VL/1OMmbTctEza2Z7/VYsrVLHLy4QOlLh4w/JdRcx/7rhiOA1ixpMxC4qUb5IGMhnqen
+ P2dDbAoqdmGUZtmA4VOfxkgkHnIaeFv+UffJGIZs1Lyb7c3zytwdpLLiezRzVLWQaStW
+ TVdcDk45pOrA29lZ46Tq8YNJP7O5zfSevFIqrB85mUjSNoyZi24gz19yxJa/09O1qb+o
+ thzw==
+ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
+ s=arc-20160816;
+ h=sender:errors-to:content-transfer-encoding:cc:reply-to
+ :list-subscribe:list-help:list-post:list-archive:list-unsubscribe
+ :list-id:precedence:subject:feedback-id:mime-version:references
+ :in-reply-to:message-id:date:to:from:delivered-to;
+ bh=Qg7uugO6uqQCX67+SdNELVYF39/WDPRDFt1+H7toQ+s=;
+ b=b1cxdqSVG1Oc157HlNUA+LfJhknU/nr3g5wnSLXmP7DrR+RQp2CFwGfjV+wTkfWLok
+ WydumkYG2biOpmhMi+mG4ci5WvU2R9bv1qpKGreRpsImGmjubQxu5CC9gwmenz3c+1v8
+ pu+qkw142w9uMerjOpaw6oWvaHq9hWGVy6Uni33AqMJhfj9WqSwBCezk62krxzBar/VN
+ XNbzzpAMIuXcj0DcHS70oDHOTbtLq4uDLGpkQwnBpYbswfGD0h8N+B+BSCs3ZqN/l5Jc
+ juIQY4i3ja2W1yHm6Zlze2qU8lFRPzRwVBZBv9vro88VyFic0UZx9wRuIqJB9BZIb0h/
+ vkiA==
+ARC-Authentication-Results: i=1; mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces(a)ffmpeg.org>
+Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100])
+ by mx.google.com with ESMTP id
+ gt37-20020a1709072da500b0096b1c38458dsi2828116ejc.409.2023.05.15.01.33.00;
+ Mon, 15 May 2023 01:33:00 -0700 (PDT)
+Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100;
+Authentication-Results: mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Received: from [127.0.1.1] (localhost [127.0.0.1])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D930568BE0C;
+ Mon, 15 May 2023 11:32:57 +0300 (EEST)
+X-Original-To: ffmpeg-devel(a)ffmpeg.org
+Delivered-To: ffmpeg-devel(a)ffmpeg.org
+Received: from bg4.exmail.qq.com (bg4.exmail.qq.com [43.155.67.158])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 522F7680274
+ for <ffmpeg-devel(a)ffmpeg.org>; Mon, 15 May 2023 11:32:49 +0300 (EEST)
+X-QQ-mid: bizesmtp68t1684139564tg642pbl
+Received: from localhost ( [103.102.203.204]) by bizesmtp.qq.com (ESMTP) with
+ id ; Mon, 15 May 2023 16:32:42 +0800 (CST)
+X-QQ-SSF: 01100000000000Z0Z000000A0000000
+X-QQ-FEAT: nCMT0YKS3i1MU7IXSsiS1Rwde6i/4Rq2kuPO2PoXw3OvtJB24MU+Y2GwdEg4Y
+ pg0ZfSggM3VBmRCkHI3ioSOH2mvVyYG9LgwhhyfixPaFItcpF4EF6xoZepQpa1H5v1BDi7s
+ iwCwF3shgH8dl96iJKKryT4TtjUTnYRoRhCPtLCGfUthaM/R44xdqxRvjDqIVn1BUMb5GPu
+ DMuaskzO8QQCFxvduUvovkXjJc5v17Krm2lf945Tmm/pIpV/qLjAgAhYHqOoxrgBGHZDYWY
+ 0XeS7RvYkKTR24z9m9Sk75veOTKtFzksnbLJYkIDYj+voAd1djXPJWtuB2elhm/DIa9+5lW
+ 2DnKrJ/Bb2Ok13ggXoC600jHcxkLbuOqDuK5k5Dhub7ECOTPJythkMV+FYQCw==
+X-QQ-GoodBg: 0
+X-BIZMAIL-ID: 14547348156280638791
+From: Steven Liu <lq(a)chinaffmpeg.org>
+To: ffmpeg-devel(a)ffmpeg.org
+Date: Mon, 15 May 2023 16:31:56 +0800
+Message-Id: <20230515083201.48201-2-lq(a)chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+References:
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ(a)mail.gmail.com>
+ <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+MIME-Version: 1.0
+X-QQ-SENDSIZE: 520
+Feedback-ID: bizesmtp:chinaffmpeg.org:qybglogicsvrsz:qybglogicsvrsz3a-3
+Subject: [FFmpeg-devel] [PATCH v10 1/6] avformat/flvenc: support mux hevc in
+ enhanced flv
+X-BeenThere: ffmpeg-devel(a)ffmpeg.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
+List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
+List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
+List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
+List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
+List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
+Reply-To: FFmpeg development discussions and patches <ffmpeg-devel(a)ffmpeg.org>
+Cc: Steven Liu <lq(a)chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces(a)ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces(a)ffmpeg.org>
+X-TUID: WUhHC4/dXuk+
+
+Signed-off-by: Steven Liu <lq(a)chinaffmpeg.org>
+---
+ libavformat/Makefile | 2 +-
+ libavformat/flv.h | 15 +++++++++++++++
+ libavformat/flvenc.c | 38 +++++++++++++++++++++++++++++---------
+ 3 files changed, 45 insertions(+), 10 deletions(-)
+
+diff --git a/libavformat/Makefile b/libavformat/Makefile
+index f8ad7c6a11..1ef3d15467 100644
+--- a/libavformat/Makefile
++++ b/libavformat/Makefile
+@@ -214,7 +214,7 @@ OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \
+ OBJS-$(CONFIG_FLIC_DEMUXER) += flic.o
+ OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o
+ OBJS-$(CONFIG_LIVE_FLV_DEMUXER) += flvdec.o
+-OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o
++OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o hevc.o
+ OBJS-$(CONFIG_FOURXM_DEMUXER) += 4xm.o
+ OBJS-$(CONFIG_FRAMECRC_MUXER) += framecrcenc.o framehash.o
+ OBJS-$(CONFIG_FRAMEHASH_MUXER) += hashenc.o framehash.o
+diff --git a/libavformat/flv.h b/libavformat/flv.h
+index 3571b90279..91e0a4140c 100644
+--- a/libavformat/flv.h
++++ b/libavformat/flv.h
+@@ -35,6 +35,12 @@
+
+ #define FLV_VIDEO_FRAMETYPE_OFFSET 4
+
++/* Extended VideoTagHeader
++ * defined in reference link:
++ * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp-v1.pdf
++ * */
++#define FLV_IS_EX_HEADER 0x80
++
+ /* bitmasks to isolate specific values */
+ #define FLV_AUDIO_CHANNEL_MASK 0x01
+ #define FLV_AUDIO_SAMPLESIZE_MASK 0x02
+@@ -112,6 +118,15 @@ enum {
+ FLV_CODECID_MPEG4 = 9,
+ };
+
++enum {
++ PacketTypeSequenceStart = 0,
++ PacketTypeCodedFrames = 1,
++ PacketTypeSequenceEnd = 2,
++ PacketTypeCodedFramesX = 3,
++ PacketTypeMetadata = 4,
++ PacketTypeMPEG2TSSequenceStart = 5,
++};
++
+ enum {
+ FLV_FRAME_KEY = 1 << FLV_VIDEO_FRAMETYPE_OFFSET, ///< key frame (for AVC, a seekable frame)
+ FLV_FRAME_INTER = 2 << FLV_VIDEO_FRAMETYPE_OFFSET, ///< inter frame (for AVC, a non-seekable frame)
+diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
+index 721f062811..35e198fa15 100644
+--- a/libavformat/flvenc.c
++++ b/libavformat/flvenc.c
+@@ -28,6 +28,7 @@
+ #include "libavcodec/mpeg4audio.h"
+ #include "avio.h"
+ #include "avc.h"
++#include "hevc.h"
+ #include "avformat.h"
+ #include "flv.h"
+ #include "internal.h"
+@@ -46,6 +47,7 @@ static const AVCodecTag flv_video_codec_ids[] = {
+ { AV_CODEC_ID_VP6, FLV_CODECID_VP6 },
+ { AV_CODEC_ID_VP6A, FLV_CODECID_VP6A },
+ { AV_CODEC_ID_H264, FLV_CODECID_H264 },
++ { AV_CODEC_ID_HEVC, MKBETAG('h', 'v', 'c', '1') },
+ { AV_CODEC_ID_NONE, 0 }
+ };
+
+@@ -489,7 +491,7 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
+ FLVContext *flv = s->priv_data;
+
+ if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
+- || par->codec_id == AV_CODEC_ID_MPEG4) {
++ || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC) {
+ int64_t pos;
+ avio_w8(pb,
+ par->codec_type == AVMEDIA_TYPE_VIDEO ?
+@@ -532,10 +534,19 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
+ }
+ avio_write(pb, par->extradata, par->extradata_size);
+ } else {
+- avio_w8(pb, par->codec_tag | FLV_FRAME_KEY); // flags
+- avio_w8(pb, 0); // AVC sequence header
+- avio_wb24(pb, 0); // composition time
+- ff_isom_write_avcc(pb, par->extradata, par->extradata_size);
++ if (par->codec_id == AV_CODEC_ID_HEVC) {
++ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeSequenceStart); // ExVideoTagHeader mode with PacketTypeSequenceStart
++ avio_write(pb, "hvc1", 4);
++ } else {
++ avio_w8(pb, par->codec_tag | FLV_FRAME_KEY); // flags
++ avio_w8(pb, 0); // AVC sequence header
++ avio_wb24(pb, 0); // composition time
++ }
++
++ if (par->codec_id == AV_CODEC_ID_HEVC)
++ ff_isom_write_hvcc(pb, par->extradata, par->extradata_size, 0);
++ else
++ ff_isom_write_avcc(pb, par->extradata, par->extradata_size);
+ }
+ data_size = avio_tell(pb) - pos;
+ avio_seek(pb, -data_size - 10, SEEK_CUR);
+@@ -832,13 +843,13 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A ||
+ par->codec_id == AV_CODEC_ID_VP6 || par->codec_id == AV_CODEC_ID_AAC)
+ flags_size = 2;
+- else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4)
++ else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC)
+ flags_size = 5;
+ else
+ flags_size = 1;
+
+ if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
+- || par->codec_id == AV_CODEC_ID_MPEG4) {
++ || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC) {
+ size_t side_size;
+ uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
+ if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
+@@ -858,7 +869,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ "Packets are not in the proper order with respect to DTS\n");
+ return AVERROR(EINVAL);
+ }
+- if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) {
++ if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC) {
+ if (pkt->pts == AV_NOPTS_VALUE) {
+ av_log(s, AV_LOG_ERROR, "Packet is missing PTS\n");
+ return AVERROR(EINVAL);
+@@ -903,6 +914,10 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1)
+ if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0)
+ return ret;
++ } else if (par->codec_id == AV_CODEC_ID_HEVC) {
++ if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1)
++ if ((ret = ff_hevc_annexb2mp4_buf(pkt->data, &data, &size, 0, NULL)) < 0)
++ return ret;
+ } else if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
+ (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
+ if (!s->streams[pkt->stream_index]->nb_frames) {
+@@ -964,7 +979,12 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ avio_wb32(pb, data_size + 11);
+ } else {
+ av_assert1(flags>=0);
+- avio_w8(pb,flags);
++ if (par->codec_id == AV_CODEC_ID_HEVC) {
++ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeCodedFramesX); // ExVideoTagHeader mode with PacketTypeCodedFramesX
++ avio_write(pb, "hvc1", 4);
++ } else {
++ avio_w8(pb, flags);
++ }
+ if (par->codec_id == AV_CODEC_ID_VP6)
+ avio_w8(pb,0);
+ if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A) {
+
+From patchwork Mon May 15 08:31:57 2023
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Steven Liu <lq(a)chinaffmpeg.org>
+X-Patchwork-Id: 41616
+Delivered-To: ffmpegpatchwork2(a)gmail.com
+Received: by 2002:a05:6a20:ba91:b0:105:feb:71f2 with SMTP id
+ fb17csp1444123pzb;
+ Mon, 15 May 2023 01:33:22 -0700 (PDT)
+X-Google-Smtp-Source:
+ ACHHUZ4qSqnHARATYvNTOiXhMIIgGWUHo612wN3Ui1r3cYPQd57E+B9kiCRYijDhzgObKMKkDm54
+X-Received: by 2002:a17:907:6e8e:b0:94f:3521:396 with SMTP id
+ sh14-20020a1709076e8e00b0094f35210396mr35740883ejc.23.1684139602011;
+ Mon, 15 May 2023 01:33:22 -0700 (PDT)
+ARC-Seal: i=1; a=rsa-sha256; t=1684139601; cv=none;
+ d=google.com; s=arc-20160816;
+ b=EFJgx9cm5ew2+PIpTeHi7QCzos//oOs5q/HndQxc0+dHYlju5X4rVSACmfk9L0DH3j
+ +cG0n2/3wAsguA1rC3B8a+qXkRfAXC1ropuhDwKCZCdw0Iv40Vm4JeHolEQWRni8Ko+F
+ MhWY7AvxrX4GsO0pp4SfKsVFaJdo18dlpn+BUd9FX5N7V6lUTadQsVcJYJBd2B2MIRUi
+ mJaEPp8WpRkiS92DgWhPzUC9ELnwrySnNL0mOo9DCd9cjFXQ9KXW6qjRoP0blbL8N2ws
+ BlY2dJVmSM36n/GK9gZb+6fUg3xVufDUfdRr0m4jpa/ILD93/nwAZsqhk3k4j00se+CO
+ 7Vrw==
+ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
+ s=arc-20160816;
+ h=sender:errors-to:content-transfer-encoding:cc:reply-to
+ :list-subscribe:list-help:list-post:list-archive:list-unsubscribe
+ :list-id:precedence:subject:feedback-id:mime-version:references
+ :in-reply-to:message-id:date:to:from:delivered-to;
+ bh=ygUb60Tr5LbPnhiS1As+hL+qX45KII+ocpY9X3Jq4TI=;
+ b=UpGhqbfo/+m9WW5qE92LKOdOlxkCWyy2QVqiXCjXpxepdDd0IKkhGqSspte9zJrUT8
+ QWg8IiDK6JTnGnvp+hO6doZjhXc1GyyTx6cMQQX+2JzqTtbWF03S94GwBgmN/U2RIK9M
+ f980SSgfNZRSJF5kJ+dO2ix4M5WIWhxEYB/MRzn/RbxAvYkwLNG1gMMBTNimogbFsXRo
+ h5WgGxO4k8mx/x8PBrtNv1aPZ86FAcXC3Aieao7aVnRDvWjepEus5jEfGu2QuqnvM2qK
+ WIjUyFrppJL/crANtgR+tFcL8395bRGYObYtIBblUQ/g5ddHzjsaClJ/42r3h1vez39q
+ nPjQ==
+ARC-Authentication-Results: i=1; mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces(a)ffmpeg.org>
+Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100])
+ by mx.google.com with ESMTP id
+ v21-20020a1709060b5500b0095ec54a22bcsi10907595ejg.106.2023.05.15.01.33.21;
+ Mon, 15 May 2023 01:33:21 -0700 (PDT)
+Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100;
+Authentication-Results: mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Received: from [127.0.1.1] (localhost [127.0.0.1])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D3F7668C092;
+ Mon, 15 May 2023 11:33:18 +0300 (EEST)
+X-Original-To: ffmpeg-devel(a)ffmpeg.org
+Delivered-To: ffmpeg-devel(a)ffmpeg.org
+Received: from bg4.exmail.qq.com (bg4.exmail.qq.com [43.155.67.158])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 8180368C004
+ for <ffmpeg-devel(a)ffmpeg.org>; Mon, 15 May 2023 11:33:11 +0300 (EEST)
+X-QQ-mid: bizesmtp62t1684139585txhp32ou
+Received: from localhost ( [103.102.203.204]) by bizesmtp.qq.com (ESMTP) with
+ id ; Mon, 15 May 2023 16:33:04 +0800 (CST)
+X-QQ-SSF: 01100000000000Z0Z000000A0000000
+X-QQ-FEAT: 6ArnuSDJ+inVC06MH1nrJeu56+35diptW3dCdHt3bMayFZoCyE8QyUO0QY9zm
+ iY62JCSpSKYEK4ca2kpxkB99PI50FiWfNtzLDZ+VzUTy013GMpLwh1CWeVX5cF15RyEAIC9
+ u3Ozg7IY8mv+GiDtf6FDgSyumE1D93qxV1R2sJ5v38V3NbNPcikg0aDxZXOlC+Hr+LdhsZi
+ 4X5tDi3NovhpCf+8Wo+ZaejHOrE8MUcUGpbh8dHRew6dnmkdkK5ytSHSZEye8RsXZnMdp4A
+ mqBZqIDGw1a4e04JAc/NDCs7qq4qthxMFB1skhaOv6DLcL+EqV2QFwnJn7V5Oof7BwfjaTG
+ mEAVpiZDnQhFvOgHemH1v61Blub2nCnAurrGhGMaywIzFXT87aOSLCDlFprSg==
+X-QQ-GoodBg: 0
+X-BIZMAIL-ID: 11210839191292587357
+From: Steven Liu <lq(a)chinaffmpeg.org>
+To: ffmpeg-devel(a)ffmpeg.org
+Date: Mon, 15 May 2023 16:31:57 +0800
+Message-Id: <20230515083201.48201-3-lq(a)chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+References:
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ(a)mail.gmail.com>
+ <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+MIME-Version: 1.0
+X-QQ-SENDSIZE: 520
+Feedback-ID: bizesmtp:chinaffmpeg.org:qybglogicsvrsz:qybglogicsvrsz3a-3
+Subject: [FFmpeg-devel] [PATCH v10 2/6] avformat/flvdec: support demux hevc
+ in enhanced flv
+X-BeenThere: ffmpeg-devel(a)ffmpeg.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
+List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
+List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
+List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
+List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
+List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
+Reply-To: FFmpeg development discussions and patches <ffmpeg-devel(a)ffmpeg.org>
+Cc: Steven Liu <lq(a)chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces(a)ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces(a)ffmpeg.org>
+X-TUID: SFsjHMHu2ISl
+
+Signed-off-by: Steven Liu <lq(a)chinaffmpeg.org>
+---
+ libavformat/flvdec.c | 58 ++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 50 insertions(+), 8 deletions(-)
+
+diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
+index d83edff727..c8e6cadf1c 100644
+--- a/libavformat/flvdec.c
++++ b/libavformat/flvdec.c
+@@ -79,6 +79,8 @@ typedef struct FLVContext {
+ int64_t last_ts;
+ int64_t time_offset;
+ int64_t time_pos;
++
++ uint8_t exheader;
+ } FLVContext;
+
+ /* AMF date type */
+@@ -302,13 +304,25 @@ static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream,
+ }
+ }
+
+-static int flv_same_video_codec(AVCodecParameters *vpar, int flags)
++static int flv_same_video_codec(AVFormatContext *s, AVCodecParameters *vpar, int flags)
+ {
+ int flv_codecid = flags & FLV_VIDEO_CODECID_MASK;
++ FLVContext *flv = s->priv_data;
+
+ if (!vpar->codec_id && !vpar->codec_tag)
+ return 1;
+
++ if (flv->exheader) {
++ uint8_t *codec_id_str = (uint8_t *)s->pb->buf_ptr;
++ uint32_t codec_id = codec_id_str[3] | codec_id_str[2] << 8 | codec_id_str[1] << 16 | codec_id_str[0] << 24;
++ switch(codec_id) {
++ case MKBETAG('h', 'v', 'c', '1'):
++ return vpar->codec_id == AV_CODEC_ID_HEVC;
++ default:
++ break;
++ }
++ }
++
+ switch (flv_codecid) {
+ case FLV_CODECID_H263:
+ return vpar->codec_id == AV_CODEC_ID_FLV1;
+@@ -331,9 +345,24 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
+ int flv_codecid, int read)
+ {
+ FFStream *const vstreami = ffstream(vstream);
++ FLVContext *flv = s->priv_data;
+ int ret = 0;
+ AVCodecParameters *par = vstream->codecpar;
+ enum AVCodecID old_codec_id = vstream->codecpar->codec_id;
++ flv_codecid &= FLV_VIDEO_CODECID_MASK;
++
++ if (flv->exheader) {
++ uint32_t codec_id = avio_rb32(s->pb);
++
++ switch(codec_id) {
++ case MKBETAG('h', 'v', 'c', '1'):
++ par->codec_id = AV_CODEC_ID_HEVC;
++ vstreami->need_parsing = AVSTREAM_PARSE_HEADERS;
++ return 4;
++ default:
++ break;
++ }
++ }
+ switch (flv_codecid) {
+ case FLV_CODECID_H263:
+ par->codec_id = AV_CODEC_ID_FLV1;
+@@ -796,6 +825,7 @@ static int flv_read_header(AVFormatContext *s)
+ s->start_time = 0;
+ flv->sum_flv_tag_size = 0;
+ flv->last_keyframe_stream_index = -1;
++ flv->exheader = 0;
+
+ return 0;
+ }
+@@ -1071,6 +1101,11 @@ retry:
+ } else if (type == FLV_TAG_TYPE_VIDEO) {
+ stream_type = FLV_STREAM_TYPE_VIDEO;
+ flags = avio_r8(s->pb);
++ /*
++ * Reference Enhancing FLV 2023-03-v1.0.0-B.8
++ * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp-v1.pdf
++ * */
++ flv->exheader = (flags >> 7) & 1;
+ size--;
+ if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
+ goto skip;
+@@ -1129,7 +1164,7 @@ skip:
+ break;
+ } else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+- (s->video_codec_id || flv_same_video_codec(st->codecpar, flags)))
++ (s->video_codec_id || flv_same_video_codec(s, st->codecpar, flags)))
+ break;
+ } else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) {
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
+@@ -1230,7 +1265,7 @@ retry_duration:
+ avcodec_parameters_free(&par);
+ }
+ } else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
+- int ret = flv_set_video_codec(s, st, flags & FLV_VIDEO_CODECID_MASK, 1);
++ int ret = flv_set_video_codec(s, st, flags, 1);
+ if (ret < 0)
+ return ret;
+ size -= ret;
+@@ -1242,16 +1277,23 @@ retry_duration:
+
+ if (st->codecpar->codec_id == AV_CODEC_ID_AAC ||
+ st->codecpar->codec_id == AV_CODEC_ID_H264 ||
+- st->codecpar->codec_id == AV_CODEC_ID_MPEG4) {
+- int type = avio_r8(s->pb);
+- size--;
++ st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
++ st->codecpar->codec_id == AV_CODEC_ID_HEVC) {
++ int type = 0;
++ if (flv->exheader && stream_type == FLV_STREAM_TYPE_VIDEO) {
++ type = flags & 0x0F;
++ } else {
++ type = avio_r8(s->pb);
++ size--;
++ }
+
+ if (size < 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto leave;
+ }
+
+- if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4) {
++ if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
++ (st->codecpar->codec_id == AV_CODEC_ID_HEVC && type == PacketTypeCodedFrames)) {
+ // sign extension
+ int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
+ pts = av_sat_add64(dts, cts);
+@@ -1267,7 +1309,7 @@ retry_duration:
+ }
+ }
+ if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
+- st->codecpar->codec_id == AV_CODEC_ID_H264)) {
++ st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC)) {
+ AVDictionaryEntry *t;
+
+ if (st->codecpar->extradata) {
+
+From patchwork Mon May 15 08:31:58 2023
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Steven Liu <lq(a)chinaffmpeg.org>
+X-Patchwork-Id: 41617
+Delivered-To: ffmpegpatchwork2(a)gmail.com
+Received: by 2002:a05:6a20:ba91:b0:105:feb:71f2 with SMTP id
+ fb17csp1444209pzb;
+ Mon, 15 May 2023 01:33:31 -0700 (PDT)
+X-Google-Smtp-Source:
+ ACHHUZ5N/MWld9fXzokkRVS1e13AYakkRyH/RvyBiJ7xA512EWdWgrGE4ferugcTRoHNahvjayC9
+X-Received: by 2002:a17:907:9724:b0:96a:1260:dbf5 with SMTP id
+ jg36-20020a170907972400b0096a1260dbf5mr18082554ejc.45.1684139611447;
+ Mon, 15 May 2023 01:33:31 -0700 (PDT)
+ARC-Seal: i=1; a=rsa-sha256; t=1684139611; cv=none;
+ d=google.com; s=arc-20160816;
+ b=op6Xl3YinOSd8d/Ya4YpQjHSbJx0t7fHaCHvvqvkJgTbKfjmTJjDFsMWkeT/ceA1lA
+ xV9Y1JGrAlZmudpgaJtXHukLJessnBrqaBy5gm0lX6bJ0X4AKJt/F7GB3FR3OPISq79w
+ 7djeHUx2VAxfWn1awCcFrcyyMPrGB2GPMdoXxcUVmySNNK0ohuroQ2JhVRajwj0sIBFg
+ f0pu7vXX9ct499tFl5rHEd//2Xl3rY6kNHfPlMOcJEclT+35TUaTWE88+rJODaiMArcZ
+ RaFK8xqfAOJjw0X9t6YiwBk1Kl/sFKEj71Fxu5khg7IvhF7kzRDSZXLCkKW9UvPYhGOl
+ 25Bw==
+ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
+ s=arc-20160816;
+ h=sender:errors-to:content-transfer-encoding:cc:reply-to
+ :list-subscribe:list-help:list-post:list-archive:list-unsubscribe
+ :list-id:precedence:subject:feedback-id:mime-version:references
+ :in-reply-to:message-id:date:to:from:delivered-to;
+ bh=0O0kUGD5r8lgXEiC2RUfiZ1ccVRPd03lWds0dqdVEq0=;
+ b=OAvZATeoNq/BI3pJd21Xz2nKh+ZI8Zkofe4Ob6USu1ZEOyZzK2xxgtxL6SjJAxecG6
+ NfECg8e13DLbnVAB5OnMK8TY/HV/4N/iqPksn6PbJSkCyafRqg477+SRs7tOl89c3isr
+ Cp8o+j7t+gW2fkV9Y6L8MZa9etJpusa0LYXVBLPDs+tHNgXNec9UTA1YnoSyMqErrh58
+ chMh6B6P+5aRcKrBfKZY1F8WAzMjphdQ78c3YZ+ikgGfkoPgRKTEUq+xQAMm7UXirMcn
+ qtndeDiQypN1eg7LiEbAsLhj7K2jibIlDmwUk+6JDE1ASz05FViAbk3nFfWydNP8iUlh
+ z+CQ==
+ARC-Authentication-Results: i=1; mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces(a)ffmpeg.org>
+Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100])
+ by mx.google.com with ESMTP id
+ rv22-20020a17090710d600b00965e8c67d7dsi11399192ejb.285.2023.05.15.01.33.31;
+ Mon, 15 May 2023 01:33:31 -0700 (PDT)
+Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100;
+Authentication-Results: mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Received: from [127.0.1.1] (localhost [127.0.0.1])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id CAF3668C08B;
+ Mon, 15 May 2023 11:33:22 +0300 (EEST)
+X-Original-To: ffmpeg-devel(a)ffmpeg.org
+Delivered-To: ffmpeg-devel(a)ffmpeg.org
+Received: from bg4.exmail.qq.com (bg4.exmail.qq.com [43.155.67.158])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 5613068C08B
+ for <ffmpeg-devel(a)ffmpeg.org>; Mon, 15 May 2023 11:33:16 +0300 (EEST)
+X-QQ-mid: bizesmtp62t1684139591t5vf5iss
+Received: from localhost ( [103.102.203.204]) by bizesmtp.qq.com (ESMTP) with
+ id ; Mon, 15 May 2023 16:33:09 +0800 (CST)
+X-QQ-SSF: 01100000000000Z0Z000000A0000000
+X-QQ-FEAT: 0VYWLLCf4rd8sf4B0xdI45yO9pa7cA5LkUN5r8jryl/9HUTcEOcDnq6sEFLpU
+ pZ/JnwSIqfqFtRB8Bq8+032WcwZIBdGWmOUpIZLcDlBPHVtS9YwSO56p7te0932mhQHQVWr
+ 2MJ60EhPcxfhXG3M89QSysYDgLjUIRbb/cP/Br05mCJ05c+Q4NzWwlRwweOG0lUJ4aMNli9
+ i3Qf8lSAK8hK3JWYZP0Fg66JaFkZvw6Yz6N4ESVf4Vp85rwWKPfpBz538IiCze/ePbVgZWB
+ zvbU1mVAkapT05cTLyqAlv7tefflgoYcrW79Z+Opy2wSYDZLpCkRIe+w4yWG7eCg71dUgnc
+ 79D+MVyHSJjuXS/sQLaeFanS1V55WK4izy9J/bFHdSprmySwmpk8hf5zhIZOQ==
+X-QQ-GoodBg: 0
+X-BIZMAIL-ID: 5377996165340525619
+From: Steven Liu <lq(a)chinaffmpeg.org>
+To: ffmpeg-devel(a)ffmpeg.org
+Date: Mon, 15 May 2023 16:31:58 +0800
+Message-Id: <20230515083201.48201-4-lq(a)chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+References:
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ(a)mail.gmail.com>
+ <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+MIME-Version: 1.0
+X-QQ-SENDSIZE: 520
+Feedback-ID: bizesmtp:chinaffmpeg.org:qybglogicsvrsz:qybglogicsvrsz3a-3
+Subject: [FFmpeg-devel] [PATCH v10 3/6] avformat/flvenc: support mux av1 in
+ enhanced flv
+X-BeenThere: ffmpeg-devel(a)ffmpeg.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
+List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
+List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
+List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
+List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
+List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
+Reply-To: FFmpeg development discussions and patches <ffmpeg-devel(a)ffmpeg.org>
+Cc: Steven Liu <lq(a)chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces(a)ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces(a)ffmpeg.org>
+X-TUID: dRfPdsIvexzh
+
+Signed-off-by: Steven Liu <lq(a)chinaffmpeg.org>
+---
+ libavformat/Makefile | 2 +-
+ libavformat/flvenc.c | 22 ++++++++++++++++++----
+ 2 files changed, 19 insertions(+), 5 deletions(-)
+
+diff --git a/libavformat/Makefile b/libavformat/Makefile
+index 1ef3d15467..c868e1626c 100644
+--- a/libavformat/Makefile
++++ b/libavformat/Makefile
+@@ -214,7 +214,7 @@ OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \
+ OBJS-$(CONFIG_FLIC_DEMUXER) += flic.o
+ OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o
+ OBJS-$(CONFIG_LIVE_FLV_DEMUXER) += flvdec.o
+-OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o hevc.o
++OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o hevc.o av1.o
+ OBJS-$(CONFIG_FOURXM_DEMUXER) += 4xm.o
+ OBJS-$(CONFIG_FRAMECRC_MUXER) += framecrcenc.o framehash.o
+ OBJS-$(CONFIG_FRAMEHASH_MUXER) += hashenc.o framehash.o
+diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
+index 35e198fa15..c1784b332d 100644
+--- a/libavformat/flvenc.c
++++ b/libavformat/flvenc.c
+@@ -28,6 +28,7 @@
+ #include "libavcodec/mpeg4audio.h"
+ #include "avio.h"
+ #include "avc.h"
++#include "av1.h"
+ #include "hevc.h"
+ #include "avformat.h"
+ #include "flv.h"
+@@ -48,6 +49,7 @@ static const AVCodecTag flv_video_codec_ids[] = {
+ { AV_CODEC_ID_VP6A, FLV_CODECID_VP6A },
+ { AV_CODEC_ID_H264, FLV_CODECID_H264 },
+ { AV_CODEC_ID_HEVC, MKBETAG('h', 'v', 'c', '1') },
++ { AV_CODEC_ID_AV1, MKBETAG('a', 'v', '0', '1') },
+ { AV_CODEC_ID_NONE, 0 }
+ };
+
+@@ -491,7 +493,8 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
+ FLVContext *flv = s->priv_data;
+
+ if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
+- || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC) {
++ || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC
++ || par->codec_id == AV_CODEC_ID_AV1) {
+ int64_t pos;
+ avio_w8(pb,
+ par->codec_type == AVMEDIA_TYPE_VIDEO ?
+@@ -537,6 +540,9 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
+ if (par->codec_id == AV_CODEC_ID_HEVC) {
+ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeSequenceStart); // ExVideoTagHeader mode with PacketTypeSequenceStart
+ avio_write(pb, "hvc1", 4);
++ } else if (par->codec_id == AV_CODEC_ID_AV1) {
++ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeSequenceStart);
++ avio_write(pb, "av01", 4);
+ } else {
+ avio_w8(pb, par->codec_tag | FLV_FRAME_KEY); // flags
+ avio_w8(pb, 0); // AVC sequence header
+@@ -545,6 +551,8 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
+
+ if (par->codec_id == AV_CODEC_ID_HEVC)
+ ff_isom_write_hvcc(pb, par->extradata, par->extradata_size, 0);
++ else if (par->codec_id == AV_CODEC_ID_AV1)
++ ff_isom_write_av1c(pb, par->extradata, par->extradata_size, 1);
+ else
+ ff_isom_write_avcc(pb, par->extradata, par->extradata_size);
+ }
+@@ -843,13 +851,15 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A ||
+ par->codec_id == AV_CODEC_ID_VP6 || par->codec_id == AV_CODEC_ID_AAC)
+ flags_size = 2;
+- else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC)
++ else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 ||
++ par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1)
+ flags_size = 5;
+ else
+ flags_size = 1;
+
+ if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
+- || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC) {
++ || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC
++ || par->codec_id == AV_CODEC_ID_AV1) {
+ size_t side_size;
+ uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
+ if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
+@@ -869,7 +879,8 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ "Packets are not in the proper order with respect to DTS\n");
+ return AVERROR(EINVAL);
+ }
+- if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC) {
++ if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 ||
++ par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1) {
+ if (pkt->pts == AV_NOPTS_VALUE) {
+ av_log(s, AV_LOG_ERROR, "Packet is missing PTS\n");
+ return AVERROR(EINVAL);
+@@ -982,6 +993,9 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ if (par->codec_id == AV_CODEC_ID_HEVC) {
+ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeCodedFramesX); // ExVideoTagHeader mode with PacketTypeCodedFramesX
+ avio_write(pb, "hvc1", 4);
++ } else if (par->codec_id == AV_CODEC_ID_AV1) {
++ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeCodedFrames);
++ avio_write(pb, "av01", 4);
+ } else {
+ avio_w8(pb, flags);
+ }
+
+From patchwork Mon May 15 08:31:59 2023
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Steven Liu <lq(a)chinaffmpeg.org>
+X-Patchwork-Id: 41618
+Delivered-To: ffmpegpatchwork2(a)gmail.com
+Received: by 2002:a05:6a20:ba91:b0:105:feb:71f2 with SMTP id
+ fb17csp1444290pzb;
+ Mon, 15 May 2023 01:33:41 -0700 (PDT)
+X-Google-Smtp-Source:
+ ACHHUZ7k5HSYVpKlutDCH3BVN03oQ1eQ9NWjKwBebLGv5fK0d2qVGGgCtBo3XdEGlDTDUuvlDzRX
+X-Received: by 2002:a17:907:9347:b0:94f:322d:909c with SMTP id
+ bv7-20020a170907934700b0094f322d909cmr26994118ejc.34.1684139620986;
+ Mon, 15 May 2023 01:33:40 -0700 (PDT)
+ARC-Seal: i=1; a=rsa-sha256; t=1684139620; cv=none;
+ d=google.com; s=arc-20160816;
+ b=BBSgegXR1u0K767R9MAxQddt49hZNhDS+YgCHGYo0B07ClteK018739TK9tupVh7pK
+ wuvk/gzkEpIZpf2I3LQnpaxvQx0ZnllSKyz+x+560wEVKkQw5tlwpgr4qA3m0ApBBmQR
+ 2ZUu6WRpBnVeXJbT5n+ymITrLd1NVXLNPqoz7kL0iDML0b2iC9PqCoGRTHF6zJZFtCH2
+ ZYUq4OdcbflvqqLBvKvSgEwuVof0bqDwD8kfq9noKTf7wrx5bcdIbq6XMYG1n6AnPq7R
+ R+ekmhosFoZ7IgohAkj9k8j6l4ipCc6yVN2M8TN1TfTwRC01vzz+SRYOXZWLNb0eqZzh
+ Zp2A==
+ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
+ s=arc-20160816;
+ h=sender:errors-to:content-transfer-encoding:cc:reply-to
+ :list-subscribe:list-help:list-post:list-archive:list-unsubscribe
+ :list-id:precedence:subject:feedback-id:mime-version:references
+ :in-reply-to:message-id:date:to:from:delivered-to;
+ bh=J5hIt8/6l7983HWQOAGA1qy6mjWmMWu6DJ2RZRfJeuQ=;
+ b=rX88kWHJtUiqnNutEQCOwUvfl5lV/FVHviaDHIsiatvB92XG71pgeFVXopTjJ+st3F
+ lu+/rKnYKAVXFqF4WHMP6bu0VT5bFE2A9806gTD5Rf1D2yGVjKWRH8fhY6Jl2KhEhQA+
+ Efc6fMZ2qZRmdx5S2INE2k+sY3zgWZsFkv2NDowFLnjnpmTGneVW82ybCbL06DRH7Jts
+ wxWDfFfTqnp2VNwD0C462f5ogLB8cH7f9uoFviTovEYcXc8iLpHP38cJa3hdAuJg972S
+ cgjJSuZUaQ38bqmw7th2MDkaFSzryck0wafneRdJUxyKG7ltbwk4hgAz89yzUB7nZeU6
+ yucA==
+ARC-Authentication-Results: i=1; mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces(a)ffmpeg.org>
+Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100])
+ by mx.google.com with ESMTP id
+ gv41-20020a1709072be900b00965f171543esi11575148ejc.148.2023.05.15.01.33.40;
+ Mon, 15 May 2023 01:33:40 -0700 (PDT)
+Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100;
+Authentication-Results: mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Received: from [127.0.1.1] (localhost [127.0.0.1])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D65AD68C0A8;
+ Mon, 15 May 2023 11:33:29 +0300 (EEST)
+X-Original-To: ffmpeg-devel(a)ffmpeg.org
+Delivered-To: ffmpeg-devel(a)ffmpeg.org
+Received: from bg4.exmail.qq.com (bg4.exmail.qq.com [43.155.67.158])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 5AA6768C09F
+ for <ffmpeg-devel(a)ffmpeg.org>; Mon, 15 May 2023 11:33:22 +0300 (EEST)
+X-QQ-mid: bizesmtp75t1684139596t4okf86m
+Received: from localhost ( [103.102.203.204]) by bizesmtp.qq.com (ESMTP) with
+ id ; Mon, 15 May 2023 16:33:15 +0800 (CST)
+X-QQ-SSF: 01100000000000Z0Z000000A0000000
+X-QQ-FEAT: KvvwR/hcPA3wY6H84uX1Z4OhW9I2bQ1QV35znBz44h8GZ/oUuMaFpDcrT3dSg
+ MUkTVTMEyhXhHNx2JIMxfw5+q/3TCUtvnKXsxLZtQsy/0Nq/y+p0xVsHJzQmM8CvbT6L6Q3
+ OmxwvGAO6ljvI/iA+SXU+3+HUNyetDE8UTRW1ZGCtG9iJRbK9wXPoiAMzLepT2+CHGO2brq
+ CwH6RA/e9/I4xOHLleywtC4oDlPuyHovxzzedsBTrXYic5tb0+D65abc6NjfHr7zrYD/DQu
+ HY0NNweX9YP/jE8jJ0TPLhcx7wighw+KDFbYf+UcUuaPHhzfAZh2f6aplibzVuvV78OPq2S
+ thQ/XeMGf/W9C/Oy4Eq145+G+pUQ7zx/OKY8Jj/33dmvwZkUr8=
+X-QQ-GoodBg: 0
+X-BIZMAIL-ID: 9530387995930120932
+From: Steven Liu <lq(a)chinaffmpeg.org>
+To: ffmpeg-devel(a)ffmpeg.org
+Date: Mon, 15 May 2023 16:31:59 +0800
+Message-Id: <20230515083201.48201-5-lq(a)chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+References:
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ(a)mail.gmail.com>
+ <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+MIME-Version: 1.0
+X-QQ-SENDSIZE: 520
+Feedback-ID: bizesmtp:chinaffmpeg.org:qybglogicsvrsz:qybglogicsvrsz3a-3
+Subject: [FFmpeg-devel] [PATCH v10 4/6] avformat/flvdec: support demux av1
+ in enhanced flv
+X-BeenThere: ffmpeg-devel(a)ffmpeg.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
+List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
+List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
+List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
+List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
+List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
+Reply-To: FFmpeg development discussions and patches <ffmpeg-devel(a)ffmpeg.org>
+Cc: Steven Liu <lq(a)chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces(a)ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces(a)ffmpeg.org>
+X-TUID: MKqjViniwIy+
+
+Signed-off-by: Steven Liu <lq(a)chinaffmpeg.org>
+---
+ libavformat/flvdec.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
+index c8e6cadf1c..a0362ff11c 100644
+--- a/libavformat/flvdec.c
++++ b/libavformat/flvdec.c
+@@ -318,6 +318,8 @@ static int flv_same_video_codec(AVFormatContext *s, AVCodecParameters *vpar, int
+ switch(codec_id) {
+ case MKBETAG('h', 'v', 'c', '1'):
+ return vpar->codec_id == AV_CODEC_ID_HEVC;
++ case MKBETAG('a', 'v', '0', '1'):
++ return vpar->codec_id == AV_CODEC_ID_AV1;
+ default:
+ break;
+ }
+@@ -359,6 +361,10 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
+ par->codec_id = AV_CODEC_ID_HEVC;
+ vstreami->need_parsing = AVSTREAM_PARSE_HEADERS;
+ return 4;
++ case MKBETAG('a', 'v', '0', '1'):
++ par->codec_id = AV_CODEC_ID_AV1;
++ vstreami->need_parsing = AVSTREAM_PARSE_HEADERS;
++ return 4;
+ default:
+ break;
+ }
+@@ -1278,7 +1284,8 @@ retry_duration:
+ if (st->codecpar->codec_id == AV_CODEC_ID_AAC ||
+ st->codecpar->codec_id == AV_CODEC_ID_H264 ||
+ st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
+- st->codecpar->codec_id == AV_CODEC_ID_HEVC) {
++ st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
++ st->codecpar->codec_id == AV_CODEC_ID_AV1) {
+ int type = 0;
+ if (flv->exheader && stream_type == FLV_STREAM_TYPE_VIDEO) {
+ type = flags & 0x0F;
+@@ -1309,7 +1316,8 @@ retry_duration:
+ }
+ }
+ if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
+- st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC)) {
++ st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
++ st->codecpar->codec_id == AV_CODEC_ID_AV1)) {
+ AVDictionaryEntry *t;
+
+ if (st->codecpar->extradata) {
+
+From patchwork Mon May 15 08:32:00 2023
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Steven Liu <lq(a)chinaffmpeg.org>
+X-Patchwork-Id: 41619
+Delivered-To: ffmpegpatchwork2(a)gmail.com
+Received: by 2002:a05:6a20:ba91:b0:105:feb:71f2 with SMTP id
+ fb17csp1444532pzb;
+ Mon, 15 May 2023 01:34:10 -0700 (PDT)
+X-Google-Smtp-Source:
+ ACHHUZ4QlFqXMa0WNHK3Z3HLgPm2UskuQZX2wmbFhYm+ZL0BsDRPhLxJboG0YhDPFi999aVCQZE+
+X-Received: by 2002:a05:6402:14c3:b0:50d:fcfb:8633 with SMTP id
+ f3-20020a05640214c300b0050dfcfb8633mr9613789edx.9.1684139650196;
+ Mon, 15 May 2023 01:34:10 -0700 (PDT)
+ARC-Seal: i=1; a=rsa-sha256; t=1684139650; cv=none;
+ d=google.com; s=arc-20160816;
+ b=sjfm4xhTPqjGNyHlxS3/kMPilx13EB+7S0YxjOI5lR9MMg8Sy3KgL187C6tuZqUwoZ
+ dJo7A3q41EK4WJyWTTUyqUOr8q8JPjbBTCJpVsERuMuMWpHrhQxvwEDibvfuDI0ZI2vK
+ y5pqRZ23OMNZLCC+fsc85gQDKPgvkYZTYisSOsWVRiZQGl04TipfZE1Uza8R7ZEXRgdH
+ ZW770YcfzVXmKKzralH4thSFhGfMZRpX7kj6oBtmpUco4Z6iu42o3iBTcaioGBzdWdPY
+ KL94WAIaMnCyO1JJaUAJGzEcQTGhPbXUzG7JvmqEwSa168GBSEjQJ3qJc8oOr+UVWcvn
+ HvaQ==
+ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
+ s=arc-20160816;
+ h=sender:errors-to:content-transfer-encoding:cc:reply-to
+ :list-subscribe:list-help:list-post:list-archive:list-unsubscribe
+ :list-id:precedence:subject:feedback-id:mime-version:references
+ :in-reply-to:message-id:date:to:from:delivered-to;
+ bh=b1Sp5oqZAMwakI7a3Zvw4MdnKPyomZo8cXqDnyJamjg=;
+ b=jcFJOli16NPqGPnMDcJVER3TEkWreNJ2Vu7711GhJhFkmXLNFhS2FUAoT9QBTy+JWm
+ jxaBjiVvs1MMQ+a3k3yT7AzVSUMMDDSagiE/jWzQ+vBN9dr/jQOMtJWxwfm4oTbBc0/r
+ GcHTgPKB2HvEiLOWaJ4CSfZcYBvosoew/IfPgKm06P2Btmc+faSXLCZ63nKEVTq7NCpx
+ qllJPkFmvlwB/+soxN7nZgTzXm/uurSOBMajImRGPOZUOZQE1I5Tk8OtJXZP6QtlSvXT
+ ZcglewhTYuHlAXbpT4sYyddMwKg9yPu6/Wmrol/wg3QpXPZ0lVtLeTozus/2UTISJrR5
+ Lp3Q==
+ARC-Authentication-Results: i=1; mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces(a)ffmpeg.org>
+Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100])
+ by mx.google.com with ESMTP id
+ f25-20020a056402151900b0050bd37278d9si11856925edw.435.2023.05.15.01.34.09;
+ Mon, 15 May 2023 01:34:10 -0700 (PDT)
+Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100;
+Authentication-Results: mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Received: from [127.0.1.1] (localhost [127.0.0.1])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0DB6568C092;
+ Mon, 15 May 2023 11:34:07 +0300 (EEST)
+X-Original-To: ffmpeg-devel(a)ffmpeg.org
+Delivered-To: ffmpeg-devel(a)ffmpeg.org
+Received: from bg4.exmail.qq.com (bg4.exmail.qq.com [43.154.221.58])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 96A14680274
+ for <ffmpeg-devel(a)ffmpeg.org>; Mon, 15 May 2023 11:33:59 +0300 (EEST)
+X-QQ-mid: bizesmtp76t1684139634tg83beu0
+Received: from localhost ( [103.102.203.204]) by bizesmtp.qq.com (ESMTP) with
+ id ; Mon, 15 May 2023 16:33:52 +0800 (CST)
+X-QQ-SSF: 01100000000000Z0Z000000A0000000
+X-QQ-FEAT: DWSCcwW/aQb83U5Bq9N00w3kkIuofNiUvlQbgR0sgGjFEas+vh7wXyRycFT/z
+ w33SH7uNRX8lmP+8+iy6jQH/gsaQRVAau2z8K0utdx9GuZMvY0e5SZfB0zBfncb1NdBZJxB
+ Ptvibavnj2rDlqrGLO9dvFEfmYj1K48HYp6rdjCb+xRPfyOtnct3Zq6ST7F1DxU1+Kmt8cw
+ 2qVgeA79DNHm1JbcDzi/2W/SpzWHWk/jamN4cAQfKyP9B4AvMPaFd8kdl6akYbR0Q84H73M
+ Pcx8UXz6iw4sCTSPFzf0zrsI4+shly9KFp4UESTfRbDEJ46pcyw8+6Uz+Q7w+7CRtPlOsms
+ K6IAbcLwicf/v8Rm2nHdrNPotcaMgY5p7IqmkY/Y/b2feqKiAM=
+X-QQ-GoodBg: 0
+X-BIZMAIL-ID: 4611718483056789364
+From: Steven Liu <lq(a)chinaffmpeg.org>
+To: ffmpeg-devel(a)ffmpeg.org
+Date: Mon, 15 May 2023 16:32:00 +0800
+Message-Id: <20230515083201.48201-6-lq(a)chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+References:
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ(a)mail.gmail.com>
+ <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+MIME-Version: 1.0
+X-QQ-SENDSIZE: 520
+Feedback-ID: bizesmtp:chinaffmpeg.org:qybglogicsvrsz:qybglogicsvrsz3a-3
+Subject: [FFmpeg-devel] [PATCH v10 5/6] avformat/flvenc: support mux vp9 in
+ enhanced flv
+X-BeenThere: ffmpeg-devel(a)ffmpeg.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
+List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
+List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
+List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
+List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
+List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
+Reply-To: FFmpeg development discussions and patches <ffmpeg-devel(a)ffmpeg.org>
+Cc: Steven Liu <lq(a)chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces(a)ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces(a)ffmpeg.org>
+X-TUID: appcyLUJeeFW
+
+Signed-off-by: Steven Liu <lq(a)chinaffmpeg.org>
+---
+ libavformat/Makefile | 2 +-
+ libavformat/flvenc.c | 22 ++++++++++++++--------
+ 2 files changed, 15 insertions(+), 9 deletions(-)
+
+diff --git a/libavformat/Makefile b/libavformat/Makefile
+index c868e1626c..16cfe107ea 100644
+--- a/libavformat/Makefile
++++ b/libavformat/Makefile
+@@ -214,7 +214,7 @@ OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \
+ OBJS-$(CONFIG_FLIC_DEMUXER) += flic.o
+ OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o
+ OBJS-$(CONFIG_LIVE_FLV_DEMUXER) += flvdec.o
+-OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o hevc.o av1.o
++OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o hevc.o av1.o vpcc.o
+ OBJS-$(CONFIG_FOURXM_DEMUXER) += 4xm.o
+ OBJS-$(CONFIG_FRAMECRC_MUXER) += framecrcenc.o framehash.o
+ OBJS-$(CONFIG_FRAMEHASH_MUXER) += hashenc.o framehash.o
+diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
+index c1784b332d..475dd0bf44 100644
+--- a/libavformat/flvenc.c
++++ b/libavformat/flvenc.c
+@@ -29,6 +29,7 @@
+ #include "avio.h"
+ #include "avc.h"
+ #include "av1.h"
++#include "vpcc.h"
+ #include "hevc.h"
+ #include "avformat.h"
+ #include "flv.h"
+@@ -50,6 +51,7 @@ static const AVCodecTag flv_video_codec_ids[] = {
+ { AV_CODEC_ID_H264, FLV_CODECID_H264 },
+ { AV_CODEC_ID_HEVC, MKBETAG('h', 'v', 'c', '1') },
+ { AV_CODEC_ID_AV1, MKBETAG('a', 'v', '0', '1') },
++ { AV_CODEC_ID_VP9, MKBETAG('v', 'p', '0', '9') },
+ { AV_CODEC_ID_NONE, 0 }
+ };
+
+@@ -494,7 +496,7 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
+
+ if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
+ || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC
+- || par->codec_id == AV_CODEC_ID_AV1) {
++ || par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9) {
+ int64_t pos;
+ avio_w8(pb,
+ par->codec_type == AVMEDIA_TYPE_VIDEO ?
+@@ -540,9 +542,9 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
+ if (par->codec_id == AV_CODEC_ID_HEVC) {
+ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeSequenceStart); // ExVideoTagHeader mode with PacketTypeSequenceStart
+ avio_write(pb, "hvc1", 4);
+- } else if (par->codec_id == AV_CODEC_ID_AV1) {
++ } else if (par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9) {
+ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeSequenceStart);
+- avio_write(pb, "av01", 4);
++ avio_write(pb, par->codec_id == AV_CODEC_ID_AV1 ? "av01" : "vp09", 4);
+ } else {
+ avio_w8(pb, par->codec_tag | FLV_FRAME_KEY); // flags
+ avio_w8(pb, 0); // AVC sequence header
+@@ -553,6 +555,8 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
+ ff_isom_write_hvcc(pb, par->extradata, par->extradata_size, 0);
+ else if (par->codec_id == AV_CODEC_ID_AV1)
+ ff_isom_write_av1c(pb, par->extradata, par->extradata_size, 1);
++ else if (par->codec_id == AV_CODEC_ID_VP9)
++ ff_isom_write_vpcc(s, pb, par->extradata, par->extradata_size, par);
+ else
+ ff_isom_write_avcc(pb, par->extradata, par->extradata_size);
+ }
+@@ -852,14 +856,15 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ par->codec_id == AV_CODEC_ID_VP6 || par->codec_id == AV_CODEC_ID_AAC)
+ flags_size = 2;
+ else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 ||
+- par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1)
++ par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
++ par->codec_id == AV_CODEC_ID_VP9)
+ flags_size = 5;
+ else
+ flags_size = 1;
+
+ if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
+ || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC
+- || par->codec_id == AV_CODEC_ID_AV1) {
++ || par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9) {
+ size_t side_size;
+ uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
+ if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
+@@ -880,7 +885,8 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ return AVERROR(EINVAL);
+ }
+ if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 ||
+- par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1) {
++ par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
++ par->codec_id == AV_CODEC_ID_VP9) {
+ if (pkt->pts == AV_NOPTS_VALUE) {
+ av_log(s, AV_LOG_ERROR, "Packet is missing PTS\n");
+ return AVERROR(EINVAL);
+@@ -993,9 +999,9 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
+ if (par->codec_id == AV_CODEC_ID_HEVC) {
+ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeCodedFramesX); // ExVideoTagHeader mode with PacketTypeCodedFramesX
+ avio_write(pb, "hvc1", 4);
+- } else if (par->codec_id == AV_CODEC_ID_AV1) {
++ } else if (par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9) {
+ avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeCodedFrames);
+- avio_write(pb, "av01", 4);
++ avio_write(pb, par->codec_id == AV_CODEC_ID_AV1 ? "av01" : "vp09", 4);
+ } else {
+ avio_w8(pb, flags);
+ }
+
+From patchwork Mon May 15 08:32:01 2023
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Steven Liu <lq(a)chinaffmpeg.org>
+X-Patchwork-Id: 41620
+Delivered-To: ffmpegpatchwork2(a)gmail.com
+Received: by 2002:a05:6a20:ba91:b0:105:feb:71f2 with SMTP id
+ fb17csp1444616pzb;
+ Mon, 15 May 2023 01:34:19 -0700 (PDT)
+X-Google-Smtp-Source:
+ ACHHUZ4K6eOJwwn7jPfy0dhTP4IQr2XzDB8PfB7Er6aQtrCrxnddiRIgdBqZB72dHhyqfbILXd5E
+X-Received: by 2002:a17:906:ee8e:b0:95e:c549:9ace with SMTP id
+ wt14-20020a170906ee8e00b0095ec5499acemr28082182ejb.62.1684139659496;
+ Mon, 15 May 2023 01:34:19 -0700 (PDT)
+ARC-Seal: i=1; a=rsa-sha256; t=1684139659; cv=none;
+ d=google.com; s=arc-20160816;
+ b=FM9SQbkYmqWaOAa8YRKsdoj3BSoNN/SsDqXgEaRL8lCygJuahCT1ybocV1IqmUSTxS
+ l5AcUJGbZbl2BeNhK5mX43aCfKBSSF3DLhmRCMBC8pU2iPmv7TuSV58kRfLY6r83j8Ic
+ dV56QUYYtN+Ve0BWnaHFOzivSNAgHxwePstQL043LHD2rn+B5CyNvq7l2CahnhMJ8JUG
+ zJNSBe/LFF0Lhkymqd877vkJ+x+UjSWEIdomIJdAcAt2D06jDxwIF/nnLDDHmvQeny2N
+ 8xqssE401QcYCq6GtRi0UTAyMrYiDU4RUPOh8Kjb5YoMXYpbI+BCsr6VJlh6/F6cFD58
+ YStw==
+ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
+ s=arc-20160816;
+ h=sender:errors-to:content-transfer-encoding:cc:reply-to
+ :list-subscribe:list-help:list-post:list-archive:list-unsubscribe
+ :list-id:precedence:subject:feedback-id:mime-version:references
+ :in-reply-to:message-id:date:to:from:delivered-to;
+ bh=JCKfqtynP85UyN4OG5PQuC2GOM45EC75rPa/TN9Pkis=;
+ b=MF78hg+0KkjUNq5Bjz6b4rjcJDJqrFufWHhDWzKgWCGo15fvnVg3UY8PDvpsUYxxSA
+ SXQJP1urvuxLvJ9m6N20/mBCgrN9Cqca537oiWWNbayAOBLuihXPNDPZLqYgD9yg+03U
+ Qo46rKs8BxkuzTKsqfFu1cf8b3qgqp2wt2mOFFnRU8p9J5foA5HCpHoEB1SWo8KqKjqz
+ NeFoyh4k/CHk8Qy2rhQ/ahuNo0zByXEVuGqBEK1GakW8bC6DpX/gX9PnsE7BvpOrO/+z
+ iEJxUd1RyUFDRETjdcqfLeRlEBO0NbFi9GTRjg0oY7m2OM8gh9zw7TIOoKfKaCVepa+1
+ zs+g==
+ARC-Authentication-Results: i=1; mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces(a)ffmpeg.org>
+Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100])
+ by mx.google.com with ESMTP id
+ f21-20020a170906825500b00965c55c71d9si10492876ejx.988.2023.05.15.01.34.19;
+ Mon, 15 May 2023 01:34:19 -0700 (PDT)
+Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100;
+Authentication-Results: mx.google.com;
+ spf=pass (google.com: domain of ffmpeg-devel-bounces(a)ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces(a)ffmpeg.org
+Received: from [127.0.1.1] (localhost [127.0.0.1])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3486468C072;
+ Mon, 15 May 2023 11:34:13 +0300 (EEST)
+X-Original-To: ffmpeg-devel(a)ffmpeg.org
+Delivered-To: ffmpeg-devel(a)ffmpeg.org
+Received: from bg4.exmail.qq.com (bg4.exmail.qq.com [43.154.221.58])
+ by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 6482B68C0A0
+ for <ffmpeg-devel(a)ffmpeg.org>; Mon, 15 May 2023 11:34:05 +0300 (EEST)
+X-QQ-mid: bizesmtp71t1684139639tsfp6osq
+Received: from localhost ( [103.102.203.204]) by bizesmtp.qq.com (ESMTP) with
+ id ; Mon, 15 May 2023 16:33:58 +0800 (CST)
+X-QQ-SSF: 01100000000000Z0Z000000A0000000
+X-QQ-FEAT: v2TBAhtyi5HmOI8RH62YXWVaml0uNXxcsJwtXrqVzXdpJwJpkYcpKS0jOn5b8
+ vputCYK1FNClBNOmv9AzELjT/K26cFOsUYKBpAudrf8Al/Kmwl8CjyT6nDK06QByrHu67A4
+ sX8VQrazIXO6ZPIrfA9ElusXtssmR22e8ju0nXX7oNy/AS4t0bZkuJRVmYCoHSCnLqnvF9r
+ YboVdmg0ZbLovrXBy26bgQr944G/tQRTeAGorAwE61Lf9tqlRKuT8TO8/BA/V7zBuaZTSxA
+ nghl61awPoduY4vd9Nepw43V2Cun4wfPTvAMJn9EQhrdUge4sIN0Q4EuWkBd9dC/nTOwVKV
+ WsjLxbyL6apFe08XmyeS9MDJkL+bFN3ykpDJqblBg8C1AYOjVyYFS2Yt/atcQ==
+X-QQ-GoodBg: 0
+X-BIZMAIL-ID: 14221595051603022987
+From: Steven Liu <lq(a)chinaffmpeg.org>
+To: ffmpeg-devel(a)ffmpeg.org
+Date: Mon, 15 May 2023 16:32:01 +0800
+Message-Id: <20230515083201.48201-7-lq(a)chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+References:
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ(a)mail.gmail.com>
+ <20230515083201.48201-1-lq(a)chinaffmpeg.org>
+MIME-Version: 1.0
+X-QQ-SENDSIZE: 520
+Feedback-ID: bizesmtp:chinaffmpeg.org:qybglogicsvrsz:qybglogicsvrsz3a-3
+Subject: [FFmpeg-devel] [PATCH v10 6/6] avformat/flvdec: support demux vp9
+ in enhanced flv
+X-BeenThere: ffmpeg-devel(a)ffmpeg.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
+List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
+List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
+List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
+List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
+List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
+ <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
+Reply-To: FFmpeg development discussions and patches <ffmpeg-devel(a)ffmpeg.org>
+Cc: Steven Liu <lq(a)chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces(a)ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces(a)ffmpeg.org>
+X-TUID: wOtvTzk+zhdw
+
+Signed-off-by: Steven Liu <lq(a)chinaffmpeg.org>
+---
+ libavformat/flvdec.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
+index a0362ff11c..a6a94a4021 100644
+--- a/libavformat/flvdec.c
++++ b/libavformat/flvdec.c
+@@ -320,6 +320,8 @@ static int flv_same_video_codec(AVFormatContext *s, AVCodecParameters *vpar, int
+ return vpar->codec_id == AV_CODEC_ID_HEVC;
+ case MKBETAG('a', 'v', '0', '1'):
+ return vpar->codec_id == AV_CODEC_ID_AV1;
++ case MKBETAG('v', 'p', '0', '9'):
++ return vpar->codec_id == AV_CODEC_ID_VP9;
+ default:
+ break;
+ }
+@@ -365,6 +367,10 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
+ par->codec_id = AV_CODEC_ID_AV1;
+ vstreami->need_parsing = AVSTREAM_PARSE_HEADERS;
+ return 4;
++ case MKBETAG('v', 'p', '0', '9'):
++ par->codec_id = AV_CODEC_ID_VP9;
++ vstreami->need_parsing = AVSTREAM_PARSE_HEADERS;
++ return 4;
+ default:
+ break;
+ }
+@@ -1285,7 +1291,8 @@ retry_duration:
+ st->codecpar->codec_id == AV_CODEC_ID_H264 ||
+ st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
+ st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
+- st->codecpar->codec_id == AV_CODEC_ID_AV1) {
++ st->codecpar->codec_id == AV_CODEC_ID_AV1 ||
++ st->codecpar->codec_id == AV_CODEC_ID_VP9) {
+ int type = 0;
+ if (flv->exheader && stream_type == FLV_STREAM_TYPE_VIDEO) {
+ type = flags & 0x0F;
+@@ -1317,7 +1324,7 @@ retry_duration:
+ }
+ if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
+ st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
+- st->codecpar->codec_id == AV_CODEC_ID_AV1)) {
++ st->codecpar->codec_id == AV_CODEC_ID_AV1 || st->codecpar->codec_id == AV_CODEC_ID_VP9)) {
+ AVDictionaryEntry *t;
+
+ if (st->codecpar->extradata) {
diff --git a/ffmpeg-ge-av1-vaapi-encode-support.patch b/ffmpeg-ge-av1-vaapi-encode-support.patch
new file mode 100644
index 0000000..6ae8258
--- /dev/null
+++ b/ffmpeg-ge-av1-vaapi-encode-support.patch
@@ -0,0 +1,3984 @@
+From 7c2ea45053b7a3d4193bb0abb9c0f3b0cdbeec7a Mon Sep 17 00:00:00 2001
+From: GloriousEggroll <gloriouseggroll(a)gmail.com>
+Date: Thu, 9 Nov 2023 17:51:19 -0700
+Subject: [PATCH] backport av1 encode support
+
+Adapted from https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=9594
+
+---
+ configure | 3 +
+ doc/encoders.texi | 14 +
+ libavcodec/Makefile | 2 +
+ libavcodec/allcodecs.c | 1 +
+ libavcodec/av1.h | 7 +
+ libavcodec/av1_levels.c | 92 +++
+ libavcodec/av1_levels.h | 58 ++
+ libavcodec/cbs.c | 155 +++--
+ libavcodec/cbs.h | 88 ++-
+ libavcodec/cbs_av1.c | 262 +++-----
+ libavcodec/cbs_av1.h | 1 +
+ libavcodec/cbs_av1_syntax_template.c | 4 +-
+ libavcodec/cbs_bsf.c | 5 +
+ libavcodec/cbs_h2645.c | 149 ++---
+ libavcodec/cbs_internal.h | 96 ++-
+ libavcodec/cbs_mpeg2.c | 15 +-
+ libavcodec/cbs_vp9.c | 122 ++--
+ libavcodec/extract_extradata_bsf.c | 7 +-
+ libavcodec/trace_headers_bsf.c | 2 +
+ libavcodec/vaapi_encode.c | 370 ++++++++---
+ libavcodec/vaapi_encode.h | 39 +-
+ libavcodec/vaapi_encode_av1.c | 949 +++++++++++++++++++++++++++
+ libavcodec/vaapi_encode_h264.c | 94 +--
+ libavcodec/vaapi_encode_h265.c | 76 ++-
+ libavcodec/vaapi_encode_mpeg2.c | 6 +-
+ libavcodec/vaapi_encode_vp8.c | 6 +-
+ libavcodec/vaapi_encode_vp9.c | 26 +-
+ 27 files changed, 2054 insertions(+), 595 deletions(-)
+ create mode 100644 libavcodec/av1_levels.c
+ create mode 100644 libavcodec/av1_levels.h
+ create mode 100644 libavcodec/vaapi_encode_av1.c
+
+diff --git a/configure b/configure
+index b6616f0..f5a91b6 100755
+--- a/configure
++++ b/configure
+@@ -3259,6 +3259,8 @@ av1_qsv_decoder_select="qsvdec"
+ av1_qsv_encoder_select="qsvenc"
+ av1_qsv_encoder_deps="libvpl"
+ av1_amf_encoder_deps="amf"
++av1_vaapi_encoder_deps="VAEncPictureParameterBufferAV1"
++av1_vaapi_encoder_select="cbs_av1 vaapi_encode"
+
+ # parsers
+ aac_parser_select="adts_header mpeg4audio"
+@@ -6973,6 +6975,7 @@ if enabled vaapi; then
+ check_type "va/va.h va/va_enc_jpeg.h" "VAEncPictureParameterBufferJPEG"
+ check_type "va/va.h va/va_enc_vp8.h" "VAEncPictureParameterBufferVP8"
+ check_type "va/va.h va/va_enc_vp9.h" "VAEncPictureParameterBufferVP9"
++ check_type "va/va.h va/va_enc_av1.h" "VAEncPictureParameterBufferAV1"
+ fi
+
+ if enabled_all opencl libdrm ; then
+diff --git a/doc/encoders.texi b/doc/encoders.texi
+index b02737b..994e27f 100644
+--- a/doc/encoders.texi
++++ b/doc/encoders.texi
+@@ -3965,6 +3965,20 @@ Average variable bitrate.
+ Each encoder also has its own specific options:
+ @table @option
+
++@item av1_vaapi
++@option{profile} sets the value of @emph{seq_profile}.
++@option{tier} sets the value of @emph{seq_tier}.
++@option{level} sets the value of @emph{seq_level_idx}.
++
++@table @option
++@item tiles
++Set the number of tiles to encode the input video with, as columns x rows.
++(default is auto, which means use minimal tile column/row number).
++@item tile_groups
++Set tile groups number. All the tiles will be distributed as evenly as possible to
++each tile group. (default is 1).
++@end table
++
+ @item h264_vaapi
+ @option{profile} sets the value of @emph{profile_idc} and the @emph{constraint_set*_flag}s.
+ @option{level} sets the value of @emph{level_idc}.
+diff --git a/libavcodec/Makefile b/libavcodec/Makefile
+index 389253f..5f620e6 100644
+--- a/libavcodec/Makefile
++++ b/libavcodec/Makefile
+@@ -255,6 +255,7 @@ OBJS-$(CONFIG_AV1_CUVID_DECODER) += cuviddec.o
+ OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER) += mediacodecdec.o
+ OBJS-$(CONFIG_AV1_NVENC_ENCODER) += nvenc_av1.o nvenc.o
+ OBJS-$(CONFIG_AV1_QSV_ENCODER) += qsvenc_av1.o
++OBJS-$(CONFIG_AV1_VAAPI_ENCODER) += vaapi_encode_av1.o av1_levels.o
+ OBJS-$(CONFIG_AVRN_DECODER) += avrndec.o
+ OBJS-$(CONFIG_AVRP_DECODER) += r210dec.o
+ OBJS-$(CONFIG_AVRP_ENCODER) += r210enc.o
+@@ -1298,6 +1299,7 @@ TESTPROGS = avcodec \
+ jpeg2000dwt \
+ mathops \
+
++TESTPROGS-$(CONFIG_AV1_VAAPI_ENCODER) += av1_levels
+ TESTPROGS-$(CONFIG_CABAC) += cabac
+ TESTPROGS-$(CONFIG_DCT) += avfft
+ TESTPROGS-$(CONFIG_FFT) += fft fft-fixed32
+diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
+index e593ad1..4706fc3 100644
+--- a/libavcodec/allcodecs.c
++++ b/libavcodec/allcodecs.c
+@@ -838,6 +838,7 @@ extern const FFCodec ff_av1_nvenc_encoder;
+ extern const FFCodec ff_av1_qsv_decoder;
+ extern const FFCodec ff_av1_qsv_encoder;
+ extern const FFCodec ff_av1_amf_encoder;
++extern const FFCodec ff_av1_vaapi_encoder;
+ extern const FFCodec ff_libopenh264_encoder;
+ extern const FFCodec ff_libopenh264_decoder;
+ extern const FFCodec ff_h264_amf_encoder;
+diff --git a/libavcodec/av1.h b/libavcodec/av1.h
+index 384f7cd..8704bc4 100644
+--- a/libavcodec/av1.h
++++ b/libavcodec/av1.h
+@@ -175,6 +175,13 @@ enum {
+ AV1_RESTORE_SWITCHABLE = 3,
+ };
+
++// TX mode (section 6.8.21)
++enum {
++ AV1_ONLY_4X4 = 0,
++ AV1_TX_MODE_LARGEST = 1,
++ AV1_TX_MODE_SELECT = 2,
++};
++
+ // Sequence Headers are actually unbounded because one can use
+ // an arbitrary number of leading zeroes when encoding via uvlc.
+ // The following estimate is based around using the lowest number
+diff --git a/libavcodec/av1_levels.c b/libavcodec/av1_levels.c
+new file mode 100644
+index 0000000..19b6ee1
+--- /dev/null
++++ b/libavcodec/av1_levels.c
+@@ -0,0 +1,92 @@
++/*
++ * Copyright (c) 2023 Intel Corporation
++ *
++ * 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
++ */
++
++#include <stddef.h>
++#include "libavutil/macros.h"
++#include "av1_levels.h"
++
++/** ignore entries which named in spec but no details. Like level 2.2 and 7.0. */
++static const AV1LevelDescriptor av1_levels[] = {
++ // Name MaxVSize MainMbps MaxTiles
++ // | level_idx | MaxDisplayRate | HighMbps | MaxTileCols
++ // | | MaxPicSize | | MaxDecodeRate | | MainCR | |
++ // | | | MaxHSize | | | MaxHeaderRate | | | HighCR| |
++ // | | | | | | | | | | | | | |
++ { "2.0", 0, 147456, 2048, 1152, 4423680, 5529600, 150, 1.5, 0, 2, 0, 8, 4 },
++ { "2.1", 1, 278784, 2816, 1584, 8363520, 10454400, 150, 3.0, 0, 2, 0, 8, 4 },
++ { "3.0", 4, 665856, 4352, 2448, 19975680, 24969600, 150, 6.0, 0, 2, 0, 16, 6 },
++ { "3.1", 5, 1065024, 5504, 3096, 31950720, 39938400, 150, 10.0, 0, 2, 0, 16, 6 },
++ { "4.0", 8, 2359296, 6144, 3456, 70778880, 77856768, 300, 12.0, 30.0, 4, 4, 32, 8 },
++ { "4.1", 9, 2359296, 6144, 3456, 141557760, 155713536, 300, 20.0, 50.0, 4, 4, 32, 8 },
++ { "5.0", 12, 8912896, 8192, 4352, 267386880, 273715200, 300, 30.0, 100.0, 6, 4, 64, 8 },
++ { "5.1", 13, 8912896, 8192, 4352, 534773760, 547430400, 300, 40.0, 160.0, 8, 4, 64, 8 },
++ { "5.2", 14, 8912896, 8192, 4352, 1069547520, 1094860800, 300, 60.0, 240.0, 8, 4, 64, 8 },
++ { "5.3", 15, 8912896, 8192, 4352, 1069547520, 1176502272, 300, 60.0, 240.0, 8, 4, 64, 8 },
++ { "6.0", 16, 35651584, 16384, 8704, 1069547520, 1176502272, 300, 60.0, 240.0, 8, 4, 128, 16 },
++ { "6.1", 17, 35651584, 16384, 8704, 2139095040, 2189721600, 300, 100.0, 480.0, 8, 4, 128, 16 },
++ { "6.2", 18, 35651584, 16384, 8704, 4278190080, 4379443200, 300, 160.0, 800.0, 8, 4, 128, 16 },
++ { "6.3", 19, 35651584, 16384, 8704, 4278190080, 4706009088, 300, 160.0, 800.0, 8, 4, 128, 16 },
++};
++
++const AV1LevelDescriptor *ff_av1_guess_level(int64_t bitrate,
++ int tier,
++ int width,
++ int height,
++ int tiles,
++ int tile_cols,
++ float fps)
++{
++ int pic_size;
++ uint64_t display_rate;
++ float max_br;
++
++ pic_size = width * height;
++ display_rate = (uint64_t)pic_size * fps;
++
++ for (int i = 0; i < FF_ARRAY_ELEMS(av1_levels); i++) {
++ const AV1LevelDescriptor *level = &av1_levels[i];
++ // Limitation: decode rate, header rate, compress rate, etc. are not considered.
++ if (pic_size > level->max_pic_size)
++ continue;
++ if (width > level->max_h_size)
++ continue;
++ if (height > level->max_v_size)
++ continue;
++ if (display_rate > level->max_display_rate)
++ continue;
++
++ if (tier)
++ max_br = level->high_mbps;
++ else
++ max_br = level->main_mbps;
++ if (!max_br)
++ continue;
++ if (bitrate > (int64_t)(1000000.0 * max_br))
++ continue;
++
++ if (tiles > level->max_tiles)
++ continue;
++ if (tile_cols > level->max_tile_cols)
++ continue;
++ return level;
++ }
++
++ return NULL;
++}
+diff --git a/libavcodec/av1_levels.h b/libavcodec/av1_levels.h
+new file mode 100644
+index 0000000..164cb87
+--- /dev/null
++++ b/libavcodec/av1_levels.h
+@@ -0,0 +1,58 @@
++/*
++ * Copyright (c) 2023 Intel Corporation
++ *
++ * 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
++ */
++
++#ifndef AVCODEC_AV1_LEVELS_H
++#define AVCODEC_AV1_LEVELS_H
++
++#include <stdint.h>
++
++typedef struct AV1LevelDescriptor {
++ char name[4];
++ uint8_t level_idx;
++
++ uint32_t max_pic_size;
++ uint32_t max_h_size;
++ uint32_t max_v_size;
++ uint64_t max_display_rate;
++ uint64_t max_decode_rate;
++
++ uint32_t max_header_rate;
++ float main_mbps;
++ float high_mbps;
++ uint32_t main_cr;
++ uint32_t high_cr;
++ uint32_t max_tiles;
++ uint32_t max_tile_cols;
++} AV1LevelDescriptor;
++
++/**
++ * Guess the level of a stream from some parameters.
++ *
++ * Unknown parameters may be zero, in which case they will be ignored.
++ */
++const AV1LevelDescriptor *ff_av1_guess_level(int64_t bitrate,
++ int tier,
++ int width,
++ int height,
++ int tile_rows,
++ int tile_cols,
++ float fps);
++
++#endif /* AVCODEC_AV1_LEVELS_H */
+diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
+index 504197e..64b9aee 100644
+--- a/libavcodec/cbs.c
++++ b/libavcodec/cbs.c
+@@ -111,8 +111,9 @@ av_cold int ff_cbs_init(CodedBitstreamContext **ctx_ptr,
+
+ ctx->decompose_unit_types = NULL;
+
+- ctx->trace_enable = 0;
+- ctx->trace_level = AV_LOG_TRACE;
++ ctx->trace_enable = 0;
++ ctx->trace_level = AV_LOG_TRACE;
++ ctx->trace_context = ctx;
+
+ *ctx_ptr = ctx;
+ return 0;
+@@ -490,19 +491,27 @@ void ff_cbs_trace_header(CodedBitstreamContext *ctx,
+ av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name);
+ }
+
+-void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
+- const char *str, const int *subscripts,
+- const char *bits, int64_t value)
++void ff_cbs_trace_read_log(void *trace_context,
++ GetBitContext *gbc, int length,
++ const char *str, const int *subscripts,
++ int64_t value)
+ {
++ CodedBitstreamContext *ctx = trace_context;
+ char name[256];
++ char bits[256];
+ size_t name_len, bits_len;
+ int pad, subs, i, j, k, n;
+-
+- if (!ctx->trace_enable)
+- return;
++ int position;
+
+ av_assert0(value >= INT_MIN && value <= UINT32_MAX);
+
++ position = get_bits_count(gbc);
++
++ av_assert0(length < 256);
++ for (i = 0; i < length; i++)
++ bits[i] = get_bits1(gbc) ? '1' : '0';
++ bits[length] = 0;
++
+ subs = subscripts ? subscripts[0] : 0;
+ n = 0;
+ for (i = j = 0; str[i];) {
+@@ -529,7 +538,7 @@ void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
+ av_assert0(n == subs);
+
+ name_len = strlen(name);
+- bits_len = strlen(bits);
++ bits_len = length;
+
+ if (name_len + bits_len > 60)
+ pad = bits_len + 2;
+@@ -540,14 +549,48 @@ void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
+ position, name, pad, bits, value);
+ }
+
+-int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
+- int width, const char *name,
+- const int *subscripts, uint32_t *write_to,
+- uint32_t range_min, uint32_t range_max)
++void ff_cbs_trace_write_log(void *trace_context,
++ PutBitContext *pbc, int length,
++ const char *str, const int *subscripts,
++ int64_t value)
+ {
+- uint32_t value;
++ CodedBitstreamContext *ctx = trace_context;
++
++ // Ensure that the syntax element is written to the output buffer,
++ // make a GetBitContext pointed at the start position, then call the
++ // read log function which can read the bits back to log them.
++
++ GetBitContext gbc;
+ int position;
+
++ if (length > 0) {
++ PutBitContext flush;
++ flush = *pbc;
++ flush_put_bits(&flush);
++ }
++
++ position = put_bits_count(pbc);
++ av_assert0(position >= length);
++
++ init_get_bits(&gbc, pbc->buf, position);
++
++ skip_bits_long(&gbc, position - length);
++
++ ff_cbs_trace_read_log(ctx, &gbc, length, str, subscripts, value);
++}
++
++static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
++ GetBitContext *gbc,
++ int width, const char *name,
++ const int *subscripts,
++ uint32_t *write_to,
++ uint32_t range_min,
++ uint32_t range_max)
++{
++ uint32_t value;
++
++ CBS_TRACE_READ_START();
++
+ av_assert0(width > 0 && width <= 32);
+
+ if (get_bits_left(gbc) < width) {
+@@ -556,21 +599,9 @@ int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ return AVERROR_INVALIDDATA;
+ }
+
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
+-
+ value = get_bits_long(gbc, width);
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (i = 0; i < width; i++)
+- bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
+- bits[i] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
+- bits, value);
+- }
++ CBS_TRACE_READ_END();
+
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+@@ -583,11 +614,29 @@ int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ return 0;
+ }
+
++int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
++ int width, const char *name,
++ const int *subscripts, uint32_t *write_to,
++ uint32_t range_min, uint32_t range_max)
++{
++ return cbs_read_unsigned(ctx, gbc, width, name, subscripts,
++ write_to, range_min, range_max);
++}
++
++int ff_cbs_read_simple_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
++ int width, const char *name, uint32_t *write_to)
++{
++ return cbs_read_unsigned(ctx, gbc, width, name, NULL,
++ write_to, 0, UINT32_MAX);
++}
++
+ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ int width, const char *name,
+ const int *subscripts, uint32_t value,
+ uint32_t range_min, uint32_t range_max)
+ {
++ CBS_TRACE_WRITE_START();
++
+ av_assert0(width > 0 && width <= 32);
+
+ if (value < range_min || value > range_max) {
+@@ -600,32 +649,31 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ if (put_bits_left(pbc) < width)
+ return AVERROR(ENOSPC);
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (i = 0; i < width; i++)
+- bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
+- bits[i] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+- name, subscripts, bits, value);
+- }
+-
+ if (width < 32)
+ put_bits(pbc, width, value);
+ else
+ put_bits32(pbc, value);
+
++ CBS_TRACE_WRITE_END();
++
+ return 0;
+ }
+
++int ff_cbs_write_simple_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
++ int width, const char *name, uint32_t value)
++{
++ return ff_cbs_write_unsigned(ctx, pbc, width, name, NULL,
++ value, 0, MAX_UINT_BITS(width));
++}
++
+ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ int width, const char *name,
+ const int *subscripts, int32_t *write_to,
+ int32_t range_min, int32_t range_max)
+ {
+ int32_t value;
+- int position;
++
++ CBS_TRACE_READ_START();
+
+ av_assert0(width > 0 && width <= 32);
+
+@@ -635,21 +683,9 @@ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ return AVERROR_INVALIDDATA;
+ }
+
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
+-
+ value = get_sbits_long(gbc, width);
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (i = 0; i < width; i++)
+- bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
+- bits[i] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
+- bits, value);
+- }
++ CBS_TRACE_READ_END();
+
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+@@ -667,6 +703,8 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ const int *subscripts, int32_t value,
+ int32_t range_min, int32_t range_max)
+ {
++ CBS_TRACE_WRITE_START();
++
+ av_assert0(width > 0 && width <= 32);
+
+ if (value < range_min || value > range_max) {
+@@ -679,22 +717,13 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ if (put_bits_left(pbc) < width)
+ return AVERROR(ENOSPC);
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (i = 0; i < width; i++)
+- bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
+- bits[i] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+- name, subscripts, bits, value);
+- }
+-
+ if (width < 32)
+ put_sbits(pbc, width, value);
+ else
+ put_bits32(pbc, value);
+
++ CBS_TRACE_WRITE_END();
++
+ return 0;
+ }
+
+diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h
+index ee21623..f6509a2 100644
+--- a/libavcodec/cbs.h
++++ b/libavcodec/cbs.h
+@@ -167,6 +167,51 @@ typedef struct CodedBitstreamFragment {
+ CodedBitstreamUnit *units;
+ } CodedBitstreamFragment;
+
++
++struct CodedBitstreamContext;
++struct GetBitContext;
++struct PutBitContext;
++
++/**
++ * Callback type for read tracing.
++ *
++ * @param ctx User-set trace context.
++ * @param gbc A GetBitContext set at the start of the syntax
++ * element. This is a copy, the callee does not
++ * need to preserve it.
++ * @param length Length in bits of the syntax element.
++ * @param name String name of the syntax elements.
++ * @param subscripts If the syntax element is an array, a pointer to
++ * an array of subscripts into the array.
++ * @param value Parsed value of the syntax element.
++ */
++typedef void (*CBSTraceReadCallback)(void *trace_context,
++ struct GetBitContext *gbc,
++ int start_position,
++ const char *name,
++ const int *subscripts,
++ int64_t value);
++
++/**
++ * Callback type for write tracing.
++ *
++ * @param ctx User-set trace context.
++ * @param pbc A PutBitContext set at the end of the syntax
++ * element. The user must not modify this, but may
++ * inspect it to determine state.
++ * @param length Length in bits of the syntax element.
++ * @param name String name of the syntax elements.
++ * @param subscripts If the syntax element is an array, a pointer to
++ * an array of subscripts into the array.
++ * @param value Written value of the syntax element.
++ */
++typedef void (*CBSTraceWriteCallback)(void *trace_context,
++ struct PutBitContext *pbc,
++ int start_position,
++ const char *name,
++ const int *subscripts,
++ int64_t value);
++
+ /**
+ * Context structure for coded bitstream operations.
+ */
+@@ -210,11 +255,29 @@ typedef struct CodedBitstreamContext {
+ */
+ int trace_enable;
+ /**
+- * Log level to use for trace output.
++ * Log level to use for default trace output.
+ *
+ * From AV_LOG_*; defaults to AV_LOG_TRACE.
+ */
+ int trace_level;
++ /**
++ * User context pointer to pass to trace callbacks.
++ */
++ void *trace_context;
++ /**
++ * Callback for read tracing.
++ *
++ * If tracing is enabled then this is called once for each syntax
++ * element parsed.
++ */
++ CBSTraceReadCallback trace_read_callback;
++ /**
++ * Callback for write tracing.
++ *
++ * If tracing is enabled then this is called once for each syntax
++ * element written.
++ */
++ CBSTraceWriteCallback trace_write_callback;
+
+ /**
+ * Write buffer. Used as intermediate buffer when writing units.
+@@ -433,4 +496,27 @@ int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx,
+ CodedBitstreamUnit *unit);
+
+
++
++/**
++ * Helper function for read tracing which formats the syntax element
++ * and logs the result.
++ *
++ * Trace context should be set to the CodedBitstreamContext.
++ */
++void ff_cbs_trace_read_log(void *trace_context,
++ struct GetBitContext *gbc, int length,
++ const char *str, const int *subscripts,
++ int64_t value);
++
++/**
++ * Helper function for write tracing which formats the syntax element
++ * and logs the result.
++ *
++ * Trace context should be set to the CodedBitstreamContext.
++ */
++void ff_cbs_trace_write_log(void *trace_context,
++ struct PutBitContext *pbc, int length,
++ const char *str, const int *subscripts,
++ int64_t value);
++
+ #endif /* AVCODEC_CBS_H */
+diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c
+index 45e1288..6098c97 100644
+--- a/libavcodec/cbs_av1.c
++++ b/libavcodec/cbs_av1.c
+@@ -31,10 +31,8 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ uint32_t range_min, uint32_t range_max)
+ {
+ uint32_t zeroes, bits_value, value;
+- int position;
+
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
++ CBS_TRACE_READ_START();
+
+ zeroes = 0;
+ while (1) {
+@@ -50,6 +48,9 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ }
+
+ if (zeroes >= 32) {
++ // Note that the spec allows an arbitrarily large number of
++ // zero bits followed by a one bit in this case, but the
++ // libaom implementation does not support it.
+ value = MAX_UINT_BITS(32);
+ } else {
+ if (get_bits_left(gbc) < zeroes) {
+@@ -62,36 +63,7 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ value = bits_value + (UINT32_C(1) << zeroes) - 1;
+ }
+
+- if (ctx->trace_enable) {
+- char bits[65];
+- int i, j, k;
+-
+- if (zeroes >= 32) {
+- while (zeroes > 32) {
+- k = FFMIN(zeroes - 32, 32);
+- for (i = 0; i < k; i++)
+- bits[i] = '0';
+- bits[i] = 0;
+- ff_cbs_trace_syntax_element(ctx, position, name,
+- NULL, bits, 0);
+- zeroes -= k;
+- position += k;
+- }
+- }
+-
+- for (i = 0; i < zeroes; i++)
+- bits[i] = '0';
+- bits[i++] = '1';
+-
+- if (zeroes < 32) {
+- for (j = 0; j < zeroes; j++)
+- bits[i++] = (bits_value >> (zeroes - j - 1) & 1) ? '1' : '0';
+- }
+-
+- bits[i] = 0;
+- ff_cbs_trace_syntax_element(ctx, position, name,
+- NULL, bits, value);
+- }
++ CBS_TRACE_READ_END_NO_SUBSCRIPTS();
+
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+@@ -109,7 +81,9 @@ static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ uint32_t range_min, uint32_t range_max)
+ {
+ uint32_t v;
+- int position, zeroes;
++ int zeroes;
++
++ CBS_TRACE_WRITE_START();
+
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+@@ -118,28 +92,17 @@ static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ return AVERROR_INVALIDDATA;
+ }
+
+- if (ctx->trace_enable)
+- position = put_bits_count(pbc);
+-
+ zeroes = av_log2(value + 1);
+ v = value - (1U << zeroes) + 1;
++
++ if (put_bits_left(pbc) < 2 * zeroes + 1)
++ return AVERROR(ENOSPC);
++
+ put_bits(pbc, zeroes, 0);
+ put_bits(pbc, 1, 1);
+ put_bits(pbc, zeroes, v);
+
+- if (ctx->trace_enable) {
+- char bits[65];
+- int i, j;
+- i = 0;
+- for (j = 0; j < zeroes; j++)
+- bits[i++] = '0';
+- bits[i++] = '1';
+- for (j = 0; j < zeroes; j++)
+- bits[i++] = (v >> (zeroes - j - 1) & 1) ? '1' : '0';
+- bits[i++] = 0;
+- ff_cbs_trace_syntax_element(ctx, position, name, NULL,
+- bits, value);
+- }
++ CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
+
+ return 0;
+ }
+@@ -148,20 +111,19 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ const char *name, uint64_t *write_to)
+ {
+ uint64_t value;
+- int position, err, i;
++ uint32_t byte;
++ int i;
+
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
++ CBS_TRACE_READ_START();
+
+ value = 0;
+ for (i = 0; i < 8; i++) {
+- int subscript[2] = { 1, i };
+- uint32_t byte;
+- err = ff_cbs_read_unsigned(ctx, gbc, 8, "leb128_byte[i]", subscript,
+- &byte, 0x00, 0xff);
+- if (err < 0)
+- return err;
+-
++ if (get_bits_left(gbc) < 8) {
++ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid leb128 at "
++ "%s: bitstream ended.\n", name);
++ return AVERROR_INVALIDDATA;
++ }
++ byte = get_bits(gbc, 8);
+ value |= (uint64_t)(byte & 0x7f) << (i * 7);
+ if (!(byte & 0x80))
+ break;
+@@ -170,39 +132,38 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ if (value > UINT32_MAX)
+ return AVERROR_INVALIDDATA;
+
+- if (ctx->trace_enable)
+- ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value);
++ CBS_TRACE_READ_END_NO_SUBSCRIPTS();
+
+ *write_to = value;
+ return 0;
+ }
+
++/** Minimum byte length will be used to indicate the len128 of value if byte_len is 0. */
+ static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc,
+- const char *name, uint64_t value)
++ const char *name, uint64_t value, uint8_t byte_len)
+ {
+- int position, err, len, i;
++ int len, i;
+ uint8_t byte;
+
+- len = (av_log2(value) + 7) / 7;
++ CBS_TRACE_WRITE_START();
++
++ if (byte_len)
++ av_assert0(byte_len >= (av_log2(value) + 7) / 7);
+
+- if (ctx->trace_enable)
+- position = put_bits_count(pbc);
++ len = byte_len ? byte_len : (av_log2(value) + 7) / 7;
+
+ for (i = 0; i < len; i++) {
+- int subscript[2] = { 1, i };
++ if (put_bits_left(pbc) < 8)
++ return AVERROR(ENOSPC);
+
+ byte = value >> (7 * i) & 0x7f;
+ if (i < len - 1)
+ byte |= 0x80;
+
+- err = ff_cbs_write_unsigned(ctx, pbc, 8, "leb128_byte[i]", subscript,
+- byte, 0x00, 0xff);
+- if (err < 0)
+- return err;
++ put_bits(pbc, 8, byte);
+ }
+
+- if (ctx->trace_enable)
+- ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value);
++ CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
+
+ return 0;
+ }
+@@ -212,12 +173,11 @@ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ const int *subscripts, uint32_t *write_to)
+ {
+ uint32_t m, v, extra_bit, value;
+- int position, w;
++ int w;
+
+- av_assert0(n > 0);
++ CBS_TRACE_READ_START();
+
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
++ av_assert0(n > 0);
+
+ w = av_log2(n) + 1;
+ m = (1 << w) - n;
+@@ -240,18 +200,7 @@ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ value = (v << 1) - m + extra_bit;
+ }
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (i = 0; i < w - 1; i++)
+- bits[i] = (v >> i & 1) ? '1' : '0';
+- if (v >= m)
+- bits[i++] = extra_bit ? '1' : '0';
+- bits[i] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, position,
+- name, subscripts, bits, value);
+- }
++ CBS_TRACE_READ_END();
+
+ *write_to = value;
+ return 0;
+@@ -262,7 +211,8 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ const int *subscripts, uint32_t value)
+ {
+ uint32_t w, m, v, extra_bit;
+- int position;
++
++ CBS_TRACE_WRITE_START();
+
+ if (value > n) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+@@ -271,9 +221,6 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ return AVERROR_INVALIDDATA;
+ }
+
+- if (ctx->trace_enable)
+- position = put_bits_count(pbc);
+-
+ w = av_log2(n) + 1;
+ m = (1 << w) - n;
+
+@@ -290,18 +237,7 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ put_bits(pbc, 1, extra_bit);
+ }
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (i = 0; i < w - 1; i++)
+- bits[i] = (v >> i & 1) ? '1' : '0';
+- if (value >= m)
+- bits[i++] = extra_bit ? '1' : '0';
+- bits[i] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, position,
+- name, subscripts, bits, value);
+- }
++ CBS_TRACE_WRITE_END();
+
+ return 0;
+ }
+@@ -311,33 +247,24 @@ static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc
+ const char *name, uint32_t *write_to)
+ {
+ uint32_t value;
+- int position, i;
+- char bits[33];
+
+- av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1);
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
++ CBS_TRACE_READ_START();
++
++ av_assert0(range_min <= range_max && range_max - range_min < 32);
+
+- for (i = 0, value = range_min; value < range_max;) {
++ for (value = range_min; value < range_max;) {
+ if (get_bits_left(gbc) < 1) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at "
+ "%s: bitstream ended.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+- if (get_bits1(gbc)) {
+- bits[i++] = '1';
++ if (get_bits1(gbc))
+ ++value;
+- } else {
+- bits[i++] = '0';
++ else
+ break;
+- }
+ }
+
+- if (ctx->trace_enable) {
+- bits[i] = 0;
+- ff_cbs_trace_syntax_element(ctx, position,
+- name, NULL, bits, value);
+- }
++ CBS_TRACE_READ_END_NO_SUBSCRIPTS();
+
+ *write_to = value;
+ return 0;
+@@ -349,6 +276,8 @@ static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
+ {
+ int len;
+
++ CBS_TRACE_WRITE_START();
++
+ av_assert0(range_min <= range_max && range_max - range_min < 32);
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+@@ -364,23 +293,11 @@ static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
+ if (put_bits_left(pbc) < len)
+ return AVERROR(ENOSPC);
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (i = 0; i < len; i++) {
+- if (range_min + i == value)
+- bits[i] = '0';
+- else
+- bits[i] = '1';
+- }
+- bits[i] = 0;
+- ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+- name, NULL, bits, value);
+- }
+-
+ if (len > 0)
+ put_bits(pbc, len, (1 << len) - 1 - (value != range_max));
+
++ CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
++
+ return 0;
+ }
+
+@@ -388,12 +305,10 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ uint32_t range_max, const char *name,
+ const int *subscripts, uint32_t *write_to)
+ {
+- uint32_t value;
+- int position, err;
+- uint32_t max_len, len, range_offset, range_bits;
++ uint32_t value, max_len, len, range_offset, range_bits;
++ int err;
+
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
++ CBS_TRACE_READ_START();
+
+ av_assert0(range_max > 0);
+ max_len = av_log2(range_max - 1) - 3;
+@@ -412,9 +327,8 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ }
+
+ if (len < max_len) {
+- err = ff_cbs_read_unsigned(ctx, gbc, range_bits,
+- "subexp_bits", NULL, &value,
+- 0, MAX_UINT_BITS(range_bits));
++ err = ff_cbs_read_simple_unsigned(ctx, gbc, range_bits,
++ "subexp_bits", &value);
+ if (err < 0)
+ return err;
+
+@@ -426,9 +340,7 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ }
+ value += range_offset;
+
+- if (ctx->trace_enable)
+- ff_cbs_trace_syntax_element(ctx, position,
+- name, subscripts, "", value);
++ CBS_TRACE_READ_END_VALUE_ONLY();
+
+ *write_to = value;
+ return err;
+@@ -438,9 +350,11 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ uint32_t range_max, const char *name,
+ const int *subscripts, uint32_t value)
+ {
+- int position, err;
++ int err;
+ uint32_t max_len, len, range_offset, range_bits;
+
++ CBS_TRACE_WRITE_START();
++
+ if (value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+ "%"PRIu32", but must be in [0,%"PRIu32"].\n",
+@@ -448,9 +362,6 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ return AVERROR_INVALIDDATA;
+ }
+
+- if (ctx->trace_enable)
+- position = put_bits_count(pbc);
+-
+ av_assert0(range_max > 0);
+ max_len = av_log2(range_max - 1) - 3;
+
+@@ -476,10 +387,9 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ return err;
+
+ if (len < max_len) {
+- err = ff_cbs_write_unsigned(ctx, pbc, range_bits,
+- "subexp_bits", NULL,
+- value - range_offset,
+- 0, MAX_UINT_BITS(range_bits));
++ err = ff_cbs_write_simple_unsigned(ctx, pbc, range_bits,
++ "subexp_bits",
++ value - range_offset);
+ if (err < 0)
+ return err;
+
+@@ -491,9 +401,7 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ return err;
+ }
+
+- if (ctx->trace_enable)
+- ff_cbs_trace_syntax_element(ctx, position,
+- name, subscripts, "", value);
++ CBS_TRACE_WRITE_END_VALUE_ONLY();
+
+ return err;
+ }
+@@ -546,8 +454,6 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
+
+ #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
+
+-#define fb(width, name) \
+- xf(width, name, current->name, 0, MAX_UINT_BITS(width), 0, )
+ #define fc(width, name, range_min, range_max) \
+ xf(width, name, current->name, range_min, range_max, 0, )
+ #define flag(name) fb(1, name)
+@@ -573,6 +479,13 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
+ #define READWRITE read
+ #define RWContext GetBitContext
+
++#define fb(width, name) do { \
++ uint32_t value; \
++ CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, \
++ #name, &value)); \
++ current->name = value; \
++ } while (0)
++
+ #define xf(width, name, var, range_min, range_max, subs, ...) do { \
+ uint32_t value; \
+ CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
+@@ -645,6 +558,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
+ #undef READ
+ #undef READWRITE
+ #undef RWContext
++#undef fb
+ #undef xf
+ #undef xsu
+ #undef uvlc
+@@ -661,6 +575,11 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
+ #define READWRITE write
+ #define RWContext PutBitContext
+
++#define fb(width, name) do { \
++ CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \
++ current->name)); \
++ } while (0)
++
+ #define xf(width, name, var, range_min, range_max, subs, ...) do { \
+ CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+@@ -703,7 +622,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
+ } while (0)
+
+ #define leb128(name) do { \
+- CHECK(cbs_av1_write_leb128(ctx, rw, #name, current->name)); \
++ CHECK(cbs_av1_write_leb128(ctx, rw, #name, current->name, 0)); \
+ } while (0)
+
+ #define infer(name, value) do { \
+@@ -723,6 +642,7 @@ static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
+ #undef WRITE
+ #undef READWRITE
+ #undef RWContext
++#undef fb
+ #undef xf
+ #undef xsu
+ #undef uvlc
+@@ -1086,9 +1006,14 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
+
+ if (obu->header.obu_has_size_field) {
+ pbc_tmp = *pbc;
+- // Add space for the size field to fill later.
+- put_bits32(pbc, 0);
+- put_bits32(pbc, 0);
++ if (obu->obu_size_byte_len) {
++ for (int i = 0; i < obu->obu_size_byte_len; i++)
++ put_bits(pbc, 8, 0);
++ } else {
++ // Add space for the size field to fill later.
++ put_bits32(pbc, 0);
++ put_bits32(pbc, 0);
++ }
+ }
+
+ td = NULL;
+@@ -1208,7 +1133,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
+ end_pos /= 8;
+
+ *pbc = pbc_tmp;
+- err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size);
++ err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size, obu->obu_size_byte_len);
+ if (err < 0)
+ goto error;
+
+@@ -1225,8 +1150,11 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
+ }
+
+ if (obu->obu_size > 0) {
+- memmove(pbc->buf + data_pos,
+- pbc->buf + start_pos, header_size);
++ if (!obu->obu_size_byte_len) {
++ obu->obu_size_byte_len = start_pos - data_pos;
++ memmove(pbc->buf + data_pos,
++ pbc->buf + start_pos, header_size);
++ }
+ skip_put_bytes(pbc, header_size);
+
+ if (td) {
+diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h
+index 1fc80dc..c5dae3c 100644
+--- a/libavcodec/cbs_av1.h
++++ b/libavcodec/cbs_av1.h
+@@ -392,6 +392,7 @@ typedef struct AV1RawOBU {
+ AV1RawOBUHeader header;
+
+ size_t obu_size;
++ uint8_t obu_size_byte_len;
+
+ union {
+ AV1RawSequenceHeader sequence_header;
+diff --git a/libavcodec/cbs_av1_syntax_template.c b/libavcodec/cbs_av1_syntax_template.c
+index e95925a..cf2e259 100644
+--- a/libavcodec/cbs_av1_syntax_template.c
++++ b/libavcodec/cbs_av1_syntax_template.c
+@@ -1018,9 +1018,9 @@ static int FUNC(read_tx_mode)(CodedBitstreamContext *ctx, RWContext *rw,
+ int err;
+
+ if (priv->coded_lossless)
+- infer(tx_mode, 0);
++ infer(tx_mode, AV1_ONLY_4X4);
+ else
+- increment(tx_mode, 1, 2);
++ increment(tx_mode, AV1_TX_MODE_LARGEST, AV1_TX_MODE_SELECT);
+
+ return 0;
+ }
+diff --git a/libavcodec/cbs_bsf.c b/libavcodec/cbs_bsf.c
+index 069f6e9..b252854 100644
+--- a/libavcodec/cbs_bsf.c
++++ b/libavcodec/cbs_bsf.c
+@@ -123,6 +123,11 @@ int ff_cbs_bsf_generic_init(AVBSFContext *bsf, const CBSBSFType *type)
+ if (err < 0)
+ return err;
+
++ ctx->output->trace_enable = 1;
++ ctx->output->trace_level = AV_LOG_TRACE;
++ ctx->output->trace_context = ctx->output;
++ ctx->output->trace_write_callback = ff_cbs_trace_write_log;
++
+ if (bsf->par_in->extradata) {
+ err = ff_cbs_read_extradata(ctx->input, frag, bsf->par_in);
+ if (err < 0) {
+diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
+index 80e4882..355f4d5 100644
+--- a/libavcodec/cbs_h2645.c
++++ b/libavcodec/cbs_h2645.c
+@@ -34,41 +34,38 @@ static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ uint32_t *write_to,
+ uint32_t range_min, uint32_t range_max)
+ {
+- uint32_t value;
+- int position, i, j;
+- unsigned int k;
+- char bits[65];
++ uint32_t leading_bits, value;
++ int max_length, leading_zeroes;
+
+- position = get_bits_count(gbc);
++ CBS_TRACE_READ_START();
+
+- for (i = 0; i < 32; i++) {
+- if (get_bits_left(gbc) < i + 1) {
++ max_length = FFMIN(get_bits_left(gbc), 32);
++
++ leading_bits = show_bits_long(gbc, max_length);
++ if (leading_bits == 0) {
++ if (max_length >= 32) {
++ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
++ "%s: more than 31 zeroes.\n", name);
++ return AVERROR_INVALIDDATA;
++ } else {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
+ "%s: bitstream ended.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+- k = get_bits1(gbc);
+- bits[i] = k ? '1' : '0';
+- if (k)
+- break;
+ }
+- if (i >= 32) {
++
++ leading_zeroes = max_length - 1 - av_log2(leading_bits);
++ skip_bits_long(gbc, leading_zeroes);
++
++ if (get_bits_left(gbc) < leading_zeroes + 1) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
+- "%s: more than 31 zeroes.\n", name);
++ "%s: bitstream ended.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+- value = 1;
+- for (j = 0; j < i; j++) {
+- k = get_bits1(gbc);
+- bits[i + j + 1] = k ? '1' : '0';
+- value = value << 1 | k;
+- }
+- bits[i + j + 1] = 0;
+- --value;
+
+- if (ctx->trace_enable)
+- ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
+- bits, value);
++ value = get_bits_long(gbc, leading_zeroes + 1) - 1;
++
++ CBS_TRACE_READ_END();
+
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+@@ -86,45 +83,44 @@ static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ int32_t *write_to,
+ int32_t range_min, int32_t range_max)
+ {
++ uint32_t leading_bits, unsigned_value;
++ int max_length, leading_zeroes;
+ int32_t value;
+- int position, i, j;
+- unsigned int k;
+- uint32_t v;
+- char bits[65];
+
+- position = get_bits_count(gbc);
++ CBS_TRACE_READ_START();
+
+- for (i = 0; i < 32; i++) {
+- if (get_bits_left(gbc) < i + 1) {
++ max_length = FFMIN(get_bits_left(gbc), 32);
++
++ leading_bits = show_bits_long(gbc, max_length);
++ if (leading_bits == 0) {
++ if (max_length >= 32) {
++ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
++ "%s: more than 31 zeroes.\n", name);
++ return AVERROR_INVALIDDATA;
++ } else {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
+ "%s: bitstream ended.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+- k = get_bits1(gbc);
+- bits[i] = k ? '1' : '0';
+- if (k)
+- break;
+ }
+- if (i >= 32) {
++
++ leading_zeroes = max_length - 1 - av_log2(leading_bits);
++ skip_bits_long(gbc, leading_zeroes);
++
++ if (get_bits_left(gbc) < leading_zeroes + 1) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
+- "%s: more than 31 zeroes.\n", name);
++ "%s: bitstream ended.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+- v = 1;
+- for (j = 0; j < i; j++) {
+- k = get_bits1(gbc);
+- bits[i + j + 1] = k ? '1' : '0';
+- v = v << 1 | k;
+- }
+- bits[i + j + 1] = 0;
+- if (v & 1)
+- value = -(int32_t)(v / 2);
++
++ unsigned_value = get_bits_long(gbc, leading_zeroes + 1);
++
++ if (unsigned_value & 1)
++ value = -(int32_t)(unsigned_value / 2);
+ else
+- value = v / 2;
++ value = unsigned_value / 2;
+
+- if (ctx->trace_enable)
+- ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
+- bits, value);
++ CBS_TRACE_READ_END();
+
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+@@ -144,6 +140,8 @@ static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ {
+ int len;
+
++ CBS_TRACE_WRITE_START();
++
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+ "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n",
+@@ -156,27 +154,14 @@ static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ if (put_bits_left(pbc) < 2 * len + 1)
+ return AVERROR(ENOSPC);
+
+- if (ctx->trace_enable) {
+- char bits[65];
+- int i;
+-
+- for (i = 0; i < len; i++)
+- bits[i] = '0';
+- bits[len] = '1';
+- for (i = 0; i < len; i++)
+- bits[len + i + 1] = (value + 1) >> (len - i - 1) & 1 ? '1' : '0';
+- bits[len + len + 1] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+- name, subscripts, bits, value);
+- }
+-
+ put_bits(pbc, len, 0);
+ if (len + 1 < 32)
+ put_bits(pbc, len + 1, value + 1);
+ else
+ put_bits32(pbc, value + 1);
+
++ CBS_TRACE_WRITE_END();
++
+ return 0;
+ }
+
+@@ -188,6 +173,8 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ int len;
+ uint32_t uvalue;
+
++ CBS_TRACE_WRITE_START();
++
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+ "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n",
+@@ -207,27 +194,14 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ if (put_bits_left(pbc) < 2 * len + 1)
+ return AVERROR(ENOSPC);
+
+- if (ctx->trace_enable) {
+- char bits[65];
+- int i;
+-
+- for (i = 0; i < len; i++)
+- bits[i] = '0';
+- bits[len] = '1';
+- for (i = 0; i < len; i++)
+- bits[len + i + 1] = (uvalue + 1) >> (len - i - 1) & 1 ? '1' : '0';
+- bits[len + len + 1] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+- name, subscripts, bits, value);
+- }
+-
+ put_bits(pbc, len, 0);
+ if (len + 1 < 32)
+ put_bits(pbc, len + 1, uvalue + 1);
+ else
+ put_bits32(pbc, uvalue + 1);
+
++ CBS_TRACE_WRITE_END();
++
+ return 0;
+ }
+
+@@ -261,8 +235,6 @@ static int cbs_h265_payload_extension_present(GetBitContext *gbc, uint32_t paylo
+
+ #define u(width, name, range_min, range_max) \
+ xu(width, name, current->name, range_min, range_max, 0, )
+-#define ub(width, name) \
+- xu(width, name, current->name, 0, MAX_UINT_BITS(width), 0, )
+ #define flag(name) ub(1, name)
+ #define ue(name, range_min, range_max) \
+ xue(name, current->name, range_min, range_max, 0, )
+@@ -298,6 +270,12 @@ static int cbs_h265_payload_extension_present(GetBitContext *gbc, uint32_t paylo
+ #define READWRITE read
+ #define RWContext GetBitContext
+
++#define ub(width, name) do { \
++ uint32_t value; \
++ CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \
++ &value)); \
++ current->name = value; \
++ } while (0)
+ #define xu(width, name, var, range_min, range_max, subs, ...) do { \
+ uint32_t value; \
+ CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
+@@ -372,6 +350,7 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
+ #undef READ
+ #undef READWRITE
+ #undef RWContext
++#undef ub
+ #undef xu
+ #undef xi
+ #undef xue
+@@ -387,6 +366,11 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
+ #define READWRITE write
+ #define RWContext PutBitContext
+
++#define ub(width, name) do { \
++ uint32_t value = current->name; \
++ CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \
++ value)); \
++ } while (0)
+ #define xu(width, name, var, range_min, range_max, subs, ...) do { \
+ uint32_t value = var; \
+ CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
+@@ -450,6 +434,7 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
+ #undef WRITE
+ #undef READWRITE
+ #undef RWContext
++#undef ub
+ #undef xu
+ #undef xi
+ #undef xue
+diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h
+index e585c77..60e31eb 100644
+--- a/libavcodec/cbs_internal.h
++++ b/libavcodec/cbs_internal.h
+@@ -151,24 +151,29 @@ typedef struct CodedBitstreamType {
+ void ff_cbs_trace_header(CodedBitstreamContext *ctx,
+ const char *name);
+
+-void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
+- const char *name, const int *subscripts,
+- const char *bitstring, int64_t value);
+-
+
+ // Helper functions for read/write of common bitstream elements, including
+-// generation of trace output.
++// generation of trace output. The simple functions are equivalent to
++// their non-simple counterparts except that their range is unrestricted
++// (i.e. only limited by the amount of bits used) and they lack
++// the ability to use subscripts.
+
+ int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ int width, const char *name,
+ const int *subscripts, uint32_t *write_to,
+ uint32_t range_min, uint32_t range_max);
+
++int ff_cbs_read_simple_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
++ int width, const char *name, uint32_t *write_to);
++
+ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ int width, const char *name,
+ const int *subscripts, uint32_t value,
+ uint32_t range_min, uint32_t range_max);
+
++int ff_cbs_write_simple_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
++ int width, const char *name, uint32_t value);
++
+ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ int width, const char *name,
+ const int *subscripts, int32_t *write_to,
+@@ -191,6 +196,87 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ // range_min in the above functions.
+ #define MIN_INT_BITS(length) (-(INT64_C(1) << ((length) - 1)))
+
++
++// Start of a syntax element during read tracing.
++#define CBS_TRACE_READ_START() \
++ GetBitContext trace_start; \
++ do { \
++ if (ctx->trace_enable) \
++ trace_start = *gbc; \
++ } while (0)
++
++// End of a syntax element for tracing, make callback.
++#define CBS_TRACE_READ_END() \
++ do { \
++ if (ctx->trace_enable) { \
++ int start_position = get_bits_count(&trace_start); \
++ int end_position = get_bits_count(gbc); \
++ av_assert0(start_position <= end_position); \
++ ctx->trace_read_callback(ctx->trace_context, &trace_start, \
++ end_position - start_position, \
++ name, subscripts, value); \
++ } \
++ } while (0)
++
++// End of a syntax element with no subscript entries.
++#define CBS_TRACE_READ_END_NO_SUBSCRIPTS() \
++ do { \
++ const int *subscripts = NULL; \
++ CBS_TRACE_READ_END(); \
++ } while (0)
++
++// End of a syntax element which is made up of subelements which
++// are aleady traced, so we are only showing the value.
++#define CBS_TRACE_READ_END_VALUE_ONLY() \
++ do { \
++ if (ctx->trace_enable) { \
++ ctx->trace_read_callback(ctx->trace_context, &trace_start, 0, \
++ name, subscripts, value); \
++ } \
++ } while (0)
++
++// Start of a syntax element during write tracing.
++#define CBS_TRACE_WRITE_START() \
++ int start_position; \
++ do { \
++ if (ctx->trace_enable) \
++ start_position = put_bits_count(pbc);; \
++ } while (0)
++
++// End of a syntax element for tracing, make callback.
++#define CBS_TRACE_WRITE_END() \
++ do { \
++ if (ctx->trace_enable) { \
++ int end_position = put_bits_count(pbc); \
++ av_assert0(start_position <= end_position); \
++ ctx->trace_write_callback(ctx->trace_context, pbc, \
++ end_position - start_position, \
++ name, subscripts, value); \
++ } \
++ } while (0)
++
++// End of a syntax element with no subscript entries.
++#define CBS_TRACE_WRITE_END_NO_SUBSCRIPTS() \
++ do { \
++ const int *subscripts = NULL; \
++ CBS_TRACE_WRITE_END(); \
++ } while (0)
++
++// End of a syntax element which is made up of subelements which are
++// aleady traced, so we are only showing the value. This forges a
++// PutBitContext to point to the position of the start of the syntax
++// element, but the other state doesn't matter because length is zero.
++#define CBS_TRACE_WRITE_END_VALUE_ONLY() \
++ do { \
++ if (ctx->trace_enable) { \
++ PutBitContext tmp; \
++ init_put_bits(&tmp, pbc->buf, start_position); \
++ skip_put_bits(&tmp, start_position); \
++ ctx->trace_write_callback(ctx->trace_context, &tmp, 0, \
++ name, subscripts, value); \
++ } \
++ } while (0)
++
+ #define TYPE_LIST(...) { __VA_ARGS__ }
+ #define CBS_UNIT_TYPE_POD(type_, structure) { \
+ .nb_unit_types = 1, \
+diff --git a/libavcodec/cbs_mpeg2.c b/libavcodec/cbs_mpeg2.c
+index 04b0c7f..37fc28a 100644
+--- a/libavcodec/cbs_mpeg2.c
++++ b/libavcodec/cbs_mpeg2.c
+@@ -40,8 +40,6 @@
+
+ #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
+
+-#define ui(width, name) \
+- xui(width, name, current->name, 0, MAX_UINT_BITS(width), 0, )
+ #define uir(width, name) \
+ xui(width, name, current->name, 1, MAX_UINT_BITS(width), 0, )
+ #define uis(width, name, subs, ...) \
+@@ -65,6 +63,12 @@
+ #define READWRITE read
+ #define RWContext GetBitContext
+
++#define ui(width, name) do { \
++ uint32_t value; \
++ CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \
++ &value)); \
++ current->name = value; \
++ } while (0)
+ #define xuia(width, string, var, range_min, range_max, subs, ...) do { \
+ uint32_t value; \
+ CHECK(ff_cbs_read_unsigned(ctx, rw, width, string, \
+@@ -95,6 +99,7 @@
+ #undef READ
+ #undef READWRITE
+ #undef RWContext
++#undef ui
+ #undef xuia
+ #undef xsi
+ #undef nextbits
+@@ -105,6 +110,11 @@
+ #define READWRITE write
+ #define RWContext PutBitContext
+
++#define ui(width, name) do { \
++ CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \
++ current->name)); \
++ } while (0)
++
+ #define xuia(width, string, var, range_min, range_max, subs, ...) do { \
+ CHECK(ff_cbs_write_unsigned(ctx, rw, width, string, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+@@ -134,6 +144,7 @@
+ #undef WRITE
+ #undef READWRITE
+ #undef RWContext
++#undef ui
+ #undef xuia
+ #undef xsi
+ #undef nextbits
+diff --git a/libavcodec/cbs_vp9.c b/libavcodec/cbs_vp9.c
+index 184fdca..816d06d 100644
+--- a/libavcodec/cbs_vp9.c
++++ b/libavcodec/cbs_vp9.c
+@@ -28,11 +28,10 @@ static int cbs_vp9_read_s(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ const int *subscripts, int32_t *write_to)
+ {
+ uint32_t magnitude;
+- int position, sign;
++ int sign;
+ int32_t value;
+
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
++ CBS_TRACE_READ_START();
+
+ if (get_bits_left(gbc) < width + 1) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid signed value at "
+@@ -44,17 +43,7 @@ static int cbs_vp9_read_s(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ sign = get_bits1(gbc);
+ value = sign ? -(int32_t)magnitude : magnitude;
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (i = 0; i < width; i++)
+- bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0';
+- bits[i] = sign ? '1' : '0';
+- bits[i + 1] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
+- bits, value);
+- }
++ CBS_TRACE_READ_END();
+
+ *write_to = value;
+ return 0;
+@@ -67,27 +56,19 @@ static int cbs_vp9_write_s(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ uint32_t magnitude;
+ int sign;
+
++ CBS_TRACE_WRITE_START();
++
+ if (put_bits_left(pbc) < width + 1)
+ return AVERROR(ENOSPC);
+
+ sign = value < 0;
+ magnitude = sign ? -value : value;
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (i = 0; i < width; i++)
+- bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0';
+- bits[i] = sign ? '1' : '0';
+- bits[i + 1] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+- name, subscripts, bits, value);
+- }
+-
+ put_bits(pbc, width, magnitude);
+ put_bits(pbc, 1, sign);
+
++ CBS_TRACE_WRITE_END();
++
+ return 0;
+ }
+
+@@ -96,32 +77,24 @@ static int cbs_vp9_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc
+ const char *name, uint32_t *write_to)
+ {
+ uint32_t value;
+- int position, i;
+- char bits[8];
+
+- av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1);
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
++ CBS_TRACE_READ_START();
++
++ av_assert0(range_min <= range_max && range_max - range_min < 32);
+
+- for (i = 0, value = range_min; value < range_max;) {
++ for (value = range_min; value < range_max;) {
+ if (get_bits_left(gbc) < 1) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at "
+ "%s: bitstream ended.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+- if (get_bits1(gbc)) {
+- bits[i++] = '1';
++ if (get_bits1(gbc))
+ ++value;
+- } else {
+- bits[i++] = '0';
++ else
+ break;
+- }
+ }
+
+- if (ctx->trace_enable) {
+- bits[i] = 0;
+- ff_cbs_trace_syntax_element(ctx, position, name, NULL, bits, value);
+- }
++ CBS_TRACE_READ_END_NO_SUBSCRIPTS();
+
+ *write_to = value;
+ return 0;
+@@ -133,6 +106,8 @@ static int cbs_vp9_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
+ {
+ int len;
+
++ CBS_TRACE_WRITE_START();
++
+ av_assert0(range_min <= range_max && range_max - range_min < 8);
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+@@ -148,23 +123,11 @@ static int cbs_vp9_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
+ if (put_bits_left(pbc) < len)
+ return AVERROR(ENOSPC);
+
+- if (ctx->trace_enable) {
+- char bits[8];
+- int i;
+- for (i = 0; i < len; i++) {
+- if (range_min + i == value)
+- bits[i] = '0';
+- else
+- bits[i] = '1';
+- }
+- bits[i] = 0;
+- ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+- name, NULL, bits, value);
+- }
+-
+ if (len > 0)
+ put_bits(pbc, len, (1 << len) - 1 - (value != range_max));
+
++ CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
++
+ return 0;
+ }
+
+@@ -173,12 +136,11 @@ static int cbs_vp9_read_le(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ const int *subscripts, uint32_t *write_to)
+ {
+ uint32_t value;
+- int position, b;
++ int b;
+
+- av_assert0(width % 8 == 0);
++ CBS_TRACE_READ_START();
+
+- if (ctx->trace_enable)
+- position = get_bits_count(gbc);
++ av_assert0(width % 8 == 0);
+
+ if (get_bits_left(gbc) < width) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid le value at "
+@@ -190,17 +152,7 @@ static int cbs_vp9_read_le(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ for (b = 0; b < width; b += 8)
+ value |= get_bits(gbc, 8) << b;
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (b = 0; b < width; b += 8)
+- for (i = 0; i < 8; i++)
+- bits[b + i] = value >> (b + i) & 1 ? '1' : '0';
+- bits[b] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
+- bits, value);
+- }
++ CBS_TRACE_READ_END();
+
+ *write_to = value;
+ return 0;
+@@ -212,26 +164,18 @@ static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ {
+ int b;
+
++ CBS_TRACE_WRITE_START();
++
+ av_assert0(width % 8 == 0);
+
+ if (put_bits_left(pbc) < width)
+ return AVERROR(ENOSPC);
+
+- if (ctx->trace_enable) {
+- char bits[33];
+- int i;
+- for (b = 0; b < width; b += 8)
+- for (i = 0; i < 8; i++)
+- bits[b + i] = value >> (b + i) & 1 ? '1' : '0';
+- bits[b] = 0;
+-
+- ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+- name, subscripts, bits, value);
+- }
+-
+ for (b = 0; b < width; b += 8)
+ put_bits(pbc, 8, value >> b & 0xff);
+
++ CBS_TRACE_WRITE_END();
++
+ return 0;
+ }
+
+@@ -251,8 +195,6 @@ static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc,
+
+ #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
+
+-#define f(width, name) \
+- xf(width, name, current->name, 0, )
+ #define s(width, name) \
+ xs(width, name, current->name, 0, )
+ #define fs(width, name, subs, ...) \
+@@ -264,6 +206,12 @@ static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ #define READWRITE read
+ #define RWContext GetBitContext
+
++#define f(width, name) do { \
++ uint32_t value; \
++ CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \
++ &value)); \
++ current->name = value; \
++ } while (0)
+ #define xf(width, name, var, subs, ...) do { \
+ uint32_t value; \
+ CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
+@@ -329,6 +277,7 @@ static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ #undef READ
+ #undef READWRITE
+ #undef RWContext
++#undef f
+ #undef xf
+ #undef xs
+ #undef increment
+@@ -344,6 +293,10 @@ static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ #define READWRITE write
+ #define RWContext PutBitContext
+
++#define f(width, name) do { \
++ CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \
++ current->name)); \
++ } while (0)
+ #define xf(width, name, var, subs, ...) do { \
+ CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+@@ -396,6 +349,7 @@ static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ #undef WRITE
+ #undef READWRITE
+ #undef RWContext
++#undef f
+ #undef xf
+ #undef xs
+ #undef increment
+diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
+index 329b1a6..7eedb16 100644
+--- a/libavcodec/extract_extradata_bsf.c
++++ b/libavcodec/extract_extradata_bsf.c
+@@ -48,10 +48,9 @@ typedef struct ExtractExtradataContext {
+ int remove;
+ } ExtractExtradataContext;
+
+-static int val_in_array(const int *arr, int len, int val)
++static int val_in_array(const int *arr, size_t len, int val)
+ {
+- int i;
+- for (i = 0; i < len; i++)
++ for (size_t i = 0; i < len; i++)
+ if (arr[i] == val)
+ return 1;
+ return 0;
+@@ -145,7 +144,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
+
+ int extradata_size = 0, filtered_size = 0;
+ const int *extradata_nal_types;
+- int nb_extradata_nal_types;
++ size_t nb_extradata_nal_types;
+ int i, has_sps = 0, has_vps = 0, ret = 0;
+
+ if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
+diff --git a/libavcodec/trace_headers_bsf.c b/libavcodec/trace_headers_bsf.c
+index 028b0a1..8781f5f 100644
+--- a/libavcodec/trace_headers_bsf.c
++++ b/libavcodec/trace_headers_bsf.c
+@@ -44,6 +44,8 @@ static int trace_headers_init(AVBSFContext *bsf)
+
+ ctx->cbc->trace_enable = 1;
+ ctx->cbc->trace_level = AV_LOG_INFO;
++ ctx->cbc->trace_context = ctx->cbc;
++ ctx->cbc->trace_read_callback = ff_cbs_trace_read_log;
+
+ if (bsf->par_in->extradata) {
+ CodedBitstreamFragment *frag = &ctx->fragment;
+diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
+index bfca315..f5bf5ab 100644
+--- a/libavcodec/vaapi_encode.c
++++ b/libavcodec/vaapi_encode.c
+@@ -276,21 +276,34 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
+ av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" "
+ "as type %s.\n", pic->display_order, pic->encode_order,
+ picture_type_name[pic->type]);
+- if (pic->nb_refs == 0) {
++ if (pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0) {
+ av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n");
+ } else {
+- av_log(avctx, AV_LOG_DEBUG, "Refers to:");
+- for (i = 0; i < pic->nb_refs; i++) {
++ av_log(avctx, AV_LOG_DEBUG, "L0 refers to");
++ for (i = 0; i < pic->nb_refs[0]; i++) {
+ av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
+- pic->refs[i]->display_order, pic->refs[i]->encode_order);
++ pic->refs[0][i]->display_order, pic->refs[0][i]->encode_order);
+ }
+ av_log(avctx, AV_LOG_DEBUG, ".\n");
++
++ if (pic->nb_refs[1]) {
++ av_log(avctx, AV_LOG_DEBUG, "L1 refers to");
++ for (i = 0; i < pic->nb_refs[1]; i++) {
++ av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
++ pic->refs[1][i]->display_order, pic->refs[1][i]->encode_order);
++ }
++ av_log(avctx, AV_LOG_DEBUG, ".\n");
++ }
+ }
+
+ av_assert0(!pic->encode_issued);
+- for (i = 0; i < pic->nb_refs; i++) {
+- av_assert0(pic->refs[i]);
+- av_assert0(pic->refs[i]->encode_issued);
++ for (i = 0; i < pic->nb_refs[0]; i++) {
++ av_assert0(pic->refs[0][i]);
++ av_assert0(pic->refs[0][i]->encode_issued);
++ }
++ for (i = 0; i < pic->nb_refs[1]; i++) {
++ av_assert0(pic->refs[1][i]);
++ av_assert0(pic->refs[1][i]->encode_issued);
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", pic->input_surface);
+@@ -650,79 +663,200 @@ fail_at_end:
+ return err;
+ }
+
+-static int vaapi_encode_output(AVCodecContext *avctx,
+- VAAPIEncodePicture *pic, AVPacket *pkt)
++static int vaapi_encode_set_output_property(AVCodecContext *avctx,
++ VAAPIEncodePicture *pic,
++ AVPacket *pkt)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++
++ if (pic->type == PICTURE_TYPE_IDR)
++ pkt->flags |= AV_PKT_FLAG_KEY;
++
++ pkt->pts = pic->pts;
++ pkt->duration = pic->duration;
++
++ // for no-delay encoders this is handled in generic codec
++ if (avctx->codec->capabilities & AV_CODEC_CAP_DELAY &&
++ avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
++ pkt->opaque = pic->opaque;
++ pkt->opaque_ref = pic->opaque_ref;
++ pic->opaque_ref = NULL;
++ }
++
++ if (ctx->codec->flags & FLAG_TIMESTAMP_NO_DELAY) {
++ pkt->dts = pkt->pts;
++ return 0;
++ }
++
++ if (ctx->output_delay == 0) {
++ pkt->dts = pkt->pts;
++ } else if (pic->encode_order < ctx->decode_delay) {
++ if (ctx->ts_ring[pic->encode_order] < INT64_MIN + ctx->dts_pts_diff)
++ pkt->dts = INT64_MIN;
++ else
++ pkt->dts = ctx->ts_ring[pic->encode_order] - ctx->dts_pts_diff;
++ } else {
++ pkt->dts = ctx->ts_ring[(pic->encode_order - ctx->decode_delay) %
++ (3 * ctx->output_delay + ctx->async_depth)];
++ }
++
++ return 0;
++}
++
++static int vaapi_encode_get_coded_buffer_size(AVCodecContext *avctx, VABufferID buf_id)
+ {
+ VAAPIEncodeContext *ctx = avctx->priv_data;
+ VACodedBufferSegment *buf_list, *buf;
++ int size = 0;
+ VAStatus vas;
+- int total_size = 0;
+- uint8_t *ptr;
+ int err;
+
+- err = vaapi_encode_wait(avctx, pic);
+- if (err < 0)
+- return err;
+-
+- buf_list = NULL;
+- vas = vaMapBuffer(ctx->hwctx->display, pic->output_buffer,
++ vas = vaMapBuffer(ctx->hwctx->display, buf_id,
+ (void**)&buf_list);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to map output buffers: "
+ "%d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR(EIO);
+- goto fail;
++ return err;
+ }
+
+ for (buf = buf_list; buf; buf = buf->next)
+- total_size += buf->size;
++ size += buf->size;
+
+- err = ff_get_encode_buffer(avctx, pkt, total_size, 0);
+- ptr = pkt->data;
++ vas = vaUnmapBuffer(ctx->hwctx->display, buf_id);
++ if (vas != VA_STATUS_SUCCESS) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to unmap output buffers: "
++ "%d (%s).\n", vas, vaErrorStr(vas));
++ err = AVERROR(EIO);
++ return err;
++ }
+
+- if (err < 0)
+- goto fail_mapped;
++ return size;
++}
++
++static int vaapi_encode_get_coded_buffer_data(AVCodecContext *avctx,
++ VABufferID buf_id, uint8_t **dst)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++ VACodedBufferSegment *buf_list, *buf;
++ VAStatus vas;
++ int err;
++
++ vas = vaMapBuffer(ctx->hwctx->display, buf_id,
++ (void**)&buf_list);
++ if (vas != VA_STATUS_SUCCESS) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to map output buffers: "
++ "%d (%s).\n", vas, vaErrorStr(vas));
++ err = AVERROR(EIO);
++ return err;
++ }
+
+ for (buf = buf_list; buf; buf = buf->next) {
+ av_log(avctx, AV_LOG_DEBUG, "Output buffer: %u bytes "
+ "(status %08x).\n", buf->size, buf->status);
+
+- memcpy(ptr, buf->buf, buf->size);
+- ptr += buf->size;
++ memcpy(*dst, buf->buf, buf->size);
++ *dst += buf->size;
+ }
+
+- if (pic->type == PICTURE_TYPE_IDR)
+- pkt->flags |= AV_PKT_FLAG_KEY;
+-
+- pkt->pts = pic->pts;
+- pkt->duration = pic->duration;
+-
+- vas = vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer);
++ vas = vaUnmapBuffer(ctx->hwctx->display, buf_id);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to unmap output buffers: "
+ "%d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR(EIO);
+- goto fail;
++ return err;
+ }
+
+- // for no-delay encoders this is handled in generic codec
+- if (avctx->codec->capabilities & AV_CODEC_CAP_DELAY &&
+- avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
+- pkt->opaque = pic->opaque;
+- pkt->opaque_ref = pic->opaque_ref;
+- pic->opaque_ref = NULL;
++ return 0;
++}
++
++static int vaapi_encode_get_coded_data(AVCodecContext *avctx,
++ VAAPIEncodePicture *pic, AVPacket *pkt)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++ VABufferID output_buffer_prev;
++ int total_size = 0;
++ uint8_t *ptr;
++ int ret;
++
++ if (ctx->coded_buffer_ref) {
++ output_buffer_prev = (VABufferID)(uintptr_t)ctx->coded_buffer_ref->data;
++ ret = vaapi_encode_get_coded_buffer_size(avctx, output_buffer_prev);
++ if (ret < 0)
++ goto end;
++ total_size += ret;
++ }
++
++ ret = vaapi_encode_get_coded_buffer_size(avctx, pic->output_buffer);
++ if (ret < 0)
++ goto end;
++ total_size += ret;
++
++ ret = ff_get_encode_buffer(avctx, pkt, total_size, 0);
++ if (ret < 0)
++ goto end;
++ ptr = pkt->data;
++
++ if (ctx->coded_buffer_ref) {
++ ret = vaapi_encode_get_coded_buffer_data(avctx, output_buffer_prev, &ptr);
++ if (ret < 0)
++ goto end;
+ }
+
++ ret = vaapi_encode_get_coded_buffer_data(avctx, pic->output_buffer, &ptr);
++ if (ret < 0)
++ goto end;
++
++end:
++ if (ctx->coded_buffer_ref) {
++ av_buffer_unref(&ctx->coded_buffer_ref);
++ }
+ av_buffer_unref(&pic->output_buffer_ref);
+ pic->output_buffer = VA_INVALID_ID;
+
++ return ret;
++}
++
++static int vaapi_encode_output(AVCodecContext *avctx,
++ VAAPIEncodePicture *pic, AVPacket *pkt)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++ AVPacket *pkt_ptr = pkt;
++ int err;
++
++ err = vaapi_encode_wait(avctx, pic);
++ if (err < 0)
++ return err;
++
++ if (pic->non_independent_frame) {
++ av_assert0(!ctx->coded_buffer_ref);
++ ctx->coded_buffer_ref = av_buffer_ref(pic->output_buffer_ref);
++
++ if (pic->tail_size) {
++ if (ctx->tail_pkt->size) {
++ err = AVERROR(AVERROR_BUG);
++ goto end;
++ }
++
++ err = ff_get_encode_buffer(avctx, ctx->tail_pkt, pic->tail_size, 0);
++ if (err < 0)
++ goto end;
++
++ memcpy(ctx->tail_pkt->data, pic->tail_data, pic->tail_size);
++ pkt_ptr = ctx->tail_pkt;
++ }
++ } else {
++ err = vaapi_encode_get_coded_data(avctx, pic, pkt);
++ if (err < 0)
++ goto end;
++ }
++
+ av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n",
+ pic->display_order, pic->encode_order);
+- return 0;
+
+-fail_mapped:
+- vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer);
+-fail:
++ vaapi_encode_set_output_property(avctx, pic, pkt_ptr);
++
++end:
+ av_buffer_unref(&pic->output_buffer_ref);
+ pic->output_buffer = VA_INVALID_ID;
+ return err;
+@@ -811,8 +945,12 @@ static void vaapi_encode_add_ref(AVCodecContext *avctx,
+
+ if (is_ref) {
+ av_assert0(pic != target);
+- av_assert0(pic->nb_refs < MAX_PICTURE_REFERENCES);
+- pic->refs[pic->nb_refs++] = target;
++ av_assert0(pic->nb_refs[0] < MAX_PICTURE_REFERENCES &&
++ pic->nb_refs[1] < MAX_PICTURE_REFERENCES);
++ if (target->display_order < pic->display_order)
++ pic->refs[0][pic->nb_refs[0]++] = target;
++ else
++ pic->refs[1][pic->nb_refs[1]++] = target;
+ ++refs;
+ }
+
+@@ -841,10 +979,16 @@ static void vaapi_encode_remove_refs(AVCodecContext *avctx,
+ if (pic->ref_removed[level])
+ return;
+
+- for (i = 0; i < pic->nb_refs; i++) {
+- av_assert0(pic->refs[i]);
+- --pic->refs[i]->ref_count[level];
+- av_assert0(pic->refs[i]->ref_count[level] >= 0);
++ for (i = 0; i < pic->nb_refs[0]; i++) {
++ av_assert0(pic->refs[0][i]);
++ --pic->refs[0][i]->ref_count[level];
++ av_assert0(pic->refs[0][i]->ref_count[level] >= 0);
++ }
++
++ for (i = 0; i < pic->nb_refs[1]; i++) {
++ av_assert0(pic->refs[1][i]);
++ --pic->refs[1][i]->ref_count[level];
++ av_assert0(pic->refs[1][i]->ref_count[level] >= 0);
+ }
+
+ for (i = 0; i < pic->nb_dpb_pics; i++) {
+@@ -889,7 +1033,7 @@ static void vaapi_encode_set_b_pictures(AVCodecContext *avctx,
+ vaapi_encode_add_ref(avctx, pic, end, 1, 1, 0);
+ vaapi_encode_add_ref(avctx, pic, prev, 0, 0, 1);
+
+- for (ref = end->refs[1]; ref; ref = ref->refs[1])
++ for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0])
+ vaapi_encode_add_ref(avctx, pic, ref, 0, 1, 0);
+ }
+ *last = prev;
+@@ -912,7 +1056,7 @@ static void vaapi_encode_set_b_pictures(AVCodecContext *avctx,
+ vaapi_encode_add_ref(avctx, pic, end, 1, 1, 0);
+ vaapi_encode_add_ref(avctx, pic, prev, 0, 0, 1);
+
+- for (ref = end->refs[1]; ref; ref = ref->refs[1])
++ for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0])
+ vaapi_encode_add_ref(avctx, pic, ref, 0, 1, 0);
+
+ if (i > 1)
+@@ -926,11 +1070,44 @@ static void vaapi_encode_set_b_pictures(AVCodecContext *avctx,
+ }
+ }
+
++static void vaapi_encode_add_next_prev(AVCodecContext *avctx,
++ VAAPIEncodePicture *pic)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++ int i;
++
++ if (!pic)
++ return;
++
++ if (pic->type == PICTURE_TYPE_IDR) {
++ for (i = 0; i < ctx->nb_next_prev; i++) {
++ --ctx->next_prev[i]->ref_count[0];
++ ctx->next_prev[i] = NULL;
++ }
++ ctx->next_prev[0] = pic;
++ ++pic->ref_count[0];
++ ctx->nb_next_prev = 1;
++
++ return;
++ }
++
++ if (ctx->nb_next_prev < MAX_PICTURE_REFERENCES) {
++ ctx->next_prev[ctx->nb_next_prev++] = pic;
++ ++pic->ref_count[0];
++ } else {
++ --ctx->next_prev[0]->ref_count[0];
++ for (i = 0; i < MAX_PICTURE_REFERENCES - 1; i++)
++ ctx->next_prev[i] = ctx->next_prev[i + 1];
++ ctx->next_prev[i] = pic;
++ ++pic->ref_count[0];
++ }
++}
++
+ static int vaapi_encode_pick_next(AVCodecContext *avctx,
+ VAAPIEncodePicture **pic_out)
+ {
+ VAAPIEncodeContext *ctx = avctx->priv_data;
+- VAAPIEncodePicture *pic = NULL, *next, *start;
++ VAAPIEncodePicture *pic = NULL, *prev = NULL, *next, *start;
+ int i, b_counter, closed_gop_end;
+
+ // If there are any B-frames already queued, the next one to encode
+@@ -941,11 +1118,18 @@ static int vaapi_encode_pick_next(AVCodecContext *avctx,
+ continue;
+ if (pic->type != PICTURE_TYPE_B)
+ continue;
+- for (i = 0; i < pic->nb_refs; i++) {
+- if (!pic->refs[i]->encode_issued)
++ for (i = 0; i < pic->nb_refs[0]; i++) {
++ if (!pic->refs[0][i]->encode_issued)
++ break;
++ }
++ if (i != pic->nb_refs[0])
++ continue;
++
++ for (i = 0; i < pic->nb_refs[1]; i++) {
++ if (!pic->refs[1][i]->encode_issued)
+ break;
+ }
+- if (i == pic->nb_refs)
++ if (i == pic->nb_refs[1])
+ break;
+ }
+
+@@ -1044,21 +1228,30 @@ static int vaapi_encode_pick_next(AVCodecContext *avctx,
+
+ vaapi_encode_add_ref(avctx, pic, pic, 0, 1, 0);
+ if (pic->type != PICTURE_TYPE_IDR) {
+- vaapi_encode_add_ref(avctx, pic, start,
+- pic->type == PICTURE_TYPE_P,
+- b_counter > 0, 0);
+- vaapi_encode_add_ref(avctx, pic, ctx->next_prev, 0, 0, 1);
++ // TODO: apply both previous and forward multi reference for all vaapi encoders.
++ // And L0/L1 reference frame number can be set dynamically through query
++ // VAConfigAttribEncMaxRefFrames attribute.
++ if (avctx->codec_id == AV_CODEC_ID_AV1) {
++ for (i = 0; i < ctx->nb_next_prev; i++)
++ vaapi_encode_add_ref(avctx, pic, ctx->next_prev[i],
++ pic->type == PICTURE_TYPE_P,
++ b_counter > 0, 0);
++ } else
++ vaapi_encode_add_ref(avctx, pic, start,
++ pic->type == PICTURE_TYPE_P,
++ b_counter > 0, 0);
++
++ vaapi_encode_add_ref(avctx, pic, ctx->next_prev[ctx->nb_next_prev - 1], 0, 0, 1);
+ }
+- if (ctx->next_prev)
+- --ctx->next_prev->ref_count[0];
+
+ if (b_counter > 0) {
+ vaapi_encode_set_b_pictures(avctx, start, pic, pic, 1,
+- &ctx->next_prev);
++ &prev);
+ } else {
+- ctx->next_prev = pic;
++ prev = pic;
+ }
+- ++ctx->next_prev->ref_count[0];
++ vaapi_encode_add_next_prev(avctx, prev);
++
+ return 0;
+ }
+
+@@ -1205,10 +1398,23 @@ fail:
+ int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
+ {
+ VAAPIEncodeContext *ctx = avctx->priv_data;
+- VAAPIEncodePicture *pic;
++ VAAPIEncodePicture *pic = NULL;
+ AVFrame *frame = ctx->frame;
+ int err;
+
++start:
++ /** if no B frame before repeat P frame, sent repeat P frame out. */
++ if (ctx->tail_pkt->size) {
++ for (VAAPIEncodePicture *tmp = ctx->pic_start; tmp; tmp = tmp->next) {
++ if (tmp->type == PICTURE_TYPE_B && tmp->pts < ctx->tail_pkt->pts)
++ break;
++ else if (!tmp->next) {
++ av_packet_move_ref(pkt, ctx->tail_pkt);
++ goto end;
++ }
++ }
++ }
++
+ err = ff_encode_get_frame(avctx, frame);
+ if (err < 0 && err != AVERROR_EOF)
+ return err;
+@@ -1228,8 +1434,6 @@ int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
+ }
+
+ if (ctx->has_sync_buffer_func) {
+- pic = NULL;
+-
+ if (av_fifo_can_write(ctx->encode_fifo)) {
+ err = vaapi_encode_pick_next(avctx, &pic);
+ if (!err) {
+@@ -1255,7 +1459,6 @@ int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
+ av_fifo_read(ctx->encode_fifo, &pic, 1);
+ ctx->encode_order = pic->encode_order + 1;
+ } else {
+- pic = NULL;
+ err = vaapi_encode_pick_next(avctx, &pic);
+ if (err < 0)
+ return err;
+@@ -1276,27 +1479,21 @@ int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
+ return err;
+ }
+
+- if (ctx->output_delay == 0) {
+- pkt->dts = pkt->pts;
+- } else if (pic->encode_order < ctx->decode_delay) {
+- if (ctx->ts_ring[pic->encode_order] < INT64_MIN + ctx->dts_pts_diff)
+- pkt->dts = INT64_MIN;
+- else
+- pkt->dts = ctx->ts_ring[pic->encode_order] - ctx->dts_pts_diff;
+- } else {
+- pkt->dts = ctx->ts_ring[(pic->encode_order - ctx->decode_delay) %
+- (3 * ctx->output_delay + ctx->async_depth)];
+- }
+- av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64" dts %"PRId64".\n",
+- pkt->pts, pkt->dts);
+-
+ ctx->output_order = pic->encode_order;
+ vaapi_encode_clear_old(avctx);
+
++ /** loop to get an available pkt in encoder flushing. */
++ if (ctx->end_of_stream && !pkt->size)
++ goto start;
++
++end:
++ if (pkt->size)
++ av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64", dts %"PRId64", "
++ "size %d bytes.\n", pkt->pts, pkt->dts, pkt->size);
++
+ return 0;
+ }
+
+-
+ static av_cold void vaapi_encode_add_global_param(AVCodecContext *avctx, int type,
+ void *buffer, size_t size)
+ {
+@@ -2597,6 +2794,12 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx)
+ ctx->device = (AVHWDeviceContext*)ctx->device_ref->data;
+ ctx->hwctx = ctx->device->hwctx;
+
++ ctx->tail_pkt = av_packet_alloc();
++ if (!ctx->tail_pkt) {
++ err = AVERROR(ENOMEM);
++ goto fail;
++ }
++
+ err = vaapi_encode_profile_entrypoint(avctx);
+ if (err < 0)
+ goto fail;
+@@ -2789,6 +2992,7 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx)
+ }
+
+ av_frame_free(&ctx->frame);
++ av_packet_free(&ctx->tail_pkt);
+
+ av_freep(&ctx->codec_sequence_params);
+ av_freep(&ctx->codec_picture_params);
+diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h
+index a1e639f..416a3ce 100644
+--- a/libavcodec/vaapi_encode.h
++++ b/libavcodec/vaapi_encode.h
+@@ -49,6 +49,7 @@ enum {
+ // A.4.1: table A.6 allows at most 20 tile columns for any level.
+ MAX_TILE_COLS = 20,
+ MAX_ASYNC_DEPTH = 64,
++ MAX_REFERENCE_LIST_NUM = 2,
+ };
+
+ extern const AVCodecHWConfigInternal *const ff_vaapi_encode_hw_configs[];
+@@ -116,10 +117,11 @@ typedef struct VAAPIEncodePicture {
+ // but not if it isn't.
+ int nb_dpb_pics;
+ struct VAAPIEncodePicture *dpb[MAX_DPB_SIZE];
+- // The reference pictures used in decoding this picture. If they are
+- // used by later pictures they will also appear in the DPB.
+- int nb_refs;
+- struct VAAPIEncodePicture *refs[MAX_PICTURE_REFERENCES];
++ // The reference pictures used in decoding this picture. If they are
++ // used by later pictures they will also appear in the DPB. ref[0][] for
++ // previous reference frames. ref[1][] for future reference frames.
++ int nb_refs[MAX_REFERENCE_LIST_NUM];
++ struct VAAPIEncodePicture *refs[MAX_REFERENCE_LIST_NUM][MAX_PICTURE_REFERENCES];
+ // The previous reference picture in encode order. Must be in at least
+ // one of the reference list and DPB list.
+ struct VAAPIEncodePicture *prev;
+@@ -131,6 +133,17 @@ typedef struct VAAPIEncodePicture {
+
+ int nb_slices;
+ VAAPIEncodeSlice *slices;
++
++ /**
++ * indicate if current frame is an independent frame that the coded data
++ * can be pushed to downstream directly. Coded of non-independent frame
++ * data will be concatenated into next independent frame.
++ */
++ int non_independent_frame;
++ /** Tail data of current pic, used only for repeat header of AV1. */
++ char tail_data[MAX_PARAM_BUFFER_SIZE];
++ /** Byte length of tail_data. */
++ size_t tail_size;
+ } VAAPIEncodePicture;
+
+ typedef struct VAAPIEncodeProfile {
+@@ -290,8 +303,9 @@ typedef struct VAAPIEncodeContext {
+ // Current encoding window, in display (input) order.
+ VAAPIEncodePicture *pic_start, *pic_end;
+ // The next picture to use as the previous reference picture in
+- // encoding order.
+- VAAPIEncodePicture *next_prev;
++ // encoding order. Order from small to large in encoding order.
++ VAAPIEncodePicture *next_prev[MAX_PICTURE_REFERENCES];
++ int nb_next_prev;
+
+ // Next input order index (display order).
+ int64_t input_order;
+@@ -364,6 +378,16 @@ typedef struct VAAPIEncodeContext {
+ AVFifo *encode_fifo;
+ // Max number of frame buffered in encoder.
+ int async_depth;
++
++ /** Head data for current output pkt, used only for AV1. */
++ //void *header_data;
++ //size_t header_data_size;
++
++ /** Buffered coded data of a pic if it is an non-independent frame. */
++ AVBufferRef *coded_buffer_ref;
++
++ /** Tail data of a pic, now only used for av1 repeat frame header. */
++ AVPacket *tail_pkt;
+ } VAAPIEncodeContext;
+
+ enum {
+@@ -380,6 +404,9 @@ enum {
+ // Codec supports non-IDR key pictures (that is, key pictures do
+ // not necessarily empty the DPB).
+ FLAG_NON_IDR_KEY_PICTURES = 1 << 5,
++ // Codec output packet without timestamp delay, which means the
++ // output packet has same PTS and DTS.
++ FLAG_TIMESTAMP_NO_DELAY = 1 << 6,
+ };
+
+ typedef struct VAAPIEncodeType {
+diff --git a/libavcodec/vaapi_encode_av1.c b/libavcodec/vaapi_encode_av1.c
+new file mode 100644
+index 0000000..9d101fa
+--- /dev/null
++++ b/libavcodec/vaapi_encode_av1.c
+@@ -0,0 +1,949 @@
++/*
++ * Copyright (c) 2023 Intel Corporation
++ *
++ * 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
++ */
++
++#include <va/va.h>
++#include <va/va_enc_av1.h>
++
++#include "libavutil/pixdesc.h"
++#include "libavutil/opt.h"
++
++#include "cbs_av1.h"
++#include "put_bits.h"
++#include "codec_internal.h"
++#include "av1_levels.h"
++#include "vaapi_encode.h"
++
++#define AV1_MAX_QUANT 255
++
++typedef struct VAAPIEncodeAV1Picture {
++ int64_t last_idr_frame;
++ int slot;
++} VAAPIEncodeAV1Picture;
++
++typedef struct VAAPIEncodeAV1Context {
++ VAAPIEncodeContext common;
++ AV1RawOBU sh; /**< sequence header.*/
++ AV1RawOBU fh; /**< frame header.*/
++ CodedBitstreamContext *cbc;
++ CodedBitstreamFragment current_obu;
++ VAConfigAttribValEncAV1 attr;
++ VAConfigAttribValEncAV1Ext1 attr_ext1;
++ VAConfigAttribValEncAV1Ext2 attr_ext2;
++
++ char sh_data[MAX_PARAM_BUFFER_SIZE]; /**< coded sequence header data. */
++ size_t sh_data_len; /**< bit length of sh_data. */
++ char fh_data[MAX_PARAM_BUFFER_SIZE]; /**< coded frame header data. */
++ size_t fh_data_len; /**< bit length of fh_data. */
++
++ uint8_t uniform_tile;
++ uint8_t use_128x128_superblock;
++ int sb_cols;
++ int sb_rows;
++ int tile_cols_log2;
++ int tile_rows_log2;
++ int max_tile_width_sb;
++ int max_tile_height_sb;
++ uint8_t width_in_sbs_minus_1[AV1_MAX_TILE_COLS];
++ uint8_t height_in_sbs_minus_1[AV1_MAX_TILE_ROWS];
++
++ int min_log2_tile_cols;
++ int max_log2_tile_cols;
++ int min_log2_tile_rows;
++ int max_log2_tile_rows;
++
++ int q_idx_idr;
++ int q_idx_p;
++ int q_idx_b;
++
++ /** bit positions in current frame header */
++ int qindex_offset;
++ int loopfilter_offset;
++ int cdef_start_offset;
++ int cdef_param_size;
++
++ /** user options */
++ int profile;
++ int level;
++ int tier;
++ int tile_cols, tile_rows;
++ int tile_groups;
++} VAAPIEncodeAV1Context;
++
++static void vaapi_encode_av1_trace_write_log(void *ctx,
++ PutBitContext *pbc, int length,
++ const char *str, const int *subscripts,
++ int64_t value)
++{
++ VAAPIEncodeAV1Context *priv = ctx;
++ int position;
++
++ position = put_bits_count(pbc);
++ av_assert0(position >= length);
++
++ if (!strcmp(str, "base_q_idx"))
++ priv->qindex_offset = position - length;
++ else if (!strcmp(str, "loop_filter_level[0]"))
++ priv->loopfilter_offset = position - length;
++ else if (!strcmp(str, "cdef_damping_minus_3"))
++ priv->cdef_start_offset = position - length;
++ else if (!strcmp(str, "cdef_uv_sec_strength[i]"))
++ priv->cdef_param_size = position - priv->cdef_start_offset;
++}
++
++static av_cold int vaapi_encode_av1_get_encoder_caps(AVCodecContext *avctx)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++
++ // Surfaces must be aligned to superblock boundaries.
++ ctx->surface_width = FFALIGN(avctx->width, priv->use_128x128_superblock ? 128 : 64);
++ ctx->surface_height = FFALIGN(avctx->height, priv->use_128x128_superblock ? 128 : 64);
++
++ return 0;
++}
++
++static av_cold int vaapi_encode_av1_configure(AVCodecContext *avctx)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++ int ret;
++
++ ret = ff_cbs_init(&priv->cbc, AV_CODEC_ID_AV1, avctx);
++ if (ret < 0)
++ return ret;
++ priv->cbc->trace_enable = 1;
++ priv->cbc->trace_level = AV_LOG_DEBUG;
++ priv->cbc->trace_context = ctx;
++ priv->cbc->trace_write_callback = vaapi_encode_av1_trace_write_log;
++
++ if (ctx->rc_mode->quality) {
++ priv->q_idx_p = av_clip(ctx->rc_quality, 0, AV1_MAX_QUANT);
++ if (fabs(avctx->i_quant_factor) > 0.0)
++ priv->q_idx_idr =
++ av_clip((fabs(avctx->i_quant_factor) * priv->q_idx_p +
++ avctx->i_quant_offset) + 0.5,
++ 0, AV1_MAX_QUANT);
++ else
++ priv->q_idx_idr = priv->q_idx_p;
++
++ if (fabs(avctx->b_quant_factor) > 0.0)
++ priv->q_idx_b =
++ av_clip((fabs(avctx->b_quant_factor) * priv->q_idx_p +
++ avctx->b_quant_offset) + 0.5,
++ 0, AV1_MAX_QUANT);
++ else
++ priv->q_idx_b = priv->q_idx_p;
++ } else {
++ /** Arbitrary value */
++ priv->q_idx_idr = priv->q_idx_p = priv->q_idx_b = 128;
++ }
++
++ return 0;
++}
++
++static int vaapi_encode_av1_add_obu(AVCodecContext *avctx,
++ CodedBitstreamFragment *au,
++ uint8_t type,
++ void *obu_unit)
++{
++ int ret;
++
++ ret = ff_cbs_insert_unit_content(au, -1,
++ type, obu_unit, NULL);
++ if (ret < 0) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to add OBU unit: "
++ "type = %d.\n", type);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int vaapi_encode_av1_write_obu(AVCodecContext *avctx,
++ char *data, size_t *data_len,
++ CodedBitstreamFragment *bs)
++{
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++ int ret;
++
++ ret = ff_cbs_write_fragment_data(priv->cbc, bs);
++ if (ret < 0) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n");
++ return ret;
++ }
++
++ if ((size_t)8 * MAX_PARAM_BUFFER_SIZE < 8 * bs->data_size - bs->data_bit_padding) {
++ av_log(avctx, AV_LOG_ERROR, "Access unit too large: "
++ "%zu < %zu.\n", (size_t)8 * MAX_PARAM_BUFFER_SIZE,
++ 8 * bs->data_size - bs->data_bit_padding);
++ return AVERROR(ENOSPC);
++ }
++
++ memcpy(data, bs->data, bs->data_size);
++ *data_len = 8 * bs->data_size - bs->data_bit_padding;
++
++ return 0;
++}
++
++static int tile_log2(int blkSize, int target) {
++ int k;
++ for (k = 0; (blkSize << k) < target; k++);
++ return k;
++}
++
++static int vaapi_encode_av1_set_tile(AVCodecContext *avctx)
++{
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++ int mi_cols, mi_rows, sb_shift, sb_size;
++ int max_tile_area_sb, max_tile_area_sb_varied;
++ int tile_width_sb, tile_height_sb, widest_tile_sb;
++ int tile_cols, tile_rows;
++ int min_log2_tiles;
++ int i;
++
++ if (priv->tile_cols > AV1_MAX_TILE_COLS ||
++ priv->tile_rows > AV1_MAX_TILE_ROWS) {
++ av_log(avctx, AV_LOG_ERROR, "Invalid tile number %dx%d, should less than %dx%d.\n",
++ priv->tile_cols, priv->tile_rows, AV1_MAX_TILE_COLS, AV1_MAX_TILE_ROWS);
++ return AVERROR(EINVAL);
++ }
++
++ mi_cols = 2 * ((avctx->width + 7) >> 3);
++ mi_rows = 2 * ((avctx->height + 7) >> 3);
++ priv->sb_cols = priv->use_128x128_superblock ?
++ ((mi_cols + 31) >> 5) : ((mi_cols + 15) >> 4);
++ priv->sb_rows = priv->use_128x128_superblock ?
++ ((mi_rows + 31) >> 5) : ((mi_rows + 15) >> 4);
++ sb_shift = priv->use_128x128_superblock ? 5 : 4;
++ sb_size = sb_shift + 2;
++ priv->max_tile_width_sb = AV1_MAX_TILE_WIDTH >> sb_size;
++ max_tile_area_sb = AV1_MAX_TILE_AREA >> (2 * sb_size);
++
++ priv->min_log2_tile_cols = tile_log2(priv->max_tile_width_sb, priv->sb_cols);
++ priv->max_log2_tile_cols = tile_log2(1, FFMIN(priv->sb_cols, AV1_MAX_TILE_COLS));
++ priv->max_log2_tile_rows = tile_log2(1, FFMIN(priv->sb_rows, AV1_MAX_TILE_ROWS));
++ min_log2_tiles = FFMAX(priv->min_log2_tile_cols,
++ tile_log2(max_tile_area_sb, priv->sb_rows * priv->sb_cols));
++
++ tile_cols = av_clip(priv->tile_cols, (priv->sb_cols + priv->max_tile_width_sb - 1) / priv->max_tile_width_sb, priv->sb_cols);
++
++ if (!priv->tile_cols)
++ priv->tile_cols = tile_cols;
++ else if (priv->tile_cols != tile_cols){
++ av_log(avctx, AV_LOG_ERROR, "Invalid tile cols %d, should be in range of %d~%d\n",
++ priv->tile_cols,
++ (priv->sb_cols + priv->max_tile_width_sb - 1) / priv->max_tile_width_sb,
++ priv->sb_cols);
++ return AVERROR(EINVAL);
++ }
++
++ priv->tile_cols_log2 = tile_log2(1, priv->tile_cols);
++ tile_width_sb = (priv->sb_cols + (1 << priv->tile_cols_log2) - 1) >>
++ priv->tile_cols_log2;
++
++ if (priv->tile_rows > priv->sb_rows) {
++ av_log(avctx, AV_LOG_ERROR, "Invalid tile rows %d, should be less than %d.\n",
++ priv->tile_rows, priv->sb_rows);
++ return AVERROR(EINVAL);
++ }
++
++ /** Try user setting tile rows number first. */
++ tile_rows = priv->tile_rows ? priv->tile_rows : 1;
++ for (; tile_rows <= priv->sb_rows && tile_rows <= AV1_MAX_TILE_ROWS; tile_rows++) {
++ /** try uniformed tile. */
++ priv->tile_rows_log2 = tile_log2(1, tile_rows);
++ if ((priv->sb_cols + tile_width_sb - 1) / tile_width_sb == priv->tile_cols) {
++ for (i = 0; i < priv->tile_cols - 1; i++)
++ priv->width_in_sbs_minus_1[i] = tile_width_sb - 1;
++ priv->width_in_sbs_minus_1[i] = priv->sb_cols - (priv->tile_cols - 1) * tile_width_sb - 1;
++
++ tile_height_sb = (priv->sb_rows + (1 << priv->tile_rows_log2) - 1) >>
++ priv->tile_rows_log2;
++
++ if ((priv->sb_rows + tile_height_sb - 1) / tile_height_sb == tile_rows &&
++ tile_height_sb <= max_tile_area_sb / tile_width_sb) {
++ for (i = 0; i < tile_rows - 1; i++)
++ priv->height_in_sbs_minus_1[i] = tile_height_sb - 1;
++ priv->height_in_sbs_minus_1[i] = priv->sb_rows - (tile_rows - 1) * tile_height_sb - 1;
++
++ priv->uniform_tile = 1;
++ priv->min_log2_tile_rows = FFMAX(min_log2_tiles - priv->tile_cols_log2, 0);
++
++ break;
++ }
++ }
++
++ /** try non-uniformed tile. */
++ widest_tile_sb = 0;
++ for (i = 0; i < priv->tile_cols; i++) {
++ priv->width_in_sbs_minus_1[i] = (i + 1) * priv->sb_cols / priv->tile_cols - i * priv->sb_cols / priv->tile_cols - 1;
++ widest_tile_sb = FFMAX(widest_tile_sb, priv->width_in_sbs_minus_1[i] + 1);
++ }
++
++ if (min_log2_tiles)
++ max_tile_area_sb_varied = (priv->sb_rows * priv->sb_cols) >> (min_log2_tiles + 1);
++ else
++ max_tile_area_sb_varied = priv->sb_rows * priv->sb_cols;
++ priv->max_tile_height_sb = FFMAX(1, max_tile_area_sb_varied / widest_tile_sb);
++
++ if (tile_rows == av_clip(tile_rows, (priv->sb_rows + priv->max_tile_height_sb - 1) / priv->max_tile_height_sb, priv->sb_rows)) {
++ for (i = 0; i < tile_rows; i++)
++ priv->height_in_sbs_minus_1[i] = (i + 1) * priv->sb_rows / tile_rows - i * priv->sb_rows / tile_rows - 1;
++
++ break;
++ }
++
++ /** Return invalid parameter if explicit tile rows is set. */
++ if (priv->tile_rows) {
++ av_log(avctx, AV_LOG_ERROR, "Invalid tile rows %d.\n", priv->tile_rows);
++ return AVERROR(EINVAL);
++ }
++ }
++
++ priv->tile_rows = tile_rows;
++ av_log(avctx, AV_LOG_DEBUG, "Setting tile cols/rows to %d/%d.\n",
++ priv->tile_cols, priv->tile_rows);
++
++ /** check if tile cols/rows is supported by driver. */
++ if (priv->attr_ext2.bits.max_tile_num_minus1) {
++ if ((priv->tile_cols * priv->tile_rows - 1) > priv->attr_ext2.bits.max_tile_num_minus1) {
++ av_log(avctx, AV_LOG_ERROR, "Unsupported tile num %d * %d = %d by driver, "
++ "should be at most %d.\n", priv->tile_cols, priv->tile_rows,
++ priv->tile_cols * priv->tile_rows,
++ priv->attr_ext2.bits.max_tile_num_minus1 + 1);
++ return AVERROR(EINVAL);
++ }
++ }
++
++ /** check if tile group numbers is valid. */
++ if (priv->tile_groups > priv->tile_cols * priv->tile_rows) {
++ av_log(avctx, AV_LOG_WARNING, "Invalid tile groups number %d, "
++ "correct to %d.\n", priv->tile_groups, priv->tile_cols * priv->tile_rows);
++ priv->tile_groups = priv->tile_cols * priv->tile_rows;
++ }
++
++ return 0;
++}
++
++static int vaapi_encode_av1_write_sequence_header(AVCodecContext *avctx,
++ char *data, size_t *data_len)
++{
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++
++ memcpy(data, &priv->sh_data, MAX_PARAM_BUFFER_SIZE * sizeof(char));
++ *data_len = priv->sh_data_len;
++
++ return 0;
++}
++
++static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++ AV1RawOBU *sh_obu = &priv->sh;
++ AV1RawSequenceHeader *sh = &sh_obu->obu.sequence_header;
++ VAEncSequenceParameterBufferAV1 *vseq = ctx->codec_sequence_params;
++ CodedBitstreamFragment *obu = &priv->current_obu;
++ const AVPixFmtDescriptor *desc;
++ int ret;
++
++ memset(sh_obu, 0, sizeof(*sh_obu));
++ sh_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER;
++
++ desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format);
++ av_assert0(desc);
++
++ sh->seq_profile = avctx->profile;
++ if (!sh->seq_force_screen_content_tools)
++ sh->seq_force_integer_mv = AV1_SELECT_INTEGER_MV;
++ sh->frame_width_bits_minus_1 = av_log2(avctx->width);
++ sh->frame_height_bits_minus_1 = av_log2(avctx->height);
++ sh->max_frame_width_minus_1 = avctx->width - 1;
++ sh->max_frame_height_minus_1 = avctx->height - 1;
++ sh->seq_tier[0] = priv->tier;
++ /** enable order hint and reserve maximum 8 bits for it by default. */
++ sh->enable_order_hint = 1;
++ sh->order_hint_bits_minus_1 = 7;
++
++ sh->color_config = (AV1RawColorConfig) {
++ .high_bitdepth = desc->comp[0].depth == 8 ? 0 : 1,
++ .color_primaries = avctx->color_primaries,
++ .transfer_characteristics = avctx->color_trc,
++ .matrix_coefficients = avctx->colorspace,
++ .color_description_present_flag = (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
++ avctx->color_trc != AVCOL_TRC_UNSPECIFIED ||
++ avctx->colorspace != AVCOL_SPC_UNSPECIFIED),
++ .color_range = avctx->color_range == AVCOL_RANGE_JPEG,
++ .subsampling_x = desc->log2_chroma_w,
++ .subsampling_y = desc->log2_chroma_h,
++ };
++
++ switch (avctx->chroma_sample_location) {
++ case AVCHROMA_LOC_LEFT:
++ sh->color_config.chroma_sample_position = AV1_CSP_VERTICAL;
++ break;
++ case AVCHROMA_LOC_TOPLEFT:
++ sh->color_config.chroma_sample_position = AV1_CSP_COLOCATED;
++ break;
++ default:
++ sh->color_config.chroma_sample_position = AV1_CSP_UNKNOWN;
++ break;
++ }
++
++ if (avctx->level != FF_PROFILE_UNKNOWN) {
++ sh->seq_level_idx[0] = avctx->level;
++ } else {
++ const AV1LevelDescriptor *level;
++ float framerate;
++
++ if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
++ framerate = avctx->framerate.num / avctx->framerate.den;
++ else
++ framerate = 0;
++
++ level = ff_av1_guess_level(avctx->bit_rate, priv->tier,
++ ctx->surface_width, ctx->surface_height,
++ priv->tile_rows * priv->tile_cols,
++ priv->tile_cols, framerate);
++ if (level) {
++ av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
++ sh->seq_level_idx[0] = level->level_idx;
++ } else {
++ av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to "
++ "any normal level, using maximum parameters level by default.\n");
++ sh->seq_level_idx[0] = 31;
++ sh->seq_tier[0] = 1;
++ }
++ }
++ vseq->seq_profile = sh->seq_profile;
++ vseq->seq_level_idx = sh->seq_level_idx[0];
++ vseq->seq_tier = sh->seq_tier[0];
++ vseq->order_hint_bits_minus_1 = sh->order_hint_bits_minus_1;
++ vseq->intra_period = ctx->gop_size;
++ vseq->ip_period = ctx->b_per_p + 1;
++
++ vseq->seq_fields.bits.enable_order_hint = sh->enable_order_hint;
++
++ if (!(ctx->va_rc_mode & VA_RC_CQP)) {
++ vseq->bits_per_second = ctx->va_bit_rate;
++ vseq->seq_fields.bits.enable_cdef = sh->enable_cdef = 1;
++ }
++
++ ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_SEQUENCE_HEADER, &priv->sh);
++ if (ret < 0)
++ goto end;
++
++ ret = vaapi_encode_av1_write_obu(avctx, priv->sh_data, &priv->sh_data_len, obu);
++ if (ret < 0)
++ goto end;
++
++end:
++ ff_cbs_fragment_reset(obu);
++ return ret;
++}
++
++static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
++ VAAPIEncodePicture *pic)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++ VAAPIEncodeAV1Picture *hpic = pic->priv_data;
++ AV1RawOBU *fh_obu = &priv->fh;
++ AV1RawFrameHeader *fh = &fh_obu->obu.frame.header;
++ VAEncPictureParameterBufferAV1 *vpic = pic->codec_picture_params;
++ CodedBitstreamFragment *obu = &priv->current_obu;
++ VAAPIEncodePicture *ref;
++ VAAPIEncodeAV1Picture *href;
++ int slot, i;
++ int ret;
++ static const int8_t default_loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME] =
++ { 1, 0, 0, 0, -1, 0, -1, -1 };
++
++ memset(fh_obu, 0, sizeof(*fh_obu));
++ pic->nb_slices = priv->tile_groups;
++ pic->non_independent_frame = pic->encode_order < pic->display_order;
++ fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER;
++ fh_obu->header.obu_has_size_field = 1;
++
++ switch (pic->type) {
++ case PICTURE_TYPE_IDR:
++ av_assert0(pic->nb_refs[0] == 0 || pic->nb_refs[1]);
++ fh->frame_type = AV1_FRAME_KEY;
++ fh->refresh_frame_flags = 0xFF;
++ fh->base_q_idx = priv->q_idx_idr;
++ hpic->slot = 0;
++ hpic->last_idr_frame = pic->display_order;
++ break;
++ case PICTURE_TYPE_P:
++ av_assert0(pic->nb_refs[0]);
++ fh->frame_type = AV1_FRAME_INTER;
++ fh->base_q_idx = priv->q_idx_p;
++ ref = pic->refs[0][pic->nb_refs[0] - 1];
++ href = ref->priv_data;
++ hpic->slot = !href->slot;
++ hpic->last_idr_frame = href->last_idr_frame;
++ fh->refresh_frame_flags = 1 << hpic->slot;
++
++ /** set the nearest frame in L0 as all reference frame. */
++ for (i = 0; i < AV1_REFS_PER_FRAME; i++) {
++ fh->ref_frame_idx[i] = href->slot;
++ }
++ fh->primary_ref_frame = href->slot;
++ fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
++ vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST;
++
++ /** set the 2nd nearest frame in L0 as Golden frame. */
++ if (pic->nb_refs[0] > 1) {
++ ref = pic->refs[0][pic->nb_refs[0] - 2];
++ href = ref->priv_data;
++ fh->ref_frame_idx[3] = href->slot;
++ fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
++ vpic->ref_frame_ctrl_l0.fields.search_idx1 = AV1_REF_FRAME_GOLDEN;
++ }
++ break;
++ case PICTURE_TYPE_B:
++ av_assert0(pic->nb_refs[0] && pic->nb_refs[1]);
++ fh->frame_type = AV1_FRAME_INTER;
++ fh->base_q_idx = priv->q_idx_b;
++ fh->refresh_frame_flags = 0x0;
++ fh->reference_select = 1;
++
++ /** B frame will not be referenced, disable its recon frame. */
++ vpic->picture_flags.bits.disable_frame_recon = 1;
++
++ /** Use LAST_FRAME and BWDREF_FRAME for reference. */
++ vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST;
++ vpic->ref_frame_ctrl_l1.fields.search_idx0 = AV1_REF_FRAME_BWDREF;
++
++ ref = pic->refs[0][pic->nb_refs[0] - 1];
++ href = ref->priv_data;
++ hpic->last_idr_frame = href->last_idr_frame;
++ fh->primary_ref_frame = href->slot;
++ fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
++ for (i = 0; i < AV1_REF_FRAME_GOLDEN; i++) {
++ fh->ref_frame_idx[i] = href->slot;
++ }
++
++ ref = pic->refs[1][pic->nb_refs[1] - 1];
++ href = ref->priv_data;
++ fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
++ for (i = AV1_REF_FRAME_GOLDEN; i < AV1_REFS_PER_FRAME; i++) {
++ fh->ref_frame_idx[i] = href->slot;
++ }
++ break;
++ default:
++ av_assert0(0 && "invalid picture type");
++ }
++
++ fh->show_frame = pic->display_order <= pic->encode_order;
++ fh->showable_frame = fh->frame_type != AV1_FRAME_KEY;
++ fh->frame_width_minus_1 = avctx->width - 1;
++ fh->frame_height_minus_1 = avctx->height - 1;
++ fh->render_width_minus_1 = fh->frame_width_minus_1;
++ fh->render_height_minus_1 = fh->frame_height_minus_1;
++ fh->order_hint = pic->display_order - hpic->last_idr_frame;
++ fh->tile_cols = priv->tile_cols;
++ fh->tile_rows = priv->tile_rows;
++ fh->tile_cols_log2 = priv->tile_cols_log2;
++ fh->tile_rows_log2 = priv->tile_rows_log2;
++ fh->uniform_tile_spacing_flag = priv->uniform_tile;
++ fh->tile_size_bytes_minus1 = priv->attr_ext2.bits.tile_size_bytes_minus1;
++
++ /** ignore ONLY_4x4 mode for codedlossless is not fully implemented. */
++ if (priv->attr_ext2.bits.tx_mode_support & 0x04)
++ fh->tx_mode = AV1_TX_MODE_SELECT;
++ else if (priv->attr_ext2.bits.tx_mode_support & 0x02)
++ fh->tx_mode = AV1_TX_MODE_LARGEST;
++ else {
++ av_log(avctx, AV_LOG_ERROR, "No available tx mode found.\n");
++ return AVERROR(EINVAL);
++ }
++
++ for (i = 0; i < fh->tile_cols; i++)
++ fh->width_in_sbs_minus_1[i] = vpic->width_in_sbs_minus_1[i] = priv->width_in_sbs_minus_1[i];
++
++ for (i = 0; i < fh->tile_rows; i++)
++ fh->height_in_sbs_minus_1[i] = vpic->height_in_sbs_minus_1[i] = priv->height_in_sbs_minus_1[i];
++
++ memcpy(fh->loop_filter_ref_deltas, default_loop_filter_ref_deltas,
++ AV1_TOTAL_REFS_PER_FRAME * sizeof(int8_t));
++
++ if (fh->frame_type == AV1_FRAME_KEY && fh->show_frame) {
++ fh->error_resilient_mode = 1;
++ }
++
++ if (fh->frame_type == AV1_FRAME_KEY || fh->error_resilient_mode)
++ fh->primary_ref_frame = AV1_PRIMARY_REF_NONE;
++
++ vpic->base_qindex = fh->base_q_idx;
++ vpic->frame_width_minus_1 = fh->frame_width_minus_1;
++ vpic->frame_height_minus_1 = fh->frame_height_minus_1;
++ vpic->primary_ref_frame = fh->primary_ref_frame;
++ vpic->reconstructed_frame = pic->recon_surface;
++ vpic->coded_buf = pic->output_buffer;
++ vpic->tile_cols = fh->tile_cols;
++ vpic->tile_rows = fh->tile_rows;
++ vpic->order_hint = fh->order_hint;
++#if VA_CHECK_VERSION(1, 15, 0)
++ vpic->refresh_frame_flags = fh->refresh_frame_flags;
++#endif
++
++ vpic->picture_flags.bits.enable_frame_obu = 0;
++ vpic->picture_flags.bits.frame_type = fh->frame_type;
++ vpic->picture_flags.bits.reduced_tx_set = fh->reduced_tx_set;
++ vpic->picture_flags.bits.error_resilient_mode = fh->error_resilient_mode;
++
++ /** let driver decide to use single or compound reference prediction mode. */
++ vpic->mode_control_flags.bits.reference_mode = fh->reference_select ? 2 : 0;
++ vpic->mode_control_flags.bits.tx_mode = fh->tx_mode;
++
++ vpic->tile_group_obu_hdr_info.bits.obu_has_size_field = 1;
++
++ /** set reference. */
++ for (i = 0; i < AV1_REFS_PER_FRAME; i++)
++ vpic->ref_frame_idx[i] = fh->ref_frame_idx[i];
++
++ for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++)
++ vpic->reference_frames[i] = VA_INVALID_SURFACE;
++
++ for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) {
++ for (int j = 0; j < pic->nb_refs[i]; j++) {
++ VAAPIEncodePicture *ref_pic = pic->refs[i][j];
++
++ slot = ((VAAPIEncodeAV1Picture*)ref_pic->priv_data)->slot;
++ av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE);
++
++ vpic->reference_frames[slot] = ref_pic->recon_surface;
++ }
++ }
++
++ fh_obu->obu_size_byte_len = priv->attr_ext2.bits.obu_size_bytes_minus1 + 1;
++ ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &priv->fh);
++ if (ret < 0)
++ goto end;
++
++ ret = vaapi_encode_av1_write_obu(avctx, priv->fh_data, &priv->fh_data_len, obu);
++ if (ret < 0)
++ goto end;
++
++ if (!(ctx->va_rc_mode & VA_RC_CQP)) {
++ vpic->min_base_qindex = av_clip(avctx->qmin, 1, AV1_MAX_QUANT);
++ vpic->max_base_qindex = av_clip(avctx->qmax, 1, AV1_MAX_QUANT);
++
++ vpic->bit_offset_qindex = priv->qindex_offset;
++ vpic->bit_offset_loopfilter_params = priv->loopfilter_offset;
++ vpic->bit_offset_cdef_params = priv->cdef_start_offset;
++ vpic->size_in_bits_cdef_params = priv->cdef_param_size;
++ vpic->size_in_bits_frame_hdr_obu = priv->fh_data_len;
++ vpic->byte_offset_frame_hdr_obu_size = (((pic->type == PICTURE_TYPE_IDR) ?
++ priv->sh_data_len / 8 : 0) +
++ (fh_obu->header.obu_extension_flag ?
++ 2 : 1));
++ }
++
++end:
++ ff_cbs_fragment_reset(obu);
++ return ret;
++}
++
++static int vaapi_encode_av1_init_slice_params(AVCodecContext *avctx,
++ VAAPIEncodePicture *pic,
++ VAAPIEncodeSlice *slice)
++{
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++ VAEncTileGroupBufferAV1 *vslice = slice->codec_slice_params;
++ CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data;
++ int div;
++
++ /** Set tile group info. */
++ div = priv->tile_cols * priv->tile_rows / priv->tile_groups;
++ vslice->tg_start = slice->index * div;
++ if (slice->index == (priv->tile_groups - 1)) {
++ vslice->tg_end = priv->tile_cols * priv->tile_rows - 1;
++ cbctx->seen_frame_header = 0;
++ } else {
++ vslice->tg_end = (slice->index + 1) * div - 1;
++ }
++
++ return 0;
++}
++
++static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx,
++ VAAPIEncodePicture *pic,
++ char *data, size_t *data_len)
++{
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++ CodedBitstreamFragment *obu = &priv->current_obu;
++ CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data;
++ AV1RawOBU *fh_obu = &priv->fh;
++ AV1RawFrameHeader *rep_fh = &fh_obu->obu.frame_header;
++ VAAPIEncodeAV1Picture *href;
++ int ret = 0;
++
++ pic->tail_size = 0;
++ /** Pack repeat frame header. */
++ if (pic->display_order > pic->encode_order) {
++ memset(fh_obu, 0, sizeof(*fh_obu));
++ href = pic->refs[0][pic->nb_refs[0] - 1]->priv_data;
++ fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER;
++ fh_obu->header.obu_has_size_field = 1;
++
++ rep_fh->show_existing_frame = 1;
++ rep_fh->frame_to_show_map_idx = href->slot == 0;
++ rep_fh->frame_type = AV1_FRAME_INTER;
++ rep_fh->frame_width_minus_1 = avctx->width - 1;
++ rep_fh->frame_height_minus_1 = avctx->height - 1;
++ rep_fh->render_width_minus_1 = rep_fh->frame_width_minus_1;
++ rep_fh->render_height_minus_1 = rep_fh->frame_height_minus_1;
++
++ cbctx->seen_frame_header = 0;
++
++ ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &priv->fh);
++ if (ret < 0)
++ goto end;
++
++ ret = vaapi_encode_av1_write_obu(avctx, pic->tail_data, &pic->tail_size, obu);
++ if (ret < 0)
++ goto end;
++
++ pic->tail_size /= 8;
++ }
++
++ memcpy(data, &priv->fh_data, MAX_PARAM_BUFFER_SIZE * sizeof(char));
++ *data_len = priv->fh_data_len;
++
++end:
++ ff_cbs_fragment_reset(obu);
++ return ret;
++}
++
++static const VAAPIEncodeProfile vaapi_encode_av1_profiles[] = {
++ { FF_PROFILE_AV1_MAIN, 8, 3, 1, 1, VAProfileAV1Profile0 },
++ { FF_PROFILE_AV1_MAIN, 10, 3, 1, 1, VAProfileAV1Profile0 },
++ { FF_PROFILE_UNKNOWN }
++};
++
++static const VAAPIEncodeType vaapi_encode_type_av1 = {
++ .profiles = vaapi_encode_av1_profiles,
++ .flags = FLAG_B_PICTURES | FLAG_TIMESTAMP_NO_DELAY,
++ .default_quality = 25,
++
++ .get_encoder_caps = &vaapi_encode_av1_get_encoder_caps,
++ .configure = &vaapi_encode_av1_configure,
++
++ .sequence_header_type = VAEncPackedHeaderSequence,
++ .sequence_params_size = sizeof(VAEncSequenceParameterBufferAV1),
++ .init_sequence_params = &vaapi_encode_av1_init_sequence_params,
++ .write_sequence_header = &vaapi_encode_av1_write_sequence_header,
++
++ .picture_priv_data_size = sizeof(VAAPIEncodeAV1Picture),
++ .picture_header_type = VAEncPackedHeaderPicture,
++ .picture_params_size = sizeof(VAEncPictureParameterBufferAV1),
++ .init_picture_params = &vaapi_encode_av1_init_picture_params,
++ .write_picture_header = &vaapi_encode_av1_write_picture_header,
++
++ .slice_params_size = sizeof(VAEncTileGroupBufferAV1),
++ .init_slice_params = &vaapi_encode_av1_init_slice_params,
++};
++
++static av_cold int vaapi_encode_av1_init(AVCodecContext *avctx)
++{
++ VAAPIEncodeContext *ctx = avctx->priv_data;
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++ VAConfigAttrib attr;
++ VAStatus vas;
++ int ret;
++
++ ctx->codec = &vaapi_encode_type_av1;
++
++ ctx->desired_packed_headers =
++ VA_ENC_PACKED_HEADER_SEQUENCE |
++ VA_ENC_PACKED_HEADER_PICTURE;
++
++ if (avctx->profile == FF_PROFILE_UNKNOWN)
++ avctx->profile = priv->profile;
++ if (avctx->level == FF_PROFILE_UNKNOWN)
++ avctx->level = priv->level;
++
++ if (avctx->level != FF_PROFILE_UNKNOWN && avctx->level & ~0x1f) {
++ av_log(avctx, AV_LOG_ERROR, "Invalid level %d\n", avctx->level);
++ return AVERROR(EINVAL);
++ }
++
++ ret = ff_vaapi_encode_init(avctx);
++ if (ret < 0)
++ return ret;
++
++ attr.type = VAConfigAttribEncAV1;
++ vas = vaGetConfigAttributes(ctx->hwctx->display,
++ ctx->va_profile,
++ ctx->va_entrypoint,
++ &attr, 1);
++ if (vas != VA_STATUS_SUCCESS) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to query "
++ "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
++ return AVERROR_EXTERNAL;
++ } else if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
++ priv->attr.value = 0;
++ av_log(avctx, AV_LOG_WARNING, "Attribute type:%d is not "
++ "supported.\n", attr.type);
++ } else {
++ priv->attr.value = attr.value;
++ }
++
++ attr.type = VAConfigAttribEncAV1Ext1;
++ vas = vaGetConfigAttributes(ctx->hwctx->display,
++ ctx->va_profile,
++ ctx->va_entrypoint,
++ &attr, 1);
++ if (vas != VA_STATUS_SUCCESS) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to query "
++ "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
++ return AVERROR_EXTERNAL;
++ } else if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
++ priv->attr_ext1.value = 0;
++ av_log(avctx, AV_LOG_WARNING, "Attribute type:%d is not "
++ "supported.\n", attr.type);
++ } else {
++ priv->attr_ext1.value = attr.value;
++ }
++
++ /** This attr provides essential indicators, return error if not support. */
++ attr.type = VAConfigAttribEncAV1Ext2;
++ vas = vaGetConfigAttributes(ctx->hwctx->display,
++ ctx->va_profile,
++ ctx->va_entrypoint,
++ &attr, 1);
++ if (vas != VA_STATUS_SUCCESS || attr.value == VA_ATTRIB_NOT_SUPPORTED) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to query "
++ "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
++ return AVERROR_EXTERNAL;
++ } else {
++ priv->attr_ext2.value = attr.value;
++ }
++
++ ret = vaapi_encode_av1_set_tile(avctx);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static av_cold int vaapi_encode_av1_close(AVCodecContext *avctx)
++{
++ VAAPIEncodeAV1Context *priv = avctx->priv_data;
++
++ ff_cbs_fragment_free(&priv->current_obu);
++ ff_cbs_close(&priv->cbc);
++
++ return ff_vaapi_encode_close(avctx);
++}
++
++#define OFFSET(x) offsetof(VAAPIEncodeAV1Context, x)
++#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
++
++static const AVOption vaapi_encode_av1_options[] = {
++ VAAPI_ENCODE_COMMON_OPTIONS,
++ VAAPI_ENCODE_RC_OPTIONS,
++ { "profile", "Set profile (seq_profile)",
++ OFFSET(profile), AV_OPT_TYPE_INT,
++ { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 0xff, FLAGS, "profile" },
++
++#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
++ { .i64 = value }, 0, 0, FLAGS, "profile"
++ { PROFILE("main", FF_PROFILE_AV1_MAIN) },
++ { PROFILE("high", FF_PROFILE_AV1_HIGH) },
++ { PROFILE("professional", FF_PROFILE_AV1_PROFESSIONAL) },
++#undef PROFILE
++
++ { "tier", "Set tier (seq_tier)",
++ OFFSET(tier), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, "tier" },
++ { "main", NULL, 0, AV_OPT_TYPE_CONST,
++ { .i64 = 0 }, 0, 0, FLAGS, "tier" },
++ { "high", NULL, 0, AV_OPT_TYPE_CONST,
++ { .i64 = 1 }, 0, 0, FLAGS, "tier" },
++ { "level", "Set level (seq_level_idx)",
++ OFFSET(level), AV_OPT_TYPE_INT,
++ { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 0x1f, FLAGS, "level" },
++
++#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
++ { .i64 = value }, 0, 0, FLAGS, "level"
++ { LEVEL("2.0", 0) },
++ { LEVEL("2.1", 1) },
++ { LEVEL("3.0", 4) },
++ { LEVEL("3.1", 5) },
++ { LEVEL("4.0", 8) },
++ { LEVEL("4.1", 9) },
++ { LEVEL("5.0", 12) },
++ { LEVEL("5.1", 13) },
++ { LEVEL("5.2", 14) },
++ { LEVEL("5.3", 15) },
++ { LEVEL("6.0", 16) },
++ { LEVEL("6.1", 17) },
++ { LEVEL("6.2", 18) },
++ { LEVEL("6.3", 19) },
++#undef LEVEL
++
++ { "tiles", "Tile columns x rows (Use minimal tile column/row number automatically by default)",
++ OFFSET(tile_cols), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS },
++ { "tile_groups", "Number of tile groups for encoding",
++ OFFSET(tile_groups), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, AV1_MAX_TILE_ROWS * AV1_MAX_TILE_COLS, FLAGS },
++
++ { NULL },
++};
++
++static const FFCodecDefault vaapi_encode_av1_defaults[] = {
++ { "b", "0" },
++ { "bf", "2" },
++ { "g", "120" },
++ { "qmin", "1" },
++ { "qmax", "255" },
++ { NULL },
++};
++
++static const AVClass vaapi_encode_av1_class = {
++ .class_name = "av1_vaapi",
++ .item_name = av_default_item_name,
++ .option = vaapi_encode_av1_options,
++ .version = LIBAVUTIL_VERSION_INT,
++};
++
++const FFCodec ff_av1_vaapi_encoder = {
++ .p.name = "av1_vaapi",
++ CODEC_LONG_NAME("AV1 (VAAPI)"),
++ .p.type = AVMEDIA_TYPE_VIDEO,
++ .p.id = AV_CODEC_ID_AV1,
++ .priv_data_size = sizeof(VAAPIEncodeAV1Context),
++ .init = &vaapi_encode_av1_init,
++ FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
++ .close = &vaapi_encode_av1_close,
++ .p.priv_class = &vaapi_encode_av1_class,
++ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
++ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
++ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
++ FF_CODEC_CAP_INIT_CLEANUP,
++ .defaults = vaapi_encode_av1_defaults,
++ .p.pix_fmts = (const enum AVPixelFormat[]) {
++ AV_PIX_FMT_VAAPI,
++ AV_PIX_FMT_NONE,
++ },
++ .hw_configs = ff_vaapi_encode_hw_configs,
++ .p.wrapper_name = "vaapi",
++};
+diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c
+index 645f6a9..c205d1e 100644
+--- a/libavcodec/vaapi_encode_h264.c
++++ b/libavcodec/vaapi_encode_h264.c
+@@ -614,7 +614,7 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
+ VAAPIEncodePicture *prev = pic->prev;
+ VAAPIEncodeH264Picture *hprev = prev ? prev->priv_data : NULL;
+ VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params;
+- int i;
++ int i, j = 0;
+
+ if (pic->type == PICTURE_TYPE_IDR) {
+ av_assert0(pic->display_order == pic->encode_order);
+@@ -715,24 +715,26 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
+ .TopFieldOrderCnt = hpic->pic_order_cnt,
+ .BottomFieldOrderCnt = hpic->pic_order_cnt,
+ };
+-
+- for (i = 0; i < pic->nb_refs; i++) {
+- VAAPIEncodePicture *ref = pic->refs[i];
+- VAAPIEncodeH264Picture *href;
+-
+- av_assert0(ref && ref->encode_order < pic->encode_order);
+- href = ref->priv_data;
+-
+- vpic->ReferenceFrames[i] = (VAPictureH264) {
+- .picture_id = ref->recon_surface,
+- .frame_idx = href->frame_num,
+- .flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE,
+- .TopFieldOrderCnt = href->pic_order_cnt,
+- .BottomFieldOrderCnt = href->pic_order_cnt,
+- };
++ for (int k = 0; k < MAX_REFERENCE_LIST_NUM; k++) {
++ for (i = 0; i < pic->nb_refs[k]; i++) {
++ VAAPIEncodePicture *ref = pic->refs[k][i];
++ VAAPIEncodeH264Picture *href;
++
++ av_assert0(ref && ref->encode_order < pic->encode_order);
++ href = ref->priv_data;
++
++ vpic->ReferenceFrames[j++] = (VAPictureH264) {
++ .picture_id = ref->recon_surface,
++ .frame_idx = href->frame_num,
++ .flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE,
++ .TopFieldOrderCnt = href->pic_order_cnt,
++ .BottomFieldOrderCnt = href->pic_order_cnt,
++ };
++ }
+ }
+- for (; i < FF_ARRAY_ELEMS(vpic->ReferenceFrames); i++) {
+- vpic->ReferenceFrames[i] = (VAPictureH264) {
++
++ for (; j < FF_ARRAY_ELEMS(vpic->ReferenceFrames); j++) {
++ vpic->ReferenceFrames[j] = (VAPictureH264) {
+ .picture_id = VA_INVALID_ID,
+ .flags = VA_PICTURE_H264_INVALID,
+ };
+@@ -934,17 +936,17 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
+
+ if (pic->type == PICTURE_TYPE_P) {
+ int need_rplm = 0;
+- for (i = 0; i < pic->nb_refs; i++) {
+- av_assert0(pic->refs[i]);
+- if (pic->refs[i] != def_l0[i])
++ for (i = 0; i < pic->nb_refs[0]; i++) {
++ av_assert0(pic->refs[0][i]);
++ if (pic->refs[0][i] != def_l0[i])
+ need_rplm = 1;
+ }
+
+ sh->ref_pic_list_modification_flag_l0 = need_rplm;
+ if (need_rplm) {
+ int pic_num = hpic->frame_num;
+- for (i = 0; i < pic->nb_refs; i++) {
+- href = pic->refs[i]->priv_data;
++ for (i = 0; i < pic->nb_refs[0]; i++) {
++ href = pic->refs[0][i]->priv_data;
+ av_assert0(href->frame_num != pic_num);
+ if (href->frame_num < pic_num) {
+ sh->rplm_l0[i].modification_of_pic_nums_idc = 0;
+@@ -963,28 +965,29 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
+ } else {
+ int need_rplm_l0 = 0, need_rplm_l1 = 0;
+ int n0 = 0, n1 = 0;
+- for (i = 0; i < pic->nb_refs; i++) {
+- av_assert0(pic->refs[i]);
+- href = pic->refs[i]->priv_data;
+- av_assert0(href->pic_order_cnt != hpic->pic_order_cnt);
+- if (href->pic_order_cnt < hpic->pic_order_cnt) {
+- if (pic->refs[i] != def_l0[n0])
+- need_rplm_l0 = 1;
+- ++n0;
+- } else {
+- if (pic->refs[i] != def_l1[n1])
+- need_rplm_l1 = 1;
+- ++n1;
+- }
++ for (i = 0; i < pic->nb_refs[0]; i++) {
++ av_assert0(pic->refs[0][i]);
++ href = pic->refs[0][i]->priv_data;
++ av_assert0(href->pic_order_cnt < hpic->pic_order_cnt);
++ if (pic->refs[0][i] != def_l0[n0])
++ need_rplm_l0 = 1;
++ ++n0;
++ }
++
++ for (i = 0; i < pic->nb_refs[1]; i++) {
++ av_assert0(pic->refs[1][i]);
++ href = pic->refs[1][i]->priv_data;
++ av_assert0(href->pic_order_cnt > hpic->pic_order_cnt);
++ if (pic->refs[1][i] != def_l1[n1])
++ need_rplm_l1 = 1;
++ ++n1;
+ }
+
+ sh->ref_pic_list_modification_flag_l0 = need_rplm_l0;
+ if (need_rplm_l0) {
+ int pic_num = hpic->frame_num;
+- for (i = j = 0; i < pic->nb_refs; i++) {
+- href = pic->refs[i]->priv_data;
+- if (href->pic_order_cnt > hpic->pic_order_cnt)
+- continue;
++ for (i = j = 0; i < pic->nb_refs[0]; i++) {
++ href = pic->refs[0][i]->priv_data;
+ av_assert0(href->frame_num != pic_num);
+ if (href->frame_num < pic_num) {
+ sh->rplm_l0[j].modification_of_pic_nums_idc = 0;
+@@ -1005,10 +1008,8 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
+ sh->ref_pic_list_modification_flag_l1 = need_rplm_l1;
+ if (need_rplm_l1) {
+ int pic_num = hpic->frame_num;
+- for (i = j = 0; i < pic->nb_refs; i++) {
+- href = pic->refs[i]->priv_data;
+- if (href->pic_order_cnt < hpic->pic_order_cnt)
+- continue;
++ for (i = j = 0; i < pic->nb_refs[1]; i++) {
++ href = pic->refs[1][i]->priv_data;
+ av_assert0(href->frame_num != pic_num);
+ if (href->frame_num < pic_num) {
+ sh->rplm_l1[j].modification_of_pic_nums_idc = 0;
+@@ -1048,14 +1049,13 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
+ vslice->RefPicList1[i].flags = VA_PICTURE_H264_INVALID;
+ }
+
+- av_assert0(pic->nb_refs <= 2);
+- if (pic->nb_refs >= 1) {
++ if (pic->nb_refs[0]) {
+ // Backward reference for P- or B-frame.
+ av_assert0(pic->type == PICTURE_TYPE_P ||
+ pic->type == PICTURE_TYPE_B);
+ vslice->RefPicList0[0] = vpic->ReferenceFrames[0];
+ }
+- if (pic->nb_refs >= 2) {
++ if (pic->nb_refs[1]) {
+ // Forward reference for B-frame.
+ av_assert0(pic->type == PICTURE_TYPE_B);
+ vslice->RefPicList1[0] = vpic->ReferenceFrames[1];
+diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c
+index aa7e532..f015e6f 100644
+--- a/libavcodec/vaapi_encode_h265.c
++++ b/libavcodec/vaapi_encode_h265.c
+@@ -764,7 +764,7 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
+ VAAPIEncodePicture *prev = pic->prev;
+ VAAPIEncodeH265Picture *hprev = prev ? prev->priv_data : NULL;
+ VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params;
+- int i;
++ int i, j = 0;
+
+ if (pic->type == PICTURE_TYPE_IDR) {
+ av_assert0(pic->display_order == pic->encode_order);
+@@ -789,8 +789,8 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
+ hpic->pic_type = 1;
+ } else {
+ VAAPIEncodePicture *irap_ref;
+- av_assert0(pic->refs[0] && pic->refs[1]);
+- for (irap_ref = pic; irap_ref; irap_ref = irap_ref->refs[1]) {
++ av_assert0(pic->refs[0][0] && pic->refs[1][0]);
++ for (irap_ref = pic; irap_ref; irap_ref = irap_ref->refs[1][0]) {
+ if (irap_ref->type == PICTURE_TYPE_I)
+ break;
+ }
+@@ -915,24 +915,27 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
+ .flags = 0,
+ };
+
+- for (i = 0; i < pic->nb_refs; i++) {
+- VAAPIEncodePicture *ref = pic->refs[i];
+- VAAPIEncodeH265Picture *href;
+-
+- av_assert0(ref && ref->encode_order < pic->encode_order);
+- href = ref->priv_data;
+-
+- vpic->reference_frames[i] = (VAPictureHEVC) {
+- .picture_id = ref->recon_surface,
+- .pic_order_cnt = href->pic_order_cnt,
+- .flags = (ref->display_order < pic->display_order ?
+- VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) |
+- (ref->display_order > pic->display_order ?
+- VA_PICTURE_HEVC_RPS_ST_CURR_AFTER : 0),
+- };
++ for (int k = 0; k < MAX_REFERENCE_LIST_NUM; k++) {
++ for (i = 0; i < pic->nb_refs[k]; i++) {
++ VAAPIEncodePicture *ref = pic->refs[k][i];
++ VAAPIEncodeH265Picture *href;
++
++ av_assert0(ref && ref->encode_order < pic->encode_order);
++ href = ref->priv_data;
++
++ vpic->reference_frames[j++] = (VAPictureHEVC) {
++ .picture_id = ref->recon_surface,
++ .pic_order_cnt = href->pic_order_cnt,
++ .flags = (ref->display_order < pic->display_order ?
++ VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) |
++ (ref->display_order > pic->display_order ?
++ VA_PICTURE_HEVC_RPS_ST_CURR_AFTER : 0),
++ };
++ }
+ }
+- for (; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++) {
+- vpic->reference_frames[i] = (VAPictureHEVC) {
++
++ for (; j < FF_ARRAY_ELEMS(vpic->reference_frames); j++) {
++ vpic->reference_frames[j] = (VAPictureHEVC) {
+ .picture_id = VA_INVALID_ID,
+ .flags = VA_PICTURE_HEVC_INVALID,
+ };
+@@ -1016,21 +1019,33 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
+ memset(rps, 0, sizeof(*rps));
+
+ rps_pics = 0;
+- for (i = 0; i < pic->nb_refs; i++) {
+- strp = pic->refs[i]->priv_data;
+- rps_poc[rps_pics] = strp->pic_order_cnt;
+- rps_used[rps_pics] = 1;
+- ++rps_pics;
++ for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) {
++ for (j = 0; j < pic->nb_refs[i]; j++) {
++ strp = pic->refs[i][j]->priv_data;
++ rps_poc[rps_pics] = strp->pic_order_cnt;
++ rps_used[rps_pics] = 1;
++ ++rps_pics;
++ }
+ }
++
+ for (i = 0; i < pic->nb_dpb_pics; i++) {
+ if (pic->dpb[i] == pic)
+ continue;
+- for (j = 0; j < pic->nb_refs; j++) {
+- if (pic->dpb[i] == pic->refs[j])
++
++ for (j = 0; j < pic->nb_refs[0]; j++) {
++ if (pic->dpb[i] == pic->refs[0][j])
++ break;
++ }
++ if (j < pic->nb_refs[0])
++ continue;
++
++ for (j = 0; j < pic->nb_refs[1]; j++) {
++ if (pic->dpb[i] == pic->refs[1][j])
+ break;
+ }
+- if (j < pic->nb_refs)
++ if (j < pic->nb_refs[1])
+ continue;
++
+ strp = pic->dpb[i]->priv_data;
+ rps_poc[rps_pics] = strp->pic_order_cnt;
+ rps_used[rps_pics] = 0;
+@@ -1155,8 +1170,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
+ vslice->ref_pic_list1[i].flags = VA_PICTURE_HEVC_INVALID;
+ }
+
+- av_assert0(pic->nb_refs <= 2);
+- if (pic->nb_refs >= 1) {
++ if (pic->nb_refs[0]) {
+ // Backward reference for P- or B-frame.
+ av_assert0(pic->type == PICTURE_TYPE_P ||
+ pic->type == PICTURE_TYPE_B);
+@@ -1165,7 +1179,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
+ // Reference for GPB B-frame, L0 == L1
+ vslice->ref_pic_list1[0] = vpic->reference_frames[0];
+ }
+- if (pic->nb_refs >= 2) {
++ if (pic->nb_refs[1]) {
+ // Forward reference for B-frame.
+ av_assert0(pic->type == PICTURE_TYPE_B);
+ vslice->ref_pic_list1[0] = vpic->reference_frames[1];
+diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c
+index 9261d19..8000ae1 100644
+--- a/libavcodec/vaapi_encode_mpeg2.c
++++ b/libavcodec/vaapi_encode_mpeg2.c
+@@ -458,12 +458,12 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx,
+ break;
+ case PICTURE_TYPE_P:
+ vpic->picture_type = VAEncPictureTypePredictive;
+- vpic->forward_reference_picture = pic->refs[0]->recon_surface;
++ vpic->forward_reference_picture = pic->refs[0][0]->recon_surface;
+ break;
+ case PICTURE_TYPE_B:
+ vpic->picture_type = VAEncPictureTypeBidirectional;
+- vpic->forward_reference_picture = pic->refs[0]->recon_surface;
+- vpic->backward_reference_picture = pic->refs[1]->recon_surface;
++ vpic->forward_reference_picture = pic->refs[0][0]->recon_surface;
++ vpic->backward_reference_picture = pic->refs[1][0]->recon_surface;
+ break;
+ default:
+ av_assert0(0 && "invalid picture type");
+diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c
+index ae6a8d3..b96e4cd 100644
+--- a/libavcodec/vaapi_encode_vp8.c
++++ b/libavcodec/vaapi_encode_vp8.c
+@@ -86,7 +86,7 @@ static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx,
+ switch (pic->type) {
+ case PICTURE_TYPE_IDR:
+ case PICTURE_TYPE_I:
+- av_assert0(pic->nb_refs == 0);
++ av_assert0(pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0);
+ vpic->ref_flags.bits.force_kf = 1;
+ vpic->ref_last_frame =
+ vpic->ref_gf_frame =
+@@ -94,14 +94,14 @@ static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx,
+ VA_INVALID_SURFACE;
+ break;
+ case PICTURE_TYPE_P:
+- av_assert0(pic->nb_refs == 1);
++ av_assert0(!pic->nb_refs[1]);
+ vpic->ref_flags.bits.no_ref_last = 0;
+ vpic->ref_flags.bits.no_ref_gf = 1;
+ vpic->ref_flags.bits.no_ref_arf = 1;
+ vpic->ref_last_frame =
+ vpic->ref_gf_frame =
+ vpic->ref_arf_frame =
+- pic->refs[0]->recon_surface;
++ pic->refs[0][0]->recon_surface;
+ break;
+ default:
+ av_assert0(0 && "invalid picture type");
+diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c
+index af1353c..d9e8ba6 100644
+--- a/libavcodec/vaapi_encode_vp9.c
++++ b/libavcodec/vaapi_encode_vp9.c
+@@ -96,15 +96,15 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
+
+ switch (pic->type) {
+ case PICTURE_TYPE_IDR:
+- av_assert0(pic->nb_refs == 0);
++ av_assert0(pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0);
+ vpic->ref_flags.bits.force_kf = 1;
+ vpic->refresh_frame_flags = 0xff;
+ hpic->slot = 0;
+ break;
+ case PICTURE_TYPE_P:
+- av_assert0(pic->nb_refs == 1);
++ av_assert0(!pic->nb_refs[1]);
+ {
+- VAAPIEncodeVP9Picture *href = pic->refs[0]->priv_data;
++ VAAPIEncodeVP9Picture *href = pic->refs[0][0]->priv_data;
+ av_assert0(href->slot == 0 || href->slot == 1);
+
+ if (ctx->max_b_depth > 0) {
+@@ -120,10 +120,10 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
+ }
+ break;
+ case PICTURE_TYPE_B:
+- av_assert0(pic->nb_refs == 2);
++ av_assert0(pic->nb_refs[0] && pic->nb_refs[1]);
+ {
+- VAAPIEncodeVP9Picture *href0 = pic->refs[0]->priv_data,
+- *href1 = pic->refs[1]->priv_data;
++ VAAPIEncodeVP9Picture *href0 = pic->refs[0][0]->priv_data,
++ *href1 = pic->refs[1][0]->priv_data;
+ av_assert0(href0->slot < pic->b_depth + 1 &&
+ href1->slot < pic->b_depth + 1);
+
+@@ -157,12 +157,14 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
+ for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++)
+ vpic->reference_frames[i] = VA_INVALID_SURFACE;
+
+- for (i = 0; i < pic->nb_refs; i++) {
+- VAAPIEncodePicture *ref_pic = pic->refs[i];
+- int slot;
+- slot = ((VAAPIEncodeVP9Picture*)ref_pic->priv_data)->slot;
+- av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE);
+- vpic->reference_frames[slot] = ref_pic->recon_surface;
++ for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) {
++ for (int j = 0; j < pic->nb_refs[i]; j++) {
++ VAAPIEncodePicture *ref_pic = pic->refs[i][j];
++ int slot;
++ slot = ((VAAPIEncodeVP9Picture*)ref_pic->priv_data)->slot;
++ av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE);
++ vpic->reference_frames[slot] = ref_pic->recon_surface;
++ }
+ }
+
+ vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR);
+--
+2.41.0
+
diff --git a/ffmpeg.spec b/ffmpeg.spec
index 3534b45..f3c8ade 100644
--- a/ffmpeg.spec
+++ b/ffmpeg.spec
@@ -112,7 +112,7 @@ ExclusiveArch: armv7hnl
Summary: Digital VCR and streaming server
Name: ffmpeg%{?flavor}
Version: 6.0.1
-Release: 2%{?date:.%{?date}%{?date:git}%{?rel}}%{?dist}
+Release: 3%{?date:.%{?date}%{?date:git}%{?rel}}%{?dist}
License: %{ffmpeg_license}
URL: https://ffmpeg.org/
%if 0%{?date}
@@ -129,6 +129,14 @@ Patch1: 0001-avfilter-vf_libplacebo-remove-deprecated-field.patch
Patch2: 0001-fftools-ffmpeg_filter-initialize-the-o-to-silence-th.patch
# We don't endorse adding this patch but fedora insists on breaking the ffmpeg ABI
Patch3: ffmpeg-chromium.patch
+# Backport AV1 VA-API encode support
+# Adapted from: https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=9594
+Patch4: ffmpeg-ge-av1-vaapi-encode-support.patch
+# Backport patches for enhanced rtmp support
+# Cf. https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=8926
+# From: https://patchwork.ffmpeg.org/series/8926/mbox/
+Patch5: FFmpeg-devel-v10-Support-enhanced-flv-in-FFmpeg.patch
+
Conflicts: %{name}-free
Provides: %{name}-bin = %{version}-%{release}
Requires: %{name}-libs%{?_isa} = %{version}-%{release}
@@ -770,7 +778,7 @@ strip %{buildroot}%{_libdir}/%{name}/libavcodec.so.*
- Revert last commit
* Sat Oct 10 2020 Leigh Scott <leigh123linux(a)gmail.com> - 4.3.1-10
-- Add VP9 10/12 Bit support for VDPAU
+- Add VP9 10/12 Bit support for VDPAU
* Tue Aug 18 2020 Leigh Scott <leigh123linux(a)gmail.com> - 4.3.1-9
- Disable vulkan on i686
@@ -884,7 +892,7 @@ strip %{buildroot}%{_libdir}/%{name}/libavcodec.so.*
- Enable vulkan support
* Sat Feb 22 2020 Leigh Scott <leigh123linux(a)googlemail.com> - 4.3-0.1.20200222git
-- Update to 20200222git
+- Update to 20200222git
* Tue Feb 04 2020 RPM Fusion Release Engineering <leigh123linux(a)gmail.com> - 4.2.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
1 year