]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/wavpack.c
libcdio: support recent cdio-paranoia
[ffmpeg] / libavcodec / wavpack.c
index 6896877fca1bddaa525da4e3e9447b9d0f06b392..e8f34fa6320d99b831ceedbf643a35c70a3cf8a3 100644 (file)
 
 #define BITSTREAM_READER_LE
 
-#include "libavutil/audioconvert.h"
+#include "libavutil/channel_layout.h"
 #include "avcodec.h"
 #include "get_bits.h"
+#include "internal.h"
 #include "unary.h"
 
 /**
@@ -112,7 +113,8 @@ typedef struct WavpackFrameContext {
     int extra_bits;
     int and, or, shift;
     int post_shift;
-    int hybrid, hybrid_bitrate, hybrid_maxclip;
+    int hybrid, hybrid_bitrate;
+    int hybrid_maxclip, hybrid_minclip;
     int float_flag;
     int float_shift;
     int float_max_exp;
@@ -412,12 +414,12 @@ static inline int wv_get_value_integer(WavpackFrameContext *s, uint32_t *crc,
     }
 
     bit = (S & s->and) | s->or;
-    bit = (((S + bit) << s->shift) - bit) << s->post_shift;
+    bit = ((S + bit) << s->shift) - bit;
 
     if (s->hybrid)
-        bit = av_clip(bit, -s->hybrid_maxclip - 1, s->hybrid_maxclip);
+        bit = av_clip(bit, s->hybrid_minclip, s->hybrid_maxclip);
 
-    return bit;
+    return bit << s->post_shift;
 }
 
 static float wv_get_value_float(WavpackFrameContext *s, uint32_t *crc, int S)
@@ -427,7 +429,7 @@ static float wv_get_value_float(WavpackFrameContext *s, uint32_t *crc, int S)
         uint32_t u;
     } value;
 
-    int sign;
+    unsigned int sign;
     int exp = s->float_max_exp;
 
     if (s->got_extra_bits) {
@@ -499,6 +501,21 @@ static void wv_reset_saved_context(WavpackFrameContext *s)
     s->sc.crc = s->extra_sc.crc = 0xFFFFFFFF;
 }
 
+static inline int wv_check_crc(WavpackFrameContext *s, uint32_t crc,
+                               uint32_t crc_extra_bits)
+{
+    if (crc != s->CRC) {
+        av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
+        return AVERROR_INVALIDDATA;
+    }
+    if (s->got_extra_bits && crc_extra_bits != s->crc_extra_bits) {
+        av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
 static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb,
                                    void *dst, const int type)
 {
@@ -609,14 +626,9 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb,
     } while (!last && count < s->samples);
 
     wv_reset_saved_context(s);
-    if (crc != s->CRC) {
-        av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
-        return -1;
-    }
-    if (s->got_extra_bits && crc_extra_bits != s->crc_extra_bits) {
-        av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n");
-        return -1;
-    }
+    if ((s->avctx->err_recognition & AV_EF_CRCCHECK) &&
+        wv_check_crc(s, crc, crc_extra_bits))
+        return AVERROR_INVALIDDATA;
 
     return count * 2;
 }
@@ -679,14 +691,9 @@ static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb,
     } while (!last && count < s->samples);
 
     wv_reset_saved_context(s);
-    if (crc != s->CRC) {
-        av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
-        return -1;
-    }
-    if (s->got_extra_bits && crc_extra_bits != s->crc_extra_bits) {
-        av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n");
-        return -1;
-    }
+    if ((s->avctx->err_recognition & AV_EF_CRCCHECK) &&
+        wv_check_crc(s, crc, crc_extra_bits))
+        return AVERROR_INVALIDDATA;
 
     return count;
 }
@@ -763,7 +770,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
     const uint8_t *orig_buf = buf;
     const uint8_t *buf_end  = buf + buf_size;
     int i, j, id, size, ssize, weights, t;
-    int bpp, chan, chmask;
+    int bpp, chan, chmask, orig_bpp;
 
     if (buf_size == 0) {
         *got_frame_ptr = 0;
@@ -799,15 +806,16 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
     s->frame_flags = AV_RL32(buf); buf += 4;
     bpp = av_get_bytes_per_sample(avctx->sample_fmt);
     samples = (uint8_t*)samples + bpp * wc->ch_offset;
+    orig_bpp = ((s->frame_flags & 0x03) + 1) << 3;
 
     s->stereo         = !(s->frame_flags & WV_MONO);
     s->stereo_in      =  (s->frame_flags & WV_FALSE_STEREO) ? 0 : s->stereo;
     s->joint          =   s->frame_flags & WV_JOINT_STEREO;
     s->hybrid         =   s->frame_flags & WV_HYBRID_MODE;
     s->hybrid_bitrate =   s->frame_flags & WV_HYBRID_BITRATE;
-    s->hybrid_maxclip = (1LL << ((((s->frame_flags & 0x03) + 1) << 3) - 1)) - 1;
-    s->post_shift     = 8 * (bpp - 1 - (s->frame_flags & 0x03)) +
-                        ((s->frame_flags >> 13) & 0x1f);
+    s->post_shift     = bpp * 8 - orig_bpp + ((s->frame_flags >> 13) & 0x1f);
+    s->hybrid_maxclip = (( 1LL << (orig_bpp - 1)) - 1);
+    s->hybrid_minclip = ((-1LL << (orig_bpp - 1)));
     s->CRC            = AV_RL32(buf); buf += 4;
     if (wc->mkv_mode)
         buf += 4; //skip block size;
@@ -904,8 +912,9 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
                 } else {
                     for (j = 0; j < s->decorr[i].value; j++) {
                         s->decorr[i].samplesA[j] = wp_exp2(AV_RL16(buf)); buf += 2;
-                        if (s->stereo_in)
+                        if (s->stereo_in) {
                             s->decorr[i].samplesB[j] = wp_exp2(AV_RL16(buf)); buf += 2;
+                        }
                     }
                     t += s->decorr[i].value * 2 * (s->stereo_in + 1);
                 }
@@ -968,6 +977,15 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
                 s->and   = 1;
                 s->shift = buf[3];
             }
+            /* original WavPack decoder forces 32-bit lossy sound to be treated
+             * as 24-bit one in order to have proper clipping
+             */
+            if (s->hybrid && bpp == 4 && s->post_shift < 8 && s->shift > 8) {
+                s->post_shift += 8;
+                s->shift      -= 8;
+                s->hybrid_maxclip >>= 8;
+                s->hybrid_minclip >>= 8;
+            }
             buf += 4;
             break;
         case WP_ID_FLOATINFO:
@@ -1185,11 +1203,12 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
         avctx->sample_fmt = AV_SAMPLE_FMT_S16;
     } else {
         avctx->sample_fmt = AV_SAMPLE_FMT_S32;
+        avctx->bits_per_raw_sample = ((frame_flags & 0x03) + 1) << 3;
     }
 
     /* get output buffer */
     s->frame.nb_samples = s->samples;
-    if ((ret = avctx->get_buffer(avctx, &s->frame)) < 0) {
+    if ((ret = ff_get_buffer(avctx, &s->frame)) < 0) {
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
         return ret;
     }
@@ -1231,7 +1250,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
 AVCodec ff_wavpack_decoder = {
     .name           = "wavpack",
     .type           = AVMEDIA_TYPE_AUDIO,
-    .id             = CODEC_ID_WAVPACK,
+    .id             = AV_CODEC_ID_WAVPACK,
     .priv_data_size = sizeof(WavpackContext),
     .init           = wavpack_decode_init,
     .close          = wavpack_decode_end,