~ubuntu-branches/ubuntu/oneiric/libav/oneiric

« back to all changes in this revision

Viewing changes to libavformat/wv.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2011-04-30 14:27:42 UTC
  • mfrom: (1.1.2 experimental)
  • Revision ID: james.westby@ubuntu.com-20110430142742-quvblxk1tj6adlh5
Tags: 4:0.7~b1-1ubuntu1
* Merge from debian. Remaining changes:
  - don't build against libfaad, libdirac, librtmp and libopenjpeg
    (all in universe)
  - explicitly --enable-pic on powerpc, cf. LP #654666
  - different arm configure bits that should probably better be
    merged into debian
* Cherry-picked from git: 
  - install doc/APIChanges and refer to them in NEWS.Debian (Closes: #623682)
  - don't try to install non-existing documentation, fixes FTBFS on powerpc

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * WavPack 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
 
3
 * Copyright (c) 2006,2011 Konstantin Shishkov
 
4
 *
 
5
 * This file is part of Libav.
 
6
 *
 
7
 * Libav is free software; you can redistribute it and/or
8
8
 * modify it under the terms of the GNU Lesser General Public
9
9
 * License as published by the Free Software Foundation; either
10
10
 * version 2.1 of the License, or (at your option) any later version.
11
11
 *
12
 
 * FFmpeg is distributed in the hope that it will be useful,
 
12
 * Libav is distributed in the hope that it will be useful,
13
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
15
 * Lesser General Public License for more details.
16
16
 *
17
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
 
18
 * License along with Libav; if not, write to the Free Software
19
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
20
 */
21
21
 
 
22
#include "libavutil/audioconvert.h"
22
23
#include "libavutil/intreadwrite.h"
23
24
#include "avformat.h"
24
25
#include "apetag.h"
29
30
 
30
31
#define WV_EXTRA_SIZE 12
31
32
 
 
33
#define WV_START_BLOCK  0x0800
 
34
#define WV_END_BLOCK    0x1000
 
35
#define WV_SINGLE_BLOCK (WV_START_BLOCK | WV_END_BLOCK)
 
36
 
32
37
enum WV_FLAGS{
33
38
    WV_MONO   = 0x0004,
34
39
    WV_HYBRID = 0x0008,
51
56
typedef struct{
52
57
    uint32_t blksize, flags;
53
58
    int rate, chan, bpp;
 
59
    uint32_t chmask;
54
60
    uint32_t samples, soff;
 
61
    int multichannel;
55
62
    int block_parsed;
56
63
    uint8_t extra[WV_EXTRA_SIZE];
57
64
    int64_t pos;
69
76
        return 0;
70
77
}
71
78
 
72
 
static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb)
 
79
static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb, int append)
73
80
{
74
81
    WVContext *wc = ctx->priv_data;
75
82
    uint32_t tag, ver;
76
83
    int size;
77
84
    int rate, bpp, chan;
 
85
    uint32_t chmask;
78
86
 
79
 
    wc->pos = url_ftell(pb);
80
 
    tag = get_le32(pb);
81
 
    if (tag != MKTAG('w', 'v', 'p', 'k'))
82
 
        return -1;
83
 
    size = get_le32(pb);
84
 
    if(size < 24 || size > WV_BLOCK_LIMIT){
85
 
        av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size);
86
 
        return -1;
87
 
    }
88
 
    wc->blksize = size;
89
 
    ver = get_le16(pb);
90
 
    if(ver < 0x402 || ver > 0x410){
91
 
        av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver);
92
 
        return -1;
93
 
    }
94
 
    get_byte(pb); // track no
95
 
    get_byte(pb); // track sub index
96
 
    wc->samples = get_le32(pb); // total samples in file
97
 
    wc->soff = get_le32(pb); // offset in samples of current block
98
 
    get_buffer(pb, wc->extra, WV_EXTRA_SIZE);
 
87
    wc->pos = avio_tell(pb);
 
