int ret;
int rate, bpp, chan;
uint32_t chmask, flags;
+ unsigned rate_x;
wc->pos = avio_tell(pb);
return ret;
}
- if (wc->header.flags & WV_DSD) {
- avpriv_report_missing_feature(ctx, "WV DSD");
- return AVERROR_PATCHWELCOME;
- }
-
if (wc->header.version < 0x402 || wc->header.version > 0x410) {
avpriv_report_missing_feature(ctx, "WV version 0x%03X",
wc->header.version);
return 0;
// parse flags
flags = wc->header.flags;
- bpp = ((flags & 3) + 1) << 3;
+ rate_x = (flags & WV_DSD) ? 4 : 1;
+ bpp = (flags & WV_DSD) ? 0 : ((flags & 3) + 1) << 3;
chan = 1 + !(flags & WV_MONO);
chmask = flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
rate = wv_rates[(flags >> 23) & 0xF];
chan = wc->chan;
chmask = wc->chmask;
}
- if ((rate == -1 || !chan) && !wc->block_parsed) {
+ if ((rate == -1 || !chan || flags & WV_DSD) && !wc->block_parsed) {
int64_t block_end = avio_tell(pb) + wc->header.blocksize;
if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
av_log(ctx, AV_LOG_ERROR,
return AVERROR_INVALIDDATA;
}
break;
+ case 0xE:
+ if (size <= 1) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid DSD block\n");
+ return AVERROR_INVALIDDATA;
+ }
+ rate_x = 1U << (avio_r8(pb) & 0x1f);
+ if (size)
+ avio_skip(pb, size-1);
+ break;
case 0x27:
rate = avio_rl24(pb);
break;
if (id & 0x40)
avio_skip(pb, 1);
}
- if (rate == -1) {
+ if (rate == -1 || rate * (uint64_t)rate_x >= INT_MAX) {
av_log(ctx, AV_LOG_ERROR,
"Cannot determine custom sampling rate\n");
return AVERROR_INVALIDDATA;
if (!wc->chmask)
wc->chmask = chmask;
if (!wc->rate)
- wc->rate = rate;
+ wc->rate = rate * rate_x;
if (flags && bpp != wc->bpp) {
av_log(ctx, AV_LOG_ERROR,
chan, wc->chan);
return AVERROR_INVALIDDATA;
}
- if (flags && rate != -1 && rate != wc->rate) {
+ if (flags && rate != -1 && !(flags & WV_DSD) && rate * rate_x != wc->rate) {
av_log(ctx, AV_LOG_ERROR,
"Sampling rate differ, this block: %i, header block: %i\n",
- rate, wc->rate);
+ rate * rate_x, wc->rate);
return AVERROR_INVALIDDATA;
}
return 0;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
+ if ((ret = ff_alloc_extradata(st->codecpar, 2)) < 0)
+ return ret;
+ AV_WL16(st->codecpar->extradata, wc->header.version);
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
st->codecpar->codec_id = AV_CODEC_ID_WAVPACK;
st->codecpar->channels = wc->chan;
return 0;
}
-AVInputFormat ff_wv_demuxer = {
+const AVInputFormat ff_wv_demuxer = {
.name = "wv",
.long_name = NULL_IF_CONFIG_SMALL("WavPack"),
.priv_data_size = sizeof(WVContext),