WavPack lossless audio decoder

Originally committed as revision 6336 to svn://svn.ffmpeg.org/ffmpeg/trunk
pull/126/head
Kostya Shishkov 19 years ago
parent 1a174c2831
commit 730581f3b4
  1. 1
      Changelog
  2. 2
      MAINTAINERS
  3. 1
      doc/ffmpeg-doc.texi
  4. 1
      libavcodec/Makefile
  5. 3
      libavcodec/allcodecs.c
  6. 2
      libavcodec/avcodec.h
  7. 548
      libavcodec/wavpack.c
  8. 1
      libavformat/Makefile
  9. 3
      libavformat/allformats.c
  10. 1
      libavformat/allformats.h
  11. 207
      libavformat/wv.c

@ -58,6 +58,7 @@ version <next>
- VMware video decoder - VMware video decoder
- VP5 video decoder - VP5 video decoder
- VP6 video decoder - VP6 video decoder
- WavPack lossless audio decoder
version 0.4.9-pre1: version 0.4.9-pre1:

@ -167,6 +167,7 @@ Codecs:
vp5 Aurelien Jacobs vp5 Aurelien Jacobs
vp6 Aurelien Jacobs vp6 Aurelien Jacobs
vqavideo.c Mike Melanson vqavideo.c Mike Melanson
wavpack.c Kostya Shishkov
wmv2.c Michael Niedermayer wmv2.c Michael Niedermayer
wnv1.c Kostya Shishkov wnv1.c Kostya Shishkov
x264.c Mans Rullgard x264.c Mans Rullgard
@ -219,6 +220,7 @@ Muxers/Demuxers:
wav.c Michael Niedermayer wav.c Michael Niedermayer
wc3movie.c Mike Melanson wc3movie.c Mike Melanson
westwood.c Mike Melanson westwood.c Mike Melanson
wv.c Kostya Shishkov
Operating systems / CPU architectures Operating systems / CPU architectures

@ -893,6 +893,7 @@ following image formats are supported:
@item DSP Group TrueSpeech @tab @tab X @item DSP Group TrueSpeech @tab @tab X
@item True Audio (TTA) @tab @tab X @item True Audio (TTA) @tab @tab X
@item Smacker Audio @tab @tab X @item Smacker Audio @tab @tab X
@item WavPack Audio @tab @tab X
@end multitable @end multitable
@code{X} means that encoding (resp. decoding) is supported. @code{X} means that encoding (resp. decoding) is supported.

@ -126,6 +126,7 @@ OBJS-$(CONFIG_VP3_DECODER) += vp3.o
OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o
OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o
OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o
OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o
OBJS-$(CONFIG_WMAV1_DECODER) += wmadec.o OBJS-$(CONFIG_WMAV1_DECODER) += wmadec.o
OBJS-$(CONFIG_WMAV2_DECODER) += wmadec.o OBJS-$(CONFIG_WMAV2_DECODER) += wmadec.o
OBJS-$(CONFIG_WMV3_DECODER) += vc1.o OBJS-$(CONFIG_WMV3_DECODER) += vc1.o

@ -540,6 +540,9 @@ void avcodec_register_all(void)
#ifdef CONFIG_VMNC_DECODER #ifdef CONFIG_VMNC_DECODER
register_avcodec(&vmnc_decoder); register_avcodec(&vmnc_decoder);
#endif //CONFIG_VMNC_DECODER #endif //CONFIG_VMNC_DECODER
#ifdef CONFIG_WAVPACK_DECODER
register_avcodec(&wavpack_decoder);
#endif //CONFIG_WAVPACK_DECODER
#endif /* CONFIG_DECODERS */ #endif /* CONFIG_DECODERS */
#if defined(CONFIG_AMR_NB) || defined(CONFIG_AMR_NB_FIXED) #if defined(CONFIG_AMR_NB) || defined(CONFIG_AMR_NB_FIXED)