88
    if(!append){
 
89
        tag = avio_rl32(pb);
 
90
        if (tag != MKTAG('w', 'v', 'p', 'k'))
 
91
            return -1;
 
92
        size = avio_rl32(pb);
 
93
        if(size < 24 || size > WV_BLOCK_LIMIT){
 
94
            av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size);
 
95
            return -1;
 
96
        }
 
97
        wc->blksize = size;
 
98
        ver = avio_rl16(pb);
 
99
        if(ver < 0x402 || ver > 0x410){
 
100
            av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver);
 
101
            return -1;
 
102
        }
 
103
        avio_r8(pb); // track no
 
104
        avio_r8(pb); // track sub index
 
105
        wc->samples = avio_rl32(pb); // total samples in file
 
106
        wc->soff = avio_rl32(pb); // offset in samples of current block
 
107
        avio_read(pb, wc->extra, WV_EXTRA_SIZE);
 
108
    }else{
 
109
        size = wc->blksize;
 
110
    }
99
111
    wc->flags = AV_RL32(wc->extra + 4);
100
112
    //parse flags
101
113
    bpp = ((wc->flags & 3) + 1) << 3;
102
114
    chan = 1 + !(wc->flags & WV_MONO);
 
115
    chmask = wc->flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
103
116
    rate = wv_rates[(wc->flags >> 23) & 0xF];
