• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/mpc8.c

Go to the documentation of this file.
00001 /*
00002  * Musepack SV8 demuxer
00003  * Copyright (c) 2007 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 "libavcodec/get_bits.h"
00023 #include "libavcodec/unary.h"
00024 #include "avformat.h"
00025 
00027 #define MKMPCTAG(a, b) (a | (b << 8))
00028 
00029 #define TAG_MPCK MKTAG('M','P','C','K')
00030 
00032 enum MPCPacketTags{
00033     TAG_STREAMHDR   = MKMPCTAG('S','H'),
00034     TAG_STREAMEND   = MKMPCTAG('S','E'),
00035 
00036     TAG_AUDIOPACKET = MKMPCTAG('A','P'),
00037 
00038     TAG_SEEKTBLOFF  = MKMPCTAG('S','O'),
00039     TAG_SEEKTABLE   = MKMPCTAG('S','T'),
00040 
00041     TAG_REPLAYGAIN  = MKMPCTAG('R','G'),
00042     TAG_ENCINFO     = MKMPCTAG('E','I'),
00043 };
00044 
00045 static const int mpc8_rate[8] = { 44100, 48000, 37800, 32000, -1, -1, -1, -1 };
00046 
00047 typedef struct {
00048     int ver;
00049     int frame;
00050     int64_t header_pos;
00051     int64_t samples;
00052 } MPCContext;
00053 
00054 static inline int64_t bs_get_v(uint8_t **bs)
00055 {
00056     int64_t v = 0;
00057     int br = 0;
00058     int c;
00059 
00060     do {
00061         c = **bs; (*bs)++;
00062         v <<= 7;
00063         v |= c & 0x7F;
00064         br++;
00065         if (br > 10)
00066             return -1;
00067     } while (c & 0x80);
00068 
00069     return v - br;
00070 }
00071 
00072 static int mpc8_probe(AVProbeData *p)
00073 {
00074     uint8_t *bs = p->buf + 4;
00075     uint8_t *bs_end = bs + p->buf_size;
00076     int64_t size;
00077 
00078     if (p->buf_size < 16)
00079         return 0;
00080     if (AV_RL32(p->buf) != TAG_MPCK)
00081         return 0;
00082     while (bs < bs_end + 3) {
00083         int header_found = (bs[0] == 'S' && bs[1] == 'H');
00084         if (bs[0] < 'A' || bs[0] > 'Z' || bs[1] < 'A' || bs[1] > 'Z')
00085             return 0;
00086         bs += 2;
00087         size = bs_get_v(&bs);
00088         if (size < 2)
00089             return 0;
00090         if (bs + size - 2 >= bs_end)
00091             return AVPROBE_SCORE_MAX / 4 - 1; //seems to be valid MPC but no header yet
00092         if (header_found) {
00093             if (size < 11 || size > 28)
00094                 return 0;
00095             if (!AV_RL32(bs)) //zero CRC is invalid
00096                 return 0;
00097             return AVPROBE_SCORE_MAX;
00098         } else {
00099             bs += size - 2;
00100         }
00101     }
00102     return 0;
00103 }
00104 
00105 static inline int64_t gb_get_v(GetBitContext *gb)
00106 {
00107     int64_t v = 0;
00108     int bits = 0;
00109     while(get_bits1(gb) && bits < 64-7){
00110         v <<= 7;
00111         v |= get_bits(gb, 7);
00112         bits += 7;
00113     }
00114     v <<= 7;
00115     v |= get_bits(gb, 7);
00116 
00117     return v;
00118 }
00119 
00120 static void mpc8_get_chunk_header(ByteIOContext *pb, int *tag, int64_t *size)
00121 {
00122     int64_t pos;
00123     pos = url_ftell(pb);
00124     *tag = get_le16(pb);
00125     *size = ff_get_v(pb);
00126     *size -= url_ftell(pb) - pos;
00127 }
00128 
00129 static void mpc8_parse_seektable(AVFormatContext *s, int64_t off)
00130 {
00131     MPCContext *c = s->priv_data;
00132     int tag;
00133     int64_t size, pos, ppos[2];
00134     uint8_t *buf;
00135     int i, t, seekd;
00136     GetBitContext gb;
00137 
00138     url_fseek(s->pb, off, SEEK_SET);
00139     mpc8_get_chunk_header(s->pb, &tag, &size);
00140     if(tag != TAG_SEEKTABLE){
00141         av_log(s, AV_LOG_ERROR, "No seek table at given position\n");
00142         return;
00143     }
00144     if(!(buf = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE)))
00145         return;
00146     get_buffer(s->pb, buf, size);
00147     init_get_bits(&gb, buf, size * 8);
00148     size = gb_get_v(&gb);
00149     if(size > UINT_MAX/4 || size > c->samples/1152){
00150         av_log(s, AV_LOG_ERROR, "Seek table is too big\n");
00151         return;
00152     }
00153     seekd = get_bits(&gb, 4);
00154     for(i = 0; i < 2; i++){
00155         pos = gb_get_v(&gb) + c->header_pos;
00156         ppos[1 - i] = pos;
00157         av_add_index_entry(s->streams[0], pos, i, 0, 0, AVINDEX_KEYFRAME);
00158     }
00159     for(; i < size; i++){
00160         t = get_unary(&gb, 1, 33) << 12;
00161         t += get_bits(&gb, 12);
00162         if(t & 1)
00163             t = -(t & ~1);
00164         pos = (t >> 1) + ppos[0]*2 - ppos[1];
00165         av_add_index_entry(s->streams[0], pos, i << seekd, 0, 0, AVINDEX_KEYFRAME);
00166         ppos[1] = ppos[0];
00167         ppos[0] = pos;
00168     }
00169     av_free(buf);
00170 }
00171 
00172 static void mpc8_handle_chunk(AVFormatContext *s, int tag, int64_t chunk_pos, int64_t size)
00173 {
00174     ByteIOContext *pb = s->pb;
00175     int64_t pos, off;
00176 
00177     switch(tag){
00178     case TAG_SEEKTBLOFF:
00179         pos = url_ftell(pb) + size;
00180         off = ff_get_v(pb);
00181         mpc8_parse_seektable(s, chunk_pos + off);
00182         url_fseek(pb, pos, SEEK_SET);
00183         break;
00184     default:
00185         url_fskip(pb, size);
00186     }
00187 }
00188 
00189 static int mpc8_read_header(AVFormatContext *s, AVFormatParameters *ap)
00190 {
00191     MPCContext *c = s->priv_data;
00192     ByteIOContext *pb = s->pb;
00193     AVStream *st;
00194     int tag = 0;
00195     int64_t size, pos;
00196 
00197     c->header_pos = url_ftell(pb);
00198     if(get_le32(pb) != TAG_MPCK){
00199         av_log(s, AV_LOG_ERROR, "Not a Musepack8 file\n");
00200         return -1;
00201     }
00202 
00203     while(!url_feof(pb)){
00204         pos = url_ftell(pb);
00205         mpc8_get_chunk_header(pb, &tag, &size);
00206         if(tag == TAG_STREAMHDR)
00207             break;
00208         mpc8_handle_chunk(s, tag, pos, size);
00209     }
00210     if(tag != TAG_STREAMHDR){
00211         av_log(s, AV_LOG_ERROR, "Stream header not found\n");
00212         return -1;
00213     }
00214     pos = url_ftell(pb);
00215     url_fskip(pb, 4); //CRC
00216     c->ver = get_byte(pb);
00217     if(c->ver != 8){
00218         av_log(s, AV_LOG_ERROR, "Unknown stream version %d\n", c->ver);
00219         return -1;
00220     }
00221     c->samples = ff_get_v(pb);
00222     ff_get_v(pb); //silence samples at the beginning
00223 
00224     st = av_new_stream(s, 0);
00225     if (!st)
00226         return AVERROR(ENOMEM);
00227     st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00228     st->codec->codec_id = CODEC_ID_MUSEPACK8;
00229     st->codec->bits_per_coded_sample = 16;
00230 
00231     st->codec->extradata_size = 2;
00232     st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
00233     get_buffer(pb, st->codec->extradata, st->codec->extradata_size);
00234 
00235     st->codec->channels = (st->codec->extradata[1] >> 4) + 1;
00236     st->codec->sample_rate = mpc8_rate[st->codec->extradata[0] >> 5];
00237     av_set_pts_info(st, 32, 1152  << (st->codec->extradata[1]&3)*2, st->codec->sample_rate);
00238     st->duration = c->samples / (1152 << (st->codec->extradata[1]&3)*2);
00239     size -= url_ftell(pb) - pos;
00240 
00241     return 0;
00242 }
00243 
00244 static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt)
00245 {
00246     MPCContext *c = s->priv_data;
00247     int tag;
00248     int64_t pos, size;
00249 
00250     while(!url_feof(s->pb)){
00251         pos = url_ftell(s->pb);
00252         mpc8_get_chunk_header(s->pb, &tag, &size);
00253         if (size < 0)
00254             return -1;
00255         if(tag == TAG_AUDIOPACKET){
00256             if(av_get_packet(s->pb, pkt, size) < 0)
00257                 return AVERROR(ENOMEM);
00258             pkt->stream_index = 0;
00259             pkt->pts = c->frame;
00260             return 0;
00261         }
00262         if(tag == TAG_STREAMEND)
00263             return AVERROR(EIO);
00264         mpc8_handle_chunk(s, tag, pos, size);
00265     }
00266     return 0;
00267 }
00268 
00269 static int mpc8_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
00270 {
00271     AVStream *st = s->streams[stream_index];
00272     MPCContext *c = s->priv_data;
00273     int index = av_index_search_timestamp(st, timestamp, flags);
00274 
00275     if(index < 0) return -1;
00276     url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET);
00277     c->frame = st->index_entries[index].timestamp;
00278     return 0;
00279 }
00280 
00281 
00282 AVInputFormat mpc8_demuxer = {
00283     "mpc8",
00284     NULL_IF_CONFIG_SMALL("Musepack SV8"),
00285     sizeof(MPCContext),
00286     mpc8_probe,
00287     mpc8_read_header,
00288     mpc8_read_packet,
00289     NULL,
00290     mpc8_read_seek,
00291 };

Generated on Fri Sep 16 2011 17:17:39 for FFmpeg by  doxygen 1.7.1