@ -224,6 +224,7 @@ enum CodecID {
CODEC_ID_TTA, CODEC_ID_TTA,
CODEC_ID_SMACKAUDIO, CODEC_ID_SMACKAUDIO,
CODEC_ID_QCELP, CODEC_ID_QCELP,
CODEC_ID_WAVPACK,
/* subtitle codecs */ /* subtitle codecs */
CODEC_ID_DVD_SUBTITLE= 0x17000, CODEC_ID_DVD_SUBTITLE= 0x17000,
@ -2285,6 +2286,7 @@ extern AVCodec kmvc_decoder;
extern AVCodec flashsv_decoder; extern AVCodec flashsv_decoder;
extern AVCodec cavs_decoder; extern AVCodec cavs_decoder;
extern AVCodec vmnc_decoder; extern AVCodec vmnc_decoder;
extern AVCodec wavpack_decoder;
/* pcm codecs */ /* pcm codecs */
#define PCM_CODEC(id, name) \ #define PCM_CODEC(id, name) \

@ -0,0 +1,548 @@
/*
* WavPack lossless audio decoder
* Copyright (c) 2006 Konstantin Shishkov
*
* This library 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 of the License, or (at your option) any later version.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define ALT_BITSTREAM_READER_LE
#include "avcodec.h"
#include "bitstream.h"
/**
* @file wavpack.c
* WavPack lossless audio decoder
*/
#define WV_JOINT 0x0010
enum WP_ID_Flags{
WP_IDF_MASK = 0x1F,
WP_IDF_IGNORE = 0x20,
WP_IDF_ODD = 0x40,
WP_IDF_LONG = 0x80
};
enum WP_ID{
WP_ID_DUMMY = 0,
WP_ID_ENCINFO,
WP_ID_DECTERMS,
WP_ID_DECWEIGHTS,
WP_ID_DECSAMPLES,
WP_ID_ENTROPY,
WP_ID_HYBRID,
WP_ID_SHAPING,
WP_ID_FLOATINFO,
WP_ID_INT32INFO,
WP_ID_DATA,
WP_ID_CORR,
WP_ID_FLT,
WP_ID_CHANINFO
};
#define MAX_TERMS 16
typedef struct Decorr {
int delta;
int value;
int weightA;
int weightB;
int samplesA[8];
int samplesB[8];
} Decorr;
typedef struct WavpackContext {
AVCodecContext *avctx;
int stereo;
int joint;
uint32_t CRC;
GetBitContext gb;
int data_size; // in bits
int samples;
int median[6];
int terms;
Decorr decorr[MAX_TERMS];
int zero, one, zeroes;
} WavpackContext;
// exponent table copied from WavPack source
static const uint8_t wp_exp2_table [256] = {
0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b,
0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16,
0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23,
0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d,
0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4,
0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9,
0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff
};
static always_inline int wp_exp2(int16_t val)
{
int res, neg = 0;
if(val < 0){
val = -val;
neg = 1;
}
res = wp_exp2_table[val & 0xFF] | 0x100;
val >>= 8;
res = (val > 9) ? (res << (val - 9)) : (res >> (9 - val));
return neg ? -res : res;
}
static inline int get_unary(GetBitContext *gb){
int r=0;
while(get_bits1(gb) && r<33)r++;
return r;
}
// macros for manipulating median values
#define GET_MED(n) ((median[n] >> 4) + 1)
#define DEC_MED(n) median[n] -= ((median[n] + (128>>n) - 2) / (128>>n)) * 2
#define INC_MED(n) median[n] += ((median[n] + (128>>n)) / (128>>n)) * 5
// macros for applying weight
#define UPDATE_WEIGHT_CLIP(weight, delta, samples, in) \
if(samples && in){ \
if((samples ^ in) < 0){ \
weight -= delta; \
if(weight < -1024) weight = -1024; \
}else{ \
weight += delta; \
if(weight > 1024) weight = 1024; \
} \
}
static always_inline int get_tail(GetBitContext *gb, int k)
{
int p, e, res;
if(k<1 || k>65535)return 0;
p = av_log2_16bit(k);
e = (1 << (p + 1)) - k - 1;
res = get_bits(gb, p);
if(res >= e){
res = (res<<1) - e + get_bits1(gb);
}
return res;
}
static int wv_get_value(WavpackContext *ctx, GetBitContext *gb, int *median, int *last)
{
int t, t2;
int sign, base, add, ret;
*last = 0;
if((ctx->median[0] < 2U) && (ctx->median[3] < 2U) && !ctx->zero && !ctx->one){
if(ctx->zeroes){
ctx->zeroes--;
if(ctx->zeroes)
return 0;
}else{
t = get_unary(gb);
if(t >= 2) t = get_bits(gb, t - 1) | (1 << (t-1));
ctx->zeroes = t;
if(ctx->zeroes){
memset(ctx->median, 0, sizeof(ctx->median));
return 0;
}
}
}
if(get_bits_count(gb) >= ctx->data_size){
*last = 1;
return 0;
}
if(ctx->zero){
t = 0;
ctx->zero = 0;
}else{
t = get_unary(gb);
if(get_bits_count(gb) >= ctx->data_size){
*last = 1;
return 0;
}
if(t == 16) {
t2 = get_unary(gb);
if(t2 < 2) t += t2;
else t += get_bits(gb, t2 - 1) | (1 << (t2 - 1));
}
if(ctx->one){
ctx->one = t&1;
t = (t>>1) + 1;
}else{
ctx->one = t&1;
t >>= 1;
}
ctx->zero = !ctx->one;
}
if(!t){
base = 0;
add = GET_MED(0) - 1;
DEC_MED(0);
}else if(t == 1){
base = GET_MED(0);
add = GET_MED(1) - 1;
INC_MED(0);
DEC_MED(1);
}else if(t == 2){
base = GET_MED(0) + GET_MED(1);
add = GET_MED(2) - 1;
INC_MED(0);
INC_MED(1);
DEC_MED(2);
}else{
base = GET_MED(0) + GET_MED(1) + GET_MED(2) * (t - 2);
add = GET_MED(2) - 1;
INC_MED(0);
INC_MED(1);
INC_MED(2);
}
ret = base + get_tail(gb, add);
sign = get_bits1(gb);
return sign ? ~ret : ret;
}
static int wv_unpack_stereo(WavpackContext *s, GetBitContext *gb, int16_t *dst)
{
int i, j, count = 0;
int last, t;
int A, B, L, L2, R, R2;
int pos = 0;
uint32_t crc = 0xFFFFFFFF;
s->one = s->zero = s->zeroes = 0;
do{
L = wv_get_value(s, gb, s->median, &last);
if(last) break;
R = wv_get_value(s, gb, s->median + 3, &last);
if(last) break;
for(i = 0; i < s->terms; i++){
t = s->decorr[i].value;
j = 0;
if(t > 0){
if(t > 8){
if(t & 1){
A = 2 * s->decorr[i].samplesA[0] - s->decorr[i].samplesA[1];
B = 2 * s->decorr[i].samplesB[0] - s->decorr[i].samplesB[1];
}else{
A = (3 * s->decorr[i].samplesA[0] - s->decorr[i].samplesA[1]) >> 1;
B = (3 * s->decorr[i].samplesB[0] - s->decorr[i].samplesB[1]) >> 1;
}
s->decorr[i].samplesA[1] = s->decorr[i].samplesA[0];
s->decorr[i].samplesB[1] = s->decorr[i].samplesB[0];
j = 0;
}else{
A = s->decorr[i].samplesA[pos];
B = s->decorr[i].samplesB[pos];
j = (pos + t) & 7;
}
L2 = L + ((s->decorr[i].weightA * A + 512) >> 10);
R2 = R + ((s->decorr[i].weightB * B + 512) >> 10);
if(A && L) s->decorr[i].weightA -= ((((L ^ A) >> 30) & 2) - 1) * s->decorr[i].delta;
if(B && R) s->decorr[i].weightB -= ((((R ^ B) >> 30) & 2) - 1) * s->decorr[i].delta;
s->decorr[i].samplesA[j] = L = L2;
s->decorr[i].samplesB[j] = R = R2;
}else if(t == -1){
L2 = L + ((s->decorr[i].weightA * s->decorr[i].samplesA[0] + 512) >> 10);
UPDATE_WEIGHT_CLIP(s->decorr[i].weightA, s->decorr[i].delta, s->decorr[i].samplesA[0], L);
L = L2;
R2 = R + ((s->decorr[i].weightB * L2 + 512) >> 10);
UPDATE_WEIGHT_CLIP(s->decorr[i].weightB, s->decorr[i].delta, L2, R);
R = R2;
s->decorr[i].samplesA[0] = R;
}else{
R2 = R + ((s->decorr[i].weightB * s->decorr[i].samplesB[0] + 512) >> 10);
UPDATE_WEIGHT_CLIP(s->decorr[i].weightB, s->decorr[i].delta, s->decorr[i].samplesB[0], R);
R = R2;
if(t == -3){
R2 = s->decorr[i].samplesA[0];
s->decorr[i].samplesA[0] = R;
}
L2 = L + ((s->decorr[i].weightA * R2 + 512) >> 10);
UPDATE_WEIGHT_CLIP(s->decorr[i].weightA, s->decorr[i].delta, R2, L);
L = L2;
s->decorr[i].samplesB[0] = L;
}
}
pos = (pos + 1) & 7;
if(s->joint)
L += (R -= (L >> 1));
crc = (crc * 3 + L) * 3 + R;
*dst++ = L;
*dst++ = R;
count++;
}while(!last && count < s->samples);
if(crc != s->CRC){
av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
return -1;
}
return count * 2;
}
static int wv_unpack_mono(WavpackContext *s, GetBitContext *gb, int16_t *dst)
{
int i, j, count = 0;
int last, t;
int A, S, T;
int pos = 0;
uint32_t crc = 0xFFFFFFFF;
s->one = s->zero = s->zeroes = 0;
do{
T = wv_get_value(s, gb, s->median, &last);
S = 0;
if(last) break;
for(i = 0; i < s->terms; i++){
t = s->decorr[i].value;
if(t > 8){
if(t & 1)
A = 2 * s->decorr[i].samplesA[0] - s->decorr[i].samplesA[1];
else
A = (3 * s->decorr[i].samplesA[0] - s->decorr[i].samplesA[1]) >> 1;
s->decorr[i].samplesA[1] = s->decorr[i].samplesA[0];
j = 0;
}else{
A = s->decorr[i].samplesA[pos];
j = (pos + t) & 7;
}
S = T + ((s->decorr[i].weightA * A + 512) >> 10);
if(A && T) s->decorr[i].weightA -= ((((T ^ A) >> 30) & 2) - 1) * s->decorr[i].delta;
s->decorr[i].samplesA[j] = T = S;
}
pos = (pos + 1) & 7;
crc = crc * 3 + S;
*dst++ = S;
count++;
}while(!last && count < s->samples);
if(crc != s->CRC){
av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
return -1;
}
return count;
}
static int wavpack_decode_init(AVCodecContext *avctx)
{
WavpackContext *s = avctx->priv_data;
s->avctx = avctx;
s->stereo = (avctx->channels == 2);
return 0;
}
static int wavpack_decode_close(AVCodecContext *avctx)
{
// WavpackContext *s = avctx->priv_data;
return 0;
}
static int wavpack_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size)
{
WavpackContext *s = avctx->priv_data;
int16_t *samples = data;
int samplecount;
int got_terms = 0, got_weights = 0, got_samples = 0, got_entropy = 0, got_bs = 0;
uint8_t* buf_end = buf + buf_size;
int i, j, id, size, ssize, weights, t;
if (buf_size == 0) return 0;
memset(s->decorr, 0, MAX_TERMS * sizeof(Decorr));
s->samples = LE_32(buf); buf += 4;
s->joint = LE_32(buf) & WV_JOINT; buf += 4;
s->CRC = LE_32(buf); buf += 4;
// parse metadata blocks
while(buf < buf_end){
id = *buf++;
size = *buf++;
if(id & WP_IDF_LONG) {
size |= (*buf++) << 8;
size |= (*buf++) << 16;
}
size <<= 1; // size is specified in words
ssize = size;
if(id & WP_IDF_ODD) size--;
if(size < 0){
av_log(avctx, AV_LOG_ERROR, "Got incorrect block %02X with size %i\n", id, size);
break;
}
if(buf + ssize > buf_end){
av_log(avctx, AV_LOG_ERROR, "Block size %i is out of bounds\n", size);
break;
}
if(id & WP_IDF_IGNORE){
buf += ssize;
continue;
}
switch(id & WP_IDF_MASK){
case WP_ID_DECTERMS:
s->terms = size;
if(s->terms > MAX_TERMS){
av_log(avctx, AV_LOG_ERROR, "Too many decorrelation terms\n");
buf += ssize;
continue;
}
for(i = 0; i < s->terms; i++) {
s->decorr[s->terms - i - 1].value = (*buf & 0x1F) - 5;
s->decorr[s->terms - i - 1].delta = *buf >> 5;
buf++;
}
got_terms = 1;
break;
case WP_ID_DECWEIGHTS:
if(!got_terms){
av_log(avctx, AV_LOG_ERROR, "No decorrelation terms met\n");
continue;
}
weights = size >> s->stereo;
if(weights > MAX_TERMS || weights > s->terms){
av_log(avctx, AV_LOG_ERROR, "Too many decorrelation weights\n");
buf += ssize;
continue;
}
for(i = 0; i < weights; i++) {
t = (int8_t)(*buf++);
s->decorr[s->terms - i - 1].weightA = t << 3;
if(s->decorr[s->terms - i - 1].weightA > 0)
s->decorr[s->terms - i - 1].weightA += (s->decorr[s->terms - i - 1].weightA + 64) >> 7;
if(s->stereo){
t = (int8_t)(*buf++);
s->decorr[s->terms - i - 1].weightB = t << 3;
if(s->decorr[s->terms - i - 1].weightB > 0)
s->decorr[s->terms - i - 1].weightB += (s->decorr[s->terms - i - 1].weightB + 64) >> 7;
}
}
got_weights = 1;
break;
case WP_ID_DECSAMPLES:
if(!got_terms){
av_log(avctx, AV_LOG_ERROR, "No decorrelation terms met\n");
continue;
}
t = 0;
for(i = s->terms - 1; (i >= 0) && (t < size); i--) {
if(s->decorr[i].value > 8){
s->decorr[i].samplesA[0] = wp_exp2(LE_16(buf)); buf += 2;
s->decorr[i].samplesA[1] = wp_exp2(LE_16(buf)); buf += 2;
if(s->stereo){
s->decorr[i].samplesB[0] = wp_exp2(LE_16(buf)); buf += 2;
s->decorr[i].samplesB[1] = wp_exp2(LE_16(buf)); buf += 2;
t += 4;
}
t += 4;
}else if(s->decorr[i].value < 0){
s->decorr[i].samplesA[0] = wp_exp2(LE_16(buf)); buf += 2;
s->decorr[i].samplesB[0] = wp_exp2(LE_16(buf)); buf += 2;
t += 4;
}else{
for(j = 0; j < s->decorr[i].value; j++){
s->decorr[i].samplesA[j] = wp_exp2(LE_16(buf)); buf += 2;
if(s->stereo){
s->decorr[i].samplesB[j] = wp_exp2(LE_16(buf)); buf += 2;
}
}
t += s->decorr[i].value * 2 * avctx->channels;
}
}
got_samples = 1;
break;
case WP_ID_ENTROPY:
if(size != 6 * avctx->channels){
av_log(avctx, AV_LOG_ERROR, "Entropy vars size should be %i, got %i", 6 * avctx->channels, size);
buf += ssize;
continue;
}
for(i = 0; i < 3 * avctx->channels; i++){
s->median[i] = wp_exp2(LE_16(buf));
buf += 2;
}
got_entropy = 1;
break;
case WP_ID_DATA:
init_get_bits(&s->gb, buf, size * 8);
s->data_size = size * 8;
buf += size;
got_bs = 1;
break;
default:
buf += size;
}
if(id & WP_IDF_ODD) buf++;
}
if(!got_terms){
av_log(avctx, AV_LOG_ERROR, "No block with decorrelation terms\n");
return -1;
}
if(!got_weights){
av_log(avctx, AV_LOG_ERROR, "No block with decorrelation weights\n");
return -1;
}
if(!got_samples){
av_log(avctx, AV_LOG_ERROR, "No block with decorrelation samples\n");
return -1;
}
if(!got_entropy){
av_log(avctx, AV_LOG_ERROR, "No block with entropy info\n");
return -1;
}
if(!got_bs){
av_log(avctx, AV_LOG_ERROR, "Packed samples not found\n");
return -1;
}
if(s->stereo)
samplecount = wv_unpack_stereo(s, &s->gb, samples);
else
samplecount = wv_unpack_mono(s, &s->gb, samples);
*data_size = samplecount * 2;
return buf_size;
}
AVCodec wavpack_decoder = {
"wavpack",
CODEC_TYPE_AUDIO,
CODEC_ID_WAVPACK,
sizeof(WavpackContext),
wavpack_decode_init,
NULL,
wavpack_decode_close,
wavpack_decode_frame,
};

