From c7864a998720d00c9977bd66fc39c6585f6c2fbf Mon Sep 17 00:00:00 2001 From: Nuo Mi Date: Tue, 21 Mar 2023 16:01:17 +0100 Subject: [PATCH] avcodec: add Metadata bsf for H266/VVC Add H.266/VVC metadata bsf. Signed-off-by: James Almer --- Changelog | 1 + configure | 1 + libavcodec/Makefile | 1 + libavcodec/bitstream_filters.c | 1 + libavcodec/h266_metadata_bsf.c | 149 +++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+) create mode 100644 libavcodec/h266_metadata_bsf.c diff --git a/Changelog b/Changelog index e9cbce7e1c..7974413627 100644 --- a/Changelog +++ b/Changelog @@ -23,6 +23,7 @@ version : - Microsoft RLE video encoder - Raw AC-4 muxer and demuxer - Raw VVC bitstream parser +- Bitstream filter for editing metadata in VVC streams version 6.0: - Radiance HDR image support diff --git a/configure b/configure index 10d12770d6..107d533b3e 100755 --- a/configure +++ b/configure @@ -3352,6 +3352,7 @@ mjpeg2jpeg_bsf_select="jpegtables" mpeg2_metadata_bsf_select="cbs_mpeg2" trace_headers_bsf_select="cbs" vp9_metadata_bsf_select="cbs_vp9" +vvc_metadata_bsf_select="cbs_h266" # external libraries aac_at_decoder_deps="audiotoolbox" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index b915464b90..6faa47d1cb 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1261,6 +1261,7 @@ OBJS-$(CONFIG_VP9_METADATA_BSF) += vp9_metadata_bsf.o OBJS-$(CONFIG_VP9_RAW_REORDER_BSF) += vp9_raw_reorder_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_SPLIT_BSF) += vp9_superframe_split_bsf.o +OBJS-$(CONFIG_VVC_METADATA_BSF) += h266_metadata_bsf.o OBJS-$(CONFIG_EVC_FRAME_MERGE_BSF) += evc_frame_merge_bsf.o # thread libraries diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index 7512fccc78..0d3f52260e 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -65,6 +65,7 @@ extern const FFBitStreamFilter ff_vp9_metadata_bsf; extern const FFBitStreamFilter ff_vp9_raw_reorder_bsf; extern const FFBitStreamFilter ff_vp9_superframe_bsf; extern const FFBitStreamFilter ff_vp9_superframe_split_bsf; +extern const FFBitStreamFilter ff_vvc_metadata_bsf; extern const FFBitStreamFilter ff_evc_frame_merge_bsf; #include "libavcodec/bsf_list.c" diff --git a/libavcodec/h266_metadata_bsf.c b/libavcodec/h266_metadata_bsf.c new file mode 100644 index 0000000000..18fa1a5c9c --- /dev/null +++ b/libavcodec/h266_metadata_bsf.c @@ -0,0 +1,149 @@ +/* + * 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 "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "bsf_internal.h" +#include "cbs.h" +#include "cbs_bsf.h" +#include "cbs_h266.h" +#include "vvc.h" + +#define IS_H266_SLICE(nut) (nut <= VVC_RASL_NUT || (nut >= VVC_IDR_W_RADL && nut <= VVC_GDR_NUT)) + +typedef struct H266MetadataContext { + CBSBSFContext common; + + H266RawAUD aud_nal; + + int aud; +} H266MetadataContext; + +static int h266_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt, + CodedBitstreamFragment *pu) +{ + H266MetadataContext *ctx = bsf->priv_data; + int err, i; + + // If an AUD is present, it must be the first NAL unit. + if (pu->units[0].type == VVC_AUD_NUT) { + if (ctx->aud == BSF_ELEMENT_REMOVE) + ff_cbs_delete_unit(pu, 0); + } else if ( pkt && ctx->aud == BSF_ELEMENT_INSERT) { + const H266RawSlice *first_slice = NULL; + const H266RawPH *ph = NULL; + H266RawAUD *aud = &ctx->aud_nal; + int pic_type = 0, temporal_id = 8, layer_id = 0; + for (i = 0; i < pu->nb_units; i++) { + const H266RawNALUnitHeader *nal = pu->units[i].content; + if (!nal) + continue; + if (nal->nuh_temporal_id_plus1 < temporal_id + 1) + temporal_id = nal->nuh_temporal_id_plus1 - 1; + if ( nal->nal_unit_type == VVC_PH_NUT ) { + ph = pu->units[i].content; + } else if (IS_H266_SLICE(nal->nal_unit_type)) { + const H266RawSlice *slice = pu->units[i].content; + layer_id = nal->nuh_layer_id; + if (slice->header.sh_slice_type == VVC_SLICE_TYPE_B && + pic_type < 2) + pic_type = 2; + if (slice->header.sh_slice_type == VVC_SLICE_TYPE_P && + pic_type < 1) + pic_type = 1; + if (!first_slice) { + first_slice = slice; + if (first_slice->header. + sh_picture_header_in_slice_header_flag) + ph = &first_slice->header.sh_picture_header; + else if (!ph) + break; + } + } + } + if (!ph) { + av_log(bsf, AV_LOG_ERROR, "no avaliable picture header"); + return AVERROR_INVALIDDATA; + } + + aud->nal_unit_header = (H266RawNALUnitHeader) { + .nal_unit_type = VVC_AUD_NUT, + .nuh_layer_id = layer_id, + .nuh_temporal_id_plus1 = temporal_id + 1, + }; + aud->aud_pic_type = pic_type; + aud->aud_irap_or_gdr_flag = ph->ph_gdr_or_irap_pic_flag; + + err = ff_cbs_insert_unit_content(pu, 0, VVC_AUD_NUT, aud, NULL); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n"); + return err; + } + } + + /* TODO: implement more metadata parsing, like VUI, Levels etc. */ + //for (i = 0; i < pu->nb_units; i++) { + // if (pu->units[i].type == VVC_SPS_NUT) { + // } + //} + return 0; +} + +static const CBSBSFType h266_metadata_type = { + .codec_id = AV_CODEC_ID_VVC, + .fragment_name = "access unit", + .unit_name = "NAL unit", + .update_fragment = &h266_metadata_update_fragment, +}; + +static int h266_metadata_init(AVBSFContext *bsf) +{ + return ff_cbs_bsf_generic_init(bsf, &h266_metadata_type); +} + +#define OFFSET(x) offsetof(H266MetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption h266_metadata_options[] = { + BSF_ELEMENT_OPTIONS_PIR("aud", "Access Unit Delimiter NAL units", + aud, FLAGS), + + { NULL } +}; + +static const AVClass h266_metadata_class = { + .class_name = "h266_metadata_bsf", + .item_name = av_default_item_name, + .option = h266_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID h266_metadata_codec_ids[] = { + AV_CODEC_ID_VVC, AV_CODEC_ID_NONE, +}; + +const FFBitStreamFilter ff_vvc_metadata_bsf = { + .p.name = "vvc_metadata", + .p.codec_ids = h266_metadata_codec_ids, + .p.priv_class = &h266_metadata_class, + .priv_data_size = sizeof(H266MetadataContext), + .init = &h266_metadata_init, + .close = &ff_cbs_bsf_generic_close, + .filter = &ff_cbs_bsf_generic_filter, +};