Skip to content

Commit eedf8f0

Browse files
committed
avcodec/hevc: workaround hevc-alpha videos generated by VideoToolbox
Apple VideoToolbox is the dominant producer of hevc-alpha videos, but early versions generates non-standard VPS extensions that fail to parse and return AVERROR_INVALIDDATA. Fix this by returning AVERROR_PATCHWELCOME instead of AVERROR_INVALIDDATA for unsupported VPS extension configurations. Setting poc_lsb_not_present for the alpha layer in the fallback path when it has no direct dependency on the base layer, so that IDR slices on the alpha layer won't incorrectly read pic_order_cnt_lsb. Fix #22384 Signed-off-by: Zhao Zhili <[email protected]>
1 parent 28ab24b commit eedf8f0

File tree

1 file changed

+23
-5
lines changed

1 file changed

+23
-5
lines changed

libavcodec/hevc/ps.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -610,8 +610,11 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
610610
}
611611
}
612612
vps->num_output_layer_sets = vps->vps_num_layer_sets + vps->num_add_layer_sets;
613-
if (vps->num_output_layer_sets != 2)
614-
return AVERROR_INVALIDDATA;
613+
if (vps->num_output_layer_sets != 2) {
614+
av_log(avctx, AV_LOG_WARNING,
615+
"Unsupported num_output_layer_sets: %d\n", vps->num_output_layer_sets);
616+
return AVERROR_PATCHWELCOME;
617+
}
615618

616619
sub_layers_max_present = get_bits1(gb); // vps_sub_layers_max_minus1_present_flag
617620
if (sub_layers_max_present) {
@@ -677,7 +680,7 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
677680

678681
if (get_ue_golomb_31(gb) != 0 /* vps_num_rep_formats_minus1 */) {
679682
av_log(avctx, AV_LOG_ERROR, "Unexpected extra rep formats\n");
680-
return AVERROR_INVALIDDATA;
683+
return AVERROR_PATCHWELCOME;
681684
}
682685

683686
vps->rep_format.pic_width_in_luma_samples = get_bits(gb, 16);
@@ -895,8 +898,23 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx,
895898
if (vps->vps_max_layers > 1 && get_bits1(gb)) { /* vps_extension_flag */
896899
int ret = decode_vps_ext(gb, avctx, vps, layer1_id_included);
897900
if (ret == AVERROR_PATCHWELCOME) {
898-
vps->nb_layers = 1;
899-
av_log(avctx, AV_LOG_WARNING, "Ignoring unsupported VPS extension\n");
901+
/* If alpha layer info was already parsed, preserve it for alpha decoding */
902+
if (!(avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT)) &&
903+
vps->nb_layers == 2 &&
904+
vps->layer_id_in_nuh[1] &&
905+
(vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY)) {
906+
av_log(avctx, AV_LOG_WARNING,
907+
"Broken VPS extension, treating as alpha video\n");
908+
/* If alpha layer has no direct dependency on base layer,
909+
* assume poc_lsb_not_present for the alpha layer, so that
910+
* IDR slices on that layer won't read pic_order_cnt_lsb.
911+
* This matches the behavior of Apple VideoToolbox encoders. */
912+
if (!vps->num_direct_ref_layers[1])
913+
vps->poc_lsb_not_present |= 1 << 1;
914+
} else {
915+
vps->nb_layers = 1;
916+
av_log(avctx, AV_LOG_WARNING, "Ignoring unsupported VPS extension\n");
917+
}
900918
ret = 0;
901919
} else if (ret < 0)
902920
goto err;

0 commit comments

Comments
 (0)