ipmovie.c 21.3 KB
Newer Older
1 2 3 4
/*
 * Interplay MVE File Demuxer
 * Copyright (c) 2003 The ffmpeg Project
 *
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/intreadwrite.h"
36
#include "avformat.h"
37
#include "internal.h"
38 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

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

84
    uint64_t frame_pts_inc;
85

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

    unsigned int audio_bits;
    unsigned int audio_channels;
    unsigned int audio_sample_rate;
97
    enum CodecID audio_type;
98 99 100 101 102
    unsigned int audio_frame_count;

    int video_stream_index;
    int audio_stream_index;

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

110
    int64_t next_chunk_offset;
111 112 113

} IPMVEContext;

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

    int chunk_type;

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

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

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

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

        pkt->stream_index = s->audio_stream_index;
139
        pkt->pts = s->audio_frame_count;
140 141 142 143 144 145 146

        /* audio frame maintenance */
        if (s->audio_type != CODEC_ID_INTERPLAY_DPCM)
            s->audio_frame_count +=
            (s->audio_chunk_size / s->audio_channels / (s->audio_bits / 8));
        else
            s->audio_frame_count +=
147
                (s->audio_chunk_size - 6 - s->audio_channels) / s->audio_channels;
148

149 150
        av_dlog(NULL, "sending audio frame with pts %"PRId64" (%d audio frames)\n",
                pkt->pts, s->audio_frame_count);
151 152 153 154 155

        chunk_type = CHUNK_VIDEO;

    } else if (s->decode_map_chunk_offset) {

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

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

161 162 163 164 165 166 167 168 169 170 171
        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;
            }
        }

172 173 174 175
        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
176
        pkt->pos= s->decode_map_chunk_offset;
177
        avio_seek(pb, s->decode_map_chunk_offset, SEEK_SET);
178 179
        s->decode_map_chunk_offset = 0;

180
        if (avio_read(pb, pkt->data, s->decode_map_chunk_size) !=
181 182 183 184 185
            s->decode_map_chunk_size) {
            av_free_packet(pkt);
            return CHUNK_EOF;
        }

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

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

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

198
        av_dlog(NULL, "sending video frame with pts %"PRId64"\n", pkt->pts);
199

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

        chunk_type = CHUNK_VIDEO;

    } else {

206
        avio_seek(pb, s->next_chunk_offset, SEEK_SET);
207 208 209 210 211 212 213 214 215
        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. */
216
static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
217 218 219 220 221 222 223 224 225 226
    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];
227
    int i, j;
228 229
    int first_color, last_color;
    int audio_flags;
230
    unsigned char r, g, b;
231
    unsigned int width, height;
232 233 234

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

    /* read the next chunk, wherever the file happens to be pointing */
    if (url_feof(pb))
        return CHUNK_EOF;
241
    if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
242 243
        CHUNK_PREAMBLE_SIZE)
        return CHUNK_BAD;
244 245
    chunk_size = AV_RL16(&chunk_preamble[0]);
    chunk_type = AV_RL16(&chunk_preamble[2]);
246

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

    switch (chunk_type) {

    case CHUNK_INIT_AUDIO:
252
        av_dlog(NULL, "initialize audio\n");
253 254 255
        break;

    case CHUNK_AUDIO_ONLY:
256
        av_dlog(NULL, "audio only\n");
257 258 259
        break;

    case CHUNK_INIT_VIDEO:
260
        av_dlog(NULL, "initialize video\n");
261 262 263
        break;

    case CHUNK_VIDEO:
264
        av_dlog(NULL, "video (and audio)\n");
265 266 267
        break;

    case CHUNK_SHUTDOWN:
268
        av_dlog(NULL, "shutdown\n");
269 270 271
        break;

    case CHUNK_END:
272
        av_dlog(NULL, "end\n");
273 274 275
        break;

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

    }

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

        /* read the next chunk, wherever the file happens to be pointing */
Reimar Döffinger's avatar
Reimar Döffinger committed
285
        if (url_feof(pb)) {
286 287 288
            chunk_type = CHUNK_EOF;
            break;
        }
289
        if (avio_read(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) !=
290 291 292 293 294
            CHUNK_PREAMBLE_SIZE) {
            chunk_type = CHUNK_BAD;
            break;
        }

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

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

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

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

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

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

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

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

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

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

        case OPCODE_AUDIO_FRAME:
424
            av_dlog(NULL, "audio frame\n");
425 426

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

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

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

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

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

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

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

        case OPCODE_SET_DECODING_MAP:
490
            av_dlog(NULL, "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_dlog(NULL, "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_dlog(NULL, "*** 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
    unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
546
    int chunk_type, i;
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);
553 554 555
        if (url_feof(pb))
            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
    for (i = 0; i < 256; i++)
        ipmovie->palette[i] = 0xFFU << 24;

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

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

    if (chunk_type == CHUNK_VIDEO)
580
        ipmovie->audio_type = CODEC_ID_NONE;  /* no audio */
581
    else if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO)
582 583 584
        return AVERROR_INVALIDDATA;

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

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

    return 0;
}

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

626
    for (;;) {
627 628 629 630
    ret = process_ipmovie_chunk(ipmovie, pb, pkt);
    if (ret == CHUNK_BAD)
        ret = AVERROR_INVALIDDATA;
    else if (ret == CHUNK_EOF)
631
        ret = AVERROR(EIO);
632
    else if (ret == CHUNK_NOMEM)
633
        ret = AVERROR(ENOMEM);
634
    else if (ret == CHUNK_VIDEO)
635
        ret = 0;
636 637
    else if (ret == CHUNK_INIT_VIDEO || ret == CHUNK_INIT_AUDIO)
        continue;
638 639
    else
        ret = -1;
640 641

    return ret;
642
    }
643 644
}

645
AVInputFormat ff_ipmovie_demuxer = {
646 647 648 649 650 651
    .name           = "ipmovie",
    .long_name      = NULL_IF_CONFIG_SMALL("Interplay MVE format"),
    .priv_data_size = sizeof(IPMVEContext),
    .read_probe     = ipmovie_probe,
    .read_header    = ipmovie_read_header,
    .read_packet    = ipmovie_read_packet,
652
};