X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fwvdec.c;h=0d5a86953d2e59c7c3831a9b78830bbdc3ac1d11;hb=bc70684e74a185d7b80c8b80bdedda659cb581b8;hp=82526563ec18aec7291e8081ec22650359abe787;hpb=185aa5e896e15ae96145609944bfc6bbb239bc64;p=ffmpeg diff --git a/libavformat/wvdec.c b/libavformat/wvdec.c index 82526563ec1..0d5a86953d2 100644 --- a/libavformat/wvdec.c +++ b/libavformat/wvdec.c @@ -40,6 +40,7 @@ enum WV_FLAGS { WV_HBAL = 0x0400, WV_MCINIT = 0x0800, WV_MCEND = 0x1000, + WV_DSD = 0x80000000, }; static const int wv_rates[16] = { @@ -59,7 +60,7 @@ typedef struct WVContext { int64_t apetag_start; } WVContext; -static int wv_probe(AVProbeData *p) +static int wv_probe(const AVProbeData *p) { /* check file header */ if (p->buf_size <= 32) @@ -80,6 +81,7 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) int ret; int rate, bpp, chan; uint32_t chmask, flags; + unsigned rate_x; wc->pos = avio_tell(pb); @@ -109,7 +111,8 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) 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]; @@ -118,7 +121,7 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) 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, @@ -153,17 +156,34 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) case 3: chmask = avio_rl32(pb); break; - case 5: + case 4: avio_skip(pb, 1); chan |= (avio_r8(pb) & 0xF) << 8; + chan += 1; chmask = avio_rl24(pb); break; + case 5: + avio_skip(pb, 1); + chan |= (avio_r8(pb) & 0xF) << 8; + chan += 1; + chmask = avio_rl32(pb); + break; default: av_log(ctx, AV_LOG_ERROR, "Invalid channel info size %d\n", size); 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; @@ -173,7 +193,7 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) 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; @@ -187,7 +207,7 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) 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, @@ -201,10 +221,10 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) 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; @@ -231,6 +251,9 @@ static int wv_read_header(AVFormatContext *s) 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; @@ -269,30 +292,26 @@ static int wv_read_packet(AVFormatContext *s, AVPacket *pkt) } pos = wc->pos; - if (av_new_packet(pkt, wc->header.blocksize + WV_HEADER_SIZE) < 0) - return AVERROR(ENOMEM); + if ((ret = av_new_packet(pkt, wc->header.blocksize + WV_HEADER_SIZE)) < 0) + return ret; memcpy(pkt->data, wc->block_header, WV_HEADER_SIZE); ret = avio_read(s->pb, pkt->data + WV_HEADER_SIZE, wc->header.blocksize); if (ret != wc->header.blocksize) { - av_packet_unref(pkt); return AVERROR(EIO); } while (!(wc->header.flags & WV_FLAG_FINAL_BLOCK)) { if ((ret = wv_read_block_header(s, s->pb)) < 0) { - av_packet_unref(pkt); return ret; } off = pkt->size; if ((ret = av_grow_packet(pkt, WV_HEADER_SIZE + wc->header.blocksize)) < 0) { - av_packet_unref(pkt); return ret; } memcpy(pkt->data + off, wc->block_header, WV_HEADER_SIZE); ret = avio_read(s->pb, pkt->data + off + WV_HEADER_SIZE, wc->header.blocksize); if (ret != wc->header.blocksize) { - av_packet_unref(pkt); return (ret < 0) ? ret : AVERROR_EOF; } } @@ -310,7 +329,7 @@ static int wv_read_packet(AVFormatContext *s, AVPacket *pkt) 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),