Hi,

ticket #3872 is about a regression on decoding of hevc:
https://trac.ffmpeg.org/ticket/3872

The reason is a stricter validation is now performed since 5ec85c97.

The sequence seems invalid to me, as it seems the SPS was truncated or
corrupted somewhere in the VUI. But if we ignore the a priori invalid
SPS, the sequence actually decodes fine.

It seems impossible to detect when this occurs:
- A local test by remuxing hevc ES streams into mkv with mkvtoolnix
7.1.0 yielded valid streams, so this muxer is maybe not responsible
(the file may have actually been transmuxed);
- I don't see any obvious extra/userdata or anything allowing to
identify the encoder (is it x265? the information has been stripped so
it may be another encoder).

The metadata (I bet irrelevant here) of this file, as found on
ffmpeg's stdout, can be seen in the attached metadata.txt file

I'm trying to dig more information to see how narrow a fix could be.
H.264 in that case simply rejects the data.

It's a pity here that the file is actually fine, but that it is
indistinguishable otherwise from a corrupt, undecodable stream.

The attached patch tries to be lenient about the VUI having errors,
but this is hardly tolerable either, as hevc extensions
(scalable/other profile data) signal their data afterwards.

-- 
Christophe
      _STATISTICS_WRITING_APP: mkvmerge v7.1.0 ('Good Love') 32bit built on Jul 
27 2014 12:59:18
      _STATISTICS_WRITING_APP-eng: mkvmerge v7.1.0 ('Good Love') 32bit built on 
Jul 27 2014 12:59:18
      _STATISTICS_WRITING_DATE_UTC: 2014-08-19 19:23:56
      _STATISTICS_WRITING_DATE_UTC-eng: 2014-08-19 19:23:56
      _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
      BPS             : 3979031
      BPS-eng         : 3979031
      DURATION        : 00:01:38.557000000
      DURATION-eng    : 00:01:38.557000000
      NUMBER_OF_FRAMES: 2363
      NUMBER_OF_FRAMES-eng: 2363
      NUMBER_OF_BYTES : 49020173
      NUMBER_OF_BYTES-eng: 49020173
From dd2edff6495c1f94746c5bff0ff3ac52717b5347 Mon Sep 17 00:00:00 2001
From: Christophe Gisquet <christophe.gisq...@gmail.com>
Date: Thu, 21 Aug 2014 01:31:53 +0200
Subject: [PATCH] hevc_ps: reorder SPS reading to allow some errors

Some streams have been found to have their VUI truncated but still decode
fine. To handle them, only abort when incorrect data has been found before
the VUI. Warn if overread occurred afterwards.

However, HEVC extensions will not be correctly handled.

Fixes ticket #3872.
---
 libavcodec/hevc_ps.c | 161 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 88 insertions(+), 73 deletions(-)

diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c
index 2ccce5f..a74f60a 100644
--- a/libavcodec/hevc_ps.c
+++ b/libavcodec/hevc_ps.c
@@ -937,79 +937,6 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
 
     sps->sps_temporal_mvp_enabled_flag          = get_bits1(gb);
     sps->sps_strong_intra_smoothing_enable_flag = get_bits1(gb);
