mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
1f4cf92cfb
The current design, where - proper init is called for the first per-thread context - first thread's private data is copied into private data for all the other threads - a "fixup" function is called for all the other threads to e.g. allocate dynamically allocated data is very fragile and hard to follow, so it is abandoned. Instead, the same init function is used to init each per-thread context. Where necessary, AVCodecInternal.is_copy can be used to differentiate between the first thread and the other ones (e.g. for decoding the extradata just once).
1708 lines
56 KiB
C
1708 lines
56 KiB
C
/*
|
|
* WavPack lossless audio decoder
|
|
* Copyright (c) 2006,2011 Konstantin Shishkov
|
|
* Copyright (c) 2020 David Bryant
|
|
*
|
|
* This file is part of FFmpeg.
|
|
*
|
|
* 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.
|
|
*
|
|
* 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 FFmpeg; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "libavutil/buffer.h"
|
|
#include "libavutil/channel_layout.h"
|
|
|
|
#define BITSTREAM_READER_LE
|
|
#include "avcodec.h"
|
|
#include "bytestream.h"
|
|
#include "get_bits.h"
|
|
#include "internal.h"
|
|
#include "thread.h"
|
|
#include "unary.h"
|
|
#include "wavpack.h"
|
|
#include "dsd.h"
|
|
|
|
/**
|
|
* @file
|
|
* WavPack lossless audio decoder
|
|
*/
|
|
|
|
#define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) & 0xff000000))
|
|
|
|
#define PTABLE_BITS 8
|
|
#define PTABLE_BINS (1<<PTABLE_BITS)
|
|
#define PTABLE_MASK (PTABLE_BINS-1)
|
|
|
|
#define UP 0x010000fe
|
|
#define DOWN 0x00010000
|
|
#define DECAY 8
|
|
|
|
#define PRECISION 20
|
|
#define VALUE_ONE (1 << PRECISION)
|
|
#define PRECISION_USE 12
|
|
|
|
#define RATE_S 20
|
|
|
|
#define MAX_HISTORY_BITS 5
|
|
#define MAX_HISTORY_BINS (1 << MAX_HISTORY_BITS)
|
|
#define MAX_BIN_BYTES 1280 // for value_lookup, per bin (2k - 512 - 256)
|
|
|
|
typedef enum {
|
|
MODULATION_PCM, // pulse code modulation
|
|
MODULATION_DSD // pulse density modulation (aka DSD)
|
|
} Modulation;
|
|
|
|
typedef struct WavpackFrameContext {
|
|
AVCodecContext *avctx;
|
|
int frame_flags;
|
|
int stereo, stereo_in;
|
|
int joint;
|
|
uint32_t CRC;
|
|
GetBitContext gb;
|
|
int got_extra_bits;
|
|
uint32_t crc_extra_bits;
|
|
GetBitContext gb_extra_bits;
|
|
int samples;
|
|
int terms;
|
|
Decorr decorr[MAX_TERMS];
|
|
int zero, one, zeroes;
|
|
int extra_bits;
|
|
int and, or, shift;
|
|
int post_shift;
|
|
int hybrid, hybrid_bitrate;
|
|
int hybrid_maxclip, hybrid_minclip;
|
|
int float_flag;
|
|
int float_shift;
|
|
int float_max_exp;
|
|
WvChannel ch[2];
|
|
|
|
GetByteContext gbyte;
|
|
int ptable [PTABLE_BINS];
|
|
uint8_t value_lookup_buffer[MAX_HISTORY_BINS*MAX_BIN_BYTES];
|
|
uint16_t summed_probabilities[MAX_HISTORY_BINS][256];
|
|
uint8_t probabilities[MAX_HISTORY_BINS][256];
|
|
uint8_t *value_lookup[MAX_HISTORY_BINS];
|
|
} WavpackFrameContext;
|
|
|
|
#define WV_MAX_FRAME_DECODERS 14
|
|
|
|
typedef struct WavpackContext {
|
|
AVCodecContext *avctx;
|
|
|
|
WavpackFrameContext *fdec[WV_MAX_FRAME_DECODERS];
|
|
int fdec_num;
|
|
|
|
int block;
|
|
int samples;
|
|
int ch_offset;
|
|
|
|
AVFrame *frame;
|
|
ThreadFrame curr_frame, prev_frame;
|
|
Modulation modulation;
|
|
|
|
AVBufferRef *dsd_ref;
|
|
DSDContext *dsdctx;
|
|
int dsd_channels;
|
|
} WavpackContext;
|
|
|
|
#define LEVEL_DECAY(a) (((a) + 0x80) >> 8)
|
|
|
|
static av_always_inline unsigned get_tail(GetBitContext *gb, int k)
|
|
{
|
|
int p, e, res;
|
|
|
|
if (k < 1)
|
|
return 0;
|
|
p = av_log2(k);
|
|
e = (1 << (p + 1)) - k - 1;
|
|
res = get_bitsz(gb, p);
|
|
if (res >= e)
|
|
res = (res << 1) - e + get_bits1(gb);
|
|
return res;
|
|
}
|
|
|
|
static int update_error_limit(WavpackFrameContext *ctx)
|
|
{
|
|
int i, br[2], sl[2];
|
|
|
|
for (i = 0; i <= ctx->stereo_in; i++) {
|
|
if (ctx->ch[i].bitrate_acc > UINT_MAX - ctx->ch[i].bitrate_delta)
|
|
return AVERROR_INVALIDDATA;
|
|
ctx->ch[i].bitrate_acc += ctx->ch[i].bitrate_delta;
|
|
br[i] = ctx->ch[i].bitrate_acc >> 16;
|
|
sl[i] = LEVEL_DECAY(ctx->ch[i].slow_level);
|
|
}
|
|
if (ctx->stereo_in && ctx->hybrid_bitrate) {
|
|
int balance = (sl[1] - sl[0] + br[1] + 1) >> 1;
|
|
if (balance > br[0]) {
|
|
br[1] = br[0] * 2;
|
|
br[0] = 0;
|
|
} else if (-balance > br[0]) {
|
|
br[0] *= 2;
|
|
br[1] = 0;
|
|
} else {
|
|
br[1] = br[0] + balance;
|
|
br[0] = br[0] - balance;
|
|
}
|
|
}
|
|
for (i = 0; i <= ctx->stereo_in; i++) {
|
|
if (ctx->hybrid_bitrate) {
|
|
if (sl[i] - br[i] > -0x100)
|
|
ctx->ch[i].error_limit = wp_exp2(sl[i] - br[i] + 0x100);
|
|
else
|
|
ctx->ch[i].error_limit = 0;
|
|
} else {
|
|
ctx->ch[i].error_limit = wp_exp2(br[i]);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wv_get_value(WavpackFrameContext *ctx, GetBitContext *gb,
|
|
int channel, int *last)
|
|
{
|
|
int t, t2;
|
|
int sign, base, add, ret;
|
|
WvChannel *c = &ctx->ch[channel];
|
|
|
|
*last = 0;
|
|
|
|
if ((ctx->ch[0].median[0] < 2U) && (ctx->ch[1].median[0] < 2U) &&
|
|
!ctx->zero && !ctx->one) {
|
|
if (ctx->zeroes) {
|
|
ctx->zeroes--;
|
|
if (ctx->zeroes) {
|
|
c->slow_level -= LEVEL_DECAY(c->slow_level);
|
|
return 0;
|
|
}
|
|
} else {
|
|
t = get_unary_0_33(gb);
|
|
if (t >= 2) {
|
|
if (t >= 32 || get_bits_left(gb) < t - 1)
|
|
goto error;
|
|
t = get_bits_long(gb, t - 1) | (1 << (t - 1));
|
|
} else {
|
|
if (get_bits_left(gb) < 0)
|
|
goto error;
|
|
}
|
|
ctx->zeroes = t;
|
|
if (ctx->zeroes) {
|
|
memset(ctx->ch[0].median, 0, sizeof(ctx->ch[0].median));
|
|
memset(ctx->ch[1].median, 0, sizeof(ctx->ch[1].median));
|
|
c->slow_level -= LEVEL_DECAY(c->slow_level);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ctx->zero) {
|
|
t = 0;
|
|
ctx->zero = 0;
|
|
} else {
|
|
t = get_unary_0_33(gb);
|
|
if (get_bits_left(gb) < 0)
|
|
goto error;
|
|
if (t == 16) {
|
|
t2 = get_unary_0_33(gb);
|
|
if (t2 < 2) {
|
|
if (get_bits_left(gb) < 0)
|
|
goto error;
|
|
t += t2;
|
|
} else {
|
|
if (t2 >= 32 || get_bits_left(gb) < t2 - 1)
|
|
goto error;
|
|
t += get_bits_long(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 (ctx->hybrid && !channel) {
|
|
if (update_error_limit(ctx) < 0)
|
|
goto error;
|
|
}
|
|
|
|
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 - 2U);
|
|
add = GET_MED(2) - 1;
|
|
INC_MED(0);
|
|
INC_MED(1);
|
|
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;
|
|
} else {
|
|
int mid = (base * 2U + add + 1) >> 1;
|
|
while (add > c->error_limit) {
|
|
if (get_bits_left(gb) <= 0)
|
|
goto error;
|
|
if (get_bits1(gb)) {
|
|
add -= (mid - (unsigned)base);
|
|
base = mid;
|
|
} else
|
|
add = mid - (unsigned)base - 1;
|
|
mid = (base * 2U + add + 1) >> 1;
|
|
}
|
|
ret = mid;
|
|
}
|
|
sign = get_bits1(gb);
|
|
if (ctx->hybrid_bitrate)
|
|
c->slow_level += wp_log2(ret) - LEVEL_DECAY(c->slow_level);
|
|
return sign ? ~ret : ret;
|
|
|
|
error:
|
|
ret = get_bits_left(gb);
|
|
if (ret <= 0) {
|
|
av_log(ctx->avctx, AV_LOG_ERROR, "Too few bits (%d) left\n", ret);
|
|
}
|
|
*last = 1;
|
|
return 0;
|
|
}
|
|
|
|
static inline int wv_get_value_integer(WavpackFrameContext *s, uint32_t *crc,
|
|
unsigned S)
|
|
{
|
|
unsigned bit;
|
|
|
|
if (s->extra_bits) {
|
|
S *= 1 << s->extra_bits;
|
|
|
|
if (s->got_extra_bits &&
|
|
get_bits_left(&s->gb_extra_bits) >= s->extra_bits) {
|
|
S |= get_bits_long(&s->gb_extra_bits, s->extra_bits);
|
|
*crc = *crc * 9 + (S & 0xffff) * 3 + ((unsigned)S >> 16);
|
|
}
|
|
}
|
|
|
|
bit = (S & s->and) | s->or;
|
|
bit = ((S + bit) << s->shift) - bit;
|
|
|
|
if (s->hybrid)
|
|
bit = av_clip(bit, s->hybrid_minclip, s->hybrid_maxclip);
|
|
|
|
return bit << s->post_shift;
|
|
}
|
|
|
|
static float wv_get_value_float(WavpackFrameContext *s, uint32_t *crc, int S)
|
|
{
|
|
union {
|
|
float f;
|
|
uint32_t u;
|
|
} value;
|
|
|
|
unsigned int sign;
|
|
int exp = s->float_max_exp;
|
|
|
|
if (s->got_extra_bits) {
|
|
const int max_bits = 1 + 23 + 8 + 1;
|
|
const int left_bits = get_bits_left(&s->gb_extra_bits);
|
|
|
|
if (left_bits + 8 * AV_INPUT_BUFFER_PADDING_SIZE < max_bits)
|
|
return 0.0;
|
|
}
|
|
|
|
if (S) {
|
|
S *= 1U << s->float_shift;
|
|
sign = S < 0;
|
|
if (sign)
|
|
S = -(unsigned)S;
|
|
if (S >= 0x1000000U) {
|
|
if (s->got_extra_bits && get_bits1(&s->gb_extra_bits))
|
|
S = get_bits(&s->gb_extra_bits, 23);
|
|
else
|
|
S = 0;
|
|
exp = 255;
|
|
} else if (exp) {
|
|
int shift = 23 - av_log2(S);
|
|
exp = s->float_max_exp;
|
|
if (exp <= shift)
|
|
shift = --exp;
|
|
exp -= shift;
|
|
|
|
if (shift) {
|
|
S <<= shift;
|
|
if ((s->float_flag & WV_FLT_SHIFT_ONES) ||
|
|
(s->got_extra_bits &&
|
|
(s->float_flag & WV_FLT_SHIFT_SAME) &&
|
|
get_bits1(&s->gb_extra_bits))) {
|
|
S |= (1 << shift) - 1;
|
|
} else if (s->got_extra_bits &&
|
|
(s->float_flag & WV_FLT_SHIFT_SENT)) {
|
|
S |= get_bits(&s->gb_extra_bits, shift);
|
|
}
|
|
}
|
|
} else {
|
|
exp = s->float_max_exp;
|
|
}
|
|
S &= 0x7fffff;
|
|
} else {
|
|
sign = 0;
|
|
exp = 0;
|
|
if (s->got_extra_bits && (s->float_flag & WV_FLT_ZERO_SENT)) {
|
|
if (get_bits1(&s->gb_extra_bits)) {
|
|
S = get_bits(&s->gb_extra_bits, 23);
|
|
if (s->float_max_exp >= 25)
|
|
exp = get_bits(&s->gb_extra_bits, 8);
|
|
sign = get_bits1(&s->gb_extra_bits);
|
|
} else {
|
|
if (s->float_flag & WV_FLT_ZERO_SIGN)
|
|
sign = get_bits1(&s->gb_extra_bits);
|
|
}
|
|
}
|
|
}
|
|
|
|
*crc = *crc * 27 + S * 9 + exp * 3 + sign;
|
|
|
|
value.u = (sign << 31) | (exp << 23) | S;
|
|
return value.f;
|
|
}
|
|
|
|
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 void init_ptable(int *table, int rate_i, int rate_s)
|
|
{
|
|
int value = 0x808000, rate = rate_i << 8;
|
|
|
|
for (int c = (rate + 128) >> 8; c--;)
|
|
value += (DOWN - value) >> DECAY;
|
|
|
|
for (int i = 0; i < PTABLE_BINS/2; i++) {
|
|
table[i] = value;
|
|
table[PTABLE_BINS-1-i] = 0x100ffff - value;
|
|
|
|
if (value > 0x010000) {
|
|
rate += (rate * rate_s + 128) >> 8;
|
|
|
|
for (int c = (rate + 64) >> 7; c--;)
|
|
value += (DOWN - value) >> DECAY;
|
|
}
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
int32_t value, fltr0, fltr1, fltr2, fltr3, fltr4, fltr5, fltr6, factor;
|
|
unsigned int byte;
|
|
} DSDfilters;
|
|
|
|
static int wv_unpack_dsd_high(WavpackFrameContext *s, uint8_t *dst_left, uint8_t *dst_right)
|
|
{
|
|
uint32_t checksum = 0xFFFFFFFF;
|
|
uint8_t *dst_l = dst_left, *dst_r = dst_right;
|
|
int total_samples = s->samples, stereo = dst_r ? 1 : 0;
|
|
DSDfilters filters[2], *sp = filters;
|
|
int rate_i, rate_s;
|
|
uint32_t low, high, value;
|
|
|
|
if (bytestream2_get_bytes_left(&s->gbyte) < (stereo ? 20 : 13))
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
rate_i = bytestream2_get_byte(&s->gbyte);
|
|
rate_s = bytestream2_get_byte(&s->gbyte);
|
|
|
|
if (rate_s != RATE_S)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
init_ptable(s->ptable, rate_i, rate_s);
|
|
|
|
for (int channel = 0; channel < stereo + 1; channel++) {
|
|
DSDfilters *sp = filters + channel;
|
|
|
|
sp->fltr1 = bytestream2_get_byte(&s->gbyte) << (PRECISION - 8);
|
|
sp->fltr2 = bytestream2_get_byte(&s->gbyte) << (PRECISION - 8);
|
|
sp->fltr3 = bytestream2_get_byte(&s->gbyte) << (PRECISION - 8);
|
|
sp->fltr4 = bytestream2_get_byte(&s->gbyte) << (PRECISION - 8);
|
|
sp->fltr5 = bytestream2_get_byte(&s->gbyte) << (PRECISION - 8);
|
|
sp->fltr6 = 0;
|
|
sp->factor = bytestream2_get_byte(&s->gbyte) & 0xff;
|
|
sp->factor |= (bytestream2_get_byte(&s->gbyte) << 8) & 0xff00;
|
|
sp->factor = (int32_t)((uint32_t)sp->factor << 16) >> 16;
|
|
}
|
|
|
|
value = bytestream2_get_be32(&s->gbyte);
|
|
high = 0xffffffff;
|
|
low = 0x0;
|
|
|
|
while (total_samples--) {
|
|
int bitcount = 8;
|
|
|
|
sp[0].value = sp[0].fltr1 - sp[0].fltr5 + ((sp[0].fltr6 * sp[0].factor) >> 2);
|
|
|
|
if (stereo)
|
|
sp[1].value = sp[1].fltr1 - sp[1].fltr5 + ((sp[1].fltr6 * sp[1].factor) >> 2);
|
|
|
|
while (bitcount--) {
|
|
int32_t *pp = s->ptable + ((sp[0].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
|
uint32_t split = low + ((high - low) >> 8) * (*pp >> 16);
|
|
|
|
if (value <= split) {
|
|
high = split;
|
|
*pp += (UP - *pp) >> DECAY;
|
|
sp[0].fltr0 = -1;
|
|
} else {
|
|
low = split + 1;
|
|
*pp += (DOWN - *pp) >> DECAY;
|
|
sp[0].fltr0 = 0;
|
|
}
|
|
|
|
while (DSD_BYTE_READY(high, low) && bytestream2_get_bytes_left(&s->gbyte)) {
|
|
value = (value << 8) | bytestream2_get_byte(&s->gbyte);
|
|
high = (high << 8) | 0xff;
|
|
low <<= 8;
|
|
}
|
|
|
|
sp[0].value += sp[0].fltr6 * 8;
|
|
sp[0].byte = (sp[0].byte << 1) | (sp[0].fltr0 & 1);
|
|
sp[0].factor += (((sp[0].value ^ sp[0].fltr0) >> 31) | 1) &
|
|
((sp[0].value ^ (sp[0].value - (sp[0].fltr6 * 16))) >> 31);
|
|
sp[0].fltr1 += ((sp[0].fltr0 & VALUE_ONE) - sp[0].fltr1) >> 6;
|
|
sp[0].fltr2 += ((sp[0].fltr0 & VALUE_ONE) - sp[0].fltr2) >> 4;
|
|
sp[0].fltr3 += (sp[0].fltr2 - sp[0].fltr3) >> 4;
|
|
sp[0].fltr4 += (sp[0].fltr3 - sp[0].fltr4) >> 4;
|
|
sp[0].value = (sp[0].fltr4 - sp[0].fltr5) >> 4;
|
|
sp[0].fltr5 += sp[0].value;
|
|
sp[0].fltr6 += (sp[0].value - sp[0].fltr6) >> 3;
|
|
sp[0].value = sp[0].fltr1 - sp[0].fltr5 + ((sp[0].fltr6 * sp[0].factor) >> 2);
|
|
|
|
if (!stereo)
|
|
continue;
|
|
|
|
pp = s->ptable + ((sp[1].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
|
split = low + ((high - low) >> 8) * (*pp >> 16);
|
|
|
|
if (value <= split) {
|
|
high = split;
|
|
*pp += (UP - *pp) >> DECAY;
|
|
sp[1].fltr0 = -1;
|
|
} else {
|
|
low = split + 1;
|
|
*pp += (DOWN - *pp) >> DECAY;
|
|
sp[1].fltr0 = 0;
|
|
}
|
|
|
|
while (DSD_BYTE_READY(high, low) && bytestream2_get_bytes_left(&s->gbyte)) {
|
|
value = (value << 8) | bytestream2_get_byte(&s->gbyte);
|
|
high = (high << 8) | 0xff;
|
|
low <<= 8;
|
|
}
|
|
|
|
sp[1].value += sp[1].fltr6 * 8;
|
|
sp[1].byte = (sp[1].byte << 1) | (sp[1].fltr0 & 1);
|
|
sp[1].factor += (((sp[1].value ^ sp[1].fltr0) >> 31) | 1) &
|
|
((sp[1].value ^ (sp[1].value - (sp[1].fltr6 * 16))) >> 31);
|
|
sp[1].fltr1 += ((sp[1].fltr0 & VALUE_ONE) - sp[1].fltr1) >> 6;
|
|
sp[1].fltr2 += ((sp[1].fltr0 & VALUE_ONE) - sp[1].fltr2) >> 4;
|
|
sp[1].fltr3 += (sp[1].fltr2 - sp[1].fltr3) >> 4;
|
|
sp[1].fltr4 += (sp[1].fltr3 - sp[1].fltr4) >> 4;
|
|
sp[1].value = (sp[1].fltr4 - sp[1].fltr5) >> 4;
|
|
sp[1].fltr5 += sp[1].value;
|
|
sp[1].fltr6 += (sp[1].value - sp[1].fltr6) >> 3;
|
|
sp[1].value = sp[1].fltr1 - sp[1].fltr5 + ((sp[1].fltr6 * sp[1].factor) >> 2);
|
|
}
|
|
|
|
checksum += (checksum << 1) + (*dst_l = sp[0].byte & 0xff);
|
|
sp[0].factor -= (sp[0].factor + 512) >> 10;
|
|
dst_l += 4;
|
|
|
|
if (stereo) {
|
|
checksum += (checksum << 1) + (*dst_r = filters[1].byte & 0xff);
|
|
filters[1].factor -= (filters[1].factor + 512) >> 10;
|
|
dst_r += 4;
|
|
}
|
|
}
|
|
|
|
if (wv_check_crc(s, checksum, 0)) {
|
|
if (s->avctx->err_recognition & AV_EF_CRCCHECK)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
memset(dst_left, 0x69, s->samples * 4);
|
|
|
|
if (dst_r)
|
|
memset(dst_right, 0x69, s->samples * 4);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wv_unpack_dsd_fast(WavpackFrameContext *s, uint8_t *dst_left, uint8_t *dst_right)
|
|
{
|
|
uint8_t *dst_l = dst_left, *dst_r = dst_right;
|
|
uint8_t history_bits, max_probability;
|
|
int total_summed_probabilities = 0;
|
|
int total_samples = s->samples;
|
|
uint8_t *vlb = s->value_lookup_buffer;
|
|
int history_bins, p0, p1, chan;
|
|
uint32_t checksum = 0xFFFFFFFF;
|
|
uint32_t low, high, value;
|
|
|
|
if (!bytestream2_get_bytes_left(&s->gbyte))
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
history_bits = bytestream2_get_byte(&s->gbyte);
|
|
|
|
if (!bytestream2_get_bytes_left(&s->gbyte) || history_bits > MAX_HISTORY_BITS)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
history_bins = 1 << history_bits;
|
|
max_probability = bytestream2_get_byte(&s->gbyte);
|
|
|
|
if (max_probability < 0xff) {
|
|
uint8_t *outptr = (uint8_t *)s->probabilities;
|
|
uint8_t *outend = outptr + sizeof(*s->probabilities) * history_bins;
|
|
|
|
while (outptr < outend && bytestream2_get_bytes_left(&s->gbyte)) {
|
|
int code = bytestream2_get_byte(&s->gbyte);
|
|
|
|
if (code > max_probability) {
|
|
int zcount = code - max_probability;
|
|
|
|
while (outptr < outend && zcount--)
|
|
*outptr++ = 0;
|
|
} else if (code) {
|
|
*outptr++ = code;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (outptr < outend ||
|
|
(bytestream2_get_bytes_left(&s->gbyte) && bytestream2_get_byte(&s->gbyte)))
|
|
return AVERROR_INVALIDDATA;
|
|
} else if (bytestream2_get_bytes_left(&s->gbyte) > (int)sizeof(*s->probabilities) * history_bins) {
|
|
bytestream2_get_buffer(&s->gbyte, (uint8_t *)s->probabilities,
|
|
sizeof(*s->probabilities) * history_bins);
|
|
} else {
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
for (p0 = 0; p0 < history_bins; p0++) {
|
|
int32_t sum_values = 0;
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
s->summed_probabilities[p0][i] = sum_values += s->probabilities[p0][i];
|
|
|
|
if (sum_values) {
|
|
total_summed_probabilities += sum_values;
|
|
|
|
if (total_summed_probabilities > history_bins * MAX_BIN_BYTES)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
s->value_lookup[p0] = vlb;
|
|
|
|
for (int i = 0; i < 256; i++) {
|
|
int c = s->probabilities[p0][i];
|
|
|
|
while (c--)
|
|
*vlb++ = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bytestream2_get_bytes_left(&s->gbyte) < 4)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
chan = p0 = p1 = 0;
|
|
low = 0; high = 0xffffffff;
|
|
value = bytestream2_get_be32(&s->gbyte);
|
|
|
|
if (dst_r)
|
|
total_samples *= 2;
|
|
|
|
while (total_samples--) {
|
|
unsigned int mult, index, code;
|
|
|
|
if (!s->summed_probabilities[p0][255])
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
mult = (high - low) / s->summed_probabilities[p0][255];
|
|
|
|
if (!mult) {
|
|
if (bytestream2_get_bytes_left(&s->gbyte) >= 4)
|
|
value = bytestream2_get_be32(&s->gbyte);
|
|
|
|
low = 0;
|
|
high = 0xffffffff;
|
|
mult = high / s->summed_probabilities[p0][255];
|
|
|
|
if (!mult)
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
index = (value - low) / mult;
|
|
|
|
if (index >= s->summed_probabilities[p0][255])
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
if (!dst_r) {
|
|
if ((*dst_l = code = s->value_lookup[p0][index]))
|
|
low += s->summed_probabilities[p0][code-1] * mult;
|
|
|
|
dst_l += 4;
|
|
} else {
|
|
if ((code = s->value_lookup[p0][index]))
|
|
low += s->summed_probabilities[p0][code-1] * mult;
|
|
|
|
if (chan) {
|
|
*dst_r = code;
|
|
dst_r += 4;
|
|
}
|
|
else {
|
|
*dst_l = code;
|
|
dst_l += 4;
|
|
}
|
|
|
|
chan ^= 1;
|
|
}
|
|
|
|
high = low + s->probabilities[p0][code] * mult - 1;
|
|
checksum += (checksum << 1) + code;
|
|
|
|
if (!dst_r) {
|
|
p0 = code & (history_bins-1);
|
|
} else {
|
|
p0 = p1;
|
|
p1 = code & (history_bins-1);
|
|
}
|
|
|
|
while (DSD_BYTE_READY(high, low) && bytestream2_get_bytes_left(&s->gbyte)) {
|
|
value = (value << 8) | bytestream2_get_byte(&s->gbyte);
|
|
high = (high << 8) | 0xff;
|
|
low <<= 8;
|
|
}
|
|
}
|
|
|
|
if (wv_check_crc(s, checksum, 0)) {
|
|
if (s->avctx->err_recognition & AV_EF_CRCCHECK)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
memset(dst_left, 0x69, s->samples * 4);
|
|
|
|
if (dst_r)
|
|
memset(dst_right, 0x69, s->samples * 4);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wv_unpack_dsd_copy(WavpackFrameContext *s, uint8_t *dst_left, uint8_t *dst_right)
|
|
{
|
|
uint8_t *dst_l = dst_left, *dst_r = dst_right;
|
|
int total_samples = s->samples;
|
|
uint32_t checksum = 0xFFFFFFFF;
|
|
|
|
if (bytestream2_get_bytes_left(&s->gbyte) != total_samples * (dst_r ? 2 : 1))
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
while (total_samples--) {
|
|
checksum += (checksum << 1) + (*dst_l = bytestream2_get_byte(&s->gbyte));
|
|
dst_l += 4;
|
|
|
|
if (dst_r) {
|
|
checksum += (checksum << 1) + (*dst_r = bytestream2_get_byte(&s->gbyte));
|
|
dst_r += 4;
|
|
}
|
|
}
|
|
|
|
if (wv_check_crc(s, checksum, 0)) {
|
|
if (s->avctx->err_recognition & AV_EF_CRCCHECK)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
memset(dst_left, 0x69, s->samples * 4);
|
|
|
|
if (dst_r)
|
|
memset(dst_right, 0x69, s->samples * 4);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb,
|
|
void *dst_l, void *dst_r, const int type)
|
|
{
|
|
int i, j, count = 0;
|
|
int last, t;
|
|
int A, B, L, L2, R, R2;
|
|
int pos = 0;
|
|
uint32_t crc = 0xFFFFFFFF;
|
|
uint32_t crc_extra_bits = 0xFFFFFFFF;
|
|
int16_t *dst16_l = dst_l;
|
|
int16_t *dst16_r = dst_r;
|
|
int32_t *dst32_l = dst_l;
|
|
int32_t *dst32_r = dst_r;
|
|
float *dstfl_l = dst_l;
|
|
float *dstfl_r = dst_r;
|
|
|
|
s->one = s->zero = s->zeroes = 0;
|
|
do {
|
|
L = wv_get_value(s, gb, 0, &last);
|
|
if (last)
|
|
break;
|
|
R = wv_get_value(s, gb, 1, &last);
|
|
if (last)
|
|
break;
|
|
for (i = 0; i < s->terms; i++) {
|
|
t = s->decorr[i].value;
|
|
if (t > 0) {
|
|
if (t > 8) {
|
|
if (t & 1) {
|
|
A = 2U * s->decorr[i].samplesA[0] - s->decorr[i].samplesA[1];
|
|
B = 2U * s->decorr[i].samplesB[0] - s->decorr[i].samplesB[1];
|
|
} else {
|
|
A = (int)(3U * s->decorr[i].samplesA[0] - s->decorr[i].samplesA[1]) >> 1;
|
|
B = (int)(3U * 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;
|
|
}
|
|
if (type != AV_SAMPLE_FMT_S16P) {
|
|
L2 = L + ((s->decorr[i].weightA * (int64_t)A + 512) >> 10);
|
|
R2 = R + ((s->decorr[i].weightB * (int64_t)B + 512) >> 10);
|
|
} else {
|
|
L2 = L + (unsigned)((int)(s->decorr[i].weightA * (unsigned)A + 512) >> 10);
|
|
R2 = R + (unsigned)((int)(s->decorr[i].weightB * (unsigned)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) {
|
|
if (type != AV_SAMPLE_FMT_S16P)
|
|
L2 = L + ((s->decorr[i].weightA * (int64_t)s->decorr[i].samplesA[0] + 512) >> 10);
|
|
else
|
|
L2 = L + (unsigned)((int)(s->decorr[i].weightA * (unsigned)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;
|
|
if (type != AV_SAMPLE_FMT_S16P)
|
|
R2 = R + ((s->decorr[i].weightB * (int64_t)L2 + 512) >> 10);
|
|
else
|
|
R2 = R + (unsigned)((int)(s->decorr[i].weightB * (unsigned)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 {
|
|
if (type != AV_SAMPLE_FMT_S16P)
|
|
R2 = R + ((s->decorr[i].weightB * (int64_t)s->decorr[i].samplesB[0] + 512) >> 10);
|
|
else
|
|
R2 = R + (unsigned)((int)(s->decorr[i].weightB * (unsigned)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;
|
|
}
|
|
|
|
if (type != AV_SAMPLE_FMT_S16P)
|
|
L2 = L + ((s->decorr[i].weightA * (int64_t)R2 + 512) >> 10);
|
|
else
|
|
L2 = L + (unsigned)((int)(s->decorr[i].weightA * (unsigned)R2 + 512) >> 10);
|
|
UPDATE_WEIGHT_CLIP(s->decorr[i].weightA, s->decorr[i].delta, R2, L);
|
|
L = L2;
|
|
s->decorr[i].samplesB[0] = L;
|
|
}
|
|
}
|
|
|
|
if (type == AV_SAMPLE_FMT_S16P) {
|
|
if (FFABS((int64_t)L) + FFABS((int64_t)R) > (1<<19)) {
|
|
av_log(s->avctx, AV_LOG_ERROR, "sample %d %d too large\n", L, R);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
}
|
|
|
|
pos = (pos + 1) & 7;
|
|
if (s->joint)
|
|
L += (unsigned)(R -= (unsigned)(L >> 1));
|
|
crc = (crc * 3 + L) * 3 + R;
|
|
|
|
if (type == AV_SAMPLE_FMT_FLTP) {
|
|
*dstfl_l++ = wv_get_value_float(s, &crc_extra_bits, L);
|
|
*dstfl_r++ = wv_get_value_float(s, &crc_extra_bits, R);
|
|
} else if (type == AV_SAMPLE_FMT_S32P) {
|
|
*dst32_l++ = wv_get_value_integer(s, &crc_extra_bits, L);
|
|
*dst32_r++ = wv_get_value_integer(s, &crc_extra_bits, R);
|
|
} else {
|
|
*dst16_l++ = wv_get_value_integer(s, &crc_extra_bits, L);
|
|
*dst16_r++ = wv_get_value_integer(s, &crc_extra_bits, R);
|
|
}
|
|
count++;
|
|
} while (!last && count < s->samples);
|
|
|
|
if (last && count < s->samples) {
|
|
int size = av_get_bytes_per_sample(type);
|
|
memset((uint8_t*)dst_l + count*size, 0, (s->samples-count)*size);
|
|
memset((uint8_t*)dst_r + count*size, 0, (s->samples-count)*size);
|
|
}
|
|
|
|
if ((s->avctx->err_recognition & AV_EF_CRCCHECK) &&
|
|
wv_check_crc(s, crc, crc_extra_bits))
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb,
|
|
void *dst, const int type)
|
|
{
|
|
int i, j, count = 0;
|
|
int last, t;
|
|
int A, S, T;
|
|
int pos = 0;
|
|
uint32_t crc = 0xFFFFFFFF;
|
|
uint32_t crc_extra_bits = 0xFFFFFFFF;
|
|
int16_t *dst16 = dst;
|
|
int32_t *dst32 = dst;
|
|
float *dstfl = dst;
|
|
|
|
s->one = s->zero = s->zeroes = 0;
|
|
do {
|
|
T = wv_get_value(s, gb, 0, &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 = 2U * s->decorr[i].samplesA[0] - s->decorr[i].samplesA[1];
|
|
else
|
|
A = (int)(3U * 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;
|
|
}
|
|
if (type != AV_SAMPLE_FMT_S16P)
|
|
S = T + ((s->decorr[i].weightA * (int64_t)A + 512) >> 10);
|
|
else
|
|
S = T + (unsigned)((int)(s->decorr[i].weightA * (unsigned)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;
|
|
|
|
if (type == AV_SAMPLE_FMT_FLTP) {
|
|
*dstfl++ = wv_get_value_float(s, &crc_extra_bits, S);
|
|
} else if (type == AV_SAMPLE_FMT_S32P) {
|
|
*dst32++ = wv_get_value_integer(s, &crc_extra_bits, S);
|
|
} else {
|
|
*dst16++ = wv_get_value_integer(s, &crc_extra_bits, S);
|
|
}
|
|
count++;
|
|
} while (!last && count < s->samples);
|
|
|
|
if (last && count < s->samples) {
|
|
int size = av_get_bytes_per_sample(type);
|
|
memset((uint8_t*)dst + count*size, 0, (s->samples-count)*size);
|
|
}
|
|
|
|
if (s->avctx->err_recognition & AV_EF_CRCCHECK) {
|
|
int ret = wv_check_crc(s, crc, crc_extra_bits);
|
|
if (ret < 0 && s->avctx->err_recognition & AV_EF_EXPLODE)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wv_dsd_reset(WavpackContext *s, int channels)
|
|
{
|
|
int i;
|
|
|
|
s->dsdctx = NULL;
|
|
s->dsd_channels = 0;
|
|
av_buffer_unref(&s->dsd_ref);
|
|
|
|
if (!channels)
|
|
return 0;
|
|
|
|
if (channels > INT_MAX / sizeof(*s->dsdctx))
|
|
return AVERROR(EINVAL);
|
|
|
|
s->dsd_ref = av_buffer_allocz(channels * sizeof(*s->dsdctx));
|
|
if (!s->dsd_ref)
|
|
return AVERROR(ENOMEM);
|
|
s->dsdctx = (DSDContext*)s->dsd_ref->data;
|
|
s->dsd_channels = channels;
|
|
|
|
for (i = 0; i < channels; i++)
|
|
memset(s->dsdctx[i].buf, 0x69, sizeof(s->dsdctx[i].buf));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if HAVE_THREADS
|
|
static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
|
|
{
|
|
WavpackContext *fsrc = src->priv_data;
|
|
WavpackContext *fdst = dst->priv_data;
|
|
int ret;
|
|
|
|
if (dst == src)
|
|
return 0;
|
|
|
|
ff_thread_release_buffer(dst, &fdst->curr_frame);
|
|
if (fsrc->curr_frame.f->data[0]) {
|
|
if ((ret = ff_thread_ref_frame(&fdst->curr_frame, &fsrc->curr_frame)) < 0)
|
|
return ret;
|
|
}
|
|
|
|
av_buffer_unref(&fdst->dsd_ref);
|
|
fdst->dsdctx = NULL;
|
|
fdst->dsd_channels = 0;
|
|
if (fsrc->dsd_ref) {
|
|
fdst->dsd_ref = av_buffer_ref(fsrc->dsd_ref);
|
|
if (!fdst->dsd_ref)
|
|
return AVERROR(ENOMEM);
|
|
fdst->dsdctx = (DSDContext*)fdst->dsd_ref->data;
|
|
fdst->dsd_channels = fsrc->dsd_channels;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static av_cold int wavpack_decode_init(AVCodecContext *avctx)
|
|
{
|
|
WavpackContext *s = avctx->priv_data;
|
|
|
|
s->avctx = avctx;
|
|
|
|
s->fdec_num = 0;
|
|
|
|
s->curr_frame.f = av_frame_alloc();
|
|
s->prev_frame.f = av_frame_alloc();
|
|
|
|
if (!s->curr_frame.f || !s->prev_frame.f)
|
|
return AVERROR(ENOMEM);
|
|
|
|
ff_init_dsd_data();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static av_cold int wavpack_decode_end(AVCodecContext *avctx)
|
|
{
|
|
WavpackContext *s = avctx->priv_data;
|
|
|
|
for (int i = 0; i < s->fdec_num; i++)
|
|
av_freep(&s->fdec[i]);
|
|
s->fdec_num = 0;
|
|
|
|
ff_thread_release_buffer(avctx, &s->curr_frame);
|
|
av_frame_free(&s->curr_frame.f);
|
|
|
|
ff_thread_release_buffer(avctx, &s->prev_frame);
|
|
av_frame_free(&s->prev_frame.f);
|
|
|
|
av_buffer_unref(&s->dsd_ref);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
|
|
const uint8_t *buf, int buf_size)
|
|
{
|
|
WavpackContext *wc = avctx->priv_data;
|
|
WavpackFrameContext *s;
|
|
GetByteContext gb;
|
|
enum AVSampleFormat sample_fmt;
|
|
void *samples_l = NULL, *samples_r = NULL;
|
|
int ret;
|
|
int got_terms = 0, got_weights = 0, got_samples = 0,
|
|
got_entropy = 0, got_pcm = 0, got_float = 0, got_hybrid = 0;
|
|
int got_dsd = 0;
|
|
int i, j, id, size, ssize, weights, t;
|
|
int bpp, chan = 0, orig_bpp, sample_rate = 0, rate_x = 1, dsd_mode = 0;
|
|
int multiblock;
|
|
uint64_t chmask = 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 AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
s = wc->fdec[block_no];
|
|
if (!s) {
|
|
av_log(avctx, AV_LOG_ERROR, "Context for block %d is not present\n",
|
|
block_no);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
memset(s->decorr, 0, MAX_TERMS * sizeof(Decorr));
|
|
memset(s->ch, 0, sizeof(s->ch));
|
|
s->extra_bits = 0;
|
|
s->and = s->or = s->shift = 0;
|
|
s->got_extra_bits = 0;
|
|
|
|
bytestream2_init(&gb, buf, buf_size);
|
|
|
|
s->samples = bytestream2_get_le32(&gb);
|
|
if (s->samples != wc->samples) {
|
|
av_log(avctx, AV_LOG_ERROR, "Mismatching number of samples in "
|
|
"a sequence: %d and %d\n", wc->samples, s->samples);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
s->frame_flags = bytestream2_get_le32(&gb);
|
|
|
|
if (s->frame_flags & (WV_FLOAT_DATA | WV_DSD_DATA))
|
|
sample_fmt = AV_SAMPLE_FMT_FLTP;
|
|
else if ((s->frame_flags & 0x03) <= 1)
|
|
sample_fmt = AV_SAMPLE_FMT_S16P;
|
|
else
|
|
sample_fmt = AV_SAMPLE_FMT_S32P;
|
|
|
|
bpp = av_get_bytes_per_sample(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->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 = bpp * 8 - orig_bpp + ((s->frame_flags >> 13) & 0x1f);
|
|
if (s->post_shift < 0 || s->post_shift > 31) {
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
s->hybrid_maxclip = ((1LL << (orig_bpp - 1)) - 1);
|
|
s->hybrid_minclip = ((-1UL << (orig_bpp - 1)));
|
|
s->CRC = bytestream2_get_le32(&gb);
|
|
|
|
// parse metadata blocks
|
|
while (bytestream2_get_bytes_left(&gb)) {
|
|
id = bytestream2_get_byte(&gb);
|
|
size = bytestream2_get_byte(&gb);
|
|
if (id & WP_IDF_LONG)
|
|
size |= (bytestream2_get_le16u(&gb)) << 8;
|
|
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 (bytestream2_get_bytes_left(&gb) < ssize) {
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
"Block size %i is out of bounds\n", size);
|
|
break;
|
|
}
|
|
switch (id & WP_IDF_MASK) {
|
|
case WP_ID_DECTERMS:
|
|
if (size > MAX_TERMS) {
|
|
av_log(avctx, AV_LOG_ERROR, "Too many decorrelation terms\n");
|
|
s->terms = 0;
|
|
bytestream2_skip(&gb, ssize);
|
|
continue;
|
|
}
|
|
s->terms = size;
|
|
for (i = 0; i < s->terms; i++) {
|
|
uint8_t val = bytestream2_get_byte(&gb);
|
|
s->decorr[s->terms - i - 1].value = (val & 0x1F) - 5;
|
|
s->decorr[s->terms - i - 1].delta = val >> 5;
|
|
}
|
|
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_in;
|
|
if (weights > MAX_TERMS || weights > s->terms) {
|
|
av_log(avctx, AV_LOG_ERROR, "Too many decorrelation weights\n");
|
|
bytestream2_skip(&gb, ssize);
|
|
continue;
|
|
}
|
|
for (i = 0; i < weights; i++) {
|
|
t = (int8_t)bytestream2_get_byte(&gb);
|
|
s->decorr[s->terms - i - 1].weightA = t * (1 << 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_in) {
|
|
t = (int8_t)bytestream2_get_byte(&gb);
|
|
s->decorr[s->terms - i - 1].weightB = t * (1 << 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(bytestream2_get_le16(&gb));
|
|
s->decorr[i].samplesA[1] =
|
|
wp_exp2(bytestream2_get_le16(&gb));
|
|
|
|
if (s->stereo_in) {
|
|
s->decorr[i].samplesB[0] =
|
|
wp_exp2(bytestream2_get_le16(&gb));
|
|
s->decorr[i].samplesB[1] =
|
|
wp_exp2(bytestream2_get_le16(&gb));
|
|
t += 4;
|
|
}
|
|
t += 4;
|
|
} else if (s->decorr[i].value < 0) {
|
|
s->decorr[i].samplesA[0] =
|
|
wp_exp2(bytestream2_get_le16(&gb));
|
|
s->decorr[i].samplesB[0] =
|
|
wp_exp2(bytestream2_get_le16(&gb));
|
|
t += 4;
|
|
} else {
|
|
for (j = 0; j < s->decorr[i].value; j++) {
|
|
s->decorr[i].samplesA[j] =
|
|
wp_exp2(bytestream2_get_le16(&gb));
|
|
if (s->stereo_in) {
|
|
s->decorr[i].samplesB[j] =
|
|
wp_exp2(bytestream2_get_le16(&gb));
|
|
}
|
|
}
|
|
t += s->decorr[i].value * 2 * (s->stereo_in + 1);
|
|
}
|
|
}
|
|
got_samples = 1;
|
|
break;
|
|
case WP_ID_ENTROPY:
|
|
if (size != 6 * (s->stereo_in + 1)) {
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
"Entropy vars size should be %i, got %i.\n",
|
|
6 * (s->stereo_in + 1), size);
|
|
bytestream2_skip(&gb, ssize);
|
|
continue;
|
|
}
|
|
for (j = 0; j <= s->stereo_in; j++)
|
|
for (i = 0; i < 3; i++) {
|
|
s->ch[j].median[i] = wp_exp2(bytestream2_get_le16(&gb));
|
|
}
|
|
got_entropy = 1;
|
|
break;
|
|
case WP_ID_HYBRID:
|
|
if (s->hybrid_bitrate) {
|
|
for (i = 0; i <= s->stereo_in; i++) {
|
|
s->ch[i].slow_level = wp_exp2(bytestream2_get_le16(&gb));
|
|
size -= 2;
|
|
}
|
|
}
|
|
for (i = 0; i < (s->stereo_in + 1); i++) {
|
|
s->ch[i].bitrate_acc = bytestream2_get_le16(&gb) << 16;
|
|
size -= 2;
|
|
}
|
|
if (size > 0) {
|
|
for (i = 0; i < (s->stereo_in + 1); i++) {
|
|
s->ch[i].bitrate_delta =
|
|
wp_exp2((int16_t)bytestream2_get_le16(&gb));
|
|
}
|
|
} else {
|
|
for (i = 0; i < (s->stereo_in + 1); i++)
|
|
s->ch[i].bitrate_delta = 0;
|
|
}
|
|
got_hybrid = 1;
|
|
break;
|
|
case WP_ID_INT32INFO: {
|
|
uint8_t val[4];
|
|
if (size != 4) {
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
"Invalid INT32INFO, size = %i\n",
|
|
size);
|
|
bytestream2_skip(&gb, ssize - 4);
|
|
continue;
|
|
}
|
|
bytestream2_get_buffer(&gb, val, 4);
|
|
if (val[0] > 30) {
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
"Invalid INT32INFO, extra_bits = %d (> 30)\n", val[0]);
|
|
continue;
|
|
} else if (val[0]) {
|
|
s->extra_bits = val[0];
|
|
} else if (val[1]) {
|
|
s->shift = val[1];
|
|
} else if (val[2]) {
|
|
s->and = s->or = 1;
|
|
s->shift = val[2];
|
|
} else if (val[3]) {
|
|
s->and = 1;
|
|
s->shift = val[3];
|
|
}
|
|
if (s->shift > 31) {
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
"Invalid INT32INFO, shift = %d (> 31)\n", s->shift);
|
|
s->and = s->or = s->shift = 0;
|
|
continue;
|
|
}
|
|
/* 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;
|
|
}
|
|
break;
|
|
}
|
|
case WP_ID_FLOATINFO:
|
|
if (size != 4) {
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
"Invalid FLOATINFO, size = %i\n", size);
|
|
bytestream2_skip(&gb, ssize);
|
|
continue;
|
|
}
|
|
s->float_flag = bytestream2_get_byte(&gb);
|
|
s->float_shift = bytestream2_get_byte(&gb);
|
|
s->float_max_exp = bytestream2_get_byte(&gb);
|
|
if (s->float_shift > 31) {
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
"Invalid FLOATINFO, shift = %d (> 31)\n", s->float_shift);
|
|
s->float_shift = 0;
|
|
continue;
|
|
}
|
|
got_float = 1;
|
|
bytestream2_skip(&gb, 1);
|
|
break;
|
|
case WP_ID_DATA:
|
|
if ((ret = init_get_bits8(&s->gb, gb.buffer, size)) < 0)
|
|
return ret;
|
|
bytestream2_skip(&gb, size);
|
|
got_pcm = 1;
|
|
break;
|
|
case WP_ID_DSD_DATA:
|
|
if (size < 2) {
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid DSD_DATA, size = %i\n",
|
|
size);
|
|
bytestream2_skip(&gb, ssize);
|
|
continue;
|
|
}
|
|
rate_x = 1 << bytestream2_get_byte(&gb);
|
|
dsd_mode = bytestream2_get_byte(&gb);
|
|
if (dsd_mode && dsd_mode != 1 && dsd_mode != 3) {
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid DSD encoding mode: %d\n",
|
|
dsd_mode);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
bytestream2_init(&s->gbyte, gb.buffer, size-2);
|
|
bytestream2_skip(&gb, size-2);
|
|
got_dsd = 1;
|
|
break;
|
|
case WP_ID_EXTRABITS:
|
|
if (size <= 4) {
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid EXTRABITS, size = %i\n",
|
|
size);
|
|
bytestream2_skip(&gb, size);
|
|
continue;
|
|
}
|
|
if ((ret = init_get_bits8(&s->gb_extra_bits, gb.buffer, size)) < 0)
|
|
return ret;
|
|
s->crc_extra_bits = get_bits_long(&s->gb_extra_bits, 32);
|
|
bytestream2_skip(&gb, 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 AVERROR_INVALIDDATA;
|
|
}
|
|
chan = bytestream2_get_byte(&gb);
|
|
switch (size - 2) {
|
|
case 0:
|
|
chmask = bytestream2_get_byte(&gb);
|
|
break;
|
|
case 1:
|
|
chmask = bytestream2_get_le16(&gb);
|
|
break;
|
|
case 2:
|
|
chmask = bytestream2_get_le24(&gb);
|
|
break;
|
|
case 3:
|
|
chmask = bytestream2_get_le32(&gb);
|
|
break;
|
|
case 4:
|
|
size = bytestream2_get_byte(&gb);
|
|
chan |= (bytestream2_get_byte(&gb) & 0xF) << 8;
|
|
chan += 1;
|
|
if (avctx->channels != chan)
|
|
av_log(avctx, AV_LOG_WARNING, "%i channels signalled"
|
|
" instead of %i.\n", chan, avctx->channels);
|
|
chmask = bytestream2_get_le24(&gb);
|
|
break;
|
|
case 5:
|
|
size = bytestream2_get_byte(&gb);
|
|
chan |= (bytestream2_get_byte(&gb) & 0xF) << 8;
|
|
chan += 1;
|
|
if (avctx->channels != chan)
|
|
av_log(avctx, AV_LOG_WARNING, "%i channels signalled"
|
|
" instead of %i.\n", chan, avctx->channels);
|
|
chmask = bytestream2_get_le32(&gb);
|
|
break;
|
|
default:
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid channel info size %d\n",
|
|
size);
|
|
chan = avctx->channels;
|
|
chmask = avctx->channel_layout;
|
|
}
|
|
break;
|
|
case WP_ID_SAMPLE_RATE:
|
|
if (size != 3) {
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid custom sample rate.\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
sample_rate = bytestream2_get_le24(&gb);
|
|
break;
|
|
default:
|
|
bytestream2_skip(&gb, size);
|
|
}
|
|
if (id & WP_IDF_ODD)
|
|
bytestream2_skip(&gb, 1);
|
|
}
|
|
|
|
if (got_pcm) {
|
|
if (!got_terms) {
|
|
av_log(avctx, AV_LOG_ERROR, "No block with decorrelation terms\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
if (!got_weights) {
|
|
av_log(avctx, AV_LOG_ERROR, "No block with decorrelation weights\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
if (!got_samples) {
|
|
av_log(avctx, AV_LOG_ERROR, "No block with decorrelation samples\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
if (!got_entropy) {
|
|
av_log(avctx, AV_LOG_ERROR, "No block with entropy info\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
if (s->hybrid && !got_hybrid) {
|
|
av_log(avctx, AV_LOG_ERROR, "Hybrid config not found\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
if (!got_float && sample_fmt == AV_SAMPLE_FMT_FLTP) {
|
|
av_log(avctx, AV_LOG_ERROR, "Float information not found\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
if (s->got_extra_bits && sample_fmt != AV_SAMPLE_FMT_FLTP) {
|
|
const int size = get_bits_left(&s->gb_extra_bits);
|
|
const int wanted = s->samples * s->extra_bits << s->stereo_in;
|
|
if (size < wanted) {
|
|
av_log(avctx, AV_LOG_ERROR, "Too small EXTRABITS\n");
|
|
s->got_extra_bits = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!got_pcm && !got_dsd) {
|
|
av_log(avctx, AV_LOG_ERROR, "Packed samples not found\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
if ((got_pcm && wc->modulation != MODULATION_PCM) ||
|
|
(got_dsd && wc->modulation != MODULATION_DSD)) {
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid PCM/DSD mix encountered\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
if (!wc->ch_offset) {
|
|
int new_channels = avctx->channels;
|
|
uint64_t new_chmask = avctx->channel_layout;
|
|
int new_samplerate;
|
|
int sr = (s->frame_flags >> 23) & 0xf;
|
|
if (sr == 0xf) {
|
|
if (!sample_rate) {
|
|
av_log(avctx, AV_LOG_ERROR, "Custom sample rate missing.\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
new_samplerate = sample_rate * rate_x;
|
|
} else
|
|
new_samplerate = wv_rates[sr] * rate_x;
|
|
|
|
if (multiblock) {
|
|
if (chan)
|
|
new_channels = chan;
|
|
if (chmask)
|
|
new_chmask = chmask;
|
|
} else {
|
|
new_channels = s->stereo ? 2 : 1;
|
|
new_chmask = s->stereo ? AV_CH_LAYOUT_STEREO :
|
|
AV_CH_LAYOUT_MONO;
|
|
}
|
|
|
|
if (new_chmask &&
|
|
av_get_channel_layout_nb_channels(new_chmask) != new_channels) {
|
|
av_log(avctx, AV_LOG_ERROR, "Channel mask does not match the channel count\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
/* clear DSD state if stream properties change */
|
|
if (new_channels != wc->dsd_channels ||
|
|
new_chmask != avctx->channel_layout ||
|
|
new_samplerate != avctx->sample_rate ||
|
|
!!got_dsd != !!wc->dsdctx) {
|
|
ret = wv_dsd_reset(wc, got_dsd ? new_channels : 0);
|
|
if (ret < 0) {
|
|
av_log(avctx, AV_LOG_ERROR, "Error reinitializing the DSD context\n");
|
|
return ret;
|
|
}
|
|
ff_thread_release_buffer(avctx, &wc->curr_frame);
|
|
}
|
|
avctx->channels = new_channels;
|
|
avctx->channel_layout = new_chmask;
|
|
avctx->sample_rate = new_samplerate;
|
|
avctx->sample_fmt = sample_fmt;
|
|
avctx->bits_per_raw_sample = orig_bpp;
|
|
|
|
ff_thread_release_buffer(avctx, &wc->prev_frame);
|
|
FFSWAP(ThreadFrame, wc->curr_frame, wc->prev_frame);
|
|
|
|
/* get output buffer */
|
|
wc->curr_frame.f->nb_samples = s->samples;
|
|
if ((ret = ff_thread_get_buffer(avctx, &wc->curr_frame, AV_GET_BUFFER_FLAG_REF)) < 0)
|
|
return ret;
|
|
|
|
wc->frame = wc->curr_frame.f;
|
|
ff_thread_finish_setup(avctx);
|
|
}
|
|
|
|
if (wc->ch_offset + s->stereo >= avctx->channels) {
|
|
av_log(avctx, AV_LOG_WARNING, "Too many channels coded in a packet.\n");
|
|
return ((avctx->err_recognition & AV_EF_EXPLODE) || !wc->ch_offset) ? AVERROR_INVALIDDATA : 0;
|
|
}
|
|
|
|
samples_l = wc->frame->extended_data[wc->ch_offset];
|
|
if (s->stereo)
|
|
samples_r = wc->frame->extended_data[wc->ch_offset + 1];
|
|
|
|
wc->ch_offset += 1 + s->stereo;
|
|
|
|
if (s->stereo_in) {
|
|
if (got_dsd) {
|
|
if (dsd_mode == 3) {
|
|
ret = wv_unpack_dsd_high(s, samples_l, samples_r);
|
|
} else if (dsd_mode == 1) {
|
|
ret = wv_unpack_dsd_fast(s, samples_l, samples_r);
|
|
} else {
|
|
ret = wv_unpack_dsd_copy(s, samples_l, samples_r);
|
|
}
|
|
} else {
|
|
ret = wv_unpack_stereo(s, &s->gb, samples_l, samples_r, avctx->sample_fmt);
|
|
}
|
|
if (ret < 0)
|
|
return ret;
|
|
} else {
|
|
if (got_dsd) {
|
|
if (dsd_mode == 3) {
|
|
ret = wv_unpack_dsd_high(s, samples_l, NULL);
|
|
} else if (dsd_mode == 1) {
|
|
ret = wv_unpack_dsd_fast(s, samples_l, NULL);
|
|
} else {
|
|
ret = wv_unpack_dsd_copy(s, samples_l, NULL);
|
|
}
|
|
} else {
|
|
ret = wv_unpack_mono(s, &s->gb, samples_l, avctx->sample_fmt);
|
|
}
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (s->stereo)
|
|
memcpy(samples_r, samples_l, bpp * s->samples);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void wavpack_decode_flush(AVCodecContext *avctx)
|
|
{
|
|
WavpackContext *s = avctx->priv_data;
|
|
|
|
wv_dsd_reset(s, 0);
|
|
}
|
|
|
|
static int dsd_channel(AVCodecContext *avctx, void *frmptr, int jobnr, int threadnr)
|
|
{
|
|
WavpackContext *s = avctx->priv_data;
|
|
AVFrame *frame = frmptr;
|
|
|
|
ff_dsd2pcm_translate (&s->dsdctx [jobnr], s->samples, 0,
|
|
(uint8_t *)frame->extended_data[jobnr], 4,
|
|
(float *)frame->extended_data[jobnr], 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
|
|
int *got_frame_ptr, AVPacket *avpkt)
|
|
{
|
|
WavpackContext *s = avctx->priv_data;
|
|
const uint8_t *buf = avpkt->data;
|
|
int buf_size = avpkt->size;
|
|
int frame_size, ret, frame_flags;
|
|
|
|
if (avpkt->size <= WV_HEADER_SIZE)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
s->frame = NULL;
|
|
s->block = 0;
|
|
s->ch_offset = 0;
|
|
|
|
/* determine number of samples */
|
|
s->samples = AV_RL32(buf + 20);
|
|
frame_flags = AV_RL32(buf + 24);
|
|
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;
|
|
}
|
|
|
|
s->modulation = (frame_flags & WV_DSD_DATA) ? MODULATION_DSD : MODULATION_PCM;
|
|
|
|
while (buf_size > WV_HEADER_SIZE) {
|
|
frame_size = AV_RL32(buf + 4) - 12;
|
|
buf += 20;
|
|
buf_size -= 20;
|
|
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);
|
|
ret = AVERROR_INVALIDDATA;
|
|
goto error;
|
|
}
|
|
if ((ret = wavpack_decode_block(avctx, s->block, buf, frame_size)) < 0)
|
|
goto error;
|
|
s->block++;
|
|
buf += frame_size;
|
|
buf_size -= frame_size;
|
|
}
|
|
|
|
if (s->ch_offset != avctx->channels) {
|
|
av_log(avctx, AV_LOG_ERROR, "Not enough channels coded in a packet.\n");
|
|
ret = AVERROR_INVALIDDATA;
|
|
goto error;
|
|
}
|
|
|
|
ff_thread_await_progress(&s->prev_frame, INT_MAX, 0);
|
|
ff_thread_release_buffer(avctx, &s->prev_frame);
|
|
|
|
if (s->modulation == MODULATION_DSD)
|
|
avctx->execute2(avctx, dsd_channel, s->frame, NULL, avctx->channels);
|
|
|
|
ff_thread_report_progress(&s->curr_frame, INT_MAX, 0);
|
|
|
|
if ((ret = av_frame_ref(data, s->frame)) < 0)
|
|
return ret;
|
|
|
|
*got_frame_ptr = 1;
|
|
|
|
return avpkt->size;
|
|
|
|
error:
|
|
if (s->frame) {
|
|
ff_thread_await_progress(&s->prev_frame, INT_MAX, 0);
|
|
ff_thread_release_buffer(avctx, &s->prev_frame);
|
|
ff_thread_report_progress(&s->curr_frame, INT_MAX, 0);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
AVCodec ff_wavpack_decoder = {
|
|
.name = "wavpack",
|
|
.long_name = NULL_IF_CONFIG_SMALL("WavPack"),
|
|
.type = AVMEDIA_TYPE_AUDIO,
|
|
.id = AV_CODEC_ID_WAVPACK,
|
|
.priv_data_size = sizeof(WavpackContext),
|
|
.init = wavpack_decode_init,
|
|
.close = wavpack_decode_end,
|
|
.decode = wavpack_decode_frame,
|
|
.flush = wavpack_decode_flush,
|
|
.update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
|
|
.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
|
|
AV_CODEC_CAP_SLICE_THREADS,
|
|
.caps_internal = FF_CODEC_CAP_ALLOCATE_PROGRESS,
|
|
};
|