diff options
author | Anton Khirnov <anton@khirnov.net> | 2013-05-28 10:55:52 +0400 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2013-05-28 19:47:30 +0400 |
commit | 0a1a94450a28eef854162f859e79ecfb9f97915b (patch) | |
tree | be83d867637378d0da802b60749af1dde1d290dc /libavformat/wv.c | |
parent | 89806691b1c39181c63d95e0fddc30f11e2a7b04 (diff) |
lavf: rename wv.c to wvdec.c
wv.c will be used for shared wavpack functions.
Diffstat (limited to 'libavformat/wv.c')
-rw-r--r-- | libavformat/wv.c | 366 |
1 files changed, 0 insertions, 366 deletions
diff --git a/libavformat/wv.c b/libavformat/wv.c deleted file mode 100644 index 3e090001c4..0000000000 --- a/libavformat/wv.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * WavPack demuxer - * Copyright (c) 2006,2011 Konstantin Shishkov - * - * This file is part of Libav. - * - * Libav 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. - * - * Libav 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 Libav; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "libavutil/channel_layout.h" -#include "libavutil/intreadwrite.h" -#include "libavutil/dict.h" -#include "avformat.h" -#include "internal.h" -#include "apetag.h" -#include "id3v1.h" - -// specs say that maximum block size is 1Mb -#define WV_BLOCK_LIMIT 1047576 - -#define WV_HEADER_SIZE 32 - -#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, - WV_JOINT = 0x0010, - WV_CROSSD = 0x0020, - WV_HSHAPE = 0x0040, - WV_FLOAT = 0x0080, - WV_INT32 = 0x0100, - WV_HBR = 0x0200, - WV_HBAL = 0x0400, - WV_MCINIT = 0x0800, - WV_MCEND = 0x1000, -}; - -static const int wv_rates[16] = { - 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, - 32000, 44100, 48000, 64000, 88200, 96000, 192000, -1 -}; - -typedef struct { - uint8_t block_header[WV_HEADER_SIZE]; - uint32_t blksize, flags; - int rate, chan, bpp; - uint32_t chmask; - uint32_t samples, soff; - int multichannel; - int block_parsed; - int64_t pos; - - int64_t apetag_start; -} WVContext; - -static int wv_probe(AVProbeData *p) -{ - /* check file header */ - if (p->buf_size <= 32) - return 0; - if (p->buf[0] == 'w' && p->buf[1] == 'v' && - p->buf[2] == 'p' && p->buf[3] == 'k') - return AVPROBE_SCORE_MAX; - else - return 0; -} - -static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) -{ - WVContext *wc = ctx->priv_data; - uint32_t ver; - int size, ret; - int rate, bpp, chan; - uint32_t chmask; - - wc->pos = avio_tell(pb); - - /* don't return bogus packets with the ape tag data */ - if (wc->apetag_start && wc->pos >= wc->apetag_start) - return AVERROR_EOF; - - ret = avio_read(pb, wc->block_header, WV_HEADER_SIZE); - if (ret != WV_HEADER_SIZE) - return (ret < 0) ? ret : AVERROR_EOF; - - if (AV_RL32(wc->block_header) != MKTAG('w', 'v', 'p', 'k')) - return AVERROR_INVALIDDATA; - - size = AV_RL32(wc->block_header + 4); - if (size < 24 || size > WV_BLOCK_LIMIT) { - av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size); - return AVERROR_INVALIDDATA; - } - wc->blksize = size; - ver = AV_RL32(wc->block_header + 8); - if (ver < 0x402 || ver > 0x410) { - av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver); - return AVERROR_PATCHWELCOME; - } - wc->samples = AV_RL32(wc->block_header + 12); // total samples in file - wc->soff = AV_RL32(wc->block_header + 16); // offset in samples of current block - wc->flags = AV_RL32(wc->block_header + 24); - /* Blocks with zero samples don't contain actual audio information - * and should be ignored */ - if (!AV_RN32(wc->block_header + 20)) - return 0; - // parse flags - bpp = ((wc->flags & 3) + 1) << 3; - chan = 1 + !(wc->flags & WV_MONO); - chmask = wc->flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; - rate = wv_rates[(wc->flags >> 23) & 0xF]; - wc->multichannel = !!((wc->flags & WV_SINGLE_BLOCK) != WV_SINGLE_BLOCK); - if (wc->multichannel) { - chan = wc->chan; - chmask = wc->chmask; - } - if ((rate == -1 || !chan) && !wc->block_parsed) { - int64_t block_end = avio_tell(pb) + wc->blksize - 24; - if (!pb->seekable) { - av_log(ctx, AV_LOG_ERROR, - "Cannot determine additional parameters\n"); - return AVERROR_INVALIDDATA; - } - while (avio_tell(pb) < block_end) { - int id, size; - id = avio_r8(pb); - size = (id & 0x80) ? avio_rl24(pb) : avio_r8(pb); - size <<= 1; - if (id & 0x40) - size--; - switch (id & 0x3F) { - case 0xD: - if (size <= 1) { - av_log(ctx, AV_LOG_ERROR, - "Insufficient channel information\n"); - return AVERROR_INVALIDDATA; - } - chan = avio_r8(pb); - switch (size - 2) { - case 0: - chmask = avio_r8(pb); - break; - case 1: - chmask = avio_rl16(pb); - break; - case 2: - chmask = avio_rl24(pb); - break; - case 3: - chmask = avio_rl32(pb); - break; - case 5: - avio_skip(pb, 1); - chan |= (avio_r8(pb) & 0xF) << 8; - chmask = avio_rl24(pb); - break; - default: - av_log(ctx, AV_LOG_ERROR, - "Invalid channel info size %d\n", size); - return AVERROR_INVALIDDATA; - } - break; - case 0x27: - rate = avio_rl24(pb); - break; - default: - avio_skip(pb, size); - } - if (id & 0x40) - avio_skip(pb, 1); - } - if (rate == -1) { - av_log(ctx, AV_LOG_ERROR, - "Cannot determine custom sampling rate\n"); - return AVERROR_INVALIDDATA; - } - avio_seek(pb, block_end - wc->blksize + 24, SEEK_SET); - } - 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 AVERROR_INVALIDDATA; - } - 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 AVERROR_INVALIDDATA; - } - if (wc->flags && rate != -1 && rate != wc->rate) { - av_log(ctx, AV_LOG_ERROR, - "Sampling rate differ, this block: %i, header block: %i\n", - rate, wc->rate); - return AVERROR_INVALIDDATA; - } - wc->blksize = size - 24; - return 0; -} - -static int wv_read_header(AVFormatContext *s) -{ - AVIOContext *pb = s->pb; - WVContext *wc = s->priv_data; - AVStream *st; - int ret; - - wc->block_parsed = 0; - for (;;) { - if ((ret = wv_read_block_header(s, pb)) < 0) - return ret; - if (!AV_RL32(wc->block_header + 20)) - avio_skip(pb, wc->blksize - 24); - else - break; - } - - /* now we are ready: build format streams */ - st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = AV_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; - avpriv_set_pts_info(st, 64, 1, wc->rate); - st->start_time = 0; - st->duration = wc->samples; - - if (s->pb->seekable) { - int64_t cur = avio_tell(s->pb); - wc->apetag_start = ff_ape_parse_tag(s); - if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) - ff_id3v1_read(s); - avio_seek(s->pb, cur, SEEK_SET); - } - - return 0; -} - -static int wv_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - WVContext *wc = s->priv_data; - int ret; - int off; - int64_t pos; - uint32_t block_samples; - - if (s->pb->eof_reached) - return AVERROR_EOF; - if (wc->block_parsed) { - if ((ret = wv_read_block_header(s, s->pb)) < 0) - return ret; - } - - pos = wc->pos; - if (av_new_packet(pkt, wc->blksize + WV_HEADER_SIZE) < 0) - return AVERROR(ENOMEM); - memcpy(pkt->data, wc->block_header, WV_HEADER_SIZE); - ret = avio_read(s->pb, pkt->data + WV_HEADER_SIZE, wc->blksize); - if (ret != wc->blksize) { - av_free_packet(pkt); - return AVERROR(EIO); - } - while (!(wc->flags & WV_END_BLOCK)) { - if ((ret = wv_read_block_header(s, s->pb)) < 0) { - av_free_packet(pkt); - return ret; - } - - off = pkt->size; - if ((ret = av_grow_packet(pkt, WV_HEADER_SIZE + wc->blksize)) < 0) { - av_free_packet(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->blksize); - if (ret != wc->blksize) { - av_free_packet(pkt); - return (ret < 0) ? ret : AVERROR_EOF; - } - } - pkt->stream_index = 0; - wc->block_parsed = 1; - pkt->pts = wc->soff; - block_samples = AV_RL32(wc->block_header + 20); - if (block_samples > INT32_MAX) - av_log(s, AV_LOG_WARNING, - "Too many samples in block: %"PRIu32"\n", block_samples); - else - pkt->duration = block_samples; - - av_add_index_entry(s->streams[0], pos, pkt->pts, 0, 0, AVINDEX_KEYFRAME); - return 0; -} - -static int wv_read_seek(AVFormatContext *s, int stream_index, - int64_t timestamp, int flags) -{ - AVStream *st = s->streams[stream_index]; - WVContext *wc = s->priv_data; - AVPacket pkt1, *pkt = &pkt1; - int ret; - int index = av_index_search_timestamp(st, timestamp, flags); - int64_t pos, pts; - - /* if found, seek there */ - if (index >= 0 && - timestamp <= st->index_entries[st->nb_index_entries - 1].timestamp) { - wc->block_parsed = 1; - avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET); - return 0; - } - /* if timestamp is out of bounds, return error */ - if (timestamp < 0 || timestamp >= s->duration) - return AVERROR(EINVAL); - - pos = avio_tell(s->pb); - do { - ret = av_read_frame(s, pkt); - if (ret < 0) { - avio_seek(s->pb, pos, SEEK_SET); - return ret; - } - pts = pkt->pts; - av_free_packet(pkt); - } while(pts < timestamp); - return 0; -} - -AVInputFormat ff_wv_demuxer = { - .name = "wv", - .long_name = NULL_IF_CONFIG_SMALL("WavPack"), - .priv_data_size = sizeof(WVContext), - .read_probe = wv_probe, - .read_header = wv_read_header, - .read_packet = wv_read_packet, - .read_seek = wv_read_seek, -}; |