104
 
    if(rate == -1 && !wc->block_parsed){
105
 
        int64_t block_end = url_ftell(pb) + wc->blksize - 24;
106
 
        if(url_is_streamed(pb)){
107
 
            av_log(ctx, AV_LOG_ERROR, "Cannot determine custom sampling rate\n");
 
117
    wc->multichannel = !!((wc->flags & WV_SINGLE_BLOCK) != WV_SINGLE_BLOCK);
 
118
    if(wc->multichannel){
 
119
        chan = wc->chan;
 
120
        chmask = wc->chmask;
 
121
    }
 
122
    if((rate == -1 || !chan) && !wc->block_parsed){
 
123
        int64_t block_end = avio_tell(pb) + wc->blksize - 24;
 
124
        if(!pb->seekable){
 
125
            av_log(ctx, AV_LOG_ERROR, "Cannot determine additional parameters\n");
108
126
            return -1;
109
127
        }
110
 
        while(url_ftell(pb) < block_end){
 
128
        while(avio_tell(pb) < block_end){
111
129
            int id, size;
112
 
            id = get_byte(pb);
113
 
            size = (id & 0x80) ? get_le24(pb) : get_byte(pb);
 
130
            id = avio_r8(pb);
 
131
            size = (id & 0x80) ? avio_rl24(pb) : avio_r8(pb);
114
132
            size <<= 1;
115
133
            if(id&0x40)
116
134
                size--;
117
 
            if((id&0x3F) == 0x27){
118
 
                rate = get_le24(pb);
119
 
                break;
120
 
            }else{
121
 
                url_fskip(pb, size);
 
135
            switch(id&0x3F){
 
136
            case 0xD:
 
137
                if(size <= 1){
 
138
                    av_log(ctx, AV_LOG_ERROR, "Insufficient channel information\n");
 
139
                    return -1;
 
140
                }
 
141
                chan = avio_r8(pb);
 
142
                switch(size - 2){
 
143
                case 0:
 
144
                    chmask = avio_r8(pb);
 
145
                    break;
 
146
                case 1:
 
147
                    chmask = avio_rl16(pb);
 
148
                    break;
 
149
                case 2:
 
150
                    chmask = avio_rl24(pb);
 
151
                    break;
 
152
                case 3:
 
153
                    chmask = avio_rl32(pb);
 
154
                    break;
 
155
                case 5:
 
156
                    avio_skip(pb, 1);
 
157
                    chan |= (avio_r8(pb) & 0xF) << 8;
 
158
                    chmask = avio_rl24(pb);
 
159
                    break;
 
160
                default:
 
161
                    av_log(ctx, AV_LOG_ERROR, "Invalid channel info size %d\n", size);
 
162
                    return -1;
 
163
                }
 
164
                break;
 
165
            case 0x27:
 
166
                rate = avio_rl24(pb);
 
167
                break;
 
168
            default:
 
169
                avio_skip(pb, size);
122
170
            }
 
171
            if(id&0x40)
 
172
                avio_skip(pb, 1);
123
173
        }
124
174
        if(rate == -1){
125
175
            av_log(ctx, AV_LOG_ERROR, "Cannot determine custom sampling rate\n");
126
176
            return -1;
127
177
        }
128
 
        url_fseek(pb, block_end - wc->blksize + 24, SEEK_SET);
 
178
        avio_seek(pb, block_end - wc->blksize + 24, SEEK_SET);
129
179
    }
130
180
    if(!wc->bpp) wc->bpp = bpp;
131
181
    if(!wc->chan) wc->chan = chan;
 
182
    if(!wc->chmask) wc->chmask = chmask;
132
183
    if(!wc->rate) wc->rate = rate;
133
184
 
134
185
    if(wc->flags && bpp != wc->bpp){
135
186
        av_log(ctx, AV_LOG_ERROR, "Bits per sample differ, this block: %i, header block: %i\n", bpp, wc->bpp);
136
187
        return -1;
137
188
    }
138
 
    if(wc->flags && chan != wc->chan){
 
189
    if(wc->flags && !wc->multichannel && chan != wc->chan){
139
190
        av_log(ctx, AV_LOG_ERROR, "Channels differ, this block: %i, header block: %i\n", chan, wc->chan);
140
191
        return -1;
141
192
    }
150
201
static int wv_read_header(AVFormatContext *s,
151
202
                          AVFormatParameters *ap)
152
203
{
153
 
    ByteIOContext *pb = s->pb;
 
204
    AVIOContext *pb = s->pb;
154
205
    WVContext *wc = s->priv_data;
155
206
    AVStream *st;
156
207
 
157
208
    wc->block_parsed = 0;
158
 
    if(wv_read_block_header(s, pb) < 0)
 
209
    if(wv_read_block_header(s, pb, 0) < 0)
159
210
        return -1;
160
211
 
161
212
    /* now we are ready: build format streams */
165
216
    st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
166
217
    st->codec->codec_id = CODEC_ID_WAVPACK;
167
218
    st->codec->channels = wc->chan;
 
219
    st->codec->channel_layout = wc->chmask;
168
220
    st->codec->sample_rate = wc->rate;
169
221
    st->codec->bits_per_coded_sample = wc->bpp;
170
222
    av_set_pts_info(st, 64, 1, wc->rate);
171
223
    st->start_time = 0;
172
224
    st->duration = wc->samples;
173
225
 
174
 
    if(!url_is_streamed(s->pb)) {
175
 
        int64_t cur = url_ftell(s->pb);
 
226
    if(s->pb->seekable) {
 
227
        int64_t cur = avio_tell(s->pb);
176
228
        ff_ape_parse_tag(s);
177
229
        if(!av_metadata_get(s->metadata, "", NULL, AV_METADATA_IGNORE_SUFFIX))
178
230
            ff_id3v1_read(s);
179
 
        url_fseek(s->pb, cur, SEEK_SET);
 
231
        avio_seek(s->pb, cur, SEEK_SET);
180
232
    }
181
233
 
182
234
    return 0;
187
239
{
188
240
    WVContext *wc = s->priv_data;
189
241
    int ret;
 
242
    int size, ver, off;
190
243
 
191
 
    if (url_feof(s->pb))
 
244
    if (s->pb->eof_reached)
192
245
        return AVERROR(EIO);
193
246
    if(wc->block_parsed){
194
 
        if(wv_read_block_header(s, s->pb) < 0)
 
247
        if(wv_read_block_header(s, s->pb, 0) < 0)
195
248
            return -1;
196
249
    }
197
250
 
198
 
    if(av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE) < 0)
 
251
    off = wc->multichannel ? 4 : 0;
 
252
    if(av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE + off) < 0)
199
253
        return AVERROR(ENOMEM);
200
 
    memcpy(pkt->data, wc->extra, WV_EXTRA_SIZE);
201
 
    ret = get_buffer(s->pb, pkt->data + WV_EXTRA_SIZE, wc->blksize);
 
254
    if(wc->multichannel)
 
255
        AV_WL32(pkt->data, wc->blksize + WV_EXTRA_SIZE + 12);
 
256
    memcpy(pkt->data + off, wc->extra, WV_EXTRA_SIZE);
 
257
    ret = avio_read(s->pb, pkt->data + WV_EXTRA_SIZE + off, wc->blksize);
202
258
    if(ret != wc->blksize){
203
259
        av_free_packet(pkt);
204
260
        return AVERROR(EIO);
205
261
    }
 
262
    while(!(wc->flags & WV_END_BLOCK)){
 
263
        if(avio_rl32(s->pb) != MKTAG('w', 'v', 'p', 'k')){
 
264
            av_free_packet(pkt);
 
265
            return -1;
 
266
        }
 
267
        if((ret = av_append_packet(s->pb, pkt, 4)) < 0){
 
268
            av_free_packet(pkt);
 
269
            return ret;
 
270
        }
 
271
        size = AV_RL32(pkt->data + pkt->size - 4);
 
272
        if(size < 24 || size > WV_BLOCK_LIMIT){
 
273
            av_free_packet(pkt);
 
274
            av_log(s, AV_LOG_ERROR, "Incorrect block size %d\n", size);
 
275
            return -1;
 
276
        }
 
277
        wc->blksize = size;
 
278
        ver = avio_rl16(s->pb);
 
279
        if(ver < 0x402 || ver > 0x410){
 
280
            av_free_packet(pkt);
 
281
            av_log(s, AV_LOG_ERROR, "Unsupported version %03X\n", ver);
 
282
            return -1;
 
283
        }
 
284
        avio_r8(s->pb); // track no
 
285
        avio_r8(s->pb); // track sub index
 
286
        wc->samples = avio_rl32(s->pb); // total samples in file
 
287
        wc->soff = avio_rl32(s->pb); // offset in samples of current block
 
288
        if((ret = av_append_packet(s->pb, pkt, WV_EXTRA_SIZE)) < 0){
 
289
            av_free_packet(pkt);
 
290
            return ret;
 
291
        }
 
292
        memcpy(wc->extra, pkt->data + pkt->size - WV_EXTRA_SIZE, WV_EXTRA_SIZE);
 
293
 
 
294
        if(wv_read_block_header(s, s->pb, 1) < 0){
 
295
            av_free_packet(pkt);
 
296
            return -1;
 
297
        }
 
298
        ret = av_append_packet(s->pb, pkt, wc->blksize);
 
299
        if(ret < 0){
 
300
            av_free_packet(pkt);
 
301
            return ret;
 
302
        }
 
303
    }
206
304
    pkt->stream_index = 0;
207
305
    wc->block_parsed = 1;
208
 
    pkt->size = ret + WV_EXTRA_SIZE;
209
306
    pkt->pts = wc->soff;
210
307
    av_add_index_entry(s->streams[0], wc->pos, pkt->pts, 0, 0, AVINDEX_KEYFRAME);
211
308
    return 0;
223
320
    /* if found, seek there */
224
321
    if (index >= 0){
225
322
        wc->block_parsed = 1;
226
 
        url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET);
 
323
        avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET);
227
324
        return 0;
228
325
    }
229
326
    /* if timestamp is out of bounds, return error */
230
327
    if(timestamp < 0 || timestamp >= s->duration)
231
328
        return -1;
232
329
 
233
 
    pos = url_ftell(s->pb);
 
330
    pos = avio_tell(s->pb);
234
331
    do{
235
332
        ret = av_read_frame(s, pkt);
236
333
        if (ret < 0){
237
 
            url_fseek(s->pb, pos, SEEK_SET);
 
334
            avio_seek(s->pb, pos, SEEK_SET);
238
335
            return -1;
239
336
        }
240
337
        pts = pkt->pts;
243
340
    return 0;
244
341
}
245
342
 
246
 
AVInputFormat wv_demuxer = {
 
343
AVInputFormat ff_wv_demuxer = {
247
344
    "wv",
248
345
    NULL_IF_CONFIG_SMALL("WavPack"),
249
346
    sizeof(WVContext),