00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avformat.h"
00022 #include "bitstream.h"
00023 #include "unary.h"
00024
00026 #define MKMPCTAG(a, b) (a | (b << 8))
00027
00028 #define TAG_MPCK MKTAG('M','P','C','K')
00029
00031 enum MPCPacketTags{
00032 TAG_STREAMHDR = MKMPCTAG('S','H'),
00033 TAG_STREAMEND = MKMPCTAG('S','E'),
00034
00035 TAG_AUDIOPACKET = MKMPCTAG('A','P'),
00036
00037 TAG_SEEKTBLOFF = MKMPCTAG('S','O'),
00038 TAG_SEEKTABLE = MKMPCTAG('S','T'),
00039
00040 TAG_REPLAYGAIN = MKMPCTAG('R','G'),
00041 TAG_ENCINFO = MKMPCTAG('E','I'),
00042 };
00043
00044 static const int mpc8_rate[8] = { 44100, 48000, 37800, 32000, -1, -1, -1, -1 };
00045
00046 typedef struct {
00047 int ver;
00048 int frame;
00049 int64_t header_pos;
00050 int64_t samples;
00051 } MPCContext;
00052
00053 static int mpc8_probe(AVProbeData *p)
00054 {
00055 if (AV_RL32(p->buf) == TAG_MPCK)
00056 return AVPROBE_SCORE_MAX;
00057 return 0;
00058 }
00059
00060 static inline int64_t gb_get_v(GetBitContext *gb)
00061 {
00062 int64_t v = 0;
00063 int bits = 0;
00064 while(get_bits1(gb) && bits < 64-7){
00065 v <<= 7;
00066 v |= get_bits(gb, 7);
00067 bits += 7;
00068 }
00069 v <<= 7;
00070 v |= get_bits(gb, 7);
00071
00072 return v;
00073 }
00074
00075 static void mpc8_get_chunk_header(ByteIOContext *pb, int *tag, int64_t *size)
00076 {
00077 int64_t pos;
00078 pos = url_ftell(pb);
00079 *tag = get_le16(pb);
00080 *size = ff_get_v(pb);
00081 *size -= url_ftell(pb) - pos;
00082 }
00083
00084 static void mpc8_parse_seektable(AVFormatContext *s, int64_t off)
00085 {
00086 MPCContext *c = s->priv_data;
00087 int tag;
00088 int64_t size, pos, ppos[2];
00089 uint8_t *buf;
00090 int i, t, seekd;
00091 GetBitContext gb;
00092
00093 url_fseek(s->pb, off, SEEK_SET);
00094 mpc8_get_chunk_header(s->pb, &tag, &size);
00095 if(tag != TAG_SEEKTABLE){
00096 av_log(s, AV_LOG_ERROR, "No seek table at given position\n");
00097 return;
00098 }
00099 if(!(buf = av_malloc(size)))
00100 return;
00101 get_buffer(s->pb, buf, size);
00102 init_get_bits(&gb, buf, size * 8);
00103 size = gb_get_v(&gb);
00104 if(size > UINT_MAX/4 || size > c->samples/1152){
00105 av_log(s, AV_LOG_ERROR, "Seek table is too big\n");
00106 return;
00107 }
00108 seekd = get_bits(&gb, 4);
00109 for(i = 0; i < 2; i++){
00110 pos = gb_get_v(&gb) + c->header_pos;
00111 ppos[1 - i] = pos;
00112 av_add_index_entry(s->streams[0], pos, i, 0, 0, AVINDEX_KEYFRAME);
00113 }
00114 for(; i < size; i++){
00115 t = get_unary(&gb, 1, 33) << 12;
00116 t += get_bits(&gb, 12);
00117 if(t & 1)
00118 t = -(t & ~1);
00119 pos = (t >> 1) + ppos[0]*2 - ppos[1];
00120 av_add_index_entry(s->streams[0], pos, i << seekd, 0, 0, AVINDEX_KEYFRAME);
00121 ppos[1] = ppos[0];
00122 ppos[0] = pos;
00123 }
00124 av_free(buf);
00125 }
00126
00127 static void mpc8_handle_chunk(AVFormatContext *s, int tag, int64_t chunk_pos, int64_t size)
00128 {
00129 ByteIOContext *pb = s->pb;
00130 int64_t pos, off;
00131
00132 switch(tag){
00133 case TAG_SEEKTBLOFF:
00134 pos = url_ftell(pb) + size;
00135 off = ff_get_v(pb);
00136 mpc8_parse_seektable(s, chunk_pos + off);
00137 url_fseek(pb, pos, SEEK_SET);
00138 break;
00139 default:
00140 url_fskip(pb, size);
00141 }
00142 }
00143
00144 static int mpc8_read_header(AVFormatContext *s, AVFormatParameters *ap)
00145 {
00146 MPCContext *c = s->priv_data;
00147 ByteIOContext *pb = s->pb;
00148 AVStream *st;
00149 int tag = 0;
00150 int64_t size, pos;
00151
00152 c->header_pos = url_ftell(pb);
00153 if(get_le32(pb) != TAG_MPCK){
00154 av_log(s, AV_LOG_ERROR, "Not a Musepack8 file\n");
00155 return -1;
00156 }
00157
00158 while(!url_feof(pb)){
00159 pos = url_ftell(pb);
00160 mpc8_get_chunk_header(pb, &tag, &size);
00161 if(tag == TAG_STREAMHDR)
00162 break;
00163 mpc8_handle_chunk(s, tag, pos, size);
00164 }
00165 if(tag != TAG_STREAMHDR){
00166 av_log(s, AV_LOG_ERROR, "Stream header not found\n");
00167 return -1;
00168 }
00169 pos = url_ftell(pb);
00170 url_fskip(pb, 4);
00171 c->ver = get_byte(pb);
00172 if(c->ver != 8){
00173 av_log(s, AV_LOG_ERROR, "Unknown stream version %d\n", c->ver);
00174 return -1;
00175 }
00176 c->samples = ff_get_v(pb);
00177 ff_get_v(pb);
00178
00179 st = av_new_stream(s, 0);
00180 if (!st)
00181 return AVERROR(ENOMEM);
00182 st->codec->codec_type = CODEC_TYPE_AUDIO;
00183 st->codec->codec_id = CODEC_ID_MUSEPACK8;
00184 st->codec->bits_per_sample = 16;
00185
00186 st->codec->extradata_size = 2;
00187 st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
00188 get_buffer(pb, st->codec->extradata, st->codec->extradata_size);
00189
00190 st->codec->channels = (st->codec->extradata[1] >> 4) + 1;
00191 st->codec->sample_rate = mpc8_rate[st->codec->extradata[0] >> 5];
00192 av_set_pts_info(st, 32, 1152 << (st->codec->extradata[1]&3)*2, st->codec->sample_rate);
00193 st->duration = c->samples / (1152 << (st->codec->extradata[1]&3)*2);
00194 size -= url_ftell(pb) - pos;
00195
00196 return 0;
00197 }
00198
00199 static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt)
00200 {
00201 MPCContext *c = s->priv_data;
00202 int tag;
00203 int64_t pos, size;
00204
00205 while(!url_feof(s->pb)){
00206 pos = url_ftell(s->pb);
00207 mpc8_get_chunk_header(s->pb, &tag, &size);
00208 if(tag == TAG_AUDIOPACKET){
00209 if(av_get_packet(s->pb, pkt, size) < 0)
00210 return AVERROR(ENOMEM);
00211 pkt->stream_index = 0;
00212 pkt->pts = c->frame;
00213 return 0;
00214 }
00215 if(tag == TAG_STREAMEND)
00216 return AVERROR(EIO);
00217 mpc8_handle_chunk(s, tag, pos, size);
00218 }
00219 return 0;
00220 }
00221
00222 static int mpc8_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
00223 {
00224 AVStream *st = s->streams[stream_index];
00225 MPCContext *c = s->priv_data;
00226 int index = av_index_search_timestamp(st, timestamp, flags);
00227
00228 if(index < 0) return -1;
00229 url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET);
00230 c->frame = st->index_entries[index].timestamp;
00231 return 0;
00232 }
00233
00234
00235 AVInputFormat mpc8_demuxer = {
00236 "mpc8",
00237 "musepack8",
00238 sizeof(MPCContext),
00239 mpc8_probe,
00240 mpc8_read_header,
00241 mpc8_read_packet,
00242 NULL,
00243 mpc8_read_seek,
00244 };