-    sps->vui.sar = (AVRational){0, 1};
-    vui_present = get_bits1(gb);
-    if (vui_present)
-        decode_vui(s, sps);
-
-    if (get_bits1(gb)) { // sps_extension_flag
-        int sps_extension_flag[1];
-        for (i = 0; i < 1; i++)
-            sps_extension_flag[i] = get_bits1(gb);
-        skip_bits(gb, 7); //sps_extension_7bits = get_bits(gb, 7);
-        if (sps_extension_flag[0]) {
-            int extended_precision_processing_flag;
-            int high_precision_offsets_enabled_flag;
-            int cabac_bypass_alignment_enabled_flag;
-
-            sps->transform_skip_rotation_enabled_flag = get_bits1(gb);
-            sps->transform_skip_context_enabled_flag  = get_bits1(gb);
-            sps->implicit_rdpcm_enabled_flag = get_bits1(gb);
-
-            sps->explicit_rdpcm_enabled_flag = get_bits1(gb);
-
-            extended_precision_processing_flag = get_bits1(gb);
-            if (extended_precision_processing_flag)
-                av_log(s->avctx, AV_LOG_WARNING,
-                   "extended_precision_processing_flag not yet implemented\n");
-
-            sps->intra_smoothing_disabled_flag       = get_bits1(gb);
-            high_precision_offsets_enabled_flag  = get_bits1(gb);
-            if (high_precision_offsets_enabled_flag)
-                av_log(s->avctx, AV_LOG_WARNING,
-                   "high_precision_offsets_enabled_flag not yet implemented\n");
-
-            sps->persistent_rice_adaptation_enabled_flag = get_bits1(gb);
-
-            cabac_bypass_alignment_enabled_flag  = get_bits1(gb);
-            if (cabac_bypass_alignment_enabled_flag)
-                av_log(s->avctx, AV_LOG_WARNING,
-                   "cabac_bypass_alignment_enabled_flag not yet implemented\n");
-        }
-    }
-    if (s->apply_defdispwin) {
-        sps->output_window.left_offset   += sps->vui.def_disp_win.left_offset;
-        sps->output_window.right_offset  += sps->vui.def_disp_win.right_offset;
-        sps->output_window.top_offset    += sps->vui.def_disp_win.top_offset;
-        sps->output_window.bottom_offset += sps->vui.def_disp_win.bottom_offset;
-    }
-    if (sps->output_window.left_offset & (0x1F >> (sps->pixel_shift)) &&
-        !(s->avctx->flags & CODEC_FLAG_UNALIGNED)) {
-        sps->output_window.left_offset &= ~(0x1F >> (sps->pixel_shift));
-        av_log(s->avctx, AV_LOG_WARNING, "Reducing left output window to %d "
-               "chroma samples to preserve alignment.\n",
-               sps->output_window.left_offset);
-    }
-    sps->output_width  = sps->width -
-                         (sps->output_window.left_offset + sps->output_window.right_offset);
-    sps->output_height = sps->height -
-                         (sps->output_window.top_offset + sps->output_window.bottom_offset);
-    if (sps->output_width <= 0 || sps->output_height <= 0) {
-        av_log(s->avctx, AV_LOG_WARNING, "Invalid visible frame dimensions: %dx%d.\n",
-               sps->output_width, sps->output_height);
-        if (s->avctx->err_recognition & AV_EF_EXPLODE) {
-            ret = AVERROR_INVALIDDATA;
-            goto err;
-        }
-        av_log(s->avctx, AV_LOG_WARNING,
-               "Displaying the whole video surface.\n");
-        sps->pic_conf_win.left_offset   =
-        sps->pic_conf_win.right_offset  =
-        sps->pic_conf_win.top_offset    =
-        sps->pic_conf_win.bottom_offset = 0;
-        sps->output_width               = sps->width;
-        sps->output_height              = sps->height;
-    }
 
     // Inferred parameters
     sps->log2_ctb_size = sps->log2_min_cb_size +
@@ -1063,6 +990,94 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
         goto err;
     }
 