@ -127,6 +127,7 @@ OBJS-$(CONFIG_WAV_MUXER) += wav.o riff.o
OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o
OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood.o OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood.o
OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood.o OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood.o
OBJS-$(CONFIG_WV_DEMUXER) += wv.o
OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o
OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o

@ -461,6 +461,9 @@ void av_register_all(void)
#ifdef CONFIG_WSVQA_DEMUXER #ifdef CONFIG_WSVQA_DEMUXER
av_register_input_format(&wsvqa_demuxer); av_register_input_format(&wsvqa_demuxer);
#endif #endif
#ifdef CONFIG_WV_DEMUXER
av_register_input_format(&wv_demuxer);
#endif
#ifdef CONFIG_YUV4MPEGPIPE_MUXER #ifdef CONFIG_YUV4MPEGPIPE_MUXER
av_register_output_format(&yuv4mpegpipe_muxer); av_register_output_format(&yuv4mpegpipe_muxer);
#endif #endif

@ -155,6 +155,7 @@ extern AVOutputFormat wav_muxer;
extern AVInputFormat wc3_demuxer; extern AVInputFormat wc3_demuxer;
extern AVInputFormat wsaud_demuxer; extern AVInputFormat wsaud_demuxer;
extern AVInputFormat wsvqa_demuxer; extern AVInputFormat wsvqa_demuxer;
extern AVInputFormat wv_demuxer;
extern AVOutputFormat yuv4mpegpipe_muxer; extern AVOutputFormat yuv4mpegpipe_muxer;
extern AVInputFormat yuv4mpegpipe_demuxer; extern AVInputFormat yuv4mpegpipe_demuxer;

