1/* 2 * WavPack demuxer 3 * Copyright (c) 2006 Konstantin Shishkov 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "libavutil/intreadwrite.h" 23#include "avformat.h" 24#include "apetag.h" 25#include "id3v1.h" 26 27// specs say that maximum block size is 1Mb 28#define WV_BLOCK_LIMIT 1047576 29 30#define WV_EXTRA_SIZE 12 31 32enum WV_FLAGS{ 33 WV_MONO = 0x0004, 34 WV_HYBRID = 0x0008, 35 WV_JOINT = 0x0010, 36 WV_CROSSD = 0x0020, 37 WV_HSHAPE = 0x0040, 38 WV_FLOAT = 0x0080, 39 WV_INT32 = 0x0100, 40 WV_HBR = 0x0200, 41 WV_HBAL = 0x0400, 42 WV_MCINIT = 0x0800, 43 WV_MCEND = 0x1000, 44}; 45 46static const int wv_rates[16] = { 47 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 48 32000, 44100, 48000, 64000, 88200, 96000, 192000, -1 49}; 50 51typedef struct{ 52 uint32_t blksize, flags; 53 int rate, chan, bpp; 54 uint32_t samples, soff; 55 int block_parsed; 56 uint8_t extra[WV_EXTRA_SIZE]; 57 int64_t pos; 58}WVContext; 59 60static int wv_probe(AVProbeData *p) 61{ 62 /* check file header */ 63 if (p->buf_size <= 32) 64 return 0; 65 if (p->buf[0] == 'w' && p->buf[1] == 'v' && 66 p->buf[2] == 'p' && p->buf[3] == 'k') 67 return AVPROBE_SCORE_MAX; 68 else 69 return 0; 70} 71 72static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb) 73{ 74 WVContext *wc = ctx->priv_data; 75 uint32_t tag, ver; 76 int size; 77 int rate, bpp, chan; 78 79 wc->pos = url_ftell(pb); 80 tag = get_le32(pb); 81 if (tag != MKTAG('w', 'v', 'p', 'k')) 82 return -1; 83 size = get_le32(pb); 84 if(size < 24 || size > WV_BLOCK_LIMIT){ 85 av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size); 86 return -1; 87 } 88 wc->blksize = size; 89 ver = get_le16(pb); 90 if(ver < 0x402 || ver > 0x410){ 91 av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver); 92 return -1; 93 } 94 get_byte(pb); // track no 95 get_byte(pb); // track sub index 96 wc->samples = get_le32(pb); // total samples in file 97 wc->soff = get_le32(pb); // offset in samples of current block 98 get_buffer(pb, wc->extra, WV_EXTRA_SIZE); 99 wc->flags = AV_RL32(wc->extra + 4); 100 //parse flags 101 bpp = ((wc->flags & 3) + 1) << 3; 102 chan = 1 + !(wc->flags & WV_MONO); 103 rate = wv_rates[(wc->flags >> 23) & 0xF]; 104 if(rate == -1 && !wc->block_parsed){ 105 int64_t block_end = url_ftell(pb) + wc->blksize - 24; 106 if(url_is_streamed(pb)){ 107 av_log(ctx, AV_LOG_ERROR, "Cannot determine custom sampling rate\n"); 108 return -1; 109 } 110 while(url_ftell(pb) < block_end){ 111 int id, size; 112 id = get_byte(pb); 113 size = (id & 0x80) ? get_le24(pb) : get_byte(pb); 114 size <<= 1; 115 if(id&0x40) 116 size--; 117 if((id&0x3F) == 0x27){ 118 rate = get_le24(pb); 119 break; 120 }else{ 121 url_fskip(pb, size); 122 } 123 } 124 if(rate == -1){ 125 av_log(ctx, AV_LOG_ERROR, "Cannot determine custom sampling rate\n"); 126 return -1; 127 } 128 url_fseek(pb, block_end - wc->blksize + 24, SEEK_SET); 129 } 130 if(!wc->bpp) wc->bpp = bpp; 131 if(!wc->chan) wc->chan = chan; 132 if(!wc->rate) wc->rate = rate; 133 134 if(wc->flags && bpp != wc->bpp){ 135 av_log(ctx, AV_LOG_ERROR, "Bits per sample differ, this block: %i, header block: %i\n", bpp, wc->bpp); 136 return -1; 137 } 138 if(wc->flags && chan != wc->chan){ 139 av_log(ctx, AV_LOG_ERROR, "Channels differ, this block: %i, header block: %i\n", chan, wc->chan); 140 return -1; 141 } 142 if(wc->flags && rate != -1 && rate != wc->rate){ 143 av_log(ctx, AV_LOG_ERROR, "Sampling rate differ, this block: %i, header block: %i\n", rate, wc->rate); 144 return -1; 145 } 146 wc->blksize = size - 24; 147 return 0; 148} 149 150static int wv_read_header(AVFormatContext *s, 151 AVFormatParameters *ap) 152{ 153 ByteIOContext *pb = s->pb; 154 WVContext *wc = s->priv_data; 155 AVStream *st; 156 157 wc->block_parsed = 0; 158 if(wv_read_block_header(s, pb) < 0) 159 return -1; 160 161 /* now we are ready: build format streams */ 162 st = av_new_stream(s, 0); 163 if (!st) 164 return -1; 165 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 166 st->codec->codec_id = CODEC_ID_WAVPACK; 167 st->codec->channels = wc->chan; 168 st->codec->sample_rate = wc->rate; 169 st->codec->bits_per_coded_sample = wc->bpp; 170 av_set_pts_info(st, 64, 1, wc->rate); 171 st->start_time = 0; 172 st->duration = wc->samples; 173 174 if(!url_is_streamed(s->pb)) { 175 int64_t cur = url_ftell(s->pb); 176 ff_ape_parse_tag(s); 177 if(!av_metadata_get(s->metadata, "", NULL, AV_METADATA_IGNORE_SUFFIX)) 178 ff_id3v1_read(s); 179 url_fseek(s->pb, cur, SEEK_SET); 180 } 181 182 return 0; 183} 184 185static int wv_read_packet(AVFormatContext *s, 186 AVPacket *pkt) 187{ 188 WVContext *wc = s->priv_data; 189 int ret; 190 191 if (url_feof(s->pb)) 192 return AVERROR(EIO); 193 if(wc->block_parsed){ 194 if(wv_read_block_header(s, s->pb) < 0) 195 return -1; 196 } 197 198 if(av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE) < 0) 199 return AVERROR(ENOMEM); 200 memcpy(pkt->data, wc->extra, WV_EXTRA_SIZE); 201 ret = get_buffer(s->pb, pkt->data + WV_EXTRA_SIZE, wc->blksize); 202 if(ret != wc->blksize){ 203 av_free_packet(pkt); 204 return AVERROR(EIO); 205 } 206 pkt->stream_index = 0; 207 wc->block_parsed = 1; 208 pkt->size = ret + WV_EXTRA_SIZE; 209 pkt->pts = wc->soff; 210 av_add_index_entry(s->streams[0], wc->pos, pkt->pts, 0, 0, AVINDEX_KEYFRAME); 211 return 0; 212} 213 214static int wv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) 215{ 216 AVStream *st = s->streams[stream_index]; 217 WVContext *wc = s->priv_data; 218 AVPacket pkt1, *pkt = &pkt1; 219 int ret; 220 int index = av_index_search_timestamp(st, timestamp, flags); 221 int64_t pos, pts; 222 223 /* if found, seek there */ 224 if (index >= 0){ 225 wc->block_parsed = 1; 226 url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET); 227 return 0; 228 } 229 /* if timestamp is out of bounds, return error */ 230 if(timestamp < 0 || timestamp >= s->duration) 231 return -1; 232 233 pos = url_ftell(s->pb); 234 do{ 235 ret = av_read_frame(s, pkt); 236 if (ret < 0){ 237 url_fseek(s->pb, pos, SEEK_SET); 238 return -1; 239 } 240 pts = pkt->pts; 241 av_free_packet(pkt); 242 }while(pts < timestamp); 243 return 0; 244} 245 246AVInputFormat wv_demuxer = { 247 "wv", 248 NULL_IF_CONFIG_SMALL("WavPack"), 249 sizeof(WVContext), 250 wv_probe, 251 wv_read_header, 252 wv_read_packet, 253 NULL, 254 wv_read_seek, 255}; 256