ipmovie.c 22.7 KB
Newer Older
1 2
/*
 * Interplay MVE File Demuxer
3
 * Copyright (c) 2003 The FFmpeg project
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * 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 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 FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 21 22
 */

/**
23
 * @file
24 25 26 27 28 29 30 31 32 33 34
 * Interplay MVE file demuxer
 * by Mike Melanson (melanson@pcisys.net)
 * For more information regarding the Interplay MVE file format, visit:
 *   http://www.pcisys.net/~melanson/codecs/
 * The aforementioned site also contains a command line utility for parsing
 * IP MVE files so that you can get a good idea of the typical structure of
 * such files. This demuxer is not the best example to use if you are trying
 * to write your own as it uses a rather roundabout approach for splitting
 * up and sending out the chunks.
 */

35
#include "libavutil/channel_layout.h"
36
#include "libavutil/intreadwrite.h"
37
#include "avformat.h"
38
#include "internal.h"
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

#define CHUNK_PREAMBLE_SIZE 4
#define OPCODE_PREAMBLE_SIZE 4

#define CHUNK_INIT_AUDIO   0x0000
#define CHUNK_AUDIO_ONLY   0x0001
#define CHUNK_INIT_VIDEO   0x0002
#define CHUNK_VIDEO        0x0003
#define CHUNK_SHUTDOWN     0x0004
#define CHUNK_END          0x0005
/* these last types are used internally */
#define CHUNK_DONE         0xFFFC
#define CHUNK_NOMEM        0xFFFD
#define CHUNK_EOF          0xFFFE
#define CHUNK_BAD          0xFFFF

#define OPCODE_END_OF_STREAM           0x00
#define OPCODE_END_OF_CHUNK            0x01
#define OPCODE_CREATE_TIMER            0x02
#define OPCODE_INIT_AUDIO_BUFFERS      0x03
#define OPCODE_START_STOP_AUDIO        0x04
#define OPCODE_INIT_VIDEO_BUFFERS      0x05
#define OPCODE_UNKNOWN_06              0x06
#define OPCODE_SEND_BUFFER             0x07
#define OPCODE_AUDIO_FRAME             0x08
#define OPCODE_SILENCE_FRAME           0x09
#define OPCODE_INIT_VIDEO_MODE         0x0A
#define OPCODE_CREATE_GRADIENT         0x0B
#define OPCODE_SET_PALETTE             0x0C
#define OPCODE_SET_PALETTE_COMPRESSED  0x0D
#define OPCODE_UNKNOWN_0E              0x0E
#define OPCODE_SET_DECODING_MAP        0x0F
#define OPCODE_UNKNOWN_10              0x10
#define OPCODE_VIDEO_DATA              0x11
#define OPCODE_UNKNOWN_12              0x12
#define OPCODE_UNKNOWN_13              0x13
#define OPCODE_UNKNOWN_14              0x14
#define OPCODE_UNKNOWN_15              0x15

#define PALETTE_COUNT 256

typedef struct IPMVEContext {
81
    AVFormatContext *avf;
82 83 84
    unsigned char *buf;
    int buf_size;

85
    uint64_t frame_pts_inc;
86

87
    unsigned int video_bpp;
88 89 90
    unsigned int video_width;
    unsigned int video_height;
    int64_t video_pts;
91 92
    uint32_t     palette[256];
    int          has_palette;
93
    int          changed;
94 95 96 97

    unsigned int audio_bits;
    unsigned int audio_channels;
    unsigned int audio_sample_rate;
98
    enum AVCodecID audio_type;
99 100 101 102 103
    unsigned int audio_frame_count;

    int video_stream_index;
    int audio_stream_index;

104
    int64_t audio_chunk_offset;
105
    int audio_chunk_size;
106
    int64_t video_chunk_offset;
107
    int video_chunk_size;
108
    int64_t decode_map_chunk_offset;
109 110
    int decode_map_chunk_size;

111
    int64_t next_chunk_offset;
112 113 114

} IPMVEContext;

115
static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb,
116 117 118 119
    AVPacket *pkt) {

    int chunk_type;

Michael Niedermayer's avatar
Michael Niedermayer committed
120
    if (s->audio_chunk_offset && s->audio_channels && s->audio_bits) {
121
        if (s->audio_type == AV_CODEC_ID_NONE) {
122
            av_log(s->avf, AV_LOG_ERROR, "Can not read audio packet before"
123 124 125
                   "audio codec is known\n");
                return CHUNK_BAD;
        }
126

127
        /* adjust for PCM audio by skipping chunk header */
128
        if (s->audio_type != AV_CODEC_ID_INTERPLAY_DPCM) {
129 130 131 132
            s->audio_chunk_offset += 6;
            s->audio_chunk_size -= 6;
        }

133
        avio_seek(pb, s->audio_chunk_offset, SEEK_SET);
134 135
        s->audio_chunk_offset = 0;

Michael Niedermayer's avatar
Michael Niedermayer committed
136 137
        if (s->audio_chunk_size != av_get_packet(pb, pkt, s->audio_chunk_size))
            return CHUNK_EOF;
138 139

        pkt->stream_index = s->audio_stream_index;
140
        pkt->pts = s->audio_frame_count;
141 142

        /* audio frame maintenance */
143
        if (s->audio_type != AV_CODEC_ID_INTERPLAY_DPCM)
144 145 146 147
            s->audio_frame_count +=
            (s->audio_chunk_size / s->audio_channels / (s->audio_bits / 8));
        else
            s->audio_frame_count +=
148
                (s->audio_chunk_size - 6 - s->audio_channels) / s->audio_channels;
149

150
        av_log(s->avf, AV_LOG_TRACE, "sending audio frame with pts %"PRId64" (%d audio frames)\n",
151
                pkt->pts, s->audio_frame_count);
152 153 154 155 156

        chunk_type = CHUNK_VIDEO;

    } else if (s->decode_map_chunk_offset) {

157
        /* send both the decode map and the video data together */
158

159
        if (av_new_packet(pkt, 2 + s->decode_map_chunk_size + s->video_chunk_size))
160 161
            return CHUNK_NOMEM;

162 163 164 165 166 167 168 169 170 171 172
        if (s->has_palette) {
            uint8_t *pal;

            pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE,
                                          AVPALETTE_SIZE);
            if (pal) {
                memcpy(pal, s->palette, AVPALETTE_SIZE);
                s->has_palette = 0;
            }
        }

173 174 175 176
        if (s->changed) {
            ff_add_param_change(pkt, 0, 0, 0, s->video_width, s->video_height);
            s->changed = 0;
        }
Michael Niedermayer's avatar
Michael Niedermayer committed
177
        pkt->pos= s->decode_map_chunk_offset;
178
        avio_seek(pb, s->decode_map_chunk_offset, SEEK_SET);
179 180
        s->decode_map_chunk_offset = 0;

181 182
        AV_WL16(pkt->data, s->decode_map_chunk_size);
        if (avio_read(pb, pkt->data + 2, s->decode_map_chunk_size) !=
183
            s->decode_map_chunk_size) {
184
            av_packet_unref(pkt);
185 186 187
            return CHUNK_EOF;
        }

188
        avio_seek(pb, s->video_chunk_offset, SEEK_SET);
189 190
        s->video_chunk_offset = 0;

191
        if (avio_read(pb, pkt->data + 2 + s->decode_map_chunk_size,
192
            s->video_chunk_size) != s->video_chunk_size) {
193
            av_packet_unref(pkt);
194 195 196
            return CHUNK_EOF;
        }

197 198 199
        pkt->stream_index = s->video_stream_index;
        pkt->pts = s->video_pts;

200
        av_log(s->avf, AV_LOG_TRACE, "sending video frame with pts %"PRId64"\n", pkt->pts);
201

202 203 204 205 206 207
        s->video_pts += s->frame_pts_inc;

        chunk_type = CHUNK_VIDEO;

    } else {

208
        avio_seek(pb, s->next_chunk_offset, SEEK_SET);
209 210 211 212 213 214 215
        chunk_type = CHUNK_DONE;

    }

    return chunk_type;
}

216 217 218 219 220 221 222 223
static int init_audio(AVFormatContext *s)
{
    IPMVEContext *ipmovie = s->priv_data;
    AVStream *st = avformat_new_stream(s, NULL);
    if (!st)
        return AVERROR(ENOMEM);
    avpriv_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate);
    ipmovie->audio_stream_index = st->index;
224 225 226 227 228
    st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
    st->codecpar->codec_id = ipmovie->audio_type;
    st->codecpar->codec_tag = 0;  /* no tag */
    st->codecpar->channels = ipmovie->audio_channels;
    st->codecpar->channel_layout = st->codecpar->channels == 1 ? AV_CH_LAYOUT_MONO :
229
                                                            AV_CH_LAYOUT_STEREO;
230 231 232 233 234 235 236
    st->codecpar->sample_rate = ipmovie->audio_sample_rate;
    st->codecpar->bits_per_coded_sample = ipmovie->audio_bits;
    st->codecpar->bit_rate = st->codecpar->channels * st->codecpar->sample_rate *
        st->codecpar->bits_per_coded_sample;
    if (st->codecpar->codec_id == AV_CODEC_ID_INTERPLAY_DPCM)
        st->codecpar->bit_rate /= 2;
    st->codecpar->block_align = st->codecpar->channels * st->codecpar->bits_per_coded_sample;
237 238 239 240

    return 0;
}

241 242
/* This function loads and processes a single chunk in an IP movie file.
 * It returns the type of chunk that was processed. */
243
static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
244 245 246 247 248 249 250 251 252 253
    AVPacket *pkt)
{
    unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
    int chunk_type;
    int chunk_size;
    unsigned char opcode_preamble[OPCODE_PREAMBLE_SIZE];
    unsigned char opcode_type;
    unsigned char opcode_version;
    int opcode_size;
    unsigned char scratch[1024];
254
    int i, j;
255 256
    int first_color, last_color;
    int audio_flags;
257
    unsigned char r, g, b;
258
    unsigned int width, height;
259 260 261

    /* see if there are any pending packets */
    chunk_type = load_ipmovie_packet(s, pb, pkt);
262
    if (chunk_type != CHUNK_DONE)
263 264 265
        return chunk_type;

    /* read the next chunk, wherever the file happens to be pointing */
266
    if (avio_feof(pb))
267
        return CHUNK_EOF;
268
    if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
269 270
        CHUNK_PREAMBLE_SIZE)
        return CHUNK_BAD;
271 272
    chunk_size = AV_RL16(&chunk_preamble[0]);
    chunk_type = AV_RL16(&chunk_preamble[2]);
273

274
    av_log(s->avf, AV_LOG_TRACE, "chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size);
275 276 277 278

    switch (chunk_type) {

    case CHUNK_INIT_AUDIO:
279
        av_log(s->avf, AV_LOG_TRACE, "initialize audio\n");
280 281 282
        break;

    case CHUNK_AUDIO_ONLY:
283
        av_log(s->avf, AV_LOG_TRACE, "audio only\n");
284 285 286
        break;

    case CHUNK_INIT_VIDEO:
287
        av_log(s->avf, AV_LOG_TRACE, "initialize video\n");
288 289 290
        break;

    case CHUNK_VIDEO:
291
        av_log(s->avf, AV_LOG_TRACE, "video (and audio)\n");
292 293 294
        break;

    case CHUNK_SHUTDOWN:
295
        av_log(s->avf, AV_LOG_TRACE, "shutdown\n");
296 297 298
        break;

    case CHUNK_END:
299
        av_log(s->avf, AV_LOG_TRACE, "end\n");
300 301 302
        break;

    default:
303
        av_log(s->avf, AV_LOG_TRACE, "invalid chunk\n");
304 305 306 307 308 309 310 311
        chunk_type = CHUNK_BAD;
        break;

    }

    while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) {

        /* read the next chunk, wherever the file happens to be pointing */
312
        if (avio_feof(pb)) {
313 314 315
            chunk_type = CHUNK_EOF;
            break;
        }
316
        if (avio_read(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) !=
317 318 319 320 321
            CHUNK_PREAMBLE_SIZE) {
            chunk_type = CHUNK_BAD;
            break;
        }

322
        opcode_size = AV_RL16(&opcode_preamble[0]);
323 324 325 326 327 328
        opcode_type = opcode_preamble[2];
        opcode_version = opcode_preamble[3];

        chunk_size -= OPCODE_PREAMBLE_SIZE;
        chunk_size -= opcode_size;
        if (chunk_size < 0) {
329
            av_log(s->avf, AV_LOG_TRACE, "chunk_size countdown just went negative\n");
330 331 332 333
            chunk_type = CHUNK_BAD;
            break;
        }

334
        av_log(s->avf, AV_LOG_TRACE, "  opcode type %02X, version %d, 0x%04X bytes: ",
335
                opcode_type, opcode_version, opcode_size);
336 337 338
        switch (opcode_type) {

        case OPCODE_END_OF_STREAM:
339
            av_log(s->avf, AV_LOG_TRACE, "end of stream\n");
340
            avio_skip(pb, opcode_size);
341 342 343
            break;

        case OPCODE_END_OF_CHUNK:
344
            av_log(s->avf, AV_LOG_TRACE, "end of chunk\n");
345
            avio_skip(pb, opcode_size);
346 347 348
            break;

        case OPCODE_CREATE_TIMER:
349
            av_log(s->avf, AV_LOG_TRACE, "create timer\n");
350
            if ((opcode_version > 0) || (opcode_size != 6)) {
351
                av_log(s->avf, AV_LOG_TRACE, "bad create_timer opcode\n");
352 353 354
                chunk_type = CHUNK_BAD;
                break;
            }
355
            if (avio_read(pb, scratch, opcode_size) !=
356 357 358 359
                opcode_size) {
                chunk_type = CHUNK_BAD;
                break;
            }
360
            s->frame_pts_inc = ((uint64_t)AV_RL32(&scratch[0])) * AV_RL16(&scratch[4]);
361
            av_log(s->avf, AV_LOG_TRACE, "  %.2f frames/second (timer div = %d, subdiv = %d)\n",
362 363
                    1000000.0 / s->frame_pts_inc, AV_RL32(&scratch[0]),
                    AV_RL16(&scratch[4]));
364 365 366
            break;

        case OPCODE_INIT_AUDIO_BUFFERS:
367
            av_log(s->avf, AV_LOG_TRACE, "initialize audio buffers\n");
368
            if (opcode_version > 1 || opcode_size > 10 || opcode_size < 6) {
369
                av_log(s->avf, AV_LOG_TRACE, "bad init_audio_buffers opcode\n");
370 371 372
                chunk_type = CHUNK_BAD;
                break;
            }
373
            if (avio_read(pb, scratch, opcode_size) !=
374 375 376 377
                opcode_size) {
                chunk_type = CHUNK_BAD;
                break;
            }
378 379
            s->audio_sample_rate = AV_RL16(&scratch[4]);
            audio_flags = AV_RL16(&scratch[2]);
380 381 382 383 384 385
            /* bit 0 of the flags: 0 = mono, 1 = stereo */
            s->audio_channels = (audio_flags & 1) + 1;
            /* bit 1 of the flags: 0 = 8 bit, 1 = 16 bit */
            s->audio_bits = (((audio_flags >> 1) & 1) + 1) * 8;
            /* bit 2 indicates compressed audio in version 1 opcode */
            if ((opcode_version == 1) && (audio_flags & 0x4))
386
                s->audio_type = AV_CODEC_ID_INTERPLAY_DPCM;
387
            else if (s->audio_bits == 16)
388
                s->audio_type = AV_CODEC_ID_PCM_S16LE;
389
            else
390
                s->audio_type = AV_CODEC_ID_PCM_U8;
391
            av_log(s->avf, AV_LOG_TRACE, "audio: %d bits, %d Hz, %s, %s format\n",
392 393
                    s->audio_bits, s->audio_sample_rate,
                    (s->audio_channels == 2) ? "stereo" : "mono",
394
                    (s->audio_type == AV_CODEC_ID_INTERPLAY_DPCM) ?
395
                    "Interplay audio" : "PCM");
396 397 398
            break;

        case OPCODE_START_STOP_AUDIO:
399
            av_log(s->avf, AV_LOG_TRACE, "start/stop audio\n");
400
            avio_skip(pb, opcode_size);
401 402 403
            break;

        case OPCODE_INIT_VIDEO_BUFFERS:
404
            av_log(s->avf, AV_LOG_TRACE, "initialize video buffers\n");
405 406 407
            if ((opcode_version > 2) || (opcode_size > 8) || opcode_size < 4
                || opcode_version == 2 && opcode_size < 8
            ) {
408
                av_log(s->avf, AV_LOG_TRACE, "bad init_video_buffers opcode\n");
409 410 411
                chunk_type = CHUNK_BAD;
                break;
            }
412
            if (avio_read(pb, scratch, opcode_size) !=
413 414 415 416
                opcode_size) {
                chunk_type = CHUNK_BAD;
                break;
            }
417 418 419 420 421 422 423 424 425 426
            width  = AV_RL16(&scratch[0]) * 8;
            height = AV_RL16(&scratch[2]) * 8;
            if (width != s->video_width) {
                s->video_width = width;
                s->changed++;
            }
            if (height != s->video_height) {
                s->video_height = height;
                s->changed++;
            }
427 428 429 430 431
            if (opcode_version < 2 || !AV_RL16(&scratch[6])) {
                s->video_bpp = 8;
            } else {
                s->video_bpp = 16;
            }
432
            av_log(s->avf, AV_LOG_TRACE, "video resolution: %d x %d\n",
433
                    s->video_width, s->video_height);
434 435 436 437 438 439 440 441 442
            break;

        case OPCODE_UNKNOWN_06:
        case OPCODE_UNKNOWN_0E:
        case OPCODE_UNKNOWN_10:
        case OPCODE_UNKNOWN_12:
        case OPCODE_UNKNOWN_13:
        case OPCODE_UNKNOWN_14:
        case OPCODE_UNKNOWN_15:
443
            av_log(s->avf, AV_LOG_TRACE, "unknown (but documented) opcode %02X\n", opcode_type);
444
            avio_skip(pb, opcode_size);
445 446 447
            break;

        case OPCODE_SEND_BUFFER:
448
            av_log(s->avf, AV_LOG_TRACE, "send buffer\n");
449
            avio_skip(pb, opcode_size);
450 451 452
            break;

        case OPCODE_AUDIO_FRAME:
453
            av_log(s->avf, AV_LOG_TRACE, "audio frame\n");
454 455

            /* log position and move on for now */
456
            s->audio_chunk_offset = avio_tell(pb);
457
            s->audio_chunk_size = opcode_size;
458
            avio_skip(pb, opcode_size);
459 460 461
            break;

        case OPCODE_SILENCE_FRAME:
462
            av_log(s->avf, AV_LOG_TRACE, "silence frame\n");
463
            avio_skip(pb, opcode_size);
464 465 466
            break;

        case OPCODE_INIT_VIDEO_MODE:
467
            av_log(s->avf, AV_LOG_TRACE, "initialize video mode\n");
468
            avio_skip(pb, opcode_size);
469 470 471
            break;

        case OPCODE_CREATE_GRADIENT:
472
            av_log(s->avf, AV_LOG_TRACE, "create gradient\n");
473
            avio_skip(pb, opcode_size);
474 475 476
            break;

        case OPCODE_SET_PALETTE:
477
            av_log(s->avf, AV_LOG_TRACE, "set palette\n");
478 479
            /* check for the logical maximum palette size
             * (3 * 256 + 4 bytes) */
480
            if (opcode_size > 0x304 || opcode_size < 4) {
481
                av_log(s->avf, AV_LOG_TRACE, "demux_ipmovie: set_palette opcode with invalid size\n");
482 483 484
                chunk_type = CHUNK_BAD;
                break;
            }
485
            if (avio_read(pb, scratch, opcode_size) != opcode_size) {
486 487 488 489 490
                chunk_type = CHUNK_BAD;
                break;
            }

            /* load the palette into internal data structure */
491 492
            first_color = AV_RL16(&scratch[0]);
            last_color = first_color + AV_RL16(&scratch[2]) - 1;
493
            /* sanity check (since they are 16 bit values) */
494 495
            if (   (first_color > 0xFF) || (last_color > 0xFF)
                || (last_color - first_color + 1)*3 + 4 > opcode_size) {
496
                av_log(s->avf, AV_LOG_TRACE, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n",
497 498 499 500 501 502
                    first_color, last_color);
                chunk_type = CHUNK_BAD;
                break;
            }
            j = 4;  /* offset of first palette data */
            for (i = first_color; i <= last_color; i++) {
503 504
                /* the palette is stored as a 6-bit VGA palette, thus each
                 * component is shifted up to a 8-bit range */
505 506 507
                r = scratch[j++] * 4;
                g = scratch[j++] * 4;
                b = scratch[j++] * 4;
508 509
                s->palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
                s->palette[i] |= s->palette[i] >> 6 & 0x30303;
510
            }
511
            s->has_palette = 1;
512 513 514
            break;

        case OPCODE_SET_PALETTE_COMPRESSED:
515
            av_log(s->avf, AV_LOG_TRACE, "set palette compressed\n");
516
            avio_skip(pb, opcode_size);
517 518 519
            break;

        case OPCODE_SET_DECODING_MAP:
520
            av_log(s->avf, AV_LOG_TRACE, "set decoding map\n");
521 522

            /* log position and move on for now */
523
            s->decode_map_chunk_offset = avio_tell(pb);
524
            s->decode_map_chunk_size = opcode_size;
525
            avio_skip(pb, opcode_size);
526 527 528
            break;

        case OPCODE_VIDEO_DATA:
529
            av_log(s->avf, AV_LOG_TRACE, "set video data\n");
530 531

            /* log position and move on for now */
532
            s->video_chunk_offset = avio_tell(pb);
533
            s->video_chunk_size = opcode_size;
534
            avio_skip(pb, opcode_size);
535 536 537
            break;

        default:
538
            av_log(s->avf, AV_LOG_TRACE, "*** unknown opcode type\n");
539 540 541 542 543 544
            chunk_type = CHUNK_BAD;
            break;

        }
    }

