[FFmpeg-devel] [PATCH v1 2/5] avformat: add muxer support for H266/VVC
Thomas Siedel
thomas.ff at spin-digital.com
Fri Jan 26 16:11:31 EET 2024
On Fri, 5 Jan 2024 at 01:31, James Almer <jamrial at gmail.com> wrote:
> On 11/3/2023 6:57 AM, Thomas Siedel wrote:
> > Add muxer for vvcc byte stream format.
> > Add AV_CODEC_ID_VVC to ff_mp4_obj_type.
> > Add AV_CODEC_ID_VVC to ISO Media codec (VvcConfigurationBox vvi1,
> > vvc1 defined in ISO/IEC 14496-15:2021).
> > Add VvcConfigurationBox vvcC which extends FullBox type in
> > ISO/IEC 14496-15:2021.
> > Add ff_vvc_muxer to RAW muxers.
> >
> > Signed-off-by: Thomas Siedel <thomas.ff at spin-digital.com>
> > ---
> > libavformat/Makefile | 6 +-
> > libavformat/isom.c | 1 +
> > libavformat/isom_tags.c | 3 +
> > libavformat/mov.c | 6 +
> > libavformat/movenc.c | 41 +-
> > libavformat/vvc.c | 998 ++++++++++++++++++++++++++++++++++++++++
> > libavformat/vvc.h | 99 ++++
> > 7 files changed, 1150 insertions(+), 4 deletions(-)
> > create mode 100644 libavformat/vvc.c
> > create mode 100644 libavformat/vvc.h
> >
> > diff --git a/libavformat/Makefile b/libavformat/Makefile
> > index 329055ccfd..595f6bdf08 100644
> > --- a/libavformat/Makefile
> > +++ b/libavformat/Makefile
> > @@ -341,7 +341,7 @@ OBJS-$(CONFIG_MATROSKA_DEMUXER) +=
> matroskadec.o matroska.o \
> > oggparsevorbis.o
> vorbiscomment.o \
> > qtpalette.o replaygain.o
> dovi_isom.o
> > OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \
> > - av1.o avc.o hevc.o \
> > + av1.o avc.o hevc.o vvc.o\
> > flacenc_header.o
> avlanguage.o \
> > vorbiscomment.o wv.o
> dovi_isom.o
> > OBJS-$(CONFIG_MCA_DEMUXER) += mca.o
> > @@ -363,7 +363,7 @@ OBJS-$(CONFIG_MODS_DEMUXER) += mods.o
> > OBJS-$(CONFIG_MOFLEX_DEMUXER) += moflex.o
> > OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o
> mov_esds.o \
> > qtpalette.o replaygain.o
> dovi_isom.o
> > -OBJS-$(CONFIG_MOV_MUXER) += movenc.o av1.o avc.o hevc.o
> vpcc.o \
> > +OBJS-$(CONFIG_MOV_MUXER) += movenc.o av1.o avc.o hevc.o
> vvc.o vpcc.o \
> > movenchint.o mov_chan.o
> rtp.o \
> > movenccenc.o movenc_ttml.o
> rawutils.o \
> > dovi_isom.o evc.o
> > @@ -516,7 +516,7 @@ OBJS-$(CONFIG_RTP_MUXER) += rtp.o
> \
> > rtpenc_vp8.o \
> > rtpenc_vp9.o
> \
> > rtpenc_xiph.o \
> > - avc.o hevc.o
> > + avc.o hevc.o vvc.o
> > OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o rtspdec.o
> httpauth.o \
> > urldecode.o
> > OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o
> httpauth.o \
> > diff --git a/libavformat/isom.c b/libavformat/isom.c
> > index 6d019881e5..9fbccd4437 100644
> > --- a/libavformat/isom.c
> > +++ b/libavformat/isom.c
> > @@ -36,6 +36,7 @@ const AVCodecTag ff_mp4_obj_type[] = {
> > { AV_CODEC_ID_MPEG4 , 0x20 },
> > { AV_CODEC_ID_H264 , 0x21 },
> > { AV_CODEC_ID_HEVC , 0x23 },
> > + { AV_CODEC_ID_VVC , 0x33 },
> > { AV_CODEC_ID_AAC , 0x40 },
> > { AV_CODEC_ID_MP4ALS , 0x40 }, /* 14496-3 ALS */
> > { AV_CODEC_ID_MPEG2VIDEO , 0x61 }, /* MPEG-2 Main */
> > diff --git a/libavformat/isom_tags.c b/libavformat/isom_tags.c
> > index a575b7c160..705811e950 100644
> > --- a/libavformat/isom_tags.c
> > +++ b/libavformat/isom_tags.c
> > @@ -123,6 +123,9 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
> > { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', 'e') }, /* HEVC-based
> Dolby Vision derived from hev1 */
> > /* dvh1 is
> handled within mov.c */
> >
> > + { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') }, /* VVC/H.266 which
> indicates parameter sets may be in ES */
> > + { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') }, /* VVC/H.266 which
> indicates parameter shall not be in ES */
> > +
> > { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, /* AVC-1/H.264 */
> > { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '2') },
> > { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
> > diff --git a/libavformat/mov.c b/libavformat/mov.c
> > index e8efccf6eb..11b43ac135 100644
> > --- a/libavformat/mov.c
> > +++ b/libavformat/mov.c
> > @@ -2117,6 +2117,11 @@ static int mov_read_glbl(MOVContext *c,
> AVIOContext *pb, MOVAtom atom)
> > if ((uint64_t)atom.size > (1<<30))
> > return AVERROR_INVALIDDATA;
> >
> > + if (atom.type == MKTAG('v','v','c','C')) {
> > + avio_rb32(pb);
>
> avio_skip(pb, 4);
>
> > + atom.size -= 4;
> > + }
> > +
> > if (atom.size >= 10) {
> > // Broken files created by legacy versions of libavformat will
> > // wrap a whole fiel atom inside of a glbl atom.
> > @@ -7921,6 +7926,7 @@ static const MOVParseTableEntry
> mov_default_parse_table[] = {
> > { MKTAG('s','g','p','d'), mov_read_sgpd },
> > { MKTAG('s','b','g','p'), mov_read_sbgp },
> > { MKTAG('h','v','c','C'), mov_read_glbl },
> > +{ MKTAG('v','v','c','C'), mov_read_glbl },
> > { MKTAG('u','u','i','d'), mov_read_uuid },
> > { MKTAG('C','i','n', 0x8e), mov_read_targa_y216 },
> > { MKTAG('f','r','e','e'), mov_read_free },
> > diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> > index e39f1ac987..093a04d0c2 100644
> > --- a/libavformat/movenc.c
> > +++ b/libavformat/movenc.c
> > @@ -68,6 +68,7 @@
> > #include "ttmlenc.h"
> > #include "version.h"
> > #include "vpcc.h"
> > +#include "vvc.h"
> >
> > static const AVOption options[] = {
> > { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags),
> AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX,
> AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
> > @@ -1473,6 +1474,23 @@ static int mov_write_evcc_tag(AVIOContext *pb,
> MOVTrack *track)
> > return update_size(pb, pos);
> > }
> >
> > +static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
> > +{
> > + int64_t pos = avio_tell(pb);
> > +
> > + avio_wb32(pb, 0);
> > + ffio_wfourcc(pb, "vvcC");
> > +
> > + avio_w8 (pb, 0); /* version */
> > + avio_wb24(pb, 0); /* flags */
>
> Is it really a fullbox? I find it odd considering h264 and h265 don't.
>
Yes it is. spec: ISO/IEC 14496-15:2021(E)
Information technology — Coding of audio-visual objects — Part 15:
Carriage of network abstraction layer (NAL) unit structured video in the
ISO base media file format
11.2.4.3.1 Definition
This subclause specifies VvcConfigurationBox that carries a VVC decoder
configuration record.
This box derives from FullBox and hence contains a version field. This
version of the specification defines version 0 of this box.
Incompatible changes to the box will be indicated by a change of version
number.
Readers shall not attempt to decode this box or the referenced CVSs if
the version number is unrecognized.
>
> > +
> > + if (track->tag == MKTAG('v','v','c','1'))
> > + ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 1);
> > + else
> > + ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 0);
> > + return update_size(pb, pos);
> > +}
> > +
> > /* also used by all avid codecs (dv, imx, meridien) and their variants
> */
> > static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
> > {
> > @@ -2382,6 +2400,8 @@ static int mov_write_video_tag(AVFormatContext *s,
> AVIOContext *pb, MOVMuxContex
> > avid = 1;
> > } else if (track->par->codec_id == AV_CODEC_ID_HEVC)
> > mov_write_hvcc_tag(pb, track);
> > + else if (track->par->codec_id == AV_CODEC_ID_VVC)
> > + mov_write_vvcc_tag(pb, track);
> > else if (track->par->codec_id == AV_CODEC_ID_H264 &&
> !TAG_IS_AVCI(track->tag)) {
> > mov_write_avcc_tag(pb, track);
> > if (track->mode == MODE_IPOD)
> > @@ -6170,6 +6190,7 @@ int ff_mov_write_packet(AVFormatContext *s,
> AVPacket *pkt)
> > if ((par->codec_id == AV_CODEC_ID_DNXHD ||
> > par->codec_id == AV_CODEC_ID_H264 ||
> > par->codec_id == AV_CODEC_ID_HEVC ||
> > + par->codec_id == AV_CODEC_ID_VVC ||
> > par->codec_id == AV_CODEC_ID_VP9 ||
> > par->codec_id == AV_CODEC_ID_EVC ||
> > par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->vos_len &&
> > @@ -6235,6 +6256,18 @@ int ff_mov_write_packet(AVFormatContext *s,
> AVPacket *pkt)
> > size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, 0,
> NULL);
> > }
> > }
> > + } else if (par->codec_id == AV_CODEC_ID_VVC && trk->vos_len > 6 &&
> > + (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) ==
> 1)) {
> > + /* extradata is Annex B, assume the bitstream is too and convert
> it */
> > + if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) {
> > + ret = ff_h266_annexb2mp4_buf(pkt->data, &reformatted_data,
> > + &size, 0, NULL);
> > + if (ret < 0)
> > + return ret;
> > + avio_write(pb, reformatted_data, size);
> > + } else {
> > + size = ff_h266_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
> > + }
> > } else if (par->codec_id == AV_CODEC_ID_AV1) {
> > if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams)
> {
> > ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
> > @@ -6281,6 +6314,9 @@ int ff_mov_write_packet(AVFormatContext *s,
> AVPacket *pkt)
> > } else if(par->codec_id == AV_CODEC_ID_HEVC &&
> par->extradata_size > 21) {
> > int nal_size_length = (par->extradata[21] & 0x3) + 1;
> > ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc,
> nal_size_length, pb, pkt->data, size);
> > + } else if(par->codec_id == AV_CODEC_ID_VVC &&
> par->extradata_size > 21) {
> > + int nal_size_length = (par->extradata[21] & 0x3) + 1;
>
> Is this really at the exact same offset as in hevc?
>
Thank you for catching this, it should be
int nal_size_length = ((par->extradata[4]>>1) & 0x3) + 1;
More information about the ffmpeg-devel
mailing list