From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> To: ffmpeg-devel@ffmpeg.org Cc: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Subject: [FFmpeg-devel] [PATCH 2/3] avcodec/qsvenc_hevc: Switch to cbs_h265 to create missing VPS Date: Tue, 26 Mar 2024 06:27:50 +0100 Message-ID: <GV1P250MB07377FE225E883EAEA7855EB8F352@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM> (raw) In-Reply-To: <GV1P250MB0737280B14FF3E29DF31B3B48F352@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM> Old MXF runtime versions did not support writing VPS and therefore one derived from the SPS has been generated via ad-hoc code in lavc/hevc_ps_enc.c that is only used for this purpose. Yet this duplicates the functionality from cbs_h265, so replace it with the latter. This patch has been tested by generating VPS from the SPS and PPS from hevc-conformance files from the FATE-suite. There were some minor differences, mostly due to hevc_ps_enc.c not handling the profile constraint flags like general_max_12bit_constraint_flag. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- Would be nice if someone could actually check this with a QSV version that needs this hack. (Do people really need this any more?) configure | 2 +- libavcodec/Makefile | 2 +- libavcodec/hevc_ps_enc.c | 121 ---------------------------- libavcodec/qsvenc_hevc.c | 168 +++++++++++++++++---------------------- 4 files changed, 77 insertions(+), 216 deletions(-) delete mode 100644 libavcodec/hevc_ps_enc.c diff --git a/configure b/configure index 9fa639fca6..6c181197b4 100755 --- a/configure +++ b/configure @@ -3341,7 +3341,7 @@ hevc_mf_encoder_deps="mediafoundation" hevc_nvenc_encoder_deps="nvenc" hevc_nvenc_encoder_select="atsc_a53" hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec" -hevc_qsv_encoder_select="hevcparse qsvenc" +hevc_qsv_encoder_select="cbs_h265 qsvenc" hevc_rkmpp_decoder_deps="rkmpp" hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf" hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 6eefeeae6e..d06b837c60 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -440,7 +440,7 @@ OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o -OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o +OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o h265_profile_level.o \ h2645data.o diff --git a/libavcodec/hevc_ps_enc.c b/libavcodec/hevc_ps_enc.c deleted file mode 100644 index 72641b2ffb..0000000000 --- a/libavcodec/hevc_ps_enc.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * HEVC Parameter Set encoding - * - * 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 "put_golomb.h" -#include "hevc_ps.h" -#include "put_bits.h" - -static void write_ptl_layer(PutBitContext *pb, PTLCommon *ptl) -{ - int i; - - put_bits(pb, 2, ptl->profile_space); - put_bits(pb, 1, ptl->tier_flag); - put_bits(pb, 5, ptl->profile_idc); - for (i = 0; i < 32; i++) - put_bits(pb, 1, ptl->profile_compatibility_flag[i]); - put_bits(pb, 1, ptl->progressive_source_flag); - put_bits(pb, 1, ptl->interlaced_source_flag); - put_bits(pb, 1, ptl->non_packed_constraint_flag); - put_bits(pb, 1, ptl->frame_only_constraint_flag); - put_bits32(pb, 0); // reserved - put_bits(pb, 12, 0); // reserved -} - -static void write_ptl(PutBitContext *pb, PTL *ptl, int max_num_sub_layers) -{ - int i; - - write_ptl_layer(pb, &ptl->general_ptl); - put_bits(pb, 8, ptl->general_ptl.level_idc); - - for (i = 0; i < max_num_sub_layers - 1; i++) { - put_bits(pb, 1, ptl->sub_layer_profile_present_flag[i]); - put_bits(pb, 1, ptl->sub_layer_level_present_flag[i]); - } - - if (max_num_sub_layers > 1) - for (i = max_num_sub_layers - 1; i < 8; i++) - put_bits(pb, 2, 0); // reserved - - for (i = 0; i < max_num_sub_layers - 1; i++) { - if (ptl->sub_layer_profile_present_flag[i]) - write_ptl_layer(pb, &ptl->sub_layer_ptl[i]); - if (ptl->sub_layer_level_present_flag[i]) - put_bits(pb, 8, ptl->sub_layer_ptl[i].level_idc); - } -} - -int ff_hevc_encode_nal_vps(HEVCVPS *vps, unsigned int id, - uint8_t *buf, int buf_size) -{ - PutBitContext pb; - int i, data_size; - - init_put_bits(&pb, buf, buf_size); - put_bits(&pb, 4, id); - put_bits(&pb, 2, 3); // reserved - put_bits(&pb, 6, vps->vps_max_layers - 1); - put_bits(&pb, 3, vps->vps_max_sub_layers - 1); - put_bits(&pb, 1, vps->vps_temporal_id_nesting_flag); - put_bits(&pb, 16, 0xffff); // reserved - - write_ptl(&pb, &vps->ptl, vps->vps_max_sub_layers); - - put_bits(&pb, 1, vps->vps_sub_layer_ordering_info_present_flag); - for (i = vps->vps_sub_layer_ordering_info_present_flag ? 0 : vps->vps_max_layers - 1; - i < vps->vps_max_sub_layers; i++) { - set_ue_golomb(&pb, vps->vps_max_dec_pic_buffering[i] - 1); - set_ue_golomb(&pb, vps->vps_num_reorder_pics[i]); - set_ue_golomb(&pb, vps->vps_max_latency_increase[i] + 1); - } - - put_bits(&pb, 6, vps->vps_max_layer_id); - set_ue_golomb(&pb, vps->vps_num_layer_sets - 1); - - if (vps->vps_num_layer_sets > 1) { - avpriv_report_missing_feature(NULL, "Writing layer_id_included_flag"); - return AVERROR_PATCHWELCOME; - } - - put_bits(&pb, 1, vps->vps_timing_info_present_flag); - if (vps->vps_timing_info_present_flag) { - put_bits32(&pb, vps->vps_num_units_in_tick); - put_bits32(&pb, vps->vps_time_scale); - put_bits(&pb, 1, vps->vps_poc_proportional_to_timing_flag); - if (vps->vps_poc_proportional_to_timing_flag) - set_ue_golomb(&pb, vps->vps_num_ticks_poc_diff_one - 1); - - set_ue_golomb(&pb, vps->vps_num_hrd_parameters); - if (vps->vps_num_hrd_parameters) { - avpriv_report_missing_feature(NULL, "Writing HRD parameters"); - return AVERROR_PATCHWELCOME; - } - } - - put_bits(&pb, 1, 0); // extension flag - - put_bits(&pb, 1, 1); // stop bit - flush_put_bits(&pb); - - data_size = put_bytes_output(&pb); - - return data_size; -} diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c index 4920b0bca4..55f4b87718 100644 --- a/libavcodec/qsvenc_hevc.c +++ b/libavcodec/qsvenc_hevc.c @@ -24,18 +24,15 @@ #include <mfxvideo.h> -#include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/mastering_display_metadata.h" #include "avcodec.h" -#include "bytestream.h" +#include "cbs.h" +#include "cbs_h265.h" #include "codec_internal.h" -#include "get_bits.h" #include "hevc.h" -#include "hevcdec.h" -#include "h2645_parse.h" -#include "qsv.h" #include "qsvenc.h" enum LoadPlugin { @@ -50,115 +47,100 @@ typedef struct QSVHEVCEncContext { int load_plugin; } QSVHEVCEncContext; -static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) +static int generate_fake_vps(AVCodecContext *avctx) { - GetByteContext gbc; - PutByteContext pbc; - - GetBitContext gb; - H2645RBSP sps_rbsp = { NULL }; - H2645NAL sps_nal = { NULL }; - HEVCSPS sps = { 0 }; - HEVCVPS vps = { 0 }; - uint8_t vps_buf[128], vps_rbsp_buf[128]; + CodedBitstreamContext *cbc; + CodedBitstreamFragment frag = { NULL }; + H265RawVPS *vps = NULL; + const H265RawSPS *sps; + uint8_t *new_extradata; - unsigned int sps_id; - int ret, i, type, vps_size; + int ret; if (!avctx->extradata_size) { av_log(avctx, AV_LOG_ERROR, "No extradata returned from libmfx\n"); return AVERROR_UNKNOWN; } - av_fast_padded_malloc(&sps_rbsp.rbsp_buffer, &sps_rbsp.rbsp_buffer_alloc_size, avctx->extradata_size); - if (!sps_rbsp.rbsp_buffer) - return AVERROR(ENOMEM); - - /* parse the SPS */ - ret = ff_h2645_extract_rbsp(avctx->extradata + 4, avctx->extradata_size - 4, &sps_rbsp, &sps_nal, 1); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error unescaping the SPS buffer\n"); + ret = ff_cbs_init(&cbc, AV_CODEC_ID_HEVC, avctx); + if (ret < 0) return ret; - } - ret = init_get_bits8(&gb, sps_nal.data, sps_nal.size); - if (ret < 0) { - av_freep(&sps_rbsp.rbsp_buffer); - return ret; - } + ret = ff_cbs_read_extradata_from_codec(cbc, &frag, avctx); + if (ret < 0) + goto fail; - get_bits(&gb, 1); - type = get_bits(&gb, 6); - if (type != HEVC_NAL_SPS) { - av_log(avctx, AV_LOG_ERROR, "Unexpected NAL type in the extradata: %d\n", - type); - av_freep(&sps_rbsp.rbsp_buffer); - return AVERROR_INVALIDDATA; + if (frag.nb_units == 0) { + ret = AVERROR_EXTERNAL; + goto fail; } - get_bits(&gb, 9); - - ret = ff_hevc_parse_sps(&sps, &gb, &sps_id, 0, NULL, avctx); - av_freep(&sps_rbsp.rbsp_buffer); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error parsing the SPS\n"); - return ret; + if (frag.units[0].type != HEVC_NAL_SPS) { + av_log(avctx, AV_LOG_ERROR, "Unexpected NALU type in extradata: %u\n", + (unsigned)frag.units[0].type); + ret = AVERROR_EXTERNAL; + goto fail; } + vps = av_mallocz(sizeof(*vps)); + if (!vps) { + ret = AVERROR(ENOMEM); + goto fail; + } + sps = frag.units[0].content; /* generate the VPS */ - vps.vps_max_layers = 1; - vps.vps_max_sub_layers = sps.max_sub_layers; - vps.vps_temporal_id_nesting_flag = sps.temporal_id_nesting_flag; - memcpy(&vps.ptl, &sps.ptl, sizeof(vps.ptl)); - vps.vps_sub_layer_ordering_info_present_flag = 1; - for (i = 0; i < HEVC_MAX_SUB_LAYERS; i++) { - vps.vps_max_dec_pic_buffering[i] = sps.temporal_layer[i].max_dec_pic_buffering; - vps.vps_num_reorder_pics[i] = sps.temporal_layer[i].num_reorder_pics; - vps.vps_max_latency_increase[i] = sps.temporal_layer[i].max_latency_increase; + vps->nal_unit_header = (H265RawNALUnitHeader){ + .nal_unit_type = HEVC_NAL_VPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + vps->vps_video_parameter_set_id = sps->sps_video_parameter_set_id; + vps->vps_base_layer_available_flag = 1; + vps->vps_base_layer_internal_flag = 1; + vps->vps_max_layers_minus1 = 0; + vps->vps_max_sub_layers_minus1 = sps->sps_max_sub_layers_minus1; + vps->layer_id_included_flag[0][0] = 1; + vps->vps_temporal_id_nesting_flag = sps->sps_temporal_id_nesting_flag; + memcpy(&vps->profile_tier_level, &sps->profile_tier_level, sizeof(vps->profile_tier_level)); + vps->vps_sub_layer_ordering_info_present_flag = 1; + for (int i = 0; i < HEVC_MAX_SUB_LAYERS; i++) { + vps->vps_max_dec_pic_buffering_minus1[i] = sps->sps_max_dec_pic_buffering_minus1[i]; + vps->vps_max_num_reorder_pics[i] = sps->sps_max_num_reorder_pics[i]; + vps->vps_max_latency_increase_plus1[i] = sps->sps_max_latency_increase_plus1[i]; } - vps.vps_num_layer_sets = 1; - vps.vps_timing_info_present_flag = sps.vui.vui_timing_info_present_flag; - vps.vps_num_units_in_tick = sps.vui.vui_num_units_in_tick; - vps.vps_time_scale = sps.vui.vui_time_scale; - vps.vps_poc_proportional_to_timing_flag = sps.vui.vui_poc_proportional_to_timing_flag; - vps.vps_num_ticks_poc_diff_one = sps.vui.vui_num_ticks_poc_diff_one_minus1 + 1; - vps.vps_num_hrd_parameters = 0; - - /* generate the encoded RBSP form of the VPS */ - ret = ff_hevc_encode_nal_vps(&vps, sps.vps_id, vps_rbsp_buf, sizeof(vps_rbsp_buf)); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error writing the VPS\n"); - return ret; - } + vps->vps_num_layer_sets_minus1 = 0; + vps->vps_timing_info_present_flag = sps->vui.vui_timing_info_present_flag; + vps->vps_num_units_in_tick = sps->vui.vui_num_units_in_tick; + vps->vps_time_scale = sps->vui.vui_time_scale; + vps->vps_poc_proportional_to_timing_flag = sps->vui.vui_poc_proportional_to_timing_flag; + vps->vps_num_ticks_poc_diff_one_minus1 = sps->vui.vui_num_ticks_poc_diff_one_minus1; + vps->vps_num_hrd_parameters = 0; - /* escape and add the startcode */ - bytestream2_init(&gbc, vps_rbsp_buf, ret); - bytestream2_init_writer(&pbc, vps_buf, sizeof(vps_buf)); + ret = ff_cbs_insert_unit_content(&frag, 0, HEVC_NAL_VPS, vps, NULL); + if (ret < 0) + goto fail; - bytestream2_put_be32(&pbc, 1); // startcode - bytestream2_put_byte(&pbc, HEVC_NAL_VPS << 1); // NAL - bytestream2_put_byte(&pbc, 1); // header + ret = ff_cbs_write_fragment_data(cbc, &frag); + if (ret < 0) + goto fail; - while (bytestream2_get_bytes_left(&gbc)) { - if (bytestream2_get_bytes_left(&gbc) >= 3 && bytestream2_peek_be24(&gbc) <= 3) { - bytestream2_put_be24(&pbc, 3); - bytestream2_skip(&gbc, 2); - } else - bytestream2_put_byte(&pbc, bytestream2_get_byte(&gbc)); + /* Fragment's data is already padded, so we can copy data + padding */ + new_extradata = av_memdup(frag.data, frag.data_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!new_extradata) { + ret = AVERROR(ENOMEM); + goto fail; } - - vps_size = bytestream2_tell_p(&pbc); - new_extradata = av_mallocz(vps_size + avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!new_extradata) - return AVERROR(ENOMEM); - memcpy(new_extradata, vps_buf, vps_size); - memcpy(new_extradata + vps_size, avctx->extradata, avctx->extradata_size); - av_freep(&avctx->extradata); - avctx->extradata = new_extradata; - avctx->extradata_size += vps_size; + avctx->extradata = new_extradata; + avctx->extradata_size = frag.data_size; - return 0; + ret = 0; +fail: + av_free(vps); + ff_cbs_fragment_free(&frag); + ff_cbs_close(&cbc); + + return ret; } static int qsv_hevc_set_encode_ctrl(AVCodecContext *avctx, @@ -274,7 +256,7 @@ static av_cold int qsv_enc_init(AVCodecContext *avctx) return ret; if (!q->qsv.hevc_vps) { - ret = generate_fake_vps(&q->qsv, avctx); + ret = generate_fake_vps(avctx); if (ret < 0) { ff_qsv_enc_close(avctx, &q->qsv); return ret; -- 2.40.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-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2024-03-26 5:28 UTC|newest] Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top 2024-03-26 5:26 [FFmpeg-devel] [PATCH 1/3] avcodec/Makefile: Remove redundant dependencies on hevc_data.o Andreas Rheinhardt 2024-03-26 5:27 ` Andreas Rheinhardt [this message] 2024-03-26 5:27 ` [FFmpeg-devel] [PATCH 3/3] avcodec/hevc_ps: Make ff_hevc_parse_ps static Andreas Rheinhardt 2024-03-28 7:44 ` [FFmpeg-devel] [PATCH 1/3] avcodec/Makefile: Remove redundant dependencies on hevc_data.o Andreas Rheinhardt
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=GV1P250MB07377FE225E883EAEA7855EB8F352@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM \ --to=andreas.rheinhardt@outlook.com \ --cc=ffmpeg-devel@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