You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2026-06-19 19:03:00 +02:00
avcodec/snowenc: fix chroma reference edge extension for odd width
When extending the edges of the reconstructed reference frame, the chroma plane width and height were passed to draw_edges() as w >> chroma_h_shift (floor) instead of AV_CEIL_RSHIFT(). For an odd width with subsampled chroma (e.g. 4:2:0) the chroma plane is one column wider than the floor, and draw_edges() replicates the edge columns, so it overwrote the last real chroma column with the previous one. The decoder does not draw_edges() its reference, so its copy kept the correct value: the encoder and decoder references diverged and every following inter frame was reconstructed differently by the two, breaking bit-exact (lossless) round-tripping and drifting lossy inter coding, for any odd-width 4:2:0 snow stream. Use AV_CEIL_RSHIFT(), matching the input_picture edge extension just above. Found-by: Claude Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
@@ -1838,10 +1838,10 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
|
||||
EDGE_WIDTH , EDGE_WIDTH , EDGE_TOP | EDGE_BOTTOM);
|
||||
if (s->current_picture->data[2]) {
|
||||
enc->mpvencdsp.draw_edges(s->current_picture->data[1],
|
||||
s->current_picture->linesize[1], w>>s->chroma_h_shift, h>>s->chroma_v_shift,
|
||||
s->current_picture->linesize[1], AV_CEIL_RSHIFT(w, s->chroma_h_shift), AV_CEIL_RSHIFT(h, s->chroma_v_shift),
|
||||
EDGE_WIDTH>>s->chroma_h_shift, EDGE_WIDTH>>s->chroma_v_shift, EDGE_TOP | EDGE_BOTTOM);
|
||||
enc->mpvencdsp.draw_edges(s->current_picture->data[2],
|
||||
s->current_picture->linesize[2], w>>s->chroma_h_shift, h>>s->chroma_v_shift,
|
||||
s->current_picture->linesize[2], AV_CEIL_RSHIFT(w, s->chroma_h_shift), AV_CEIL_RSHIFT(h, s->chroma_v_shift),
|
||||
EDGE_WIDTH>>s->chroma_h_shift, EDGE_WIDTH>>s->chroma_v_shift, EDGE_TOP | EDGE_BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user