+    sps->vui.sar = (AVRational){0, 1};
+    vui_present = get_bits1(gb);
+
+    if (vui_present)
+        decode_vui(s, sps);
+
+    if (s->apply_defdispwin) {
+        sps->output_window.left_offset   += sps->vui.def_disp_win.left_offset;
+        sps->output_window.right_offset  += sps->vui.def_disp_win.right_offset;
+        sps->output_window.top_offset    += sps->vui.def_disp_win.top_offset;
+        sps->output_window.bottom_offset += sps->vui.def_disp_win.bottom_offset;
+    }
+    if (sps->output_window.left_offset & (0x1F >> (sps->pixel_shift)) &&
+        !(s->avctx->flags & CODEC_FLAG_UNALIGNED)) {
+        sps->output_window.left_offset &= ~(0x1F >> (sps->pixel_shift));
+        av_log(s->avctx, AV_LOG_WARNING, "Reducing left output window to %d "
+               "chroma samples to preserve alignment.\n",
+               sps->output_window.left_offset);
+    }
+    sps->output_width  = sps->width -
+                         (sps->output_window.left_offset + sps->output_window.right_offset);
+    sps->output_height = sps->height -
+                         (sps->output_window.top_offset + sps->output_window.bottom_offset);
+    if (sps->output_width <= 0 || sps->output_height <= 0) {
+        av_log(s->avctx, AV_LOG_WARNING, "Invalid visible frame dimensions: %dx%d.\n",
+               sps->output_width, sps->output_height);
+        if (s->avctx->err_recognition & AV_EF_EXPLODE) {
+            ret = AVERROR_INVALIDDATA;
+            goto err;
+        }
+        av_log(s->avctx, AV_LOG_WARNING,
+               "Displaying the whole video surface.\n");
+        sps->pic_conf_win.left_offset   =
+        sps->pic_conf_win.right_offset  =
+        sps->pic_conf_win.top_offset    =
+        sps->pic_conf_win.bottom_offset = 0;
+        sps->output_width               = sps->width;
+        sps->output_height              = sps->height;
+    }
+
+    if (get_bits1(gb)) { // sps_extension_flag
+        int sps_extension_flag[1];
+        for (i = 0; i < 1; i++)
+            sps_extension_flag[i] = get_bits1(gb);
+        skip_bits(gb, 7); //sps_extension_7bits = get_bits(gb, 7);
+        if (sps_extension_flag[0]) {
+            int extended_precision_processing_flag;
+            int high_precision_offsets_enabled_flag;
+            int cabac_bypass_alignment_enabled_flag;
+
+            sps->transform_skip_rotation_enabled_flag = get_bits1(gb);
+            sps->transform_skip_context_enabled_flag  = get_bits1(gb);
+            sps->implicit_rdpcm_enabled_flag = get_bits1(gb);
+
+            sps->explicit_rdpcm_enabled_flag = get_bits1(gb);
+
+            extended_precision_processing_flag = get_bits1(gb);
+            if (extended_precision_processing_flag)
+                av_log(s->avctx, AV_LOG_WARNING,
+                   "extended_precision_processing_flag not yet implemented\n");
+
+            sps->intra_smoothing_disabled_flag       = get_bits1(gb);
+            high_precision_offsets_enabled_flag  = get_bits1(gb);
+            if (high_precision_offsets_enabled_flag)
+                av_log(s->avctx, AV_LOG_WARNING,
+                   "high_precision_offsets_enabled_flag not yet implemented\n");
+
+            sps->persistent_rice_adaptation_enabled_flag = get_bits1(gb);
+
+            cabac_bypass_alignment_enabled_flag  = get_bits1(gb);
+            if (cabac_bypass_alignment_enabled_flag)
+                av_log(s->avctx, AV_LOG_WARNING,
+                   "cabac_bypass_alignment_enabled_flag not yet implemented\n");
+        }
+
+        if (get_bits_left(gb) < 0) {
+            av_log(s->avctx, AV_LOG_ERROR,
+                   "Overread in extensions of SPS by %d bits\n",
+                   -get_bits_left(gb));
+            goto err;
+        }
+    }
+
+    if (get_bits_left(gb) < 0)
+        av_log(s->avctx, AV_LOG_WARNING,
+               "Overread in VUI and/or extensions of SPS by %d bits\n",
+               -get_bits_left(gb));
+
     if (s->avctx->debug & FF_DEBUG_BITSTREAM) {
         av_log(s->avctx, AV_LOG_DEBUG,
                "Parsed SPS: id %d; coded wxh: %dx%d; "
-- 
1.9.2.msysgit.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to