PR #22927 opened by Zhao Zhili (quink) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22927 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22927.patch
>From f5d8ac13fda5f95426144bc7f2cefea29790bf14 Mon Sep 17 00:00:00 2001 From: Zhao Zhili <[email protected]> Date: Sun, 26 Apr 2026 20:14:07 +0800 Subject: [PATCH 1/2] avcodec/hevc: do not reset decoder on non-coding SPS changes Clearing the DPB on every SPS change breaks decoding when only non-coding parameters change, because reference frames are lost while subsequent inter frames still depend on. Add sps_needs_reinit() that checks whether the new SPS differs in any coding-relevant field. When it does not, update the SPS/VPS references and re-export stream parameters without touching the DPB. Signed-off-by: Zhao Zhili <[email protected]> --- libavcodec/hevc/hevcdec.c | 128 +++++++++++++++++++++++++++++++++++--- 1 file changed, 118 insertions(+), 10 deletions(-) diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c index ae5f0fe69d..5758e1980b 100644 --- a/libavcodec/hevc/hevcdec.c +++ b/libavcodec/hevc/hevcdec.c @@ -736,6 +736,103 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) return 0; } +static int sps_needs_reinit(const HEVCSPS *sps_old, const HEVCSPS *sps_new) +{ + if (!sps_old) + return 1; + + if (sps_old->pix_fmt != sps_new->pix_fmt || + sps_old->width != sps_new->width || + sps_old->height != sps_new->height || + sps_old->bit_depth != sps_new->bit_depth || + sps_old->bit_depth_chroma != sps_new->bit_depth_chroma || + sps_old->pixel_shift != sps_new->pixel_shift || + sps_old->chroma_format_idc != sps_new->chroma_format_idc || + sps_old->separate_colour_plane != sps_new->separate_colour_plane) + return 1; + + if (sps_old->log2_ctb_size != sps_new->log2_ctb_size || + sps_old->log2_min_cb_size != sps_new->log2_min_cb_size || + sps_old->log2_min_tb_size != sps_new->log2_min_tb_size || + sps_old->log2_max_trafo_size != sps_new->log2_max_trafo_size || + sps_old->log2_min_pu_size != sps_new->log2_min_pu_size || + sps_old->log2_diff_max_min_coding_block_size != + sps_new->log2_diff_max_min_coding_block_size || + sps_old->log2_diff_max_min_transform_block_size != + sps_new->log2_diff_max_min_transform_block_size) + return 1; + + if (sps_old->max_transform_hierarchy_depth_inter != + sps_new->max_transform_hierarchy_depth_inter || + sps_old->max_transform_hierarchy_depth_intra != + sps_new->max_transform_hierarchy_depth_intra) + return 1; + + if (sps_old->log2_max_poc_lsb != sps_new->log2_max_poc_lsb || + sps_old->max_sub_layers != sps_new->max_sub_layers || + sps_old->temporal_mvp_enabled != sps_new->temporal_mvp_enabled || + sps_old->sao_enabled != sps_new->sao_enabled || + sps_old->pcm_enabled != sps_new->pcm_enabled || + sps_old->scaling_list_enabled != sps_new->scaling_list_enabled || + sps_old->amp_enabled != sps_new->amp_enabled || + sps_old->strong_intra_smoothing_enabled != + sps_new->strong_intra_smoothing_enabled) + return 1; + + if (sps_old->pcm_enabled && + (memcmp(&sps_old->pcm, &sps_new->pcm, sizeof(sps_old->pcm)) || + sps_old->pcm_loop_filter_disabled != sps_new->pcm_loop_filter_disabled)) + return 1; + + if (sps_old->nb_st_rps != sps_new->nb_st_rps || + memcmp(sps_old->st_rps, sps_new->st_rps, sizeof(sps_old->st_rps))) + return 1; + + if (sps_old->long_term_ref_pics_present != + sps_new->long_term_ref_pics_present || + sps_old->num_long_term_ref_pics_sps != + sps_new->num_long_term_ref_pics_sps || + memcmp(sps_old->lt_ref_pic_poc_lsb_sps, + sps_new->lt_ref_pic_poc_lsb_sps, + sizeof(sps_old->lt_ref_pic_poc_lsb_sps)) || + sps_old->used_by_curr_pic_lt != sps_new->used_by_curr_pic_lt) + return 1; + + if (memcmp(sps_old->temporal_layer, sps_new->temporal_layer, + sizeof(sps_old->temporal_layer))) + return 1; + + if (sps_old->scaling_list_enabled && + memcmp(&sps_old->scaling_list, &sps_new->scaling_list, + sizeof(sps_old->scaling_list))) + return 1; + + if (sps_old->range_extension != sps_new->range_extension || + sps_old->transform_skip_rotation_enabled != sps_new->transform_skip_rotation_enabled || + sps_old->transform_skip_context_enabled != sps_new->transform_skip_context_enabled || + sps_old->implicit_rdpcm_enabled != sps_new->implicit_rdpcm_enabled || + sps_old->explicit_rdpcm_enabled != sps_new->explicit_rdpcm_enabled || + sps_old->extended_precision_processing != sps_new->extended_precision_processing || + sps_old->intra_smoothing_disabled != sps_new->intra_smoothing_disabled || + sps_old->high_precision_offsets_enabled != sps_new->high_precision_offsets_enabled || + sps_old->persistent_rice_adaptation_enabled != sps_new->persistent_rice_adaptation_enabled || + sps_old->cabac_bypass_alignment_enabled != sps_new->cabac_bypass_alignment_enabled) + return 1; + + if (sps_old->scc_extension != sps_new->scc_extension || + sps_old->curr_pic_ref_enabled != sps_new->curr_pic_ref_enabled || + sps_old->palette_mode_enabled != sps_new->palette_mode_enabled || + sps_old->palette_predictor_initializers_present != + sps_new->palette_predictor_initializers_present || + sps_old->intra_boundary_filtering_disabled != + sps_new->intra_boundary_filtering_disabled || + sps_old->motion_vector_resolution_control_idc != + sps_new->motion_vector_resolution_control_idc) + return 1; + + return 0; +} + static int set_sps(HEVCContext *s, HEVCLayerContext *l, const HEVCSPS *sps) { int ret; @@ -3230,6 +3327,7 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, if (l->sps != sps) { const HEVCSPS *sps_base = s->layers[0].sps; enum AVPixelFormat pix_fmt = sps->pix_fmt; + int needs_reinit; if (l != &s->layers[0]) { if (!sps_base) { @@ -3261,22 +3359,32 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, } } - ff_hevc_clear_refs(l); + needs_reinit = sps_needs_reinit(l->sps, sps); + if (needs_reinit) { + ff_hevc_clear_refs(l); - ret = set_sps(s, l, sps); - if (ret < 0) - return ret; + ret = set_sps(s, l, sps); + if (ret < 0) + return ret; + } else { + av_log(s->avctx, AV_LOG_DEBUG, + "Keeping DPB for non-coding SPS change\n"); + av_refstruct_replace(&l->sps, sps); + av_refstruct_replace(&s->vps, sps->vps); + } if (l == &s->layers[0]) { export_stream_params(s, sps); - ret = get_format(s, sps); - if (ret < 0) { - set_sps(s, l, NULL); - return ret; - } + if (needs_reinit) { + ret = get_format(s, sps); + if (ret < 0) { + set_sps(s, l, NULL); + return ret; + } - new_sequence = 1; + new_sequence = 1; + } } } -- 2.52.0 >From e3a9a03c41e655bf80f489d704fb705d39a3131f Mon Sep 17 00:00:00 2001 From: Zhao Zhili <[email protected]> Date: Sun, 26 Apr 2026 20:15:12 +0800 Subject: [PATCH 2/2] fate/hevc: add test for non-coding SPS update Test that the decoder preserves reference frames when an SPS update changes only VUI parameters. Signed-off-by: Zhao Zhili <[email protected]> --- tests/fate/hevc.mak | 4 ++++ tests/ref/fate/hevc-sps-vui-change | 13 +++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/ref/fate/hevc-sps-vui-change diff --git a/tests/fate/hevc.mak b/tests/fate/hevc.mak index 351f188968..ac6dde77dd 100644 --- a/tests/fate/hevc.mak +++ b/tests/fate/hevc.mak @@ -314,6 +314,10 @@ FATE_HEVC-$(call FRAMECRC, MOV, HEVC) += fate-hevc-alpha fate-hevc-color-reserved: CMD = framecrc -bsf:v hevc_metadata=colour_primaries=0:transfer_characteristics=0:matrix_coefficients=3 -i $(TARGET_SAMPLES)/hevc-conformance/AMP_A_Samsung_4.bit -vf scale,format=nv12 -frames:v 1 FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_METADATA_BSF SCALE_FILTER) += fate-hevc-color-reserved +# SPS update mid-stream with only VUI changes (no IDR follows). +fate-hevc-sps-vui-change: CMD = framecrc -i $(TARGET_SAMPLES)/hevc/sps_vui_change.hevc +FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_PARSER) += fate-hevc-sps-vui-change + FATE_SAMPLES_AVCONV += $(FATE_HEVC-yes) FATE_SAMPLES_FFPROBE += $(FATE_HEVC_FFPROBE-yes) diff --git a/tests/ref/fate/hevc-sps-vui-change b/tests/ref/fate/hevc-sps-vui-change new file mode 100644 index 0000000000..b300f8739d --- /dev/null +++ b/tests/ref/fate/hevc-sps-vui-change @@ -0,0 +1,13 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 416x240 +#sar 0: 0/1 +0, 0, 0, 1, 149760, 0x8edb27d7 +0, 1, 1, 1, 149760, 0x187419b5 +0, 2, 2, 1, 149760, 0x61100980 +0, 3, 3, 1, 149760, 0xd799123e +0, 4, 4, 1, 149760, 0x9011c8d0 +0, 5, 5, 1, 149760, 0xeafe7d99 +0, 6, 6, 1, 149760, 0x94f32245 +0, 7, 7, 1, 149760, 0x8185910a -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
