Merge commit '7d039e70a5ff23a7deaa866684d2e8872acc5169'
authorMichael Niedermayer <michaelni@gmx.at>
Wed, 29 May 2013 02:37:53 +0000 (04:37 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Wed, 29 May 2013 02:37:58 +0000 (04:37 +0200)
* commit '7d039e70a5ff23a7deaa866684d2e8872acc5169':
  wavpack: extract channel information from the bitstream

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavcodec/wavpack.c

diff --combined libavcodec/wavpack.c
index 3a9772eba15841c29b678b57cceda0bb4077e68a,9c766ca181197271f2e2be91ae6789023d52d4be..5a7aae2dd3b381b095336744feb2b82b1dc8c0db
@@@ -2,20 -2,20 +2,20 @@@
   * WavPack lossless audio decoder
   * Copyright (c) 2006,2011 Konstantin Shishkov
   *
 - * 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
   */
  
  #define WV_HYBRID_SHAPE   0x00000008
  #define WV_HYBRID_BITRATE 0x00000200
  #define WV_HYBRID_BALANCE 0x00000400
+ #define WV_INITIAL_BLOCK  0x00000800
+ #define WV_FINAL_BLOCK    0x00001000
+ #define WV_SINGLE_BLOCK (WV_INITIAL_BLOCK | WV_FINAL_BLOCK)
  
  #define WV_FLT_SHIFT_ONES 0x01
  #define WV_FLT_SHIFT_SAME 0x02
@@@ -50,8 -54,6 +54,8 @@@
  #define WV_FLT_ZERO_SENT  0x08
  #define WV_FLT_ZERO_SIGN  0x10
  
 +#define WV_MAX_SAMPLES    131072
 +
  enum WP_ID_Flags {
      WP_IDF_MASK   = 0x3F,
      WP_IDF_IGNORE = 0x20,
@@@ -137,7 -139,6 +141,6 @@@ typedef struct WavpackContext 
      WavpackFrameContext *fdec[WV_MAX_FRAME_DECODERS];
      int fdec_num;
  
-     int multichannel;
      int block;
      int samples;
      int ch_offset;
@@@ -380,10 -381,6 +383,10 @@@ static int wv_get_value(WavpackFrameCon
          INC_MED(2);
      }
      if (!c->error_limit) {
 +        if (add >= 0x2000000U) {
 +            av_log(ctx->avctx, AV_LOG_ERROR, "k %d is too large\n", add);
 +            goto error;
 +        }
          ret = base + get_tail(gb, add);
          if (get_bits_left(gb) <= 0)
              goto error;
@@@ -730,12 -727,6 +733,6 @@@ static av_cold int wavpack_decode_init(
  
      s->avctx = avctx;
  
-     if (avctx->channels <= 2 && !avctx->channel_layout)
-         avctx->channel_layout = (avctx->channels == 2) ? AV_CH_LAYOUT_STEREO
-                                                        : AV_CH_LAYOUT_MONO;
-     s->multichannel = avctx->channels > 2;
      s->fdec_num = 0;
  
      return 0;
@@@ -764,7 -755,8 +761,8 @@@ static int wavpack_decode_block(AVCodec
      int got_terms   = 0, got_weights = 0, got_samples = 0,
          got_entropy = 0, got_bs      = 0, got_float   = 0, got_hybrid = 0;
      int i, j, id, size, ssize, weights, t;
-     int bpp, chan, chmask, orig_bpp, sample_rate = 0;
+     int bpp, chan = 0, chmask = 0, orig_bpp, sample_rate = 0;
+     int multiblock;
  
      if (block_no >= wc->fdec_num && wv_alloc_frame_context(wc) < 0) {
          av_log(avctx, AV_LOG_ERROR, "Error creating frame decode context\n");
      s->frame_flags = bytestream2_get_le32(&gb);
      bpp            = av_get_bytes_per_sample(avctx->sample_fmt);
      orig_bpp       = ((s->frame_flags & 0x03) + 1) << 3;
+     multiblock     = (s->frame_flags & WV_SINGLE_BLOCK) != WV_SINGLE_BLOCK;
  
      s->stereo         = !(s->frame_flags & WV_MONO);
      s->stereo_in      =  (s->frame_flags & WV_FALSE_STEREO) ? 0 : s->stereo;
      s->hybrid_minclip = ((-1LL << (orig_bpp - 1)));
      s->CRC            = bytestream2_get_le32(&gb);
  
 +    if (wc->ch_offset + s->stereo >= avctx->channels) {
 +        av_log(avctx, AV_LOG_ERROR, "too many channels\n");
 +        return -1;
 +    }
 +
      // parse metadata blocks
      while (bytestream2_get_bytes_left(&gb)) {
          id   = bytestream2_get_byte(&gb);
                  chmask = bytestream2_get_le24(&gb);
                  break;
              case 3:
 -                chmask = bytestream2_get_le32(&gb);;
 +                chmask = bytestream2_get_le32(&gb);
                  break;
              case 5:
                  bytestream2_skip(&gb, 1);
                  chan   = avctx->channels;
                  chmask = avctx->channel_layout;
              }
-             if (chan != avctx->channels) {
-                 av_log(avctx, AV_LOG_ERROR,
-                        "Block reports total %d channels, "
-                        "decoder believes it's %d channels\n",
-                        chan, avctx->channels);
-                 return AVERROR_INVALIDDATA;
-             }
-             if (!avctx->channel_layout)
-                 avctx->channel_layout = chmask;
              break;
          case WP_ID_SAMPLE_RATE:
              if (size != 3) {
          } else
              avctx->sample_rate = wv_rates[sr];
  
+         if (multiblock) {
+             if (chan)
+                 avctx->channels = chan;
+             if (chmask)
+                 avctx->channel_layout = chmask;
+         } else {
+             avctx->channels       = s->stereo ? 2 : 1;
+             avctx->channel_layout = s->stereo ? AV_CH_LAYOUT_STEREO :
+                                                 AV_CH_LAYOUT_MONO;
+         }
          /* get output buffer */
 -        frame->nb_samples = s->samples;
 +        frame->nb_samples = s->samples + 1;
          if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
              av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
              return ret;
          }
 +        frame->nb_samples = s->samples;
      }
  
      samples_l = frame->extended_data[wc->ch_offset];
@@@ -1180,7 -1169,7 +1181,7 @@@ static int wavpack_decode_frame(AVCodec
      /* determine number of samples */
      s->samples  = AV_RL32(buf + 20);
      frame_flags = AV_RL32(buf + 24);
 -    if (s->samples <= 0) {
 +    if (s->samples <= 0 || s->samples > WV_MAX_SAMPLES) {
          av_log(avctx, AV_LOG_ERROR, "Invalid number of samples: %d\n",
                 s->samples);
          return AVERROR_INVALIDDATA;