From: Zhao Zhili <zhiliz...@tencent.com> For example, to extract alpha layer with nuh_layer_id equal to 1:
./ffmpeg -i alpha.mp4 \ -an -c:v copy \ -bsf:v hevc_extract_layer=nuh_layer_id=1 \ output.mp4 Signed-off-by: Zhao Zhili <zhiliz...@tencent.com> --- configure | 1 + doc/bitstream_filters.texi | 12 +++ libavcodec/Makefile | 1 + libavcodec/bitstream_filters.c | 1 + libavcodec/hevc_extract_layer_bsf.c | 126 ++++++++++++++++++++++++++++ libavcodec/version.h | 4 +- 6 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 libavcodec/hevc_extract_layer_bsf.c diff --git a/configure b/configure index 870d426b0e..a398b28790 100755 --- a/configure +++ b/configure @@ -3278,6 +3278,7 @@ filter_units_bsf_select="cbs" h264_metadata_bsf_deps="const_nan" h264_metadata_bsf_select="cbs_h264" h264_redundant_pps_bsf_select="cbs_h264" +hevc_extract_layer_bsf_select="cbs_h265" hevc_metadata_bsf_select="cbs_h265" mjpeg2jpeg_bsf_select="jpegtables" mpeg2_metadata_bsf_select="cbs_mpeg2" diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index c63c20370f..55ed8d91f9 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -382,6 +382,18 @@ This applies a specific fixup to some Blu-ray streams which contain redundant PPSs modifying irrelevant parameters of the stream which confuse other transformations which require correct extradata. +@section hevc_extract_layer + +Extract NALUs with the specified nuh_layer_id and rewrite as base +layer. Only works with INBL (independent non-base layer). + +@table @option + +@item nuh_layer_id +Which layer to extract. + +@end table + @section hevc_metadata Modify metadata embedded in an HEVC stream. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 3ab448dd49..f27d169741 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1208,6 +1208,7 @@ OBJS-$(CONFIG_H264_METADATA_BSF) += h264_metadata_bsf.o h264_levels.o \ OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF) += h264_mp4toannexb_bsf.o OBJS-$(CONFIG_H264_REDUNDANT_PPS_BSF) += h264_redundant_pps_bsf.o OBJS-$(CONFIG_HAPQA_EXTRACT_BSF) += hapqa_extract_bsf.o hap.o +OBJS-$(CONFIG_HEVC_EXTRACT_LAYER_BSF) += hevc_extract_layer_bsf.o OBJS-$(CONFIG_HEVC_METADATA_BSF) += h265_metadata_bsf.o h265_profile_level.o \ h2645data.o OBJS-$(CONFIG_HEVC_MP4TOANNEXB_BSF) += hevc_mp4toannexb_bsf.o diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index a3bebefe5f..ac013e8072 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -40,6 +40,7 @@ extern const FFBitStreamFilter ff_h264_metadata_bsf; extern const FFBitStreamFilter ff_h264_mp4toannexb_bsf; extern const FFBitStreamFilter ff_h264_redundant_pps_bsf; extern const FFBitStreamFilter ff_hapqa_extract_bsf; +extern const FFBitStreamFilter ff_hevc_extract_layer_bsf; extern const FFBitStreamFilter ff_hevc_metadata_bsf; extern const FFBitStreamFilter ff_hevc_mp4toannexb_bsf; extern const FFBitStreamFilter ff_imx_dump_header_bsf; diff --git a/libavcodec/hevc_extract_layer_bsf.c b/libavcodec/hevc_extract_layer_bsf.c new file mode 100644 index 0000000000..84c1c87a80 --- /dev/null +++ b/libavcodec/hevc_extract_layer_bsf.c @@ -0,0 +1,126 @@ +/* + * 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_h265.h" +#include "hevc.h" + +typedef struct HevcExtractLayerContext { + CBSBSFContext common; + + int nuh_layer_id; +} HevcExtractLayerContext; + +static int hevc_update_vps(AVBSFContext *bsf, H265RawVPS *vps) +{ + HevcExtractLayerContext *ctx = bsf->priv_data; + + if (ctx->nuh_layer_id > 0) { + if (vps->vps_max_layers_minus1 == 0) + av_log(bsf, AV_LOG_ERROR, + "vps_max_layers_minus1 is zero, only base layer is available.\n"); + else if (ctx->nuh_layer_id > vps->vps_max_layer_id) + // It's a known issue that Apple videotoolbox encoder doesn't set + // vps_max_layer_id correctly. So this can be a false positive. + av_log(bsf, AV_LOG_ERROR, "Specified nuh_layer_id %d is larger than vps_max_layer_id %d, " + "this might leading to empty output\n", + ctx->nuh_layer_id, vps->vps_max_layer_id); + } + + vps->vps_max_layers_minus1 = 0; + vps->vps_max_layer_id = 0; + // TODO: update vps_extension to reflect the layer changes, other than + // drop it entirely. + vps->vps_extension_flag = 0; + + return 0; +} + +static int hevc_update_fragment(AVBSFContext *bsf, AVPacket *pkt, + CodedBitstreamFragment *au) +{ + HevcExtractLayerContext *ctx = bsf->priv_data; + H265RawNALUnitHeader *header; + int ret; + + for (int i = 0; i < au->nb_units; i++) { + if (au->units[i].type == HEVC_NAL_VPS) { + ret = hevc_update_vps(bsf, au->units[i].content); + if (ret) + return ret; + continue; + } + + header = au->units[i].content; + if (header->nuh_layer_id != ctx->nuh_layer_id) { + ff_cbs_delete_unit(au, i); + i--; + continue; + } + header->nuh_layer_id = 0; + } + + return 0; +} + +static const CBSBSFType hevc_extract_layer_type = { + .codec_id = AV_CODEC_ID_HEVC, + .fragment_name = "access unit", + .unit_name = "NAL unit", + .update_fragment = &hevc_update_fragment, +}; + +static int hevc_extract_layer_init(AVBSFContext *bsf) +{ + return ff_cbs_bsf_generic_init(bsf, &hevc_extract_layer_type); +} + +#define OFFSET(x) offsetof(HevcExtractLayerContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption hevc_extract_layer_options[] = { + { "nuh_layer_id", "Extract NALUs with the specified nuh_layer_id and rewrite as base layer", + OFFSET(nuh_layer_id), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 62, FLAGS }, + { NULL } +}; + +static const AVClass hevc_extract_layer_class = { + .class_name = "hevc_extract_layer_bsf", + .item_name = av_default_item_name, + .option = hevc_extract_layer_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID hevc_extract_layer_codec_ids[] = { + AV_CODEC_ID_HEVC, AV_CODEC_ID_NONE, +}; + +const FFBitStreamFilter ff_hevc_extract_layer_bsf = { + .p.name = "hevc_extract_layer", + .p.codec_ids = hevc_extract_layer_codec_ids, + .p.priv_class = &hevc_extract_layer_class, + .priv_data_size = sizeof(HevcExtractLayerContext), + .init = &hevc_extract_layer_init, + .close = &ff_cbs_bsf_generic_close, + .filter = &ff_cbs_bsf_generic_filter, +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index 15f7c3fe3d..dfd3d5d7e5 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,8 +29,8 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 56 -#define LIBAVCODEC_VERSION_MICRO 101 +#define LIBAVCODEC_VERSION_MINOR 57 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ -- 2.25.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".