Libav
|
00001 /* 00002 * WavPack demuxer 00003 * Copyright (c) 2006 Konstantin Shishkov 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include "libavutil/intreadwrite.h" 00023 #include "avformat.h" 00024 #include "apetag.h" 00025 #include "id3v1.h" 00026 00027 // specs say that maximum block size is 1Mb 00028 #define WV_BLOCK_LIMIT 1047576 00029 00030 #define WV_EXTRA_SIZE 12 00031 00032 enum WV_FLAGS{ 00033 WV_MONO = 0x0004, 00034 WV_HYBRID = 0x0008, 00035 WV_JOINT = 0x0010, 00036 WV_CROSSD = 0x0020, 00037 WV_HSHAPE = 0x0040, 00038 WV_FLOAT = 0x0080, 00039 WV_INT32 = 0x0100, 00040 WV_HBR = 0x0200, 00041 WV_HBAL = 0x0400, 00042 WV_MCINIT = 0x0800, 00043 WV_MCEND = 0x1000, 00044 }; 00045 00046 static const int wv_rates[16] = { 00047 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 00048 32000, 44100, 48000, 64000, 88200, 96000, 192000, -1 00049 }; 00050 00051 typedef struct{ 00052 uint32_t blksize, flags; 00053 int rate, chan, bpp; 00054 uint32_t samples, soff; 00055 int block_parsed; 00056 uint8_t extra[WV_EXTRA_SIZE]; 00057 int64_t pos; 00058 }WVContext; 00059 00060 static int wv_probe(AVProbeData *p) 00061 { 00062 /* check file header */ 00063 if (p->buf_size <= 32) 00064 return 0; 00065 if (p->buf[0] == 'w' && p->buf[1] == 'v' && 00066 p->buf[2] == 'p' && p->buf[3] == 'k') 00067 return AVPROBE_SCORE_MAX; 00068 else 00069 return 0; 00070 } 00071 00072 static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb) 00073 { 00074 WVContext *wc = ctx->priv_data; 00075 uint32_t tag, ver; 00076 int size; 00077 int rate, bpp, chan; 00078 00079 wc->pos = url_ftell(pb); 00080 tag = get_le32(pb); 00081 if (tag != MKTAG('w', 'v', 'p', 'k')) 00082 return -1; 00083 size = get_le32(pb); 00084 if(size < 24 || size > WV_BLOCK_LIMIT){ 00085 av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size); 00086 return -1; 00087 } 00088 wc->blksize = size; 00089 ver = get_le16(pb); 00090 if(ver < 0x402 || ver > 0x410){ 00091 av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver); 00092 return -1; 00093 } 00094 get_byte(pb); // track no 00095 get_byte(pb); // track sub index 00096 wc->samples = get_le32(pb); // total samples in file 00097 wc->soff = get_le32(pb); // offset in samples of current block 00098 get_buffer(pb, wc->extra, WV_EXTRA_SIZE); 00099 wc->flags = AV_RL32(wc->extra + 4); 00100 //parse flags 00101 bpp = ((wc->flags & 3) + 1) << 3; 00102 chan = 1 + !(wc->flags & WV_MONO); 00103 rate = wv_rates[(wc->flags >> 23) & 0xF]; 00104 if(rate == -1 && !wc->block_parsed){ 00105 int64_t block_end = url_ftell(pb) + wc->blksize - 24; 00106 if(url_is_streamed(pb)){ 00107 av_log(ctx, AV_LOG_ERROR, "Cannot determine custom sampling rate\n"); 00108 return -1; 00109 } 00110 while(url_ftell(pb) < block_end){ 00111 int id, size; 00112 id = get_byte(pb); 00113 size = (id & 0x80) ? get_le24(pb) : get_byte(pb); 00114 size <<= 1; 00115 if(id&0x40) 00116 size--; 00117 if((id&0x3F) == 0x27){ 00118 rate = get_le24(pb); 00119 break; 00120 }else{ 00121 url_fskip(pb, size); 00122 } 00123 } 00124 if(rate == -1){ 00125 av_log(ctx, AV_LOG_ERROR, "Cannot determine custom sampling rate\n"); 00126 return -1; 00127 } 00128 url_fseek(pb, block_end - wc->blksize + 24, SEEK_SET); 00129 } 00130 if(!wc->bpp) wc->bpp = bpp; 00131 if(!wc->chan) wc->chan = chan; 00132 if(!wc->rate) wc->rate = rate; 00133 00134 if(wc->flags && bpp != wc->bpp){ 00135 av_log(ctx, AV_LOG_ERROR, "Bits per sample differ, this block: %i, header block: %i\n", bpp, wc->bpp); 00136 return -1; 00137 } 00138 if(wc->flags && chan != wc->chan){ 00139 av_log(ctx, AV_LOG_ERROR, "Channels differ, this block: %i, header block: %i\n", chan, wc->chan); 00140 return -1; 00141 } 00142 if(wc->flags && rate != -1 && rate != wc->rate){ 00143 av_log(ctx, AV_LOG_ERROR, "Sampling rate differ, this block: %i, header block: %i\n", rate, wc->rate); 00144 return -1; 00145 } 00146 wc->blksize = size - 24; 00147 return 0; 00148 } 00149 00150 static int wv_read_header(AVFormatContext *s, 00151 AVFormatParameters *ap) 00152 { 00153 ByteIOContext *pb = s->pb; 00154 WVContext *wc = s->priv_data; 00155 AVStream *st; 00156 00157 wc->block_parsed = 0; 00158 if(wv_read_block_header(s, pb) < 0) 00159 return -1; 00160 00161 /* now we are ready: build format streams */ 00162 st = av_new_stream(s, 0); 00163 if (!st) 00164 return -1; 00165 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00166 st->codec->codec_id = CODEC_ID_WAVPACK; 00167 st->codec->channels = wc->chan; 00168 st->codec->sample_rate = wc->rate; 00169 st->codec->bits_per_coded_sample = wc->bpp; 00170 av_set_pts_info(st, 64, 1, wc->rate); 00171 st->start_time = 0; 00172 st->duration = wc->samples; 00173 00174 if(!url_is_streamed(s->pb)) { 00175 int64_t cur = url_ftell(s->pb); 00176 ff_ape_parse_tag(s); 00177 if(!av_metadata_get(s->metadata, "", NULL, AV_METADATA_IGNORE_SUFFIX)) 00178 ff_id3v1_read(s); 00179 url_fseek(s->pb, cur, SEEK_SET); 00180 } 00181 00182 return 0; 00183 } 00184 00185 static int wv_read_packet(AVFormatContext *s, 00186 AVPacket *pkt) 00187 { 00188 WVContext *wc = s->priv_data; 00189 int ret; 00190 00191 if (url_feof(s->pb)) 00192 return AVERROR(EIO); 00193 if(wc->block_parsed){ 00194 if(wv_read_block_header(s, s->pb) < 0) 00195 return -1; 00196 } 00197 00198 if(av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE) < 0) 00199 return AVERROR(ENOMEM); 00200 memcpy(pkt->data, wc->extra, WV_EXTRA_SIZE); 00201 ret = get_buffer(s->pb, pkt->data + WV_EXTRA_SIZE, wc->blksize); 00202 if(ret != wc->blksize){ 00203 av_free_packet(pkt); 00204 return AVERROR(EIO); 00205 } 00206 pkt->stream_index = 0; 00207 wc->block_parsed = 1; 00208 pkt->size = ret + WV_EXTRA_SIZE; 00209 pkt->pts = wc->soff; 00210 av_add_index_entry(s->streams[0], wc->pos, pkt->pts, 0, 0, AVINDEX_KEYFRAME); 00211 return 0; 00212 } 00213 00214 static int wv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) 00215 { 00216 AVStream *st = s->streams[stream_index]; 00217 WVContext *wc = s->priv_data; 00218 AVPacket pkt1, *pkt = &pkt1; 00219 int ret; 00220 int index = av_index_search_timestamp(st, timestamp, flags); 00221 int64_t pos, pts; 00222 00223 /* if found, seek there */ 00224 if (index >= 0){ 00225 wc->block_parsed = 1; 00226 url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET); 00227 return 0; 00228 } 00229 /* if timestamp is out of bounds, return error */ 00230 if(timestamp < 0 || timestamp >= s->duration) 00231 return -1; 00232 00233 pos = url_ftell(s->pb); 00234 do{ 00235 ret = av_read_frame(s, pkt); 00236 if (ret < 0){ 00237 url_fseek(s->pb, pos, SEEK_SET); 00238 return -1; 00239 } 00240 pts = pkt->pts; 00241 av_free_packet(pkt); 00242 }while(pts < timestamp); 00243 return 0; 00244 } 00245 00246 AVInputFormat wv_demuxer = { 00247 "wv", 00248 NULL_IF_CONFIG_SMALL("WavPack"), 00249 sizeof(WVContext), 00250 wv_probe, 00251 wv_read_header, 00252 wv_read_packet, 00253 NULL, 00254 wv_read_seek, 00255 };