Merge commit 'aae159a7cc4df7d0521901022b778c9da251c24e'
authorMichael Niedermayer <michaelni@gmx.at>
Wed, 14 Aug 2013 08:07:38 +0000 (10:07 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Wed, 14 Aug 2013 08:10:14 +0000 (10:10 +0200)
* commit 'aae159a7cc4df7d0521901022b778c9da251c24e':
  nuv: Do not ignore lzo decompression failures

Conflicts:
libavcodec/nuv.c
tests/ref/fate/nuv-rtjpeg

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavcodec/nuv.c
tests/ref/fate/nuv-rtjpeg

diff --combined libavcodec/nuv.c
@@@ -2,26 -2,25 +2,26 @@@
   * NuppelVideo decoder
   * Copyright (c) 2006 Reimar Doeffinger
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
  #include <stdio.h>
  #include <stdlib.h>
 +#include <limits.h>
  
  #include "libavutil/bswap.h"
  #include "libavutil/common.h"
@@@ -121,16 -120,12 +121,16 @@@ static int codec_reinit(AVCodecContext 
      if (quality >= 0)
          get_quant_quality(c, quality);
      if (width != c->width || height != c->height) {
 +        // also reserve space for a possible additional header
 +        int buf_size = 24 + height * width * 3 / 2 + AV_LZO_OUTPUT_PADDING;
 +        if (buf_size > INT_MAX/8)
 +            return -1;
          if ((ret = av_image_check_size(height, width, 0, avctx)) < 0)
              return ret;
          avctx->width  = c->width  = width;
          avctx->height = c->height = height;
          av_fast_malloc(&c->decomp_buf, &c->decomp_size,
 -                       c->height * c->width * 3 / 2);
 +                       buf_size);
          if (!c->decomp_buf) {
              av_log(avctx, AV_LOG_ERROR,
                     "Can't allocate decompression buffer.\n");
          }
          ff_rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height,
                                c->lq, c->cq);
 +        return 1;
      } else if (quality != c->quality)
          ff_rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height,
                                c->lq, c->cq);
@@@ -155,7 -149,6 +155,7 @@@ static int decode_frame(AVCodecContext 
      AVFrame *picture   = data;
      int orig_size      = buf_size;
      int keyframe;
 +    int size_change = 0;
      int result, init_frame = !avctx->frame_number;
      enum {
          NUV_UNCOMPRESSED  = '0',
          return orig_size;
      }
  
 -    if (buf[0] != 'V' || buf_size < 12) {
 +    if (buf_size < 12 || buf[0] != 'V') {
          av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
          return AVERROR_INVALIDDATA;
      }
          keyframe = 1;
          break;
      }
 +retry:
      // skip rest of the frameheader.
      buf       = &buf[12];
      buf_size -= 12;
      if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
 -        int outlen = c->decomp_size, inlen = buf_size;
 +        int outlen = c->decomp_size - AV_LZO_OUTPUT_PADDING, inlen = buf_size;
-         if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
+         if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) {
              av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
+             return AVERROR_INVALIDDATA;
+         }
          buf      = c->decomp_buf;
 -        buf_size = c->decomp_size;
 +        buf_size = c->decomp_size - AV_LZO_OUTPUT_PADDING - outlen;
      }
      if (c->codec_frameheader) {
          int w, h, q;
 -        if (buf_size < RTJPEG_HEADER_SIZE || buf[4] != RTJPEG_HEADER_SIZE ||
 -            buf[5] != RTJPEG_FILE_VERSION) {
 -            av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n");
 +        if (buf_size < RTJPEG_HEADER_SIZE) {
 +            av_log(avctx, AV_LOG_ERROR, "Too small NUV video frame\n");
 +            return AVERROR_INVALIDDATA;
 +        }
 +        // There seem to exist two variants of this header: one starts with 'V'
 +        // and 5 bytes unknown, the other matches current MythTV and is 4 bytes size,
 +        // 1 byte header size (== 12), 1 byte version (== 0)
 +        if (buf[0] != 'V' && AV_RL16(&buf[4]) != 0x000c) {
 +            av_log(avctx, AV_LOG_ERROR, "Unknown secondary frame header (wrong codec_tag?)\n");
              return AVERROR_INVALIDDATA;
          }
          w = AV_RL16(&buf[6]);
          q = buf[10];
          if ((result = codec_reinit(avctx, w, h, q)) < 0)
              return result;
 +        if (result) {
 +            buf = avpkt->data;
 +            buf_size = avpkt->size;
 +            size_change = 1;
 +            goto retry;
 +        }
          buf       = &buf[RTJPEG_HEADER_SIZE];
          buf_size -= RTJPEG_HEADER_SIZE;
      }
  
 -    if (keyframe) {
 +    if (size_change || keyframe) {
          av_frame_unref(&c->pic);
          init_frame = 1;
      }
  
 -    result = ff_reget_buffer(avctx, &c->pic);
 -    if (result < 0) {
 -        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
 +    if ((result = ff_reget_buffer(avctx, &c->pic)) < 0)
          return result;
 -    }
      if (init_frame) {
          memset(c->pic.data[0], 0,    avctx->height * c->pic.linesize[0]);
          memset(c->pic.data[1], 0x80, avctx->height * c->pic.linesize[1] / 2);
              av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
              height = buf_size / c->width / 3 * 2;
          }
 -        copy_frame(&c->pic, buf, c->width, height);
 +        if(height > 0)
 +            copy_frame(&c->pic, buf, c->width, height);
          break;
      }
      case NUV_RTJPEG_IN_LZO:
@@@ -1,10 -1,9 +1,9 @@@
 -#tb 0: 1/1000
 -0,        118,        118,        0,   460800, 0x54aedafe
 -0,        152,        152,        0,   460800, 0xb7aa8b56
 -0,        177,        177,        0,   460800, 0x283ea3b5
 -0,        202,        202,        0,   460800, 0x283ea3b5
 -0,        235,        235,        0,   460800, 0x10e577de
 -0,        269,        269,        0,   460800, 0x4e091ee2
 -0,        302,        302,        0,   460800, 0x2ea88828
 -0,        335,        335,        0,   460800, 0x4b7f4df0
 +#tb 0: 100/2997
 +0,          4,          4,        1,   460800, 0x54aedafe
 +0,          5,          5,        1,   460800, 0xb7aa8b56
 +0,          6,          6,        1,   460800, 0x283ea3b5
 +0,          7,          7,        1,   460800, 0x283ea3b5
 +0,          8,          8,        1,   460800, 0x10e577de
 +0,          9,          9,        1,   460800, 0x4e091ee2
 +0,         10,         10,        1,   460800, 0x2ea88828
 +0,         11,         11,        1,   460800, 0x4b7f4df0
- 0,         12,         12,        1,   460800, 0xa57f20d0