@ -0,0 +1,207 @@
/*
* WavPack demuxer
* Copyright (c) 2006 Konstantin Shishkov.
*
* This library 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 of the License, or (at your option) any later version.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "allformats.h"
#include "bswap.h"
// specs say that maximum block size is 1Mb
#define WV_BLOCK_LIMIT 1047576
#define WV_EXTRA_SIZE 12
enum WV_FLAGS{
WV_MONO = 0x0004,
WV_HYBRID = 0x0008,
WV_JOINT = 0x0010,
WV_CROSSD = 0x0020,
WV_HSHAPE = 0x0040,
WV_FLOAT = 0x0080,
WV_INT32 = 0x0100,
WV_HBR = 0x0200,
WV_HBAL = 0x0400,
WV_MCINIT = 0x0800,
WV_MCEND = 0x1000,
};
static const int wv_rates[16] = {
6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
32000, 44100, 48000, 64000, 88200, 96000, 192000, -1
};
typedef struct{
uint32_t blksize, flags;
int rate, chan, bpp;
int block_parsed;
uint8_t extra[WV_EXTRA_SIZE];
}WVContext;
static int wv_probe(AVProbeData *p)
{
/* check file header */
if (p->buf_size <= 32)
return 0;
if (p->buf[0] == 'w' && p->buf[1] == 'v' &&
p->buf[2] == 'p' && p->buf[3] == 'k')
return AVPROBE_SCORE_MAX;
else
return 0;
}
static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb)
{
WVContext *wc = ctx->priv_data;
uint32_t tag, ver;
int size;
int rate, bpp, chan;
tag = get_le32(pb);
if (tag != MKTAG('w', 'v', 'p', 'k'))
return -1;
size = get_le32(pb);
if(size < 24 || size > WV_BLOCK_LIMIT){
av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size);
return -1;
}
wc->blksize = size;
ver = get_le16(pb);
if(ver < 0x402 || ver > 0x40F){
av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver);
return -1;
}
get_byte(pb); // track no
get_byte(pb); // track sub index
get_le32(pb); // total samples in file
get_le32(pb); // offset in samples of current block
get_buffer(pb, wc->extra, WV_EXTRA_SIZE);
wc->flags = LE_32(wc->extra + 4);
//parse flags
if(wc->flags & WV_FLOAT){
av_log(ctx, AV_LOG_ERROR, "Floating point data is not supported\n");
return -1;
}
if(wc->flags & WV_HYBRID){
av_log(ctx, AV_LOG_ERROR, "Hybrid coding mode is not supported\n");
return -1;
}
if(wc->flags & WV_INT32){
av_log(ctx, AV_LOG_ERROR, "Integer point data is not supported\n");
return -1;
}
bpp = ((wc->flags & 3) + 1) << 3;
chan = 1 + !(wc->flags & WV_MONO);
rate = wv_rates[(wc->flags >> 23) & 0xF];
if(rate == -1){
av_log(ctx, AV_LOG_ERROR, "Unknown sampling rate\n");
return -1;
}
if(!wc->bpp) wc->bpp = bpp;
if(!wc->chan) wc->chan = chan;
if(!wc->rate) wc->rate = rate;
if(bpp != wc->bpp){
av_log(ctx, AV_LOG_ERROR, "Bits per sample differ, this block: %i, header block: %i\n", bpp, wc->bpp);
return -1;
}
if(chan != wc->chan){
av_log(ctx, AV_LOG_ERROR, "Channels differ, this block: %i, header block: %i\n", chan, wc->chan);
return -1;
}
if(rate != wc->rate){
av_log(ctx, AV_LOG_ERROR, "Sampling rate differ, this block: %i, header block: %i\n", rate, wc->rate);
return -1;
}
wc->blksize = size - 24;
return 0;
}
static int wv_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
ByteIOContext *pb = &s->pb;
WVContext *wc = s->priv_data;
AVStream *st;
if(wv_read_block_header(s, pb) < 0)
return -1;
wc->block_parsed = 0;
/* now we are ready: build format streams */
st = av_new_stream(s, 0);
if (!st)
return -1;
st->codec->codec_type = CODEC_TYPE_AUDIO;
st->codec->codec_id = CODEC_ID_WAVPACK;
st->codec->channels = wc->chan;
st->codec->sample_rate = wc->rate;
st->codec->bits_per_sample = wc->bpp;
av_set_pts_info(st, 64, 1, wc->rate);
return 0;
}
static int wv_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
WVContext *wc = s->priv_data;
int ret, samples;
if (url_feof(&s->pb))
return -EIO;
if(wc->block_parsed){
if(wv_read_block_header(s, &s->pb) < 0)
return -1;
}
samples = LE_32(wc->extra);
/* should not happen but who knows */
if(samples * 2 * wc->chan > AVCODEC_MAX_AUDIO_FRAME_SIZE){
av_log(s, AV_LOG_ERROR, "Packet size is too big to be handled in lavc!\n");
return -EIO;
}
if(av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE) < 0)
return AVERROR_NOMEM;
memcpy(pkt->data, wc->extra, WV_EXTRA_SIZE);
ret = get_buffer(&s->pb, pkt->data + WV_EXTRA_SIZE, wc->blksize);
if(ret != wc->blksize){
av_free_packet(pkt);
return AVERROR_IO;
}
pkt->stream_index = 0;
wc->block_parsed = 1;
pkt->size = ret + WV_EXTRA_SIZE;
return 0;
}
static int wv_read_close(AVFormatContext *s)
{
return 0;
}
AVInputFormat wv_demuxer = {
"wv",
"WavPack",
sizeof(WVContext),
wv_probe,
wv_read_header,
wv_read_packet,
wv_read_close,
pcm_read_seek,
};
Loading…
Cancel
Save