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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 -- [email protected] To unsubscribe send an email to [email protected]
