From: stevenliu via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: stevenliu <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PR] add vvc codec into enhanced flv format (PR #21658)
Date: Fri, 06 Feb 2026 03:35:23 -0000
Message-ID: <177034892667.25.8396930072792832614@4457048688e7> (raw)
PR #21658 opened by stevenliu
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21658
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21658.patch
reference document:
https://github.com/veovera/enhanced-rtmp/blob/docs/vvc/docs/enhanced/enhanced-rtmp-v2.md
>From 62ad91205e82c16fc0c4a49c6a85d1307930c196 Mon Sep 17 00:00:00 2001
From: Steven Liu <lq@chinaffmpeg.org>
Date: Wed, 4 Feb 2026 18:09:06 +0800
Subject: [PATCH 1/3] avformat/flvenc: support mux vvc in enhanced flv
---
libavformat/flvenc.c | 38 ++++++++++++++++++++++++++++----------
1 file changed, 28 insertions(+), 10 deletions(-)
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index a0503c1799..37d0ae6528 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -33,6 +33,7 @@
#include "av1.h"
#include "vpcc.h"
#include "hevc.h"
+#include "vvc.h"
#include "avformat.h"
#include "flv.h"
#include "internal.h"
@@ -53,6 +54,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_VVC, MKBETAG('v', '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 }
@@ -520,6 +522,9 @@ static void write_codec_fourcc(AVIOContext *pb, enum AVCodecID codec_id)
case AV_CODEC_ID_HEVC:
avio_write(pb, "hvc1", 4);
return;
+ case AV_CODEC_ID_VVC:
+ avio_write(pb, "vvc1", 4);
+ return;
case AV_CODEC_ID_AV1:
avio_write(pb, "av01", 4);
return;
@@ -546,7 +551,7 @@ static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par
return;
if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
- par->codec_id == AV_CODEC_ID_VP9) {
+ par->codec_id == AV_CODEC_ID_VP9 || par->codec_id == AV_CODEC_ID_VVC) {
int flags_size = 5;
side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
@@ -807,6 +812,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_VP9
+ || par->codec_id == AV_CODEC_ID_VVC
|| (par->codec_id == AV_CODEC_ID_MP3 && track_idx)
|| par->codec_id == AV_CODEC_ID_OPUS || par->codec_id == AV_CODEC_ID_FLAC
|| par->codec_id == AV_CODEC_ID_AC3 || par->codec_id == AV_CODEC_ID_EAC3) {
@@ -855,6 +861,7 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
// If video stream has track_idx > 0 we need to send H.264 as extended video packet
extended_flv = (par->codec_id == AV_CODEC_ID_H264 && track_idx) ||
par->codec_id == AV_CODEC_ID_HEVC ||
+ par->codec_id == AV_CODEC_ID_VVC ||
par->codec_id == AV_CODEC_ID_AV1 ||
par->codec_id == AV_CODEC_ID_VP9;
@@ -878,6 +885,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, s);
+ else if (par->codec_id == AV_CODEC_ID_VVC)
+ ff_isom_write_vvcc(pb, par->extradata, par->extradata_size, 1);
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)
@@ -980,7 +989,8 @@ static int flv_init(struct AVFormatContext *s)
par->codec_id != AV_CODEC_ID_VP9 &&
par->codec_id != AV_CODEC_ID_AV1 &&
par->codec_id != AV_CODEC_ID_H264 &&
- par->codec_id != AV_CODEC_ID_HEVC) {
+ par->codec_id != AV_CODEC_ID_HEVC &&
+ par->codec_id != AV_CODEC_ID_VVC) {
av_log(s, AV_LOG_ERROR, "Unsupported multi-track video codec.\n");
return AVERROR(EINVAL);
}
@@ -1222,7 +1232,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
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_VP9)
+ par->codec_id == AV_CODEC_ID_VP9 || par->codec_id == AV_CODEC_ID_VVC)
flags_size = 5;
else
flags_size = 1;
@@ -1230,13 +1240,14 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
if ((par->codec_type == AVMEDIA_TYPE_VIDEO || par->codec_type == AVMEDIA_TYPE_AUDIO) && track_idx)
flags_size += 2; // additional header bytes for multi-track flv
- if ((par->codec_id == AV_CODEC_ID_HEVC ||
+ if ((par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_VVC ||
(par->codec_id == AV_CODEC_ID_H264 && track_idx))
&& pkt->pts != pkt->dts)
flags_size += 3;
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_VVC
|| par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9
|| par->codec_id == AV_CODEC_ID_OPUS || par->codec_id == AV_CODEC_ID_FLAC) {
size_t side_size;
@@ -1260,8 +1271,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_VP9) {
+ par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
+ par->codec_id == AV_CODEC_ID_VP9 || par->codec_id == AV_CODEC_ID_VVC) {
if (pkt->pts == AV_NOPTS_VALUE) {
av_log(s, AV_LOG_ERROR, "Packet is missing PTS\n");
return AVERROR(EINVAL);
@@ -1308,6 +1319,10 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
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_VVC) {
+ if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1)
+ if ((ret = ff_vvc_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) {
@@ -1370,15 +1385,17 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
} else {
int extended_video = (par->codec_id == AV_CODEC_ID_H264 && track_idx) ||
par->codec_id == AV_CODEC_ID_HEVC ||
+ par->codec_id == AV_CODEC_ID_VVC ||
par->codec_id == AV_CODEC_ID_AV1 ||
par->codec_id == AV_CODEC_ID_VP9;
if (extended_video) {
- int h2645 = par->codec_id == AV_CODEC_ID_H264 ||
+ int h26456 = par->codec_id == AV_CODEC_ID_H264 ||
+ par->codec_id == AV_CODEC_ID_VVC ||
par->codec_id == AV_CODEC_ID_HEVC;
int pkttype = PacketTypeCodedFrames;
- // Optimisation for HEVC/H264: Do not send composition time if DTS == PTS
- if (h2645 && pkt->pts == pkt->dts)
+ // Optimisation for VVC/HEVC/H264: Do not send composition time if DTS == PTS
+ if (h26456 && pkt->pts == pkt->dts)
pkttype = PacketTypeCodedFramesX;
if (track_idx) {
@@ -1392,7 +1409,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
if (track_idx)
avio_w8(pb, track_idx);
- if (h2645 && pkttype == PacketTypeCodedFrames)
+ if (h26456 && pkttype == PacketTypeCodedFrames)
avio_wb24(pb, pkt->pts - pkt->dts);
} else if (extended_audio) {
if (track_idx) {
@@ -1476,6 +1493,7 @@ static int flv_check_bitstream(AVFormatContext *s, AVStream *st,
if (!st->codecpar->extradata_size &&
(st->codecpar->codec_id == AV_CODEC_ID_H264 ||
st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
+ st->codecpar->codec_id == AV_CODEC_ID_VVC ||
st->codecpar->codec_id == AV_CODEC_ID_AV1 ||
st->codecpar->codec_id == AV_CODEC_ID_MPEG4))
return ff_stream_add_bitstream_filter(st, "extract_extradata", NULL);
--
2.52.0
>From 24ba0578ba5d0722d659afc9591076ddb7cda705 Mon Sep 17 00:00:00 2001
From: Steven Liu <lq@chinaffmpeg.org>
Date: Wed, 4 Feb 2026 18:09:51 +0800
Subject: [PATCH 2/3] avformat/flvdec: support demux vvc in enhanced flv
---
libavformat/flvdec.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index c75345d882..81374d6d7f 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -386,6 +386,8 @@ static int flv_same_video_codec(AVCodecParameters *vpar, uint32_t flv_codecid)
return 1;
switch (flv_codecid) {
+ case MKBETAG('v', 'v', 'c', '1'):
+ return vpar->codec_id == AV_CODEC_ID_VVC;
case FLV_CODECID_X_HEVC:
case MKBETAG('h', 'v', 'c', '1'):
return vpar->codec_id == AV_CODEC_ID_HEVC;
@@ -420,6 +422,10 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
enum AVCodecID old_codec_id = vstream->codecpar->codec_id;
switch (flv_codecid) {
+ case MKBETAG('v', 'v', 'c', '1'):
+ par->codec_id = AV_CODEC_ID_VVC;
+ vstreami->need_parsing = AVSTREAM_PARSE_HEADERS;
+ break;
case FLV_CODECID_X_HEVC:
case MKBETAG('h', 'v', 'c', '1'):
par->codec_id = AV_CODEC_ID_HEVC;
@@ -1731,6 +1737,7 @@ 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_VVC ||
st->codecpar->codec_id == AV_CODEC_ID_AV1 ||
st->codecpar->codec_id == AV_CODEC_ID_VP9) {
int type = 0;
@@ -1754,7 +1761,9 @@ retry_duration:
}
if (st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
- ((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_VVC ||
+ st->codecpar->codec_id == AV_CODEC_ID_HEVC) &&
(!enhanced_flv || type == PacketTypeCodedFrames))) {
// sign extension
int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
@@ -1775,6 +1784,7 @@ retry_duration:
if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
st->codecpar->codec_id == AV_CODEC_ID_OPUS || st->codecpar->codec_id == AV_CODEC_ID_FLAC ||
st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
+ st->codecpar->codec_id == AV_CODEC_ID_VVC ||
st->codecpar->codec_id == AV_CODEC_ID_AV1 || st->codecpar->codec_id == AV_CODEC_ID_VP9)) {
AVDictionaryEntry *t;
--
2.52.0
>From 604e89b7576a45bb3afd9df3085979126398093f Mon Sep 17 00:00:00 2001
From: Steven Liu <lq@chinaffmpeg.org>
Date: Wed, 4 Feb 2026 18:14:53 +0800
Subject: [PATCH 3/3] avformat/rtmpproto: add vvc1 string into enhanced_codecs
list
---
libavformat/rtmpproto.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index b029c57621..d4c9047266 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -362,7 +362,7 @@ static int gen_connect(URLContext *s, RTMPContext *rt)
// check the string, fourcc + ',' + ... + end fourcc correct length should be (4+1)*n+4
if ((fourcc_str_len + 1) % 5 != 0) {
av_log(s, AV_LOG_ERROR, "Malformed rtmp_enhanched_codecs, "
- "should be of the form hvc1[,av01][,vp09][,...]\n");
+ "should be of the form hvc1[,av01][,vp09][,vvc1][,...]\n");
ff_rtmp_packet_destroy(&pkt);
return AVERROR(EINVAL);
}
@@ -379,6 +379,7 @@ static int gen_connect(URLContext *s, RTMPContext *rt)
!strncmp(fourcc_data, "ec-3", 4) ||
!strncmp(fourcc_data, "fLaC", 4) ||
!strncmp(fourcc_data, "hvc1", 4) ||
+ !strncmp(fourcc_data, "vvc1", 4) ||
!strncmp(fourcc_data, ".mp3", 4) ||
!strncmp(fourcc_data, "mp4a", 4) ||
!strncmp(fourcc_data, "Opus", 4) ||
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
reply other threads:[~2026-02-06 3:36 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=177034892667.25.8396930072792832614@4457048688e7 \
--to=ffmpeg-devel@ffmpeg.org \
--cc=code@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git