Enable forward seek in Musepack demuxer
[ffmpeg.git] / libavformat / mpc.c
1 /*
2  * Musepack 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 St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 #include "avformat.h"
22 #include "bitstream.h"
23
24 #define MPC_FRAMESIZE  1152
25
26 static const int mpc_rate[4] = { 44100, 48000, 37800, 32000 };
27 typedef struct {
28     int64_t pos;
29     int size, skip;
30 }MPCFrame;
31
32 typedef struct {
33     int ver;
34     uint32_t curframe, lastframe;
35     uint32_t fcount;
36     MPCFrame *frames;
37     int curbits;
38     int frames_noted;
39 } MPCContext;
40
41 static int mpc_probe(AVProbeData *p)
42 {
43     const uint8_t *d = p->buf;
44     if (p->buf_size < 32)
45         return 0;
46     if (d[0] == 'M' && d[1] == 'P' && d[2] == '+' && (d[3] == 0x17 || d[3] == 0x7))
47         return AVPROBE_SCORE_MAX;
48     return 0;
49 }
50
51 static int mpc_read_header(AVFormatContext *s, AVFormatParameters *ap)
52 {
53     MPCContext *c = s->priv_data;
54     AVStream *st;
55
56     if(get_le24(&s->pb) != MKTAG('M', 'P', '+', 0)){
57         av_log(s, AV_LOG_ERROR, "Not a Musepack file\n");
58         return -1;
59     }
60     c->ver = get_byte(&s->pb);
61     if(c->ver != 0x07 && c->ver != 0x17){
62         av_log(s, AV_LOG_ERROR, "Can demux Musepack SV7, got version %02X\n", c->ver);
63         return -1;
64     }
65     c->fcount = get_le32(&s->pb);
66     if((int64_t)c->fcount * sizeof(MPCFrame) >= UINT_MAX){
67         av_log(s, AV_LOG_ERROR, "Too many frames, seeking is not possible\n");
68         return -1;
69     }
70     c->frames = av_malloc(c->fcount * sizeof(MPCFrame));
71     c->curframe = 0;
72     c->lastframe = -1;
73     c->curbits = 8;
74     c->frames_noted = 0;
75
76     st = av_new_stream(s, 0);
77     if (!st)
78         return AVERROR_NOMEM;
79     st->codec->codec_type = CODEC_TYPE_AUDIO;
80     st->codec->codec_id = CODEC_ID_MUSEPACK7;
81     st->codec->channels = 2;
82     st->codec->bits_per_sample = 16;
83
84     st->codec->extradata_size = 16;
85     st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE);
86     get_buffer(&s->pb, st->codec->extradata, 16);
87     st->codec->sample_rate = mpc_rate[st->codec->extradata[2] & 3];
88     av_set_pts_info(st, 32, MPC_FRAMESIZE, st->codec->sample_rate);
89     /* scan for seekpoints */
90     s->start_time = 0;
91     s->duration = (int64_t)c->fcount * MPC_FRAMESIZE * AV_TIME_BASE / st->codec->sample_rate;
92
93     return 0;
94 }
95
96 static int mpc_read_packet(AVFormatContext *s, AVPacket *pkt)
97 {
98     MPCContext *c = s->priv_data;
99     int ret, size, size2, curbits, cur = c->curframe;
100     int64_t tmp, pos;
101
102     if (c->curframe > c->fcount)
103         return -1;
104
105     if(c->curframe != c->lastframe + 1){
106         url_fseek(&s->pb, c->frames[c->curframe].pos, SEEK_SET);
107         c->curbits = c->frames[c->curframe].skip;
108     }
109     c->lastframe = c->curframe;
110     c->curframe++;
111     curbits = c->curbits;
112     pos = url_ftell(&s->pb);
113     tmp = get_le32(&s->pb);
114     if(curbits <= 12){
115         size2 = (tmp >> (12 - curbits)) & 0xFFFFF;
116     }else{
117         tmp = (tmp << 32) | get_le32(&s->pb);
118         size2 = (tmp >> (44 - curbits)) & 0xFFFFF;
119     }
120     curbits += 20;
121     url_fseek(&s->pb, pos, SEEK_SET);
122
123     size = ((size2 + curbits + 31) & ~31) >> 3;
124     if(cur == c->frames_noted){
125         c->frames[cur].pos = pos;
126         c->frames[cur].size = size;
127         c->frames[cur].skip = curbits - 20;
128         av_add_index_entry(s->streams[0], cur, cur, size, 0, AVINDEX_KEYFRAME);
129         c->frames_noted++;
130     }
131     c->curbits = (curbits + size2) & 0x1F;
132
133     if (av_new_packet(pkt, size) < 0)
134         return AVERROR_IO;
135
136     pkt->data[0] = curbits;
137     pkt->data[1] = (c->curframe > c->fcount);
138
139     pkt->stream_index = 0;
140     ret = get_buffer(&s->pb, pkt->data + 4, size);
141     if(c->curbits)
142         url_fseek(&s->pb, -4, SEEK_CUR);
143     if(ret < size){
144         av_free_packet(pkt);
145         return AVERROR_IO;
146     }
147     pkt->size = ret + 4;
148
149     return 0;
150 }
151
152 static int mpc_read_close(AVFormatContext *s)
153 {
154     MPCContext *c = s->priv_data;
155
156     av_freep(&c->frames);
157     return 0;
158 }
159
160 /**
161  * Seek to the given position
162  * If position is unknown but is within the limits of file
163  * then packets are skipped unless desired position is reached
164  *
165  * Also this function makes use of the fact that timestamp == frameno
166  */
167 static int mpc_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
168 {
169     AVStream *st = s->streams[stream_index];
170     MPCContext *c = s->priv_data;
171     AVPacket pkt1, *pkt = &pkt1;
172     int ret;
173     int index = av_index_search_timestamp(st, timestamp, flags);
174     uint32_t lastframe;
175
176     /* if found, seek there */
177     if (index >= 0){
178         c->curframe = st->index_entries[index].pos;
179         return 0;
180     }
181     /* if timestamp is out of bounds, return error */
182     if(timestamp < 0 || timestamp >= c->fcount)
183         return -1;
184     /* seek to the furthest known position and read packets until
185        we reach desired position */
186     lastframe = c->curframe;
187     if(c->frames_noted) c->curframe = c->frames_noted - 1;
188     while(c->curframe < timestamp){
189         ret = av_read_frame(s, pkt);
190         if (ret < 0){
191             c->curframe = lastframe;
192             return -1;
193         }
194         av_free_packet(pkt);
195     }
196     return 0;
197 }
198
199
200 AVInputFormat mpc_demuxer = {
201     "mpc",
202     "musepack",
203     sizeof(MPCContext),
204     mpc_probe,
205     mpc_read_header,
206     mpc_read_packet,
207     mpc_read_close,
208     mpc_read_seek,
209     .extensions = "mpc",
210 };