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 +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: +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 ; 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 +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: + + <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 +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Reply-To: FFmpeg development discussions and patches +Cc: Steven Liu +Errors-To: ffmpeg-devel-bounces@ffmpeg.org +Sender: "ffmpeg-devel" +X-TUID: WUhHC4/dXuk+ + +Signed-off-by: Steven Liu +--- + 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 +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: +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 ; 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 +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: + + <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 +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Reply-To: FFmpeg development discussions and patches +Cc: Steven Liu +Errors-To: ffmpeg-devel-bounces@ffmpeg.org +Sender: "ffmpeg-devel" +X-TUID: SFsjHMHu2ISl + +Signed-off-by: Steven Liu +--- + 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 +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: +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 ; 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 +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: + + <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 +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Reply-To: FFmpeg development discussions and patches +Cc: Steven Liu +Errors-To: ffmpeg-devel-bounces@ffmpeg.org +Sender: "ffmpeg-devel" +X-TUID: dRfPdsIvexzh + +Signed-off-by: Steven Liu +--- + 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 +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: +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 ; 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 +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: + + <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 +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Reply-To: FFmpeg development discussions and patches +Cc: Steven Liu +Errors-To: ffmpeg-devel-bounces@ffmpeg.org +Sender: "ffmpeg-devel" +X-TUID: MKqjViniwIy+ + +Signed-off-by: Steven Liu +--- + 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 +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: +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 ; 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 +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: + + <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 +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Reply-To: FFmpeg development discussions and patches +Cc: Steven Liu +Errors-To: ffmpeg-devel-bounces@ffmpeg.org +Sender: "ffmpeg-devel" +X-TUID: appcyLUJeeFW + +Signed-off-by: Steven Liu +--- + 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 +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: +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 ; 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 +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: + + <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 +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Reply-To: FFmpeg development discussions and patches +Cc: Steven Liu +Errors-To: ffmpeg-devel-bounces@ffmpeg.org +Sender: "ffmpeg-devel" +X-TUID: wOtvTzk+zhdw + +Signed-off-by: Steven Liu +--- + 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 +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 ++#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 ++ ++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 ++#include ++ ++#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 - 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 - 6.0-15 - Backport upstream patch to fix segfault when passing non-existent filter option (rfbz#6773)