public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/ffmpeg] epel9-next: Add patches to support enhanced RTMP and AV1 encoding through VA-API
@ 2026-07-20 17:31 Neal Gompa
  0 siblings, 0 replies; only message in thread
From: Neal Gompa @ 2026-07-20 17:31 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/ffmpeg
            Branch : epel9-next
            Commit : d30a3b67b3683d62ac44a073e0cc730e4089fb1d
            Author : Neal Gompa <ngompa@fedoraproject.org>
            Date   : 2023-11-10T07:13:31-05:00
            Stats  : +5230/-2 in 5 file(s)
            URL    : https://src.fedoraproject.org/rpms/ffmpeg/c/d30a3b67b3683d62ac44a073e0cc730e4089fb1d?branch=epel9-next

            Log:
            Add patches to support enhanced RTMP and AV1 encoding through VA-API

- Force AAC decoding through fdk-aac-free

---
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@chinaffmpeg.org>
+X-Patchwork-Id: 41615
+Delivered-To: ffmpegpatchwork2@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces@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@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@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@ffmpeg.org
+Delivered-To: ffmpeg-devel@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@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@chinaffmpeg.org>
+To: ffmpeg-devel@ffmpeg.org
+Date: Mon, 15 May 2023 16:31:56 +0800
+Message-Id: <20230515083201.48201-2-lq@chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq@chinaffmpeg.org>
+References: 
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ@mail.gmail.com>
+ <20230515083201.48201-1-lq@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@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@ffmpeg.org>
+Cc: Steven Liu <lq@chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces@ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
+X-TUID: WUhHC4/dXuk+
+
+Signed-off-by: Steven Liu <lq@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@chinaffmpeg.org>
+X-Patchwork-Id: 41616
+Delivered-To: ffmpegpatchwork2@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces@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@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@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@ffmpeg.org
+Delivered-To: ffmpeg-devel@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@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@chinaffmpeg.org>
+To: ffmpeg-devel@ffmpeg.org
+Date: Mon, 15 May 2023 16:31:57 +0800
+Message-Id: <20230515083201.48201-3-lq@chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq@chinaffmpeg.org>
+References: 
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ@mail.gmail.com>
+ <20230515083201.48201-1-lq@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@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@ffmpeg.org>
+Cc: Steven Liu <lq@chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces@ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
+X-TUID: SFsjHMHu2ISl
+
+Signed-off-by: Steven Liu <lq@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@chinaffmpeg.org>
+X-Patchwork-Id: 41617
+Delivered-To: ffmpegpatchwork2@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces@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@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@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@ffmpeg.org
+Delivered-To: ffmpeg-devel@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@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@chinaffmpeg.org>
+To: ffmpeg-devel@ffmpeg.org
+Date: Mon, 15 May 2023 16:31:58 +0800
+Message-Id: <20230515083201.48201-4-lq@chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq@chinaffmpeg.org>
+References: 
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ@mail.gmail.com>
+ <20230515083201.48201-1-lq@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@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@ffmpeg.org>
+Cc: Steven Liu <lq@chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces@ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
+X-TUID: dRfPdsIvexzh
+
+Signed-off-by: Steven Liu <lq@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@chinaffmpeg.org>
+X-Patchwork-Id: 41618
+Delivered-To: ffmpegpatchwork2@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces@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@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@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@ffmpeg.org
+Delivered-To: ffmpeg-devel@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@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@chinaffmpeg.org>
+To: ffmpeg-devel@ffmpeg.org
+Date: Mon, 15 May 2023 16:31:59 +0800
+Message-Id: <20230515083201.48201-5-lq@chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq@chinaffmpeg.org>
+References: 
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ@mail.gmail.com>
+ <20230515083201.48201-1-lq@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@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@ffmpeg.org>
+Cc: Steven Liu <lq@chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces@ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
+X-TUID: MKqjViniwIy+
+
+Signed-off-by: Steven Liu <lq@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@chinaffmpeg.org>
+X-Patchwork-Id: 41619
+Delivered-To: ffmpegpatchwork2@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces@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@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@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@ffmpeg.org
+Delivered-To: ffmpeg-devel@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@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@chinaffmpeg.org>
+To: ffmpeg-devel@ffmpeg.org
+Date: Mon, 15 May 2023 16:32:00 +0800
+Message-Id: <20230515083201.48201-6-lq@chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq@chinaffmpeg.org>
+References: 
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ@mail.gmail.com>
+ <20230515083201.48201-1-lq@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@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@ffmpeg.org>
+Cc: Steven Liu <lq@chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces@ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
+X-TUID: appcyLUJeeFW
+
+Signed-off-by: Steven Liu <lq@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@chinaffmpeg.org>
+X-Patchwork-Id: 41620
+Delivered-To: ffmpegpatchwork2@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org
+Return-Path: <ffmpeg-devel-bounces@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@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@ffmpeg.org
+ designates 79.124.17.100 as permitted sender)
+ smtp.mailfrom=ffmpeg-devel-bounces@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@ffmpeg.org
+Delivered-To: ffmpeg-devel@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@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@chinaffmpeg.org>
+To: ffmpeg-devel@ffmpeg.org
+Date: Mon, 15 May 2023 16:32:01 +0800
+Message-Id: <20230515083201.48201-7-lq@chinaffmpeg.org>
+X-Mailer: git-send-email 2.40.0
+In-Reply-To: <20230515083201.48201-1-lq@chinaffmpeg.org>
+References: 
+ <CAEg-Je-vYD97KnbaqTkK5=UJ9T3htmtH3Qykcwo3+rNCx=w+jQ@mail.gmail.com>
+ <20230515083201.48201-1-lq@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@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@ffmpeg.org>
+Cc: Steven Liu <lq@chinaffmpeg.org>
+Errors-To: ffmpeg-devel-bounces@ffmpeg.org
+Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
+X-TUID: wOtvTzk+zhdw
+
+Signed-off-by: Steven Liu <lq@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/enable_decoders b/enable_decoders
index 296c3a3..ea1c38e 100644
--- a/enable_decoders
+++ b/enable_decoders
@@ -1,5 +1,4 @@
 ## module name # reason for enablement in ffmpeg (usually there is another package that already got legal review)
