|
|
|
@@ -1,6 +1,7 @@ |
|
|
|
/* |
|
|
|
* WavPack lossless audio decoder |
|
|
|
* Copyright (c) 2006,2011 Konstantin Shishkov |
|
|
|
* Copyright (c) 2020 David Bryant |
|
|
|
* |
|
|
|
* This file is part of FFmpeg. |
|
|
|
* |
|
|
|
@@ -29,18 +30,37 @@ |
|
|
|
#include "thread.h" |
|
|
|
#include "unary.h" |
|
|
|
#include "wavpack.h" |
|
|
|
#include "dsd.h" |
|
|
|
|
|
|
|
/** |
|
|
|
* @file |
|
|
|
* WavPack lossless audio decoder |
|
|
|
*/ |
|
|
|
|
|
|
|
typedef struct SavedContext { |
|
|
|
int offset; |
|
|
|
int size; |
|
|
|
int bits_used; |
|
|
|
uint32_t crc; |
|
|
|
} SavedContext; |
|
|
|
#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; |
|
|
|
@@ -52,7 +72,6 @@ typedef struct WavpackFrameContext { |
|
|
|
int got_extra_bits; |
|
|
|
uint32_t crc_extra_bits; |
|
|
|
GetBitContext gb_extra_bits; |
|
|
|
int data_size; // in bits |
|
|
|
int samples; |
|
|
|
int terms; |
|
|
|
Decorr decorr[MAX_TERMS]; |
|
|
|
@@ -66,8 +85,13 @@ typedef struct WavpackFrameContext { |
|
|
|
int float_shift; |
|
|
|
int float_max_exp; |
|
|
|
WvChannel ch[2]; |
|
|
|
int pos; |
|
|
|
SavedContext sc, extra_sc; |
|
|
|
|
|
|
|
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 |
|
|
|
@@ -81,6 +105,11 @@ typedef struct WavpackContext { |
|
|
|
int block; |
|
|
|
int samples; |
|
|
|
int ch_offset; |
|
|
|
|
|
|
|
AVFrame *frame; |
|
|
|
ThreadFrame curr_frame, prev_frame; |
|
|
|
Modulation modulation; |
|
|
|
DSDContext *dsdctx; |
|
|
|
} WavpackContext; |
|
|
|
|
|
|
|
#define LEVEL_DECAY(a) (((a) + 0x80) >> 8) |
|
|
|
@@ -365,12 +394,6 @@ static float wv_get_value_float(WavpackFrameContext *s, uint32_t *crc, int S) |
|
|
|
return value.f; |
|
|
|
} |
|
|
|
|
|
|
|
static void wv_reset_saved_context(WavpackFrameContext *s) |
|
|
|
{ |
|
|
|
s->pos = 0; |
|
|
|
s->sc.crc = s->extra_sc.crc = 0xFFFFFFFF; |
|
|
|
} |
|
|
|
|
|
|
|
static inline int wv_check_crc(WavpackFrameContext *s, uint32_t crc, |
|
|
|
uint32_t crc_extra_bits) |
|
|
|
{ |
|
|
|
@@ -386,15 +409,372 @@ static inline int wv_check_crc(WavpackFrameContext *s, uint32_t crc, |
|
|
|
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 = s->pos; |
|
|
|
uint32_t crc = s->sc.crc; |
|
|
|
uint32_t crc_extra_bits = s->extra_sc.crc; |
|
|
|
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; |
|
|
|
@@ -504,8 +884,6 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, |
|
|
|
count++; |
|
|
|
} while (!last && count < s->samples); |
|
|
|
|
|
|
|
wv_reset_saved_context(s); |
|
|
|
|
|
|
|
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); |
|
|
|
@@ -525,9 +903,9 @@ static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb, |
|
|
|
int i, j, count = 0; |
|
|
|
int last, t; |
|
|
|
int A, S, T; |
|
|
|
int pos = s->pos; |
|
|
|
uint32_t crc = s->sc.crc; |
|
|
|
uint32_t crc_extra_bits = s->extra_sc.crc; |
|
|
|
int pos = 0; |
|
|
|
uint32_t crc = 0xFFFFFFFF; |
|
|
|
uint32_t crc_extra_bits = 0xFFFFFFFF; |
|
|
|
int16_t *dst16 = dst; |
|
|
|
int32_t *dst32 = dst; |
|
|
|
float *dstfl = dst; |
|
|
|
@@ -572,8 +950,6 @@ static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb, |
|
|
|
count++; |
|
|
|
} while (!last && count < s->samples); |
|
|
|
|
|
|
|
wv_reset_saved_context(s); |
|
|
|
|
|
|
|
if (last && count < s->samples) { |
|
|
|
int size = av_get_bytes_per_sample(type); |
|
|
|
memset((uint8_t*)dst + count*size, 0, (s->samples-count)*size); |
|
|
|
@@ -598,7 +974,6 @@ static av_cold int wv_alloc_frame_context(WavpackContext *c) |
|
|
|
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; |
|
|
|
} |
|
|
|
@@ -608,6 +983,28 @@ static int init_thread_copy(AVCodecContext *avctx) |
|
|
|
{ |
|
|
|
WavpackContext *s = avctx->priv_data; |
|
|
|
s->avctx = avctx; |
|
|
|
|
|
|
|
s->curr_frame.f = av_frame_alloc(); |
|
|
|
s->prev_frame.f = av_frame_alloc(); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@@ -620,35 +1017,60 @@ static av_cold int wavpack_decode_init(AVCodecContext *avctx) |
|
|
|
|
|
|
|
s->fdec_num = 0; |
|
|
|
|
|
|
|
avctx->internal->allocate_progress = 1; |
|
|
|
|
|
|
|
s->curr_frame.f = av_frame_alloc(); |
|
|
|
s->prev_frame.f = av_frame_alloc(); |
|
|
|
|
|
|
|
// the DSD to PCM context is shared (and used serially) between all decoding threads |
|
|
|
s->dsdctx = av_calloc(avctx->channels, sizeof (DSDContext)); |
|
|
|
|
|
|
|
if (!s->curr_frame.f || !s->prev_frame.f || !s->dsdctx) |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
for (int i = 0; i < avctx->channels; i++) |
|
|
|
memset(s->dsdctx[i].buf, 0x69, sizeof(s->dsdctx[i].buf)); |
|
|
|
|
|
|
|
ff_init_dsd_data(); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static av_cold int wavpack_decode_end(AVCodecContext *avctx) |
|
|
|
{ |
|
|
|
WavpackContext *s = avctx->priv_data; |
|
|
|
int i; |
|
|
|
|
|
|
|
for (i = 0; i < s->fdec_num; i++) |
|
|
|
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); |
|
|
|
|
|
|
|
if (!avctx->internal->is_copy) |
|
|
|
av_freep(&s->dsdctx); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int wavpack_decode_block(AVCodecContext *avctx, int block_no, |
|
|
|
AVFrame *frame, const uint8_t *buf, int buf_size) |
|
|
|
const uint8_t *buf, int buf_size) |
|
|
|
{ |
|
|
|
WavpackContext *wc = avctx->priv_data; |
|
|
|
ThreadFrame tframe = { .f = frame }; |
|
|
|
WavpackFrameContext *s; |
|
|
|
GetByteContext gb; |
|
|
|
void *samples_l = NULL, *samples_r = NULL; |
|
|
|
int ret; |
|
|
|
int got_terms = 0, got_weights = 0, got_samples = 0, |
|
|
|
got_entropy = 0, got_bs = 0, got_float = 0, got_hybrid = 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, chmask = 0, orig_bpp, sample_rate = 0; |
|
|
|
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"); |
|
|
|
@@ -698,10 +1120,8 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, |
|
|
|
while (bytestream2_get_bytes_left(&gb)) { |
|
|
|
id = bytestream2_get_byte(&gb); |
|
|
|
size = bytestream2_get_byte(&gb); |
|
|
|
if (id & WP_IDF_LONG) { |
|
|
|
size |= (bytestream2_get_byte(&gb)) << 8; |
|
|
|
size |= (bytestream2_get_byte(&gb)) << 16; |
|
|
|
} |
|
|
|
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) |
|
|
|
@@ -897,13 +1317,28 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, |
|
|
|
bytestream2_skip(&gb, 1); |
|
|
|
break; |
|
|
|
case WP_ID_DATA: |
|
|
|
s->sc.offset = bytestream2_tell(&gb); |
|
|
|
s->sc.size = size * 8; |
|
|
|
if ((ret = init_get_bits8(&s->gb, gb.buffer, size)) < 0) |
|
|
|
return ret; |
|
|
|
s->data_size = size * 8; |
|
|
|
bytestream2_skip(&gb, size); |
|
|
|
got_bs = 1; |
|
|
|
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) { |
|
|
|
@@ -912,8 +1347,6 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, |
|
|
|
bytestream2_skip(&gb, size); |
|
|
|
continue; |
|
|
|
} |
|
|
|
s->extra_sc.offset = bytestream2_tell(&gb); |
|
|
|
s->extra_sc.size = size * 8; |
|
|
|
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); |
|
|
|
@@ -979,41 +1412,50 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, |
|
|
|
bytestream2_skip(&gb, 1); |
|
|
|
} |
|
|
|
|
|
|
|
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_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 && avctx->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 && avctx->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_bs) { |
|
|
|
|
|
|
|
if (!got_pcm && !got_dsd) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Packed samples not found\n"); |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
if (!got_float && avctx->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 && avctx->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 && 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) { |
|
|
|
@@ -1023,9 +1465,9 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Custom sample rate missing.\n"); |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
avctx->sample_rate = sample_rate; |
|
|
|
avctx->sample_rate = sample_rate * rate_x; |
|
|
|
} else |
|
|
|
avctx->sample_rate = wv_rates[sr]; |
|
|
|
avctx->sample_rate = wv_rates[sr] * rate_x; |
|
|
|
|
|
|
|
if (multiblock) { |
|
|
|
if (chan) |
|
|
|
@@ -1038,11 +1480,16 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, |
|
|
|
AV_CH_LAYOUT_MONO; |
|
|
|
} |
|
|
|
|
|
|
|
ff_thread_release_buffer(avctx, &wc->prev_frame); |
|
|
|
FFSWAP(ThreadFrame, wc->curr_frame, wc->prev_frame); |
|
|
|
|
|
|
|
/* get output buffer */ |
|
|
|
frame->nb_samples = s->samples + 1; |
|
|
|
if ((ret = ff_thread_get_buffer(avctx, &tframe, 0)) < 0) |
|
|
|
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; |
|
|
|
frame->nb_samples = s->samples; |
|
|
|
|
|
|
|
wc->frame = wc->curr_frame.f; |
|
|
|
ff_thread_finish_setup(avctx); |
|
|
|
} |
|
|
|
|
|
|
|
if (wc->ch_offset + s->stereo >= avctx->channels) { |
|
|
|
@@ -1050,18 +1497,36 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, |
|
|
|
return ((avctx->err_recognition & AV_EF_EXPLODE) || !wc->ch_offset) ? AVERROR_INVALIDDATA : 0; |
|
|
|
} |
|
|
|
|
|
|
|
samples_l = frame->extended_data[wc->ch_offset]; |
|
|
|
samples_l = wc->frame->extended_data[wc->ch_offset]; |
|
|
|
if (s->stereo) |
|
|
|
samples_r = frame->extended_data[wc->ch_offset + 1]; |
|
|
|
samples_r = wc->frame->extended_data[wc->ch_offset + 1]; |
|
|
|
|
|
|
|
wc->ch_offset += 1 + s->stereo; |
|
|
|
|
|
|
|
if (s->stereo_in) { |
|
|
|
ret = wv_unpack_stereo(s, &s->gb, samples_l, samples_r, avctx->sample_fmt); |
|
|
|
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 { |
|
|
|
ret = wv_unpack_mono(s, &s->gb, samples_l, avctx->sample_fmt); |
|
|
|
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; |
|
|
|
|
|
|
|
@@ -1075,10 +1540,23 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, |
|
|
|
static void wavpack_decode_flush(AVCodecContext *avctx) |
|
|
|
{ |
|
|
|
WavpackContext *s = avctx->priv_data; |
|
|
|
int i; |
|
|
|
|
|
|
|
for (i = 0; i < s->fdec_num; i++) |
|
|
|
wv_reset_saved_context(s->fdec[i]); |
|
|
|
if (!avctx->internal->is_copy) { |
|
|
|
for (int i = 0; i < avctx->channels; i++) |
|
|
|
memset(s->dsdctx[i].buf, 0x69, sizeof(s->dsdctx[i].buf)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
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, |
|
|
|
@@ -1087,12 +1565,12 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data, |
|
|
|
WavpackContext *s = avctx->priv_data; |
|
|
|
const uint8_t *buf = avpkt->data; |
|
|
|
int buf_size = avpkt->size; |
|
|
|
AVFrame *frame = data; |
|
|
|
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; |
|
|
|
|
|
|
|
@@ -1105,7 +1583,9 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data, |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
|
|
|
|
if (frame_flags & 0x80) { |
|
|
|
s->modulation = (frame_flags & WV_DSD_DATA) ? MODULATION_DSD : MODULATION_PCM; |
|
|
|
|
|
|
|
if (frame_flags & (WV_FLOAT_DATA | WV_DSD_DATA)) { |
|
|
|
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; |
|
|
|
} else if ((frame_flags & 0x03) <= 1) { |
|
|
|
avctx->sample_fmt = AV_SAMPLE_FMT_S16P; |
|
|
|
@@ -1122,14 +1602,11 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data, |
|
|
|
av_log(avctx, AV_LOG_ERROR, |
|
|
|
"Block %d has invalid size (size %d vs. %d bytes left)\n", |
|
|
|
s->block, frame_size, buf_size); |
|
|
|
wavpack_decode_flush(avctx); |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
if ((ret = wavpack_decode_block(avctx, s->block, |
|
|
|
frame, buf, frame_size)) < 0) { |
|
|
|
wavpack_decode_flush(avctx); |
|
|
|
return ret; |
|
|
|
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; |
|
|
|
@@ -1137,12 +1614,33 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data, |
|
|
|
|
|
|
|
if (s->ch_offset != avctx->channels) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Not enough channels coded in a packet.\n"); |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
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 = { |
|
|
|
@@ -1156,5 +1654,7 @@ AVCodec ff_wavpack_decoder = { |
|
|
|
.decode = wavpack_decode_frame, |
|
|
|
.flush = wavpack_decode_flush, |
|
|
|
.init_thread_copy = ONLY_IF_THREADS_ENABLED(init_thread_copy), |
|
|
|
.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, |
|
|
|
.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 |
|
|
|
}; |