mpc8.c 8.4 KB
Newer Older
K
Kostya Shishkov 已提交
1 2 3 4
/*
 * Musepack SV8 demuxer
 * Copyright (c) 2007 Konstantin Shishkov
 *
5
 * This file is part of Libav.
K
Kostya Shishkov 已提交
6
 *
7
 * Libav is free software; you can redistribute it and/or
K
Kostya Shishkov 已提交
8 9 10 11
 * 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.
 *
12
 * Libav is distributed in the hope that it will be useful,
K
Kostya Shishkov 已提交
13 14 15 16 17
 * 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
18
 * License along with Libav; if not, write to the Free Software
K
Kostya Shishkov 已提交
19 20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
21

22
#include "libavcodec/get_bits.h"
23
#include "libavcodec/unary.h"
A
Anton Khirnov 已提交
24
#include "apetag.h"
K
Kostya Shishkov 已提交
25
#include "avformat.h"
26
#include "internal.h"
27
#include "avio_internal.h"
K
Kostya Shishkov 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

/// Two-byte MPC tag
#define MKMPCTAG(a, b) (a | (b << 8))

#define TAG_MPCK MKTAG('M','P','C','K')

/// Reserved MPC tags
enum MPCPacketTags{
    TAG_STREAMHDR   = MKMPCTAG('S','H'),
    TAG_STREAMEND   = MKMPCTAG('S','E'),

    TAG_AUDIOPACKET = MKMPCTAG('A','P'),

    TAG_SEEKTBLOFF  = MKMPCTAG('S','O'),
    TAG_SEEKTABLE   = MKMPCTAG('S','T'),

    TAG_REPLAYGAIN  = MKMPCTAG('R','G'),
    TAG_ENCINFO     = MKMPCTAG('E','I'),
};

static const int mpc8_rate[8] = { 44100, 48000, 37800, 32000, -1, -1, -1, -1 };

typedef struct {
    int ver;
    int64_t header_pos;
    int64_t samples;
54 55

    int64_t apetag_start;
K
Kostya Shishkov 已提交
56 57
} MPCContext;

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
static inline int64_t bs_get_v(uint8_t **bs)
{
    int64_t v = 0;
    int br = 0;
    int c;

    do {
        c = **bs; (*bs)++;
        v <<= 7;
        v |= c & 0x7F;
        br++;
        if (br > 10)
            return -1;
    } while (c & 0x80);

    return v - br;
}

K
Kostya Shishkov 已提交
76 77
static int mpc8_probe(AVProbeData *p)
{
78 79 80 81
    uint8_t *bs = p->buf + 4;
    uint8_t *bs_end = bs + p->buf_size;
    int64_t size;

82 83 84 85
    if (p->buf_size < 16)
        return 0;
    if (AV_RL32(p->buf) != TAG_MPCK)
        return 0;
86 87 88
    while (bs < bs_end + 3) {
        int header_found = (bs[0] == 'S' && bs[1] == 'H');
        if (bs[0] < 'A' || bs[0] > 'Z' || bs[1] < 'A' || bs[1] > 'Z')
89
            return 0;
90 91 92
        bs += 2;
        size = bs_get_v(&bs);
        if (size < 2)
93
            return 0;
94
        if (bs + size - 2 >= bs_end)
95
            return AVPROBE_SCORE_EXTENSION - 1; // seems to be valid MPC but no header yet
96
        if (header_found) {
97 98 99 100 101
            if (size < 11 || size > 28)
                return 0;
            if (!AV_RL32(bs)) //zero CRC is invalid
                return 0;
            return AVPROBE_SCORE_MAX;
102 103 104
        } else {
            bs += size - 2;
        }
105
    }
106
    return 0;
K
Kostya Shishkov 已提交
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
}

static inline int64_t gb_get_v(GetBitContext *gb)
{
    int64_t v = 0;
    int bits = 0;
    while(get_bits1(gb) && bits < 64-7){
        v <<= 7;
        v |= get_bits(gb, 7);
        bits += 7;
    }
    v <<= 7;
    v |= get_bits(gb, 7);

    return v;
}

124
static void mpc8_get_chunk_header(AVIOContext *pb, int *tag, int64_t *size)
K
Kostya Shishkov 已提交
125 126
{
    int64_t pos;
127
    pos = avio_tell(pb);
128
    *tag = avio_rl16(pb);
129
    *size = ffio_read_varlen(pb);
130
    *size -= avio_tell(pb) - pos;
K
Kostya Shishkov 已提交
131 132 133 134 135 136 137 138 139 140 141
}

static void mpc8_parse_seektable(AVFormatContext *s, int64_t off)
{
    MPCContext *c = s->priv_data;
    int tag;
    int64_t size, pos, ppos[2];
    uint8_t *buf;
    int i, t, seekd;
    GetBitContext gb;

A
Anton Khirnov 已提交
142
    avio_seek(s->pb, off, SEEK_SET);
143
    mpc8_get_chunk_header(s->pb, &tag, &size);
K
Kostya Shishkov 已提交
144 145 146 147
    if(tag != TAG_SEEKTABLE){
        av_log(s, AV_LOG_ERROR, "No seek table at given position\n");
        return;
    }
148 149 150 151
    if (size < 0 || size >= INT_MAX / 2) {
        av_log(s, AV_LOG_ERROR, "Bad seek table size\n");
        return;
    }
152
    if(!(buf = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE)))
K
Kostya Shishkov 已提交
153
        return;
154
    avio_read(s->pb, buf, size);
K
Kostya Shishkov 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    init_get_bits(&gb, buf, size * 8);
    size = gb_get_v(&gb);
    if(size > UINT_MAX/4 || size > c->samples/1152){
        av_log(s, AV_LOG_ERROR, "Seek table is too big\n");
        return;
    }
    seekd = get_bits(&gb, 4);
    for(i = 0; i < 2; i++){
        pos = gb_get_v(&gb) + c->header_pos;
        ppos[1 - i] = pos;
        av_add_index_entry(s->streams[0], pos, i, 0, 0, AVINDEX_KEYFRAME);
    }
    for(; i < size; i++){
        t = get_unary(&gb, 1, 33) << 12;
        t += get_bits(&gb, 12);
        if(t & 1)
            t = -(t & ~1);
        pos = (t >> 1) + ppos[0]*2 - ppos[1];
        av_add_index_entry(s->streams[0], pos, i << seekd, 0, 0, AVINDEX_KEYFRAME);
        ppos[1] = ppos[0];
        ppos[0] = pos;
    }
    av_free(buf);
}

static void mpc8_handle_chunk(AVFormatContext *s, int tag, int64_t chunk_pos, int64_t size)
{
182
    AVIOContext *pb = s->pb;
K
Kostya Shishkov 已提交
183 184 185 186
    int64_t pos, off;

    switch(tag){
    case TAG_SEEKTBLOFF:
187
        pos = avio_tell(pb) + size;
188
        off = ffio_read_varlen(pb);
K
Kostya Shishkov 已提交
189
        mpc8_parse_seektable(s, chunk_pos + off);
A
Anton Khirnov 已提交
190
        avio_seek(pb, pos, SEEK_SET);
K
Kostya Shishkov 已提交
191 192
        break;
    default:
193
        avio_skip(pb, size);
K
Kostya Shishkov 已提交
194 195 196
    }
}

197
static int mpc8_read_header(AVFormatContext *s)
K
Kostya Shishkov 已提交
198 199
{
    MPCContext *c = s->priv_data;
200
    AVIOContext *pb = s->pb;
K
Kostya Shishkov 已提交
201 202 203 204
    AVStream *st;
    int tag = 0;
    int64_t size, pos;

205
    c->header_pos = avio_tell(pb);
206
    if(avio_rl32(pb) != TAG_MPCK){
K
Kostya Shishkov 已提交
207
        av_log(s, AV_LOG_ERROR, "Not a Musepack8 file\n");
208
        return AVERROR_INVALIDDATA;
K
Kostya Shishkov 已提交
209 210
    }

A
Anton Khirnov 已提交
211
    while(!pb->eof_reached){
212
        pos = avio_tell(pb);
K
Kostya Shishkov 已提交
213 214 215 216 217 218 219
        mpc8_get_chunk_header(pb, &tag, &size);
        if(tag == TAG_STREAMHDR)
            break;
        mpc8_handle_chunk(s, tag, pos, size);
    }
    if(tag != TAG_STREAMHDR){
        av_log(s, AV_LOG_ERROR, "Stream header not found\n");
220
        return AVERROR_INVALIDDATA;
K
Kostya Shishkov 已提交
221
    }
222
    pos = avio_tell(pb);
223
    avio_skip(pb, 4); //CRC
224
    c->ver = avio_r8(pb);
K
Kostya Shishkov 已提交
225 226
    if(c->ver != 8){
        av_log(s, AV_LOG_ERROR, "Unknown stream version %d\n", c->ver);
227
        return AVERROR_PATCHWELCOME;
K
Kostya Shishkov 已提交
228
    }
229 230
    c->samples = ffio_read_varlen(pb);
    ffio_read_varlen(pb); //silence samples at the beginning
K
Kostya Shishkov 已提交
231

232
    st = avformat_new_stream(s, NULL);
K
Kostya Shishkov 已提交
233 234
    if (!st)
        return AVERROR(ENOMEM);
235
    st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
236
    st->codec->codec_id = AV_CODEC_ID_MUSEPACK8;
237
    st->codec->bits_per_coded_sample = 16;
K
Kostya Shishkov 已提交
238 239 240

    st->codec->extradata_size = 2;
    st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
241
    avio_read(pb, st->codec->extradata, st->codec->extradata_size);
K
Kostya Shishkov 已提交
242 243 244

    st->codec->channels = (st->codec->extradata[1] >> 4) + 1;
    st->codec->sample_rate = mpc8_rate[st->codec->extradata[0] >> 5];
245
    avpriv_set_pts_info(st, 32, 1152  << (st->codec->extradata[1]&3)*2, st->codec->sample_rate);
246
    st->start_time = 0;
K
Kostya Shishkov 已提交
247
    st->duration = c->samples / (1152 << (st->codec->extradata[1]&3)*2);
248
    size -= avio_tell(pb) - pos;
K
Kostya Shishkov 已提交
249

A
Anton Khirnov 已提交
250 251
    if (pb->seekable) {
        int64_t pos = avio_tell(s->pb);
252
        c->apetag_start = ff_ape_parse_tag(s);
A
Anton Khirnov 已提交
253 254 255
        avio_seek(s->pb, pos, SEEK_SET);
    }

K
Kostya Shishkov 已提交
256 257 258 259 260 261 262 263 264
    return 0;
}

static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    MPCContext *c = s->priv_data;
    int tag;
    int64_t pos, size;

A
Anton Khirnov 已提交
265
    while(!s->pb->eof_reached){
266
        pos = avio_tell(s->pb);
267 268 269 270 271

        /* don't return bogus packets with the ape tag data */
        if (c->apetag_start && pos >= c->apetag_start)
            return AVERROR_EOF;

