Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
3bdc886c
Commit
3bdc886c
authored
Jan 22, 2011
by
Kostya
Committed by
Janne Grunau
Jan 24, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Extend WavPack demuxer and decoder to support >2 channel audio
Signed-off-by:
Janne Grunau
<
janne-ffmpeg@jannau.net
>
parent
07b48f8c
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
324 additions
and
66 deletions
+324
-66
wavpack.c
libavcodec/wavpack.c
+216
-50
wv.c
libavformat/wv.c
+108
-16
No files found.
libavcodec/wavpack.c
View file @
3bdc886c
/*
* WavPack lossless audio decoder
* Copyright (c) 2006 Konstantin Shishkov
* Copyright (c) 2006
,2011
Konstantin Shishkov
*
* This file is part of FFmpeg.
*
...
...
@@ -91,7 +91,7 @@ typedef struct WvChannel {
int
bitrate_acc
,
bitrate_delta
;
}
WvChannel
;
typedef
struct
WavpackContext
{
typedef
struct
Wavpack
Frame
Context
{
AVCodecContext
*
avctx
;
int
frame_flags
;
int
stereo
,
stereo_in
;
...
...
@@ -118,6 +118,22 @@ typedef struct WavpackContext {
int
max_samples
;
int
pos
;
SavedContext
sc
,
extra_sc
;
}
WavpackFrameContext
;
#define WV_MAX_FRAME_DECODERS 14
typedef
struct
WavpackContext
{
AVCodecContext
*
avctx
;
WavpackFrameContext
*
fdec
[
WV_MAX_FRAME_DECODERS
];
int
fdec_num
;
int
multichannel
;
int
mkv_mode
;
int
block
;
int
samples
;
int
samples_left
;
int
ch_offset
;
}
WavpackContext
;
// exponent table copied from WavPack source
...
...
@@ -224,7 +240,7 @@ static av_always_inline int get_tail(GetBitContext *gb, int k)
return
res
;
}
static
void
update_error_limit
(
WavpackContext
*
ctx
)
static
void
update_error_limit
(
Wavpack
Frame
Context
*
ctx
)
{
int
i
,
br
[
2
],
sl
[
2
];
...
...
@@ -258,7 +274,7 @@ static void update_error_limit(WavpackContext *ctx)
}
}
static
int
wv_get_value
(
WavpackContext
*
ctx
,
GetBitContext
*
gb
,
int
channel
,
int
*
last
)
static
int
wv_get_value
(
Wavpack
Frame
Context
*
ctx
,
GetBitContext
*
gb
,
int
channel
,
int
*
last
)
{
int
t
,
t2
;
int
sign
,
base
,
add
,
ret
;
...
...
@@ -361,7 +377,7 @@ static int wv_get_value(WavpackContext *ctx, GetBitContext *gb, int channel, int
return
sign
?
~
ret
:
ret
;
}
static
inline
int
wv_get_value_integer
(
WavpackContext
*
s
,
uint32_t
*
crc
,
int
S
)
static
inline
int
wv_get_value_integer
(
Wavpack
Frame
Context
*
s
,
uint32_t
*
crc
,
int
S
)
{
int
bit
;
...
...
@@ -377,7 +393,7 @@ static inline int wv_get_value_integer(WavpackContext *s, uint32_t *crc, int S)
return
(((
S
+
bit
)
<<
s
->
shift
)
-
bit
)
<<
s
->
post_shift
;
}
static
float
wv_get_value_float
(
WavpackContext
*
s
,
uint32_t
*
crc
,
int
S
)
static
float
wv_get_value_float
(
Wavpack
Frame
Context
*
s
,
uint32_t
*
crc
,
int
S
)
{
union
{
float
f
;
...
...
@@ -450,13 +466,13 @@ static float wv_get_value_float(WavpackContext *s, uint32_t *crc, int S)
return
value
.
f
;
}
static
void
wv_reset_saved_context
(
WavpackContext
*
s
)
static
void
wv_reset_saved_context
(
Wavpack
Frame
Context
*
s
)
{
s
->
pos
=
0
;
s
->
sc
.
crc
=
s
->
extra_sc
.
crc
=
0xFFFFFFFF
;
}
static
inline
int
wv_unpack_stereo
(
WavpackContext
*
s
,
GetBitContext
*
gb
,
void
*
dst
,
const
int
type
)
static
inline
int
wv_unpack_stereo
(
Wavpack
Frame
Context
*
s
,
GetBitContext
*
gb
,
void
*
dst
,
const
int
type
)
{
int
i
,
j
,
count
=
0
;
int
last
,
t
;
...
...
@@ -467,6 +483,7 @@ static inline int wv_unpack_stereo(WavpackContext *s, GetBitContext *gb, void *d
int16_t
*
dst16
=
dst
;
int32_t
*
dst32
=
dst
;
float
*
dstfl
=
dst
;
const
int
channel_pad
=
s
->
avctx
->
channels
-
2
;
if
(
s
->
samples_left
==
s
->
samples
)
s
->
one
=
s
->
zero
=
s
->
zeroes
=
0
;
...
...
@@ -549,12 +566,15 @@ static inline int wv_unpack_stereo(WavpackContext *s, GetBitContext *gb, void *d
if
(
type
==
AV_SAMPLE_FMT_FLT
){
*
dstfl
++
=
wv_get_value_float
(
s
,
&
crc_extra_bits
,
L
);
*
dstfl
++
=
wv_get_value_float
(
s
,
&
crc_extra_bits
,
R
);
dstfl
+=
channel_pad
;
}
else
if
(
type
==
AV_SAMPLE_FMT_S32
){
*
dst32
++
=
wv_get_value_integer
(
s
,
&
crc_extra_bits
,
L
);
*
dst32
++
=
wv_get_value_integer
(
s
,
&
crc_extra_bits
,
R
);
dst32
+=
channel_pad
;
}
else
{
*
dst16
++
=
wv_get_value_integer
(
s
,
&
crc_extra_bits
,
L
);
*
dst16
++
=
wv_get_value_integer
(
s
,
&
crc_extra_bits
,
R
);
dst16
+=
channel_pad
;
}
count
++
;
}
while
(
!
last
&&
count
<
s
->
max_samples
);
...
...
@@ -582,7 +602,7 @@ static inline int wv_unpack_stereo(WavpackContext *s, GetBitContext *gb, void *d
return
count
*
2
;
}
static
inline
int
wv_unpack_mono
(
WavpackContext
*
s
,
GetBitContext
*
gb
,
void
*
dst
,
const
int
type
)
static
inline
int
wv_unpack_mono
(
Wavpack
Frame
Context
*
s
,
GetBitContext
*
gb
,
void
*
dst
,
const
int
type
)
{
int
i
,
j
,
count
=
0
;
int
last
,
t
;
...
...
@@ -593,6 +613,7 @@ static inline int wv_unpack_mono(WavpackContext *s, GetBitContext *gb, void *dst
int16_t
*
dst16
=
dst
;
int32_t
*
dst32
=
dst
;
float
*
dstfl
=
dst
;
const
int
channel_stride
=
s
->
avctx
->
channels
;
if
(
s
->
samples_left
==
s
->
samples
)
s
->
one
=
s
->
zero
=
s
->
zeroes
=
0
;
...
...
@@ -623,12 +644,16 @@ static inline int wv_unpack_mono(WavpackContext *s, GetBitContext *gb, void *dst
pos
=
(
pos
+
1
)
&
7
;
crc
=
crc
*
3
+
S
;
if
(
type
==
AV_SAMPLE_FMT_FLT
)
*
dstfl
++
=
wv_get_value_float
(
s
,
&
crc_extra_bits
,
S
);
else
if
(
type
==
AV_SAMPLE_FMT_S32
)
*
dst32
++
=
wv_get_value_integer
(
s
,
&
crc_extra_bits
,
S
);
else
*
dst16
++
=
wv_get_value_integer
(
s
,
&
crc_extra_bits
,
S
);
if
(
type
==
AV_SAMPLE_FMT_FLT
){
*
dstfl
=
wv_get_value_float
(
s
,
&
crc_extra_bits
,
S
);
dstfl
+=
channel_stride
;
}
else
if
(
type
==
AV_SAMPLE_FMT_S32
){
*
dst32
=
wv_get_value_integer
(
s
,
&
crc_extra_bits
,
S
);
dst32
+=
channel_stride
;
}
else
{
*
dst16
=
wv_get_value_integer
(
s
,
&
crc_extra_bits
,
S
);
dst16
+=
channel_stride
;
}
count
++
;
}
while
(
!
last
&&
count
<
s
->
max_samples
);
...
...
@@ -655,47 +680,92 @@ static inline int wv_unpack_mono(WavpackContext *s, GetBitContext *gb, void *dst
return
count
;
}
static
av_cold
int
wv_alloc_frame_context
(
WavpackContext
*
c
)
{
if
(
c
->
fdec_num
==
WV_MAX_FRAME_DECODERS
)
return
-
1
;
c
->
fdec
[
c
->
fdec_num
]
=
av_mallocz
(
sizeof
(
**
c
->
fdec
));
if
(
!
c
->
fdec
[
c
->
fdec_num
])
return
-
1
;
c
->
fdec_num
++
;
c
->
fdec
[
c
->
fdec_num
-
1
]
->
avctx
=
c
->
avctx
;
wv_reset_saved_context
(
c
->
fdec
[
c
->
fdec_num
-
1
]);
return
0
;
}
static
av_cold
int
wavpack_decode_init
(
AVCodecContext
*
avctx
)
{
WavpackContext
*
s
=
avctx
->
priv_data
;
s
->
avctx
=
avctx
;
if
(
avctx
->
channels
>
2
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Multichannel WavPack is not supported yet.
\n
"
);
return
-
1
;
}
s
->
stereo
=
(
avctx
->
channels
==
2
);
if
(
avctx
->
bits_per_coded_sample
<=
16
)
avctx
->
sample_fmt
=
AV_SAMPLE_FMT_S16
;
else
avctx
->
sample_fmt
=
AV_SAMPLE_FMT_S32
;
if
(
avctx
->
channels
<=
2
&&
!
avctx
->
channel_layout
)
avctx
->
channel_layout
=
(
avctx
->
channels
==
2
)
?
CH_LAYOUT_STEREO
:
CH_LAYOUT_MONO
;
wv_reset_saved_context
(
s
);
s
->
multichannel
=
avctx
->
channels
>
2
;
/* lavf demuxer does not provide extradata, Matroska stores 0x403
there, use this to detect decoding mode for multichannel */
s
->
mkv_mode
=
0
;
if
(
s
->
multichannel
&&
avctx
->
extradata
&&
avctx
->
extradata_size
==
2
){
int
ver
=
AV_RL16
(
avctx
->
extradata
);
if
(
ver
>=
0x402
&&
ver
<=
0x410
)
s
->
mkv_mode
=
1
;
}
s
->
fdec_num
=
0
;
return
0
;
}
static
int
wavpack_decode_frame
(
AVCodecContext
*
avctx
,
void
*
data
,
int
*
data_size
,
AVPacket
*
avpkt
)
static
av_cold
int
wavpack_decode_end
(
AVCodecContext
*
avctx
)
{
const
uint8_t
*
buf
=
avpkt
->
data
;
int
buf_size
=
avpkt
->
size
;
WavpackContext
*
s
=
avctx
->
priv_data
;
int
i
;
for
(
i
=
0
;
i
<
s
->
fdec_num
;
i
++
)
av_freep
(
&
s
->
fdec
[
i
]);
s
->
fdec_num
=
0
;
return
0
;
}
static
int
wavpack_decode_block
(
AVCodecContext
*
avctx
,
int
block_no
,
void
*
data
,
int
*
data_size
,
const
uint8_t
*
buf
,
int
buf_size
)
{
WavpackContext
*
wc
=
avctx
->
priv_data
;
WavpackFrameContext
*
s
;
void
*
samples
=
data
;
int
samplecount
;
int
got_terms
=
0
,
got_weights
=
0
,
got_samples
=
0
,
got_entropy
=
0
,
got_bs
=
0
,
got_float
=
0
;
int
got_hybrid
=
0
;
const
uint8_t
*
orig_buf
=
buf
;
const
uint8_t
*
buf_end
=
buf
+
buf_size
;
int
i
,
j
,
id
,
size
,
ssize
,
weights
,
t
;
int
bpp
;
int
bpp
,
chan
,
chmask
;
if
(
buf_size
==
0
){
*
data_size
=
0
;
return
0
;
}
if
(
block_no
>=
wc
->
fdec_num
&&
wv_alloc_frame_context
(
wc
)
<
0
){
av_log
(
avctx
,
AV_LOG_ERROR
,
"Error creating frame decode context
\n
"
);
return
-
1
;
}
s
=
wc
->
fdec
[
block_no
];
if
(
!
s
){
av_log
(
avctx
,
AV_LOG_ERROR
,
"Context for block %d is not present
\n
"
,
block_no
);
return
-
1
;
}
if
(
!
s
->
samples_left
){
memset
(
s
->
decorr
,
0
,
MAX_TERMS
*
sizeof
(
Decorr
));
memset
(
s
->
ch
,
0
,
sizeof
(
s
->
ch
));
...
...
@@ -704,11 +774,15 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
s
->
got_extra_bits
=
0
;
}
if
(
!
wc
->
mkv_mode
){
s
->
samples
=
AV_RL32
(
buf
);
buf
+=
4
;
if
(
!
s
->
samples
){
*
data_size
=
0
;
return
buf_size
;
}
}
else
{
s
->
samples
=
wc
->
samples
;
}
s
->
frame_flags
=
AV_RL32
(
buf
);
buf
+=
4
;
if
(
s
->
frame_flags
&
0x80
){
bpp
=
sizeof
(
float
);
...
...
@@ -720,12 +794,19 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
bpp
=
4
;
avctx
->
sample_fmt
=
AV_SAMPLE_FMT_S32
;
}
samples
=
(
uint8_t
*
)
samples
+
bpp
*
wc
->
ch_offset
;
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
->
post_shift
=
8
*
(
bpp
-
1
-
(
s
->
frame_flags
&
0x03
))
+
((
s
->
frame_flags
>>
13
)
&
0x1f
);
s
->
CRC
=
AV_RL32
(
buf
);
buf
+=
4
;
if
(
wc
->
mkv_mode
)
buf
+=
4
;
//skip block size;
wc
->
ch_offset
+=
1
+
s
->
stereo
;
s
->
max_samples
=
*
data_size
/
(
bpp
*
avctx
->
channels
);
s
->
max_samples
=
FFMIN
(
s
->
max_samples
,
s
->
samples
);
...
...
@@ -899,7 +980,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
got_float
=
1
;
break
;
case
WP_ID_DATA
:
s
->
sc
.
offset
=
buf
-
avpkt
->
data
;
s
->
sc
.
offset
=
buf
-
orig_buf
;
s
->
sc
.
size
=
size
*
8
;
init_get_bits
(
&
s
->
gb
,
buf
,
size
*
8
);
s
->
data_size
=
size
*
8
;
...
...
@@ -912,13 +993,50 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
buf
+=
size
;
continue
;
}
s
->
extra_sc
.
offset
=
buf
-
avpkt
->
data
;
s
->
extra_sc
.
offset
=
buf
-
orig_buf
;
s
->
extra_sc
.
size
=
size
*
8
;
init_get_bits
(
&
s
->
gb_extra_bits
,
buf
,
size
*
8
);
s
->
crc_extra_bits
=
get_bits_long
(
&
s
->
gb_extra_bits
,
32
);
buf
+=
size
;
s
->
got_extra_bits
=
1
;
break
;
case
WP_ID_CHANINFO
:
if
(
size
<=
1
){
av_log
(
avctx
,
AV_LOG_ERROR
,
"Insufficient channel information
\n
"
);
return
-
1
;
}
chan
=
*
buf
++
;
switch
(
size
-
2
){
case
0
:
chmask
=
*
buf
;
break
;
case
1
:
chmask
=
AV_RL16
(
buf
);
break
;
case
2
:
chmask
=
AV_RL24
(
buf
);
break
;
case
3
:
chmask
=
AV_RL32
(
buf
);
break
;
case
5
:
chan
|=
(
buf
[
1
]
&
0xF
)
<<
8
;
chmask
=
AV_RL24
(
buf
+
2
);
break
;
default:
av_log
(
avctx
,
AV_LOG_ERROR
,
"Invalid channel info size %d
\n
"
,
size
);
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
-
1
;
}
if
(
!
avctx
->
channel_layout
)
avctx
->
channel_layout
=
chmask
;
buf
+=
size
-
1
;
break
;
default:
buf
+=
size
;
}
...
...
@@ -963,10 +1081,10 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
}
s
->
samples_left
=
s
->
samples
;
}
else
{
init_get_bits
(
&
s
->
gb
,
avpkt
->
data
+
s
->
sc
.
offset
,
s
->
sc
.
size
);
init_get_bits
(
&
s
->
gb
,
orig_buf
+
s
->
sc
.
offset
,
s
->
sc
.
size
);
skip_bits_long
(
&
s
->
gb
,
s
->
sc
.
bits_used
);
if
(
s
->
got_extra_bits
){
init_get_bits
(
&
s
->
gb_extra_bits
,
avpkt
->
data
+
s
->
extra_sc
.
offset
,
init_get_bits
(
&
s
->
gb_extra_bits
,
orig_buf
+
s
->
extra_sc
.
offset
,
s
->
extra_sc
.
size
);
skip_bits_long
(
&
s
->
gb_extra_bits
,
s
->
extra_sc
.
bits_used
);
}
...
...
@@ -979,8 +1097,10 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
samplecount
=
wv_unpack_stereo
(
s
,
&
s
->
gb
,
samples
,
AV_SAMPLE_FMT_S32
);
else
samplecount
=
wv_unpack_stereo
(
s
,
&
s
->
gb
,
samples
,
AV_SAMPLE_FMT_FLT
);
samplecount
>>=
1
;
}
else
{
const
int
channel_stride
=
avctx
->
channels
;
if
(
avctx
->
sample_fmt
==
AV_SAMPLE_FMT_S16
)
samplecount
=
wv_unpack_mono
(
s
,
&
s
->
gb
,
samples
,
AV_SAMPLE_FMT_S16
);
else
if
(
avctx
->
sample_fmt
==
AV_SAMPLE_FMT_S32
)
...
...
@@ -989,37 +1109,83 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
samplecount
=
wv_unpack_mono
(
s
,
&
s
->
gb
,
samples
,
AV_SAMPLE_FMT_FLT
);
if
(
s
->
stereo
&&
avctx
->
sample_fmt
==
AV_SAMPLE_FMT_S16
){
int16_t
*
dst
=
(
int16_t
*
)
samples
+
samplecount
*
2
;
int16_t
*
src
=
(
int16_t
*
)
samples
+
samplecount
;
int16_t
*
dst
=
(
int16_t
*
)
samples
+
1
;
int16_t
*
src
=
(
int16_t
*
)
samples
;
int
cnt
=
samplecount
;
while
(
cnt
--
){
*--
dst
=
*--
src
;
*--
dst
=
*
src
;
*
dst
=
*
src
;
src
+=
channel_stride
;
dst
+=
channel_stride
;
}
samplecount
*=
2
;
}
else
if
(
s
->
stereo
&&
avctx
->
sample_fmt
==
AV_SAMPLE_FMT_S32
){
int32_t
*
dst
=
(
int32_t
*
)
samples
+
samplecount
*
2
;
int32_t
*
src
=
(
int32_t
*
)
samples
+
samplecount
;
int32_t
*
dst
=
(
int32_t
*
)
samples
+
1
;
int32_t
*
src
=
(
int32_t
*
)
samples
;
int
cnt
=
samplecount
;
while
(
cnt
--
){
*--
dst
=
*--
src
;
*--
dst
=
*
src
;
*
dst
=
*
src
;
src
+=
channel_stride
;
dst
+=
channel_stride
;
}
samplecount
*=
2
;
}
else
if
(
s
->
stereo
){
float
*
dst
=
(
float
*
)
samples
+
samplecount
*
2
;
float
*
src
=
(
float
*
)
samples
+
samplecount
;
float
*
dst
=
(
float
*
)
samples
+
1
;
float
*
src
=
(
float
*
)
samples
;
int
cnt
=
samplecount
;
while
(
cnt
--
){
*--
dst
=
*--
src
;
*--
dst
=
*
src
;
*
dst
=
*
src
;
src
+=
channel_stride
;
dst
+=
channel_stride
;
}
}
}
wc
->
samples_left
=
s
->
samples_left
;
return
samplecount
*
bpp
;
}
static
int
wavpack_decode_frame
(
AVCodecContext
*
avctx
,
void
*
data
,
int
*
data_size
,
AVPacket
*
avpkt
)
{
WavpackContext
*
s
=
avctx
->
priv_data
;
const
uint8_t
*
buf
=
avpkt
->
data
;
int
buf_size
=
avpkt
->
size
;
int
frame_size
;
int
samplecount
=
0
;
s
->
block
=
0
;
s
->
samples_left
=
0
;
s
->
ch_offset
=
0
;
if
(
s
->
mkv_mode
){
s
->
samples
=
AV_RL32
(
buf
);
buf
+=
4
;
}
samplecount
*=
2
;
while
(
buf_size
>
0
){
if
(
!
s
->
multichannel
){
frame_size
=
buf_size
;
}
else
{
if
(
!
s
->
mkv_mode
){
frame_size
=
AV_RL32
(
buf
)
-
12
;
buf
+=
4
;
buf_size
-=
4
;
}
else
{
if
(
buf_size
<
12
)
//MKV files can have zero flags after last block
break
;
frame_size
=
AV_RL32
(
buf
+
8
)
+
12
;
}
}
*
data_size
=
samplecount
*
bpp
;
if
(
frame_size
<
0
||
frame_size
>
buf_size
){
av_log
(
avctx
,
AV_LOG_ERROR
,
"Block %d has invalid size (size %d vs. %d bytes left)
\n
"
,
s
->
block
,
frame_size
,
buf_size
);
return
-
1
;
}
if
((
samplecount
=
wavpack_decode_block
(
avctx
,
s
->
block
,
data
,
data_size
,
buf
,
frame_size
))
<
0
)
return
-
1
;
s
->
block
++
;
buf
+=
frame_size
;
buf_size
-=
frame_size
;
}
*
data_size
=
samplecount
*
avctx
->
channels
;
return
s
->
samples_left
>
0
?
0
:
buf_
size
;
return
s
->
samples_left
>
0
?
0
:
avpkt
->
size
;
}
AVCodec
wavpack_decoder
=
{
...
...
@@ -1029,7 +1195,7 @@ AVCodec wavpack_decoder = {
sizeof
(
WavpackContext
),
wavpack_decode_init
,
NULL
,
NULL
,
wavpack_decode_end
,
wavpack_decode_frame
,
.
capabilities
=
CODEC_CAP_SUBFRAMES
,
.
long_name
=
NULL_IF_CONFIG_SMALL
(
"WavPack"
),
...
...
libavformat/wv.c
View file @
3bdc886c
/*
* WavPack demuxer
* Copyright (c) 2006 Konstantin Shishkov
* Copyright (c) 2006
,2011
Konstantin Shishkov
*
* This file is part of FFmpeg.
*
...
...
@@ -29,6 +29,10 @@
#define WV_EXTRA_SIZE 12
#define WV_START_BLOCK 0x0800
#define WV_END_BLOCK 0x1000
#define WV_SINGLE_BLOCK (WV_START_BLOCK | WV_END_BLOCK)
enum
WV_FLAGS
{
WV_MONO
=
0x0004
,
WV_HYBRID
=
0x0008
,
...
...
@@ -51,7 +55,9 @@ static const int wv_rates[16] = {
typedef
struct
{
uint32_t
blksize
,
flags
;
int
rate
,
chan
,
bpp
;
uint32_t
chmask
;
uint32_t
samples
,
soff
;
int
multichannel
;
int
block_parsed
;
uint8_t
extra
[
WV_EXTRA_SIZE
];
int64_t
pos
;
...
...
@@ -69,14 +75,16 @@ static int wv_probe(AVProbeData *p)
return
0
;
}
static
int
wv_read_block_header
(
AVFormatContext
*
ctx
,
ByteIOContext
*
pb
)
static
int
wv_read_block_header
(
AVFormatContext
*
ctx
,
ByteIOContext
*
pb
,
int
append
)
{
WVContext
*
wc
=
ctx
->
priv_data
;
uint32_t
tag
,
ver
;
int
size
;
int
rate
,
bpp
,
chan
;
uint32_t
chmask
;
wc
->
pos
=
url_ftell
(
pb
);
if
(
!
append
){
tag
=
get_le32
(
pb
);
if
(
tag
!=
MKTAG
(
'w'
,
'v'
,
'p'
,
'k'
))
return
-
1
;
...
...
@@ -96,19 +104,24 @@ static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb)
wc
->
samples
=
get_le32
(
pb
);
// total samples in file
wc
->
soff
=
get_le32
(
pb
);
// offset in samples of current block
get_buffer
(
pb
,
wc
->
extra
,
WV_EXTRA_SIZE
);
}
else
{
size
=
wc
->
blksize
;
}
wc
->
flags
=
AV_RL32
(
wc
->
extra
+
4
);
//parse flags
bpp
=
((
wc
->
flags
&
3
)
+
1
)
<<
3
;
chan
=
1
+
!
(
wc
->
flags
&
WV_MONO
);
chmask
=
wc
->
flags
&
WV_MONO
?
CH_LAYOUT_MONO
:
CH_LAYOUT_STEREO
;
rate
=
wv_rates
[(
wc
->
flags
>>
23
)
&
0xF
];
if
((
wc
->
flags
&
0x1800
)
!=
0x1800
){
av_log
(
ctx
,
AV_LOG_ERROR
,
"Multichannel WavPack is not supported yet.
\n
"
);
return
-
1
;
wc
->
multichannel
=
!!
((
wc
->
flags
&
WV_SINGLE_BLOCK
)
!=
WV_SINGLE_BLOCK
);
if
(
wc
->
multichannel
){
chan
=
wc
->
chan
;
chmask
=
wc
->
chmask
;
}
if
(
rate
==
-
1
&&
!
wc
->
block_parsed
){
if
(
(
rate
==
-
1
||
!
chan
)
&&
!
wc
->
block_parsed
){
int64_t
block_end
=
url_ftell
(
pb
)
+
wc
->
blksize
-
24
;
if
(
url_is_streamed
(
pb
)){
av_log
(
ctx
,
AV_LOG_ERROR
,
"Cannot determine
custom sampling rate
\n
"
);
av_log
(
ctx
,
AV_LOG_ERROR
,
"Cannot determine
additional parameters
\n
"
);
return
-
1
;
}
while
(
url_ftell
(
pb
)
<
block_end
){
...
...
@@ -118,12 +131,44 @@ static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb)
size
<<=
1
;
if
(
id
&
0x40
)
size
--
;
if
((
id
&
0x3F
)
==
0x27
){
switch
(
id
&
0x3F
){
case
0xD
:
if
(
size
<=
1
){
av_log
(
ctx
,
AV_LOG_ERROR
,
"Insufficient channel information
\n
"
);
return
-
1
;
}
chan
=
get_byte
(
pb
);
switch
(
size
-
2
){
case
0
:
chmask
=
get_byte
(
pb
);
break
;
case
1
:
chmask
=
get_le16
(
pb
);
break
;
case
2
:
chmask
=
get_le24
(
pb
);
break
;
case
3
:
chmask
=
get_le32
(
pb
);
break
;
case
5
:
url_fskip
(
pb
,
1
);
chan
|=
(
get_byte
(
pb
)
&
0xF
)
<<
8
;
chmask
=
get_le24
(
pb
);
break
;
default:
av_log
(
ctx
,
AV_LOG_ERROR
,
"Invalid channel info size %d
\n
"
,
size
);
return
-
1
;
}
break
;
case
0x27
:
rate
=
get_le24
(
pb
);
break
;
}
else
{
default:
url_fskip
(
pb
,
size
);
}
if
(
id
&
0x40
)
url_fskip
(
pb
,
1
);
}
if
(
rate
==
-
1
){
av_log
(
ctx
,
AV_LOG_ERROR
,
"Cannot determine custom sampling rate
\n
"
);
...
...
@@ -133,13 +178,14 @@ static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb)
}
if
(
!
wc
->
bpp
)
wc
->
bpp
=
bpp
;
if
(
!
wc
->
chan
)
wc
->
chan
=
chan
;
if
(
!
wc
->
chmask
)
wc
->
chmask
=
chmask
;
if
(
!
wc
->
rate
)
wc
->
rate
=
rate
;
if
(
wc
->
flags
&&
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
(
wc
->
flags
&&
chan
!=
wc
->
chan
){
if
(
wc
->
flags
&&
!
wc
->
multichannel
&&
chan
!=
wc
->
chan
){
av_log
(
ctx
,
AV_LOG_ERROR
,
"Channels differ, this block: %i, header block: %i
\n
"
,
chan
,
wc
->
chan
);
return
-
1
;
}
...
...
@@ -159,7 +205,7 @@ static int wv_read_header(AVFormatContext *s,
AVStream
*
st
;
wc
->
block_parsed
=
0
;
if
(
wv_read_block_header
(
s
,
pb
)
<
0
)
if
(
wv_read_block_header
(
s
,
pb
,
0
)
<
0
)
return
-
1
;
/* now we are ready: build format streams */
...
...
@@ -169,6 +215,7 @@ static int wv_read_header(AVFormatContext *s,
st
->
codec
->
codec_type
=
AVMEDIA_TYPE_AUDIO
;
st
->
codec
->
codec_id
=
CODEC_ID_WAVPACK
;
st
->
codec
->
channels
=
wc
->
chan
;
st
->
codec
->
channel_layout
=
wc
->
chmask
;
st
->
codec
->
sample_rate
=
wc
->
rate
;
st
->
codec
->
bits_per_coded_sample
=
wc
->
bpp
;
av_set_pts_info
(
st
,
64
,
1
,
wc
->
rate
);
...
...
@@ -191,25 +238,70 @@ static int wv_read_packet(AVFormatContext *s,
{
WVContext
*
wc
=
s
->
priv_data
;
int
ret
;
int
size
,
ver
,
off
;
if
(
url_feof
(
s
->
pb
))
return
AVERROR
(
EIO
);
if
(
wc
->
block_parsed
){
if
(
wv_read_block_header
(
s
,
s
->
pb
)
<
0
)
if
(
wv_read_block_header
(
s
,
s
->
pb
,
0
)
<
0
)
return
-
1
;
}
if
(
av_new_packet
(
pkt
,
wc
->
blksize
+
WV_EXTRA_SIZE
)
<
0
)
off
=
wc
->
multichannel
?
4
:
0
;
if
(
av_new_packet
(
pkt
,
wc
->
blksize
+
WV_EXTRA_SIZE
+
off
)
<
0
)
return
AVERROR
(
ENOMEM
);
memcpy
(
pkt
->
data
,
wc
->
extra
,
WV_EXTRA_SIZE
);
ret
=
get_buffer
(
s
->
pb
,
pkt
->
data
+
WV_EXTRA_SIZE
,
wc
->
blksize
);
if
(
wc
->
multichannel
)
AV_WL32
(
pkt
->
data
,
wc
->
blksize
+
WV_EXTRA_SIZE
+
12
);
memcpy
(
pkt
->
data
+
off
,
wc
->
extra
,
WV_EXTRA_SIZE
);
ret
=
get_buffer
(
s
->
pb
,
pkt
->
data
+
WV_EXTRA_SIZE
+
off
,
wc
->
blksize
);
if
(
ret
!=
wc
->
blksize
){
av_free_packet
(
pkt
);
return
AVERROR
(
EIO
);
}
while
(
!
(
wc
->
flags
&
WV_END_BLOCK
)){
if
(
get_le32
(
s
->
pb
)
!=
MKTAG
(
'w'
,
'v'
,
'p'
,
'k'
)){
av_free_packet
(
pkt
);
return
-
1
;
}
if
((
ret
=
av_append_packet
(
s
->
pb
,
pkt
,
4
))
<
0
){
av_free_packet
(
pkt
);
return
ret
;
}
size
=
AV_RL32
(
pkt
->
data
+
pkt
->
size
-
4
);
if
(
size
<
24
||
size
>
WV_BLOCK_LIMIT
){
av_free_packet
(
pkt
);
av_log
(
s
,
AV_LOG_ERROR
,
"Incorrect block size %d
\n
"
,
size
);
return
-
1
;
}
wc
->
blksize
=
size
;
ver
=
get_le16
(
s
->
pb
);
if
(
ver
<
0x402
||
ver
>
0x410
){
av_free_packet
(
pkt
);
av_log
(
s
,
AV_LOG_ERROR
,
"Unsupported version %03X
\n
"
,
ver
);
return
-
1
;
}
get_byte
(
s
->
pb
);
// track no
get_byte
(
s
->
pb
);
// track sub index
wc
->
samples
=
get_le32
(
s
->
pb
);
// total samples in file
wc
->
soff
=
get_le32
(
s
->
pb
);
// offset in samples of current block
if
((
ret
=
av_append_packet
(
s
->
pb
,
pkt
,
WV_EXTRA_SIZE
))
<
0
){
av_free_packet
(
pkt
);
return
ret
;
}
memcpy
(
wc
->
extra
,
pkt
->
data
+
pkt
->
size
-
WV_EXTRA_SIZE
,
WV_EXTRA_SIZE
);
if
(
wv_read_block_header
(
s
,
s
->
pb
,
1
)
<
0
){
av_free_packet
(
pkt
);
return
-
1
;
}
ret
=
av_append_packet
(
s
->
pb
,
pkt
,
wc
->
blksize
);
if
(
ret
<
0
){
av_free_packet
(
pkt
);
return
ret
;
}
}
pkt
->
stream_index
=
0
;
wc
->
block_parsed
=
1
;
pkt
->
size
=
ret
+
WV_EXTRA_SIZE
;
pkt
->
pts
=
wc
->
soff
;
av_add_index_entry
(
s
->
streams
[
0
],
wc
->
pos
,
pkt
->
pts
,
0
,
0
,
AVINDEX_KEYFRAME
);
return
0
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment