wav.c 11 KB
Newer Older
1
/*
2
 * WAV muxer and demuxer
3
 * Copyright (c) 2001, 2002 Fabrice Bellard
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
Daniel Verkamp's avatar
Daniel Verkamp committed
5
 * Sony Wave64 demuxer
6
 * RF64 demuxer
Daniel Verkamp's avatar
Daniel Verkamp committed
7 8
 * Copyright (c) 2009 Daniel Verkamp
 *
9 10 11
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
12 13
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
14
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
15
 *
16
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
20
 *
21
 * You should have received a copy of the GNU Lesser General Public
22
 * License along with FFmpeg; if not, write to the Free Software
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
24 25
 */
#include "avformat.h"
26
#include "raw.h"
27
#include "riff.h"
28

Fabrice Bellard's avatar
Fabrice Bellard committed
29
typedef struct {
30 31
    int64_t data;
    int64_t data_end;
32 33 34
    int64_t minpts;
    int64_t maxpts;
    int last_duration;
Daniel Verkamp's avatar
Daniel Verkamp committed
35
    int w64;
Fabrice Bellard's avatar
Fabrice Bellard committed
36 37
} WAVContext;

38
#if CONFIG_WAV_MUXER
Fabrice Bellard's avatar
Fabrice Bellard committed
39 40
static int wav_write_header(AVFormatContext *s)
{
Fabrice Bellard's avatar
Fabrice Bellard committed
41
    WAVContext *wav = s->priv_data;
42
    ByteIOContext *pb = s->pb;
43
    int64_t fmt, fact;
Fabrice Bellard's avatar
Fabrice Bellard committed
44 45 46 47 48 49

    put_tag(pb, "RIFF");
    put_le32(pb, 0); /* file length */
    put_tag(pb, "WAVE");

    /* format header */
50 51
    fmt = ff_start_tag(pb, "fmt ");
    if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) {
52
        av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n",
53
               s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE");
54
        av_free(wav);
55 56
        return -1;
    }
57
    ff_end_tag(pb, fmt);
Fabrice Bellard's avatar
Fabrice Bellard committed
58

59 60
    if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */
        && !url_is_streamed(s->pb)) {
61
        fact = ff_start_tag(pb, "fact");
62
        put_le32(pb, 0);
63
        ff_end_tag(pb, fact);
64 65
    }

66
    av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
67 68
    wav->maxpts = wav->last_duration = 0;
    wav->minpts = INT64_MAX;
69

Fabrice Bellard's avatar
Fabrice Bellard committed
70
    /* data header */
71
    wav->data = ff_start_tag(pb, "data");
72

Fabrice Bellard's avatar
Fabrice Bellard committed
73 74 75 76 77
    put_flush_packet(pb);

    return 0;
}

