PR #24235 opened by J. Brandt Buckley (brandt)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24235
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24235.patch
The P- and B-picture per-MB guards added in 2a8785966c bail out of the loop
to error concealment when get_bits_left() <= 1, but P- and B-picture MBs can
legitimately cost exactly 1 bit in certain cases. This patch relaxes the guards
to accommodate those cases.
## Explanation
With the SKIPMB bitplane in Raw mode a skipped macroblock is a single SKIPMBBIT
(SMPTE ST 421:2013, 7.1.3.7, p.109) and then "may only contain the HYBRIDPRED
syntax element" (8.3.4.4, p.140), which is only read when predictors A and C
are in-bounds and the predicted vector differs from A or C by more than 32
quarter-pels (8.3.5.3.5, Figure 55, pp.149-150). That condition isn't met in a
static region so such a MB costs just 1 bit. A direct+skipped B-picture MB
likewise reads nothing beyond its raw flag (Table 30, p.86).
In Simple/Main profile a picture is byte-aligned with no stop bit, so if a
picture ends with a 1-bit skipped macroblock and its last coded bit lands on a
byte boundary, the final MB is reached with exactly one bit left. The guard
then conceals a valid macroblock, sets FF_DECODE_ERROR_CONCEALMENT_ACTIVE
on an undamaged frame, and the damage propagates to every frame up to the next
keyframe. (Advanced Profile BDUs end in a trailing '1' bit per Annex E.2/E.3
p.437, so they always have at least two bit left and are therefore unaffected.)
## Reproducing
Reproducible with an existing sample (prior to this patch):
$ ffmpeg -i
https://samples.ffmpeg.org/V-codecs/WMV9/wmv-samples/[email protected]
-map 0:v -f null - 2>&1 | grep -A1 concealing
[wmv3 @ 0x122605430] concealing 75 DC, 75 AC, 75 MV errors in P frame
[vist#0:0/wmv3 @ 0x122604080] [dec:wmv3 @ 0x122604df0] corrupt decoded frame
[wmv3 @ 0x122605430] concealing 50 DC, 50 AC, 50 MV errors in P frame
[vist#0:0/wmv3 @ 0x122604080] [dec:wmv3 @ 0x122604df0] corrupt decoded frame
[wmv3 @ 0x122605430] concealing 100 DC, 100 AC, 100 MV errors in P frame
[vist#0:0/wmv3 @ 0x122604080] [dec:wmv3 @ 0x122604df0] corrupt decoded frame
## References
- SMPTE ST 421:2013 spec: https://pub.smpte.org/doc/st421/20131008-pub/
Signed-off-by: J. Brandt Buckley <[email protected]>
>From ac8f924be0bfef6428b3f054b3f97d5cd11b5987 Mon Sep 17 00:00:00 2001
From: "J. Brandt Buckley" <[email protected]>
Date: Fri, 21 Aug 2026 09:49:15 -0600
Subject: [PATCH] avcodec/vc1_block: don't drop the last macroblock when 1 bit
remains
The P- and B-picture per-MB guards added in 2a8785966c bail out of the loop
to error concealment when get_bits_left() <= 1, but P- and B-picture MBs can
legitimately cost exactly 1 bit in certain cases. This patch relaxes the guards
to accommodate those cases.
## Explanation
With the SKIPMB bitplane in Raw mode a skipped macroblock is a single SKIPMBBIT
(SMPTE ST 421:2013, 7.1.3.7, p.109) and then "may only contain the HYBRIDPRED
syntax element" (8.3.4.4, p.140), which is only read when predictors A and C
are in-bounds and the predicted vector differs from A or C by more than 32
quarter-pels (8.3.5.3.5, Figure 55, pp.149-150). That condition isn't met in a
static region so such a MB costs just 1 bit. A direct+skipped B-picture MB
likewise reads nothing beyond its raw flag (Table 30, p.86).
In Simple/Main profile a picture is byte-aligned with no stop bit, so if a
picture ends with a 1-bit skipped macroblock and its last coded bit lands on a
byte boundary, the final MB is reached with exactly one bit left. The guard
then conceals a valid macroblock, sets FF_DECODE_ERROR_CONCEALMENT_ACTIVE
on an undamaged frame, and the damage propagates to every frame up to the next
keyframe. (Advanced Profile BDUs end in a trailing '1' bit per Annex E.2/E.3
p.437, so they always have at least two bit left and are therefore unaffected.)
## Reproducing
Reproducible with an existing sample (prior to this patch):
$ ffmpeg -i
https://samples.ffmpeg.org/V-codecs/WMV9/wmv-samples/[email protected]
-map 0:v -f null - 2>&1 | grep -A1 concealing
[wmv3 @ 0x122605430] concealing 75 DC, 75 AC, 75 MV errors in P frame
[vist#0:0/wmv3 @ 0x122604080] [dec:wmv3 @ 0x122604df0] corrupt decoded frame
[wmv3 @ 0x122605430] concealing 50 DC, 50 AC, 50 MV errors in P frame
[vist#0:0/wmv3 @ 0x122604080] [dec:wmv3 @ 0x122604df0] corrupt decoded frame
[wmv3 @ 0x122605430] concealing 100 DC, 100 AC, 100 MV errors in P frame
[vist#0:0/wmv3 @ 0x122604080] [dec:wmv3 @ 0x122604df0] corrupt decoded frame
## References
- SMPTE ST 421:2013 spec: https://pub.smpte.org/doc/st421/20131008-pub/
Signed-off-by: J. Brandt Buckley <[email protected]>
---
libavcodec/vc1_block.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libavcodec/vc1_block.c b/libavcodec/vc1_block.c
index 10cb459082..a84c853b6f 100644
--- a/libavcodec/vc1_block.c
+++ b/libavcodec/vc1_block.c
@@ -2788,7 +2788,7 @@ static void vc1_decode_p_blocks(VC1Context *v)
update_block_index(s);
if (v->fcm == ILACE_FIELD || (v->fcm == PROGRESSIVE &&
v->mv_type_is_raw) || v->skip_is_raw)
- if (get_bits_left(&v->gb) <= 1) {
+ if (get_bits_left(&v->gb) < 1) {
ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x,
s->mb_y, ER_MB_ERROR);
return;
}
@@ -2873,7 +2873,7 @@ static void vc1_decode_b_blocks(VC1Context *v)
update_block_index(s);
if (v->fcm == ILACE_FIELD || v->skip_is_raw || v->dmb_is_raw)
- if (get_bits_left(&v->gb) <= 1) {
+ if (get_bits_left(&v->gb) < 1) {
ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x,
s->mb_y, ER_MB_ERROR);
return;
}
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]