[FFmpeg-devel,4/7] avcodec/ffv1enc: prevent encoder to create non-lossless streams with some chroma subsamplings

Submitted by Jerome Martinez on March 7, 2018, 3:50 p.m.

Details

Message ID 1c68f255-3063-26d2-0aee-585c48aeb869@mediaarea.net
State New
Headers show

Commit Message

Jerome Martinez March 7, 2018, 3:50 p.m.
When all luma samples for a chroma sample are not in the same slice, 
resulting bitstream is valid but the compression then decompression is 
not lossless.

ffmpeg -y -f lavfi -i mandelbrot=s=1925x1080 -vf format=yuv411p -vframes 
1 -c ffv1 -slices 16 a.mkv
ffmpeg -y -f lavfi -i mandelbrot=s=1925x1080 -vf format=yuv411p -vframes 
1 -f framemd5 source.md5
ffmpeg -y -i a.mkv -vframes 1 -f framemd5 a.mkv.md5
Framemd5 are not same.

For e.g. 4:1:1 and 4 horizontal slices (-slices 16), we have
1920-1921-1922-1923-1924 1926-1927-1928 1931-1932 1936 OK
1925 1929-1930 1933-1934-1935 NOK

This patch is an hotfix for preventing the encoder to create such stream.
Note that it blocks more than needed (e.g, all the listed widths above 
except multiples of 16 are blocked) as I didn't find the exact pattern 
that makes the conversion NOK, the hotfix is definitely not nice and I 
would welcome another proposal.
From 954817ec1f78396d04383a1ea19aec7739fdd7fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Martinez?= <jerome@mediaarea.net>
Date: Wed, 7 Mar 2018 10:41:10 +0100
Subject: [PATCH 4/7] avcodec/ffv1enc: prevent encoder to create non-lossless
 streams with some chroma subsamplings

Some combinations having chroma subsampling are not lossless with current code
---
 libavcodec/ffv1enc.c | 4 ++++
 1 file changed, 4 insertions(+)

Patch hide | download patch | download mbox

diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index 51aa8c2898..16987117d8 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -876,6 +876,10 @@  FF_ENABLE_DEPRECATION_WARNINGS
             for (s->num_h_slices = s->num_v_slices; s->num_h_slices < 2*s->num_v_slices; s->num_h_slices++) {
                 int maxw = (avctx->width  + s->num_h_slices - 1) / s->num_h_slices;
                 int maxh = (avctx->height + s->num_v_slices - 1) / s->num_v_slices;
+                if (s->chroma_h_shift && (avctx->width % (s->num_h_slices << s->chroma_h_shift))) // Hotfix: some combinations having chroma subsampling are not lossless with current code, e.g. width of 1919 with 422 subsampling and 2 horizontal slices, or width of 1921 with 422 subsampling and 2 horizontal slices
+                    continue;
+                if (s->chroma_v_shift && (avctx->height % (s->num_v_slices << s->chroma_v_shift))) // Hotfix: some combinations having chroma subsampling are not lossless with current code, e.g. width of 1919 with 422 subsampling and 2 horizontal slices, or width of 1921 with 422 subsampling and 2 horizontal slices
+                    continue;
                 if (s->num_h_slices > max_h_slices || s->num_v_slices > max_v_slices)
                     continue;
                 if (maxw * maxh * (int64_t)(s->bits_per_raw_sample+1) * plane_count > 8<<24)