272
        mpc8_get_chunk_header(s->pb, &tag, &size);
273 274
        if (size < 0)
            return -1;
K
Kostya Shishkov 已提交
275
        if(tag == TAG_AUDIOPACKET){
276
            if(av_get_packet(s->pb, pkt, size) < 0)
K
Kostya Shishkov 已提交
277 278
                return AVERROR(ENOMEM);
            pkt->stream_index = 0;
279
            pkt->duration     = 1;
K
Kostya Shishkov 已提交
280 281 282 283 284 285
            return 0;
        }
        if(tag == TAG_STREAMEND)
            return AVERROR(EIO);
        mpc8_handle_chunk(s, tag, pos, size);
    }
L
Laurent Aimar 已提交
286
    return AVERROR_EOF;
K
Kostya Shishkov 已提交
287 288 289 290 291 292 293 294
}

static int mpc8_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
{
    AVStream *st = s->streams[stream_index];
    int index = av_index_search_timestamp(st, timestamp, flags);

    if(index < 0) return -1;
295 296
    if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0)
        return -1;
297
    ff_update_cur_dts(s, st, st->index_entries[index].timestamp);
K
Kostya Shishkov 已提交
298 299 300 301
    return 0;
}


302
AVInputFormat ff_mpc8_demuxer = {
303 304 305 306 307 308 309
    .name           = "mpc8",
    .long_name      = NULL_IF_CONFIG_SMALL("Musepack SV8"),
    .priv_data_size = sizeof(MPCContext),
    .read_probe     = mpc8_probe,
    .read_header    = mpc8_read_header,
    .read_packet    = mpc8_read_packet,
    .read_seek      = mpc8_read_seek,
K
Kostya Shishkov 已提交
310
};