545 546 547
    if (s->avf->nb_streams == 1 && s->audio_type)
        init_audio(s->avf);

548
    /* make a note of where the stream is sitting */
549
    s->next_chunk_offset = avio_tell(pb);
550 551 552 553 554 555 556 557

    /* dispatch the first of any pending packets */
    if ((chunk_type == CHUNK_VIDEO) || (chunk_type == CHUNK_AUDIO_ONLY))
        chunk_type = load_ipmovie_packet(s, pb, pkt);

    return chunk_type;
}

558 559
static const char signature[] = "Interplay MVE File\x1A\0\x1A";

560 561
static int ipmovie_probe(AVProbeData *p)
{
562 563
    const uint8_t *b = p->buf;
    const uint8_t *b_end = p->buf + p->buf_size - sizeof(signature);
564
    do {
565
        if (b[0] == signature[0] && memcmp(b, signature, sizeof(signature)) == 0)
566
            return AVPROBE_SCORE_MAX;
567
        b++;
568 569 570
    } while (b < b_end);

    return 0;
571 572
}

573
static int ipmovie_read_header(AVFormatContext *s)
574
{
575
    IPMVEContext *ipmovie = s->priv_data;
576
    AVIOContext *pb = s->pb;
577 578
    AVPacket pkt;
    AVStream *st;
579
    unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
580
    int chunk_type, i;
581 582
    uint8_t signature_buffer[sizeof(signature)];

583 584
    ipmovie->avf = s;

585
    avio_read(pb, signature_buffer, sizeof(signature_buffer));
586 587
    while (memcmp(signature_buffer, signature, sizeof(signature))) {
        memmove(signature_buffer, signature_buffer + 1, sizeof(signature_buffer) - 1);
588
        signature_buffer[sizeof(signature_buffer) - 1] = avio_r8(pb);
589
        if (avio_feof(pb))
590 591
            return AVERROR_EOF;
    }
592 593 594 595 596 597
    /* initialize private context members */
    ipmovie->video_pts = ipmovie->audio_frame_count = 0;
    ipmovie->audio_chunk_offset = ipmovie->video_chunk_offset =
    ipmovie->decode_map_chunk_offset = 0;

    /* on the first read, this will position the stream at the first chunk */
598
    ipmovie->next_chunk_offset = avio_tell(pb) + 4;
599

600 601 602
    for (i = 0; i < 256; i++)
        ipmovie->palette[i] = 0xFFU << 24;

603 604 605 606
    /* process the first chunk which should be CHUNK_INIT_VIDEO */
    if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO)
        return AVERROR_INVALIDDATA;

607 608
    /* peek ahead to the next chunk-- if it is an init audio chunk, process
     * it; if it is the first video chunk, this is a silent file */
609
    if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
610
        CHUNK_PREAMBLE_SIZE)
611
        return AVERROR(EIO);
612
    chunk_type = AV_RL16(&chunk_preamble[2]);
613
    avio_seek(pb, -CHUNK_PREAMBLE_SIZE, SEEK_CUR);
614 615

    if (chunk_type == CHUNK_VIDEO)
616
        ipmovie->audio_type = AV_CODEC_ID_NONE;  /* no audio */
617
    else if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO)
618 619 620
        return AVERROR_INVALIDDATA;

    /* initialize the stream decoders */
621
    st = avformat_new_stream(s, NULL);
622
    if (!st)
623
        return AVERROR(ENOMEM);
624
    avpriv_set_pts_info(st, 63, 1, 1000000);
625
    ipmovie->video_stream_index = st->index;
626 627 628 629 630 631
    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
    st->codecpar->codec_id = AV_CODEC_ID_INTERPLAY_VIDEO;
    st->codecpar->codec_tag = 0;  /* no fourcc */
    st->codecpar->width = ipmovie->video_width;
    st->codecpar->height = ipmovie->video_height;
    st->codecpar->bits_per_coded_sample = ipmovie->video_bpp;
632

633
    if (ipmovie->audio_type) {
634
        return init_audio(s);
635 636
    } else
       s->ctx_flags |= AVFMTCTX_NOHEADER;
637 638 639 640 641 642 643

    return 0;
}

static int ipmovie_read_packet(AVFormatContext *s,
                               AVPacket *pkt)
{
644
    IPMVEContext *ipmovie = s->priv_data;
645
    AVIOContext *pb = s->pb;
646 647
    int ret;

648
    for (;;) {
649 650 651 652
    ret = process_ipmovie_chunk(ipmovie, pb, pkt);
    if (ret == CHUNK_BAD)
        ret = AVERROR_INVALIDDATA;
    else if (ret == CHUNK_EOF)
653
        ret = AVERROR(EIO);
654
    else if (ret == CHUNK_NOMEM)
655
        ret = AVERROR(ENOMEM);
656
    else if (ret == CHUNK_VIDEO)
657
        ret = 0;
658 659
    else if (ret == CHUNK_INIT_VIDEO || ret == CHUNK_INIT_AUDIO)
        continue;
660
    else
661
        continue;
662 663

    return ret;
664
    }
665 666
}

667
AVInputFormat ff_ipmovie_demuxer = {
668
    .name           = "ipmovie",
669
    .long_name      = NULL_IF_CONFIG_SMALL("Interplay MVE"),
670 671 672 673
    .priv_data_size = sizeof(IPMVEContext),
    .read_probe     = ipmovie_probe,
    .read_header    = ipmovie_read_header,
    .read_packet    = ipmovie_read_packet,
674
};