78
static int wav_write_packet(AVFormatContext *s, AVPacket *pkt)
Fabrice Bellard's avatar
Fabrice Bellard committed
79
{
80 81
    ByteIOContext *pb  = s->pb;
    WAVContext    *wav = s->priv_data;
82
    put_buffer(pb, pkt->data, pkt->size);
83
    if(pkt->pts != AV_NOPTS_VALUE) {
84 85
        wav->minpts        = FFMIN(wav->minpts, pkt->pts);
        wav->maxpts        = FFMAX(wav->maxpts, pkt->pts);
86 87 88
        wav->last_duration = pkt->duration;
    } else
        av_log(s, AV_LOG_ERROR, "wav_write_packet: NOPTS\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
89 90 91 92 93
    return 0;
}

static int wav_write_trailer(AVFormatContext *s)
{
94 95
    ByteIOContext *pb  = s->pb;
    WAVContext    *wav = s->priv_data;
96
    int64_t file_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
97

98
    if (!url_is_streamed(s->pb)) {
99
        ff_end_tag(pb, wav->data);
Fabrice Bellard's avatar
Fabrice Bellard committed
100 101 102 103

        /* update file size */
        file_size = url_ftell(pb);
        url_fseek(pb, 4, SEEK_SET);
104
        put_le32(pb, (uint32_t)(file_size - 8));
Fabrice Bellard's avatar
Fabrice Bellard committed
105 106 107
        url_fseek(pb, file_size, SEEK_SET);

        put_flush_packet(pb);
108 109 110 111 112 113 114 115 116 117 118 119

        if(s->streams[0]->codec->codec_tag != 0x01) {
            /* Update num_samps in fact chunk */
            int number_of_samples;
            number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
                                           s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num,
                                           s->streams[0]->time_base.den);
            url_fseek(pb, wav->data-12, SEEK_SET);
            put_le32(pb, number_of_samples);
            url_fseek(pb, file_size, SEEK_SET);
            put_flush_packet(pb);
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
120 121 122
    }
    return 0;
}
123 124 125 126 127 128 129 130 131 132 133 134 135 136

AVOutputFormat wav_muxer = {
    "wav",
    NULL_IF_CONFIG_SMALL("WAV format"),
    "audio/x-wav",
    "wav",
    sizeof(WAVContext),
    CODEC_ID_PCM_S16LE,
    CODEC_ID_NONE,
    wav_write_header,
    wav_write_packet,
    wav_write_trailer,
    .codec_tag= (const AVCodecTag* const []){ff_codec_wav_tags, 0},
};
137
#endif /* CONFIG_WAV_MUXER */
Fabrice Bellard's avatar
Fabrice Bellard committed
138

139 140

#if CONFIG_WAV_DEMUXER
Fabrice Bellard's avatar
Fabrice Bellard committed
141
/* return the size of the found tag */
142
static int64_t find_tag(ByteIOContext *pb, uint32_t tag1)
Fabrice Bellard's avatar
Fabrice Bellard committed
143 144
{
    unsigned int tag;
145
    int64_t size;
Fabrice Bellard's avatar
Fabrice Bellard committed
146

147
    for (;;) {
Fabrice Bellard's avatar
Fabrice Bellard committed
148 149
        if (url_feof(pb))
            return -1;
150
        tag  = get_le32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
151 152 153 154 155 156 157 158
        size = get_le32(pb);
        if (tag == tag1)
            break;
        url_fseek(pb, size, SEEK_CUR);
    }
    return size;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
159 160 161 162 163
static int wav_probe(AVProbeData *p)
{
    /* check file header */
    if (p->buf_size <= 32)
        return 0;
164 165
    if (!memcmp(p->buf + 8, "WAVE", 4)) {
        if (!memcmp(p->buf, "RIFF", 4))
Daniel Verkamp's avatar
Daniel Verkamp committed
166 167 168 169 170 171
            /*
              Since ACT demuxer has standard WAV header at top of it's own,
              returning score is decreased to avoid probe conflict
              between ACT and WAV.
            */
            return AVPROBE_SCORE_MAX - 1;
172 173 174 175
        else if (!memcmp(p->buf,      "RF64", 4) &&
                 !memcmp(p->buf + 12, "ds64", 4))
            return AVPROBE_SCORE_MAX;
    }
Daniel Verkamp's avatar
Daniel Verkamp committed
176
    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
177 178
}

Fabrice Bellard's avatar
Fabrice Bellard committed
179 180 181 182
/* wav input */
static int wav_read_header(AVFormatContext *s,
                           AVFormatParameters *ap)
{
183 184
    int64_t size, av_uninit(data_size);
    int rf64;
Fabrice Bellard's avatar
Fabrice Bellard committed
185
    unsigned int tag;
186
    ByteIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
187
    AVStream *st;
188
    WAVContext *wav = s->priv_data;
Fabrice Bellard's avatar
Fabrice Bellard committed
189 190 191 192

    /* check RIFF header */
    tag = get_le32(pb);

193 194
    rf64 = tag == MKTAG('R', 'F', '6', '4');
    if (!rf64 && tag != MKTAG('R', 'I', 'F', 'F'))
Fabrice Bellard's avatar
Fabrice Bellard committed
195 196 197 198 199
        return -1;
    get_le32(pb); /* file size */
    tag = get_le32(pb);
    if (tag != MKTAG('W', 'A', 'V', 'E'))
        return -1;
200

201 202 203 204 205 206 207 208 209 210 211
    if (rf64) {
        if (get_le32(pb) != MKTAG('d', 's', '6', '4'))
            return -1;
        size = get_le32(pb);
        if (size < 16)
            return -1;
        get_le64(pb); /* RIFF size */
        data_size = get_le64(pb);
        url_fskip(pb, size - 16); /* skip rest of ds64 chunk */
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
212 213 214 215
    /* parse fmt header */
    size = find_tag(pb, MKTAG('f', 'm', 't', ' '));
    if (size < 0)
        return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
216
    st = av_new_stream(s, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
217
    if (!st)
218
        return AVERROR(ENOMEM);
Fabrice Bellard's avatar
Fabrice Bellard committed
219

220
    ff_get_wav_header(pb, st->codec, size);
221
    st->need_parsing = AVSTREAM_PARSE_FULL;
222

223
    av_set_pts_info(st, 64, 1, st->codec->sample_rate);
224

225
    size = find_tag(pb, MKTAG('d', 'a', 't', 'a'));
226 227
    if (rf64)
        size = data_size;
228 229
    if (size < 0)
        return -1;
230 231 232
    if (!size) {
        wav->data_end = INT64_MAX;
    } else
Daniel Verkamp's avatar
Daniel Verkamp committed
233
        wav->data_end= url_ftell(pb) + size;
Fabrice Bellard's avatar
Fabrice Bellard committed
234 235 236
    return 0;
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
/** Find chunk with w64 GUID by skipping over other chunks
 * @return the size of the found chunk
 */
static int64_t find_guid(ByteIOContext *pb, const uint8_t guid1[16])
{
    uint8_t guid[16];
    int64_t size;

    while (!url_feof(pb)) {
        get_buffer(pb, guid, 16);
        size = get_le64(pb);
        if (size <= 24)
            return -1;
        if (!memcmp(guid, guid1, 16))
            return size;
        url_fskip(pb, FFALIGN(size, INT64_C(8)) - 24);
    }
    return -1;
}

static const uint8_t guid_data[16] = { 'd', 'a', 't', 'a',
    0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A };

Fabrice Bellard's avatar
Fabrice Bellard committed
260 261 262 263 264
#define MAX_SIZE 4096

static int wav_read_packet(AVFormatContext *s,
                           AVPacket *pkt)
{
Daniel Verkamp's avatar
Daniel Verkamp committed
265 266
    int ret, size;
    int64_t left;
267
    AVStream *st;
268
    WAVContext *wav = s->priv_data;
Fabrice Bellard's avatar
Fabrice Bellard committed
269

270 271
    st = s->streams[0];

272 273 274
    left = wav->data_end - url_ftell(s->pb);
    if (left <= 0){
        if (CONFIG_W64_DEMUXER && wav->w64)
Daniel Verkamp's avatar
Daniel Verkamp committed
275
            left = find_guid(s->pb, guid_data) - 24;
276 277 278
        else
            left = find_tag(s->pb, MKTAG('d', 'a', 't', 'a'));
        if (left < 0)
279
            return AVERROR_EOF;
280
        wav->data_end= url_ftell(s->pb) + left;
281 282
    }

283
    size = MAX_SIZE;
284 285 286 287
    if (st->codec->block_align > 1) {
        if (size < st->codec->block_align)
            size = st->codec->block_align;
        size = (size / st->codec->block_align) * st->codec->block_align;
288
    }
289 290
    size = FFMIN(size, left);
    ret  = av_get_packet(s->pb, pkt, size);
291 292
    if (ret < 0)
        return ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
293 294 295 296 297
    pkt->stream_index = 0;

    return ret;
}

298
static int wav_read_seek(AVFormatContext *s,
299
                         int stream_index, int64_t timestamp, int flags)
300 301 302 303
{
    AVStream *st;

    st = s->streams[0];
304
    switch (st->codec->codec_id) {
305 306 307
    case CODEC_ID_MP2:
    case CODEC_ID_MP3:
    case CODEC_ID_AC3:
308
    case CODEC_ID_DTS:
309 310 311 312 313
        /* use generic seeking with dynamically generated indexes */
        return -1;
    default:
        break;
    }
314
    return pcm_read_seek(s, stream_index, timestamp, flags);
315 316
}

317
AVInputFormat wav_demuxer = {
Fabrice Bellard's avatar
Fabrice Bellard committed
318
    "wav",
319
    NULL_IF_CONFIG_SMALL("WAV format"),
320
    sizeof(WAVContext),
Fabrice Bellard's avatar
Fabrice Bellard committed
321 322 323
    wav_probe,
    wav_read_header,
    wav_read_packet,
324
    NULL,
325
    wav_read_seek,
326
    .flags= AVFMT_GENERIC_INDEX,
327
    .codec_tag= (const AVCodecTag* const []){ff_codec_wav_tags, 0},
Fabrice Bellard's avatar
Fabrice Bellard committed
328
};
329
#endif /* CONFIG_WAV_DEMUXER */
330 331


Daniel Verkamp's avatar
Daniel Verkamp committed
332
#if CONFIG_W64_DEMUXER
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
static const uint8_t guid_riff[16] = { 'r', 'i', 'f', 'f',
    0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00 };

static const uint8_t guid_wave[16] = { 'w', 'a', 'v', 'e',
    0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A };

static const uint8_t guid_fmt [16] = { 'f', 'm', 't', ' ',
    0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A };

static int w64_probe(AVProbeData *p)
{
    if (p->buf_size <= 40)
        return 0;
    if (!memcmp(p->buf,      guid_riff, 16) &&
        !memcmp(p->buf + 24, guid_wave, 16))
        return AVPROBE_SCORE_MAX;
    else
        return 0;
}

static int w64_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
    int64_t size;
    ByteIOContext *pb  = s->pb;
    WAVContext    *wav = s->priv_data;
    AVStream *st;
    uint8_t guid[16];

    get_buffer(pb, guid, 16);
    if (memcmp(guid, guid_riff, 16))
        return -1;

    if (get_le64(pb) < 16 + 8 + 16 + 8 + 16 + 8) /* riff + wave + fmt + sizes */
        return -1;

    get_buffer(pb, guid, 16);
    if (memcmp(guid, guid_wave, 16)) {
        av_log(s, AV_LOG_ERROR, "could not find wave guid\n");
        return -1;
    }

    size = find_guid(pb, guid_fmt);
    if (size < 0) {
        av_log(s, AV_LOG_ERROR, "could not find fmt guid\n");
        return -1;
    }

    st = av_new_stream(s, 0);
    if (!st)
        return AVERROR(ENOMEM);

    /* subtract chunk header size - normal wav file doesn't count it */
    ff_get_wav_header(pb, st->codec, size - 24);
    url_fskip(pb, FFALIGN(size, INT64_C(8)) - size);

    st->need_parsing = AVSTREAM_PARSE_FULL;

    av_set_pts_info(st, 64, 1, st->codec->sample_rate);

    size = find_guid(pb, guid_data);
    if (size < 0) {
        av_log(s, AV_LOG_ERROR, "could not find data guid\n");
        return -1;
    }
    wav->data_end = url_ftell(pb) + size - 24;
    wav->w64      = 1;

    return 0;
}

Daniel Verkamp's avatar
Daniel Verkamp committed
403 404 405 406 407 408 409 410 411 412 413 414
AVInputFormat w64_demuxer = {
    "w64",
    NULL_IF_CONFIG_SMALL("Sony Wave64 format"),
    sizeof(WAVContext),
    w64_probe,
    w64_read_header,
    wav_read_packet,
    NULL,
    wav_read_seek,
    .flags = AVFMT_GENERIC_INDEX,
    .codec_tag = (const AVCodecTag* const []){ff_codec_wav_tags, 0},
};
415
#endif /* CONFIG_W64_DEMUXER */