-aac
 aasc
 libfdk_aac # fdk-aac-free
 ac3

diff --git a/enable_encoders b/enable_encoders
index e0f3cfb..10dd53a 100644
--- a/enable_encoders
+++ b/enable_encoders
@@ -30,6 +30,7 @@ asv2
 av1_amf
 av1_nvenc
 av1_qsv
+av1_vaapi
 ayuv # trival
 bitpacked # trivial
 bmp # trivial

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@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 d68704b..4a20644 100644
--- a/ffmpeg.spec
+++ b/ffmpeg.spec
@@ -92,7 +92,7 @@ Name:           ffmpeg
 %global pkg_name %{name}%{?pkg_suffix}
 
 Version:        6.0
-Release:        15%{?dist}
+Release:        16%{?dist}
 Summary:        A complete solution to record, convert and stream audio and video
 License:        GPL-3.0-or-later
 URL:            https://ffmpeg.org/
@@ -129,6 +129,16 @@ Patch6:         0001-avcodec-x86-mathops-clip-constants-used-with-shift-i.patch
 # See: https://bugzilla.rpmfusion.org/show_bug.cgi?id=6773
 Patch7:         0001-fftools-ffmpeg_filter-initialize-the-o-to-silence-th.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/
+Patch8:         FFmpeg-devel-v10-Support-enhanced-flv-in-FFmpeg.patch
+
+# Backport AV1 VA-API encode support
+# Courtesy of GloriousEggroll
+## Adapted from: https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=9594
+Patch9:         ffmpeg-ge-av1-vaapi-encode-support.patch
+
 # Set up dlopen for openh264
 Patch1001:      ffmpeg-dlopen-openh264.patch
 
@@ -861,6 +871,10 @@ rm -rf %{buildroot}%{_datadir}/%{name}/examples
 %{_mandir}/man3/libswscale.3*
 
 %changelog
+* Fri Nov 10 2023 Neal Gompa <ngompa@fedoraproject.org> - 6.0-16
+- Add patches to support enhanced RTMP and AV1 encoding through VA-API
+- Force AAC decoding through fdk-aac-free
+
 * Sun Oct 08 2023 Dominik Mierzejewski <dominik@greysector.net> - 6.0-15
 - Backport upstream patch to fix segfault when passing non-existent filter
   option (rfbz#6773)

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-07-20 17:31 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-20 17:31 [rpms/ffmpeg] epel9-next: Add patches to support enhanced RTMP and AV1 encoding through VA-API Neal Gompa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox