ipmovie.c 21.7 KB
Newer Older
1 2 3 4
/*
 * Interplay MVE File Demuxer
 * Copyright (c) 2003 The ffmpeg Project
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav 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
 * Libav 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 Libav; 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 81 82 83 84

#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 {

    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 120
    AVPacket *pkt) {

    int chunk_type;

    if (s->audio_chunk_offset) {
121
        if (s->audio_type == AV_CODEC_ID_NONE) {
122 123 124 125
            av_log(NULL, AV_LOG_ERROR, "Can not read audio packet before"
                   "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(NULL, 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, 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
        if (avio_read(pb, pkt->data, s->decode_map_chunk_size) !=
182
            s->decode_map_chunk_size) {
183
            av_packet_unref(pkt);
184 185 186
            return CHUNK_EOF;
        }

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

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

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

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

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

        chunk_type = CHUNK_VIDEO;

    } else {

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

    }

    return chunk_type;
}

/* This function loads and processes a single chunk in an IP movie file.
 * It returns the type of chunk that was processed. */
217
static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
218 219 220 221 222 223 224 225 226 227
    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];
228
    int i, j;
229 230
    int first_color, last_color;
    int audio_flags;
231
    unsigned char r, g, b;
232
    unsigned int width, height;
233 234 235

    /* see if there are any pending packets */
    chunk_type = load_ipmovie_packet(s, pb, pkt);
236
    if (chunk_type != CHUNK_DONE)
237 238 239
        return chunk_type;

    /* read the next chunk, wherever the file happens to be pointing */
Anton Khirnov's avatar
Anton Khirnov committed
240
    if (pb->eof_reached)
241
        return CHUNK_EOF;
242
    if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
243 244
        CHUNK_PREAMBLE_SIZE)
        return CHUNK_BAD;
245 246
    chunk_size = AV_RL16(&chunk_preamble[0]);
    chunk_type = AV_RL16(&chunk_preamble[2]);
247

248
    av_log(NULL, AV_LOG_TRACE, "chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size);
249 250 251 252

    switch (chunk_type) {

    case CHUNK_INIT_AUDIO:
253
        av_log(NULL, AV_LOG_TRACE, "initialize audio\n");
254 255 256
        break;

    case CHUNK_AUDIO_ONLY:
257
        av_log(NULL, AV_LOG_TRACE, "audio only\n");
258 259 260
        break;

    case CHUNK_INIT_VIDEO:
261
        av_log(NULL, AV_LOG_TRACE, "initialize video\n");
262 263 264
        break;

    case CHUNK_VIDEO:
265
        av_log(NULL, AV_LOG_TRACE, "video (and audio)\n");
266 267 268
        break;

    case CHUNK_SHUTDOWN:
269
        av_log(NULL, AV_LOG_TRACE, "shutdown\n");
270 271 272
        break;

    case CHUNK_END:
273
        av_log(NULL, AV_LOG_TRACE, "end\n");
274 275 276
        break;

    default:
277
        av_log(NULL, AV_LOG_TRACE, "invalid chunk\n");
278 279 280 281 282 283 284 285
        chunk_type = CHUNK_BAD;
        break;

    }

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

        /* read the next chunk, wherever the file happens to be pointing */
Anton Khirnov's avatar
Anton Khirnov committed
286
        if (pb->eof_reached) {
287 288 289
            chunk_type = CHUNK_EOF;
            break;
        }
290
        if (avio_read(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) !=
291 292 293 294 295
            CHUNK_PREAMBLE_SIZE) {
            chunk_type = CHUNK_BAD;
            break;
        }

296
        opcode_size = AV_RL16(&opcode_preamble[0]);
297 298 299 300 301 302
        opcode_type = opcode_preamble[2];
        opcode_version = opcode_preamble[3];

        chunk_size -= OPCODE_PREAMBLE_SIZE;
        chunk_size -= opcode_size;
        if (chunk_size < 0) {
303
            av_log(NULL, AV_LOG_TRACE, "chunk_size countdown just went negative\n");
304 305 306 307
            chunk_type = CHUNK_BAD;
            break;
        }

308
        av_log(NULL, AV_LOG_TRACE, "  opcode type %02X, version %d, 0x%04X bytes: ",
309
                opcode_type, opcode_version, opcode_size);
310 311 312
        switch (opcode_type) {

        case OPCODE_END_OF_STREAM:
313
            av_log(NULL, AV_LOG_TRACE, "end of stream\n");
314
            avio_skip(pb, opcode_size);
315 316 317
            break;

        case OPCODE_END_OF_CHUNK:
318
            av_log(NULL, AV_LOG_TRACE, "end of chunk\n");
319
            avio_skip(pb, opcode_size);
320 321 322
            break;

        case OPCODE_CREATE_TIMER:
323
            av_log(NULL, AV_LOG_TRACE, "create timer\n");
324
            if ((opcode_version > 0) || (opcode_size > 6)) {
325
                av_log(NULL, AV_LOG_TRACE, "bad create_timer opcode\n");
326 327 328
                chunk_type = CHUNK_BAD;
                break;
            }
329
            if (avio_read(pb, scratch, opcode_size) !=
330 331 332 333
                opcode_size) {
                chunk_type = CHUNK_BAD;
                break;
            }
334
            s->frame_pts_inc = ((uint64_t)AV_RL32(&scratch[0])) * AV_RL16(&scratch[4]);
335
            av_log(NULL, AV_LOG_TRACE, "  %.2f frames/second (timer div = %d, subdiv = %d)\n",
336 337
                    1000000.0 / s->frame_pts_inc, AV_RL32(&scratch[0]),
                    AV_RL16(&scratch[4]));
338 339 340
            break;

        case OPCODE_INIT_AUDIO_BUFFERS:
341
            av_log(NULL, AV_LOG_TRACE, "initialize audio buffers\n");
342
            if ((opcode_version > 1) || (opcode_size > 10)) {
343
                av_log(NULL, AV_LOG_TRACE, "bad init_audio_buffers opcode\n");
344 345 346
                chunk_type = CHUNK_BAD;
                break;
            }
347
            if (avio_read(pb, scratch, opcode_size) !=
348 349 350 351
                opcode_size) {
                chunk_type = CHUNK_BAD;
                break;
            }
352 353
            s->audio_sample_rate = AV_RL16(&scratch[4]);
            audio_flags = AV_RL16(&scratch[2]);
354 355 356 357 358 359
            /* 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))
360
                s->audio_type = AV_CODEC_ID_INTERPLAY_DPCM;
361
            else if (s->audio_bits == 16)
362
                s->audio_type = AV_CODEC_ID_PCM_S16LE;
363
            else
364
                s->audio_type = AV_CODEC_ID_PCM_U8;
365
            av_log(NULL, AV_LOG_TRACE, "audio: %d bits, %d Hz, %s, %s format\n",
366 367
                    s->audio_bits, s->audio_sample_rate,
                    (s->audio_channels == 2) ? "stereo" : "mono",
368
                    (s->audio_type == AV_CODEC_ID_INTERPLAY_DPCM) ?
369
                    "Interplay audio" : "PCM");
370 371 372
            break;

        case OPCODE_START_STOP_AUDIO:
373
            av_log(NULL, AV_LOG_TRACE, "start/stop audio\n");
374
            avio_skip(pb, opcode_size);
375 376 377
            break;

        case OPCODE_INIT_VIDEO_BUFFERS:
378
            av_log(NULL, AV_LOG_TRACE, "initialize video buffers\n");
379
            if ((opcode_version > 2) || (opcode_size > 8)) {
380
                av_log(NULL, AV_LOG_TRACE, "bad init_video_buffers opcode\n");
381 382 383
                chunk_type = CHUNK_BAD;
                break;
            }
384
            if (avio_read(pb, scratch, opcode_size) !=
385 386 387 388
                opcode_size) {
                chunk_type = CHUNK_BAD;
                break;
            }
389 390 391 392 393 394 395 396 397 398
            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++;
            }
399 400 401 402 403
            if (opcode_version < 2 || !AV_RL16(&scratch[6])) {
                s->video_bpp = 8;
            } else {
                s->video_bpp = 16;
            }
404
            av_log(NULL, AV_LOG_TRACE, "video resolution: %d x %d\n",
405
                    s->video_width, s->video_height);
406 407 408 409 410 411 412 413 414
            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:
415
            av_log(NULL, AV_LOG_TRACE, "unknown (but documented) opcode %02X\n", opcode_type);
416
            avio_skip(pb, opcode_size);
417 418 419
            break;

        case OPCODE_SEND_BUFFER:
420
            av_log(NULL, AV_LOG_TRACE, "send buffer\n");
421
            avio_skip(pb, opcode_size);
422 423 424
            break;

        case OPCODE_AUDIO_FRAME:
425
            av_log(NULL, AV_LOG_TRACE, "audio frame\n");
426 427

            /* log position and move on for now */
428
            s->audio_chunk_offset = avio_tell(pb);
429
            s->audio_chunk_size = opcode_size;
430
            avio_skip(pb, opcode_size);
431 432 433
            break;

        case OPCODE_SILENCE_FRAME:
434
            av_log(NULL, AV_LOG_TRACE, "silence frame\n");
435
            avio_skip(pb, opcode_size);
436 437 438
            break;

        case OPCODE_INIT_VIDEO_MODE:
439
            av_log(NULL, AV_LOG_TRACE, "initialize video mode\n");
440
            avio_skip(pb, opcode_size);
441 442 443
            break;

        case OPCODE_CREATE_GRADIENT:
444
            av_log(NULL, AV_LOG_TRACE, "create gradient\n");
445
            avio_skip(pb, opcode_size);
446 447 448
            break;

        case OPCODE_SET_PALETTE:
449
            av_log(NULL, AV_LOG_TRACE, "set palette\n");
450 451 452
            /* check for the logical maximum palette size
             * (3 * 256 + 4 bytes) */
            if (opcode_size > 0x304) {
453
                av_log(NULL, AV_LOG_TRACE, "demux_ipmovie: set_palette opcode too large\n");
454 455 456
                chunk_type = CHUNK_BAD;
                break;
            }
457
            if (avio_read(pb, scratch, opcode_size) != opcode_size) {
458 459 460 461 462
                chunk_type = CHUNK_BAD;
                break;
            }

            /* load the palette into internal data structure */
463 464
            first_color = AV_RL16(&scratch[0]);
            last_color = first_color + AV_RL16(&scratch[2]) - 1;
465 466
            /* sanity check (since they are 16 bit values) */
            if ((first_color > 0xFF) || (last_color > 0xFF)) {
467
                av_log(NULL, AV_LOG_TRACE, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n",
468 469 470 471 472 473
                    first_color, last_color);
                chunk_type = CHUNK_BAD;
                break;
            }
            j = 4;  /* offset of first palette data */
            for (i = first_color; i <= last_color; i++) {
474 475
                /* the palette is stored as a 6-bit VGA palette, thus each
                 * component is shifted up to a 8-bit range */
476 477 478
                r = scratch[j++] * 4;
                g = scratch[j++] * 4;
                b = scratch[j++] * 4;
479
                s->palette[i] = (r << 16) | (g << 8) | (b);
480
            }
481
            s->has_palette = 1;
482 483 484
            break;

        case OPCODE_SET_PALETTE_COMPRESSED:
485
            av_log(NULL, AV_LOG_TRACE, "set palette compressed\n");
486
            avio_skip(pb, opcode_size);
487 488 489
            break;

        case OPCODE_SET_DECODING_MAP:
490
            av_log(NULL, AV_LOG_TRACE, "set decoding map\n");
491 492

            /* log position and move on for now */
493
            s->decode_map_chunk_offset = avio_tell(pb);
494
            s->decode_map_chunk_size = opcode_size;
495
            avio_skip(pb, opcode_size);
496 497 498
            break;

        case OPCODE_VIDEO_DATA:
499
            av_log(NULL, AV_LOG_TRACE, "set video data\n");
500 501

            /* log position and move on for now */
502
            s->video_chunk_offset = avio_tell(pb);
503
            s->video_chunk_size = opcode_size;
504
            avio_skip(pb, opcode_size);
505 506 507
            break;

        default:
508
            av_log(NULL, AV_LOG_TRACE, "*** unknown opcode type\n");
509 510 511 512 513 514 515
            chunk_type = CHUNK_BAD;
            break;

        }
    }

    /* make a note of where the stream is sitting */
516
    s->next_chunk_offset = avio_tell(pb);
517 518 519 520 521 522 523 524

    /* 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;
}

525 526
static const char signature[] = "Interplay MVE File\x1A\0\x1A";

527 528
static int ipmovie_probe(AVProbeData *p)
{
529 530 531 532 533 534 535 536
    uint8_t *b = p->buf;
    uint8_t *b_end = p->buf + p->buf_size - sizeof(signature);
    do {
        if (memcmp(b++, signature, sizeof(signature)) == 0)
            return AVPROBE_SCORE_MAX;
    } while (b < b_end);

    return 0;
537 538
}

539
static int ipmovie_read_header(AVFormatContext *s)
540
{
541
    IPMVEContext *ipmovie = s->priv_data;
542
    AVIOContext *pb = s->pb;
543 544
    AVPacket pkt;
    AVStream *st;
545 546
    unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
    int chunk_type;
547 548
    uint8_t signature_buffer[sizeof(signature)];

549
    avio_read(pb, signature_buffer, sizeof(signature_buffer));
550 551
    while (memcmp(signature_buffer, signature, sizeof(signature))) {
        memmove(signature_buffer, signature_buffer + 1, sizeof(signature_buffer) - 1);
552
        signature_buffer[sizeof(signature_buffer) - 1] = avio_r8(pb);
Anton Khirnov's avatar
Anton Khirnov committed
553
        if (pb->eof_reached)
554 555
            return AVERROR_EOF;
    }
556 557 558 559 560 561
    /* 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 */
562
    ipmovie->next_chunk_offset = avio_tell(pb) + 4;
563 564 565 566 567

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

568 569
    /* 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 */
570
    if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
571
        CHUNK_PREAMBLE_SIZE)
572
        return AVERROR(EIO);
573
    chunk_type = AV_RL16(&chunk_preamble[2]);
574
    avio_seek(pb, -CHUNK_PREAMBLE_SIZE, SEEK_CUR);
575 576

    if (chunk_type == CHUNK_VIDEO)
577
        ipmovie->audio_type = AV_CODEC_ID_NONE;  /* no audio */
578
    else if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO)
579 580 581
        return AVERROR_INVALIDDATA;

    /* initialize the stream decoders */
582
    st = avformat_new_stream(s, NULL);
583
    if (!st)
584
        return AVERROR(ENOMEM);
585
    avpriv_set_pts_info(st, 63, 1, 1000000);
586
    ipmovie->video_stream_index = st->index;
587
    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
588
    st->codec->codec_id = AV_CODEC_ID_INTERPLAY_VIDEO;
589 590 591
    st->codec->codec_tag = 0;  /* no fourcc */
    st->codec->width = ipmovie->video_width;
    st->codec->height = ipmovie->video_height;
592
    st->codec->bits_per_coded_sample = ipmovie->video_bpp;
593

594
    if (ipmovie->audio_type) {
595
        st = avformat_new_stream(s, NULL);
596
        if (!st)
597
            return AVERROR(ENOMEM);
598
        avpriv_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate);
599
        ipmovie->audio_stream_index = st->index;
600
        st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
601 602 603
        st->codec->codec_id = ipmovie->audio_type;
        st->codec->codec_tag = 0;  /* no tag */
        st->codec->channels = ipmovie->audio_channels;
604 605
        st->codec->channel_layout = st->codec->channels == 1 ? AV_CH_LAYOUT_MONO :
                                                               AV_CH_LAYOUT_STEREO;
606
        st->codec->sample_rate = ipmovie->audio_sample_rate;
607
        st->codec->bits_per_coded_sample = ipmovie->audio_bits;
608
        st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
609
            st->codec->bits_per_coded_sample;
610
        if (st->codec->codec_id == AV_CODEC_ID_INTERPLAY_DPCM)
611
            st->codec->bit_rate /= 2;
612
        st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
613
    }
614 615 616 617 618 619 620

    return 0;
}

static int ipmovie_read_packet(AVFormatContext *s,
                               AVPacket *pkt)
{
621
    IPMVEContext *ipmovie = s->priv_data;
622
    AVIOContext *pb = s->pb;
623 624 625 626 627 628
    int ret;

    ret = process_ipmovie_chunk(ipmovie, pb, pkt);
    if (ret == CHUNK_BAD)
        ret = AVERROR_INVALIDDATA;
    else if (ret == CHUNK_EOF)
629
        ret = AVERROR(EIO);
630
    else if (ret == CHUNK_NOMEM)
631
        ret = AVERROR(ENOMEM);
632
    else if (ret == CHUNK_VIDEO)
633
        ret = 0;
634 635
    else
        ret = -1;
636 637 638 639

    return ret;
}

640
AVInputFormat ff_ipmovie_demuxer = {
641
    .name           = "ipmovie",
642
    .long_name      = NULL_IF_CONFIG_SMALL("Interplay MVE"),
643 644 645 646
    .priv_data_size = sizeof(IPMVEContext),
    .read_probe     = ipmovie_probe,
    .read_header    = ipmovie_read_header,
    .read_packet    = ipmovie_read_packet,
647
};