Statistics
| Branch: | Revision:

ffmpeg / libavformat / ipmovie.c @ a7eb3c8d

History | View | Annotate | Download (20.4 KB)

1
/*
2
 * Interplay MVE File Demuxer
3
 * Copyright (c) 2003 The ffmpeg Project
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19

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

    
33
#include "avformat.h"
34

    
35
/* debugging support: #define DEBUG_IPMOVIE as non-zero to see extremely
36
 * verbose information about the demux process */
37
#define DEBUG_IPMOVIE 0
38

    
39
#if DEBUG_IPMOVIE
40
#define debug_ipmovie printf
41
#else
42
static inline void debug_ipmovie(const char *format, ...) { }
43
#endif
44

    
45

    
46
#define LE_16(x)  ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
47
#define LE_32(x)  ((((uint8_t*)(x))[3] << 24) | \
48
                   (((uint8_t*)(x))[2] << 16) | \
49
                   (((uint8_t*)(x))[1] << 8) | \
50
                    ((uint8_t*)(x))[0])
51

    
52
#define IPMOVIE_SIGNATURE "Interplay MVE File\x1A\0"
53
#define IPMOVIE_SIGNATURE_SIZE 20
54
#define CHUNK_PREAMBLE_SIZE 4
55
#define OPCODE_PREAMBLE_SIZE 4
56

    
57
#define CHUNK_INIT_AUDIO   0x0000
58
#define CHUNK_AUDIO_ONLY   0x0001
59
#define CHUNK_INIT_VIDEO   0x0002
60
#define CHUNK_VIDEO        0x0003
61
#define CHUNK_SHUTDOWN     0x0004
62
#define CHUNK_END          0x0005
63
/* these last types are used internally */
64
#define CHUNK_DONE         0xFFFC
65
#define CHUNK_NOMEM        0xFFFD
66
#define CHUNK_EOF          0xFFFE
67
#define CHUNK_BAD          0xFFFF
68

    
69
#define OPCODE_END_OF_STREAM           0x00
70
#define OPCODE_END_OF_CHUNK            0x01
71
#define OPCODE_CREATE_TIMER            0x02
72
#define OPCODE_INIT_AUDIO_BUFFERS      0x03
73
#define OPCODE_START_STOP_AUDIO        0x04
74
#define OPCODE_INIT_VIDEO_BUFFERS      0x05
75
#define OPCODE_UNKNOWN_06              0x06
76
#define OPCODE_SEND_BUFFER             0x07
77
#define OPCODE_AUDIO_FRAME             0x08
78
#define OPCODE_SILENCE_FRAME           0x09
79
#define OPCODE_INIT_VIDEO_MODE         0x0A
80
#define OPCODE_CREATE_GRADIENT         0x0B
81
#define OPCODE_SET_PALETTE             0x0C
82
#define OPCODE_SET_PALETTE_COMPRESSED  0x0D
83
#define OPCODE_UNKNOWN_0E              0x0E
84
#define OPCODE_SET_DECODING_MAP        0x0F
85
#define OPCODE_UNKNOWN_10              0x10
86
#define OPCODE_VIDEO_DATA              0x11
87
#define OPCODE_UNKNOWN_12              0x12
88
#define OPCODE_UNKNOWN_13              0x13
89
#define OPCODE_UNKNOWN_14              0x14
90
#define OPCODE_UNKNOWN_15              0x15
91

    
92
#define PALETTE_COUNT 256
93

    
94
typedef struct IPMVEContext {
95

    
96
    unsigned char *buf;
97
    int buf_size;
98

    
99
    float fps;
100
    int frame_pts_inc;
101

    
102
    unsigned int video_width;
103
    unsigned int video_height;
104
    int64_t video_pts;
105

    
106
    unsigned int audio_bits;
107
    unsigned int audio_channels;
108
    unsigned int audio_sample_rate;
109
    unsigned int audio_type;
110
    unsigned int audio_frame_count;
111

    
112
    int video_stream_index;
113
    int audio_stream_index;
114

    
115
    offset_t audio_chunk_offset;
116
    int audio_chunk_size;
117
    offset_t video_chunk_offset;
118
    int video_chunk_size;
119
    offset_t decode_map_chunk_offset;
120
    int decode_map_chunk_size;
121

    
122
    offset_t next_chunk_offset;
123

    
124
    AVPaletteControl palette_control;
125

    
126
} IPMVEContext;
127

    
128
static int load_ipmovie_packet(IPMVEContext *s, ByteIOContext *pb, 
129
    AVPacket *pkt) {
130

    
131
    int chunk_type;
132
    int64_t audio_pts = 0;
133

    
134
    if (s->audio_chunk_offset) {
135

    
136
        /* adjust for PCM audio by skipping chunk header */
137
        if (s->audio_type != CODEC_ID_INTERPLAY_DPCM) {
138
            s->audio_chunk_offset += 6;
139
            s->audio_chunk_size -= 6;
140
        }
141

    
142
        url_fseek(pb, s->audio_chunk_offset, SEEK_SET);
143
        s->audio_chunk_offset = 0;
144

    
145
        /* figure out the audio pts */
146
        audio_pts = 90000;
147
        audio_pts *= s->audio_frame_count;
148
        audio_pts /= s->audio_sample_rate;
149

    
150
        if (av_new_packet(pkt, s->audio_chunk_size))
151
            return CHUNK_NOMEM;
152

    
153
        pkt->stream_index = s->audio_stream_index;
154
        pkt->pts = audio_pts;
155
        if (get_buffer(pb, pkt->data, s->audio_chunk_size) != 
156
            s->audio_chunk_size) {
157
            av_free_packet(pkt);
158
            return CHUNK_EOF;
159
        }
160

    
161
        /* audio frame maintenance */
162
        if (s->audio_type != CODEC_ID_INTERPLAY_DPCM)
163
            s->audio_frame_count +=
164
            (s->audio_chunk_size / s->audio_channels / (s->audio_bits / 8));
165
        else
166
            s->audio_frame_count +=
167
                (s->audio_chunk_size - 6) / s->audio_channels;
168

    
169
        debug_ipmovie("sending audio frame with pts %lld (%d audio frames)\n",
170
            audio_pts, s->audio_frame_count);
171

    
172
        chunk_type = CHUNK_VIDEO;
173

    
174
    } else if (s->decode_map_chunk_offset) {
175

    
176
        /* send both the decode map and the video data together */
177

    
178
        if (av_new_packet(pkt, s->decode_map_chunk_size + s->video_chunk_size))
179
            return CHUNK_NOMEM;
180

    
181
        url_fseek(pb, s->decode_map_chunk_offset, SEEK_SET);
182
        s->decode_map_chunk_offset = 0;
183

    
184
        if (get_buffer(pb, pkt->data, s->decode_map_chunk_size) != 
185
            s->decode_map_chunk_size) {
186
            av_free_packet(pkt);
187
            return CHUNK_EOF;
188
        }
189

    
190
        url_fseek(pb, s->video_chunk_offset, SEEK_SET);
191
        s->video_chunk_offset = 0;
192

    
193
        if (get_buffer(pb, pkt->data + s->decode_map_chunk_size,
194
            s->video_chunk_size) != s->video_chunk_size) {
195
            av_free_packet(pkt);
196
            return CHUNK_EOF;
197
        }
198

    
199
        pkt->stream_index = s->video_stream_index;
200
        pkt->pts = s->video_pts;
201

    
202
        debug_ipmovie("sending video frame with pts %lld\n",
203
            pkt->pts);
204

    
205
        s->video_pts += s->frame_pts_inc;
206

    
207
        chunk_type = CHUNK_VIDEO;
208

    
209
    } else {
210

    
211
        url_fseek(pb, s->next_chunk_offset, SEEK_SET);
212
        chunk_type = CHUNK_DONE;
213

    
214
    }
215

    
216
    return chunk_type;
217
}
218

    
219
/* This function loads and processes a single chunk in an IP movie file.
220
 * It returns the type of chunk that was processed. */
221
static int process_ipmovie_chunk(IPMVEContext *s, ByteIOContext *pb, 
222
    AVPacket *pkt)
223
{
224
    unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
225
    int chunk_type;
226
    int chunk_size;
227
    unsigned char opcode_preamble[OPCODE_PREAMBLE_SIZE];
228
    unsigned char opcode_type;
229
    unsigned char opcode_version;
230
    int opcode_size;
231
    unsigned char scratch[1024];
232
    int i, j;
233
    int first_color, last_color;
234
    int audio_flags;
235
    unsigned char r, g, b;
236

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

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

    
251
    debug_ipmovie("chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size);
252

    
253
    switch (chunk_type) {
254

    
255
    case CHUNK_INIT_AUDIO:
256
        debug_ipmovie("initialize audio\n");
257
        break;
258

    
259
    case CHUNK_AUDIO_ONLY:
260
        debug_ipmovie("audio only\n");
261
        break;
262

    
263
    case CHUNK_INIT_VIDEO:
264
        debug_ipmovie("initialize video\n");
265
        break;
266

    
267
    case CHUNK_VIDEO:
268
        debug_ipmovie("video (and audio)\n");
269
        break;
270

    
271
    case CHUNK_SHUTDOWN:
272
        debug_ipmovie("shutdown\n");
273
        break;
274

    
275
    case CHUNK_END:
276
        debug_ipmovie("end\n");
277
        break;
278

    
279
    default:
280
        debug_ipmovie("invalid chunk\n");
281
        chunk_type = CHUNK_BAD;
282
        break;
283

    
284
    }
285

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

    
288
        /* read the next chunk, wherever the file happens to be pointing */
289
       if (url_feof(pb)) {
290
            chunk_type = CHUNK_EOF;
291
            break;
292
        }
293
        if (get_buffer(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) !=
294
            CHUNK_PREAMBLE_SIZE) {
295
            chunk_type = CHUNK_BAD;
296
            break;
297
        }
298

    
299
        opcode_size = LE_16(&opcode_preamble[0]);
300
        opcode_type = opcode_preamble[2];
301
        opcode_version = opcode_preamble[3];
302

    
303
        chunk_size -= OPCODE_PREAMBLE_SIZE;
304
        chunk_size -= opcode_size;
305
        if (chunk_size < 0) {
306
            debug_ipmovie("chunk_size countdown just went negative\n");
307
            chunk_type = CHUNK_BAD;
308
            break;
309
        }
310

    
311
        debug_ipmovie("  opcode type %02X, version %d, 0x%04X bytes: ",
312
            opcode_type, opcode_version, opcode_size);
313
        switch (opcode_type) {
314

    
315
        case OPCODE_END_OF_STREAM:
316
            debug_ipmovie("end of stream\n");
317
            url_fseek(pb, opcode_size, SEEK_CUR);
318
            break;
319

    
320
        case OPCODE_END_OF_CHUNK:
321
            debug_ipmovie("end of chunk\n");
322
            url_fseek(pb, opcode_size, SEEK_CUR);
323
            break;
324

    
325
        case OPCODE_CREATE_TIMER:
326
            debug_ipmovie("create timer\n");
327
            if ((opcode_version > 0) || (opcode_size > 6)) {
328
                debug_ipmovie("bad create_timer opcode\n");
329
                chunk_type = CHUNK_BAD;
330
                break;
331
            }
332
            if (get_buffer(pb, scratch, opcode_size) !=
333
                opcode_size) {
334
                chunk_type = CHUNK_BAD;
335
                break;
336
            }
337
            s->fps = 1000000.0 / (LE_32(&scratch[0]) * LE_16(&scratch[4]));
338
            s->frame_pts_inc = 90000 / s->fps;
339
            debug_ipmovie("  %.2f frames/second (timer div = %d, subdiv = %d)\n",
340
                s->fps, LE_32(&scratch[0]), LE_16(&scratch[4]));
341
            break;
342

    
343
        case OPCODE_INIT_AUDIO_BUFFERS:
344
            debug_ipmovie("initialize audio buffers\n");
345
            if ((opcode_version > 1) || (opcode_size > 10)) {
346
                debug_ipmovie("bad init_audio_buffers opcode\n");
347
                chunk_type = CHUNK_BAD;
348
                break;
349
            }
350
            if (get_buffer(pb, scratch, opcode_size) !=
351
                opcode_size) {
352
                chunk_type = CHUNK_BAD;
353
                break;
354
            }
355
            s->audio_sample_rate = LE_16(&scratch[4]);
356
            audio_flags = LE_16(&scratch[2]);
357
            /* bit 0 of the flags: 0 = mono, 1 = stereo */
358
            s->audio_channels = (audio_flags & 1) + 1;
359
            /* bit 1 of the flags: 0 = 8 bit, 1 = 16 bit */
360
            s->audio_bits = (((audio_flags >> 1) & 1) + 1) * 8;
361
            /* bit 2 indicates compressed audio in version 1 opcode */
362
            if ((opcode_version == 1) && (audio_flags & 0x4))
363
                s->audio_type = CODEC_ID_INTERPLAY_DPCM;
364
            else if (s->audio_bits == 16)
365
                s->audio_type = CODEC_ID_PCM_S16LE;
366
            else
367
                s->audio_type = CODEC_ID_PCM_U8;
368
            debug_ipmovie("audio: %d bits, %d Hz, %s, %s format\n",
369
                s->audio_bits,
370
                s->audio_sample_rate,
371
                (s->audio_channels == 2) ? "stereo" : "mono",
372
                (s->audio_type == CODEC_ID_INTERPLAY_DPCM) ? 
373
                "Interplay audio" : "PCM");
374
            break;
375

    
376
        case OPCODE_START_STOP_AUDIO:
377
            debug_ipmovie("start/stop audio\n");
378
            url_fseek(pb, opcode_size, SEEK_CUR);
379
            break;
380

    
381
        case OPCODE_INIT_VIDEO_BUFFERS:
382
            debug_ipmovie("initialize video buffers\n");
383
            if ((opcode_version > 2) || (opcode_size > 8)) {
384
                debug_ipmovie("bad init_video_buffers opcode\n");
385
                chunk_type = CHUNK_BAD;
386
                break;
387
            }
388
            if (get_buffer(pb, scratch, opcode_size) !=
389
                opcode_size) {
390
                chunk_type = CHUNK_BAD;
391
                break;
392
            }
393
            s->video_width = LE_16(&scratch[0]) * 8;
394
            s->video_height = LE_16(&scratch[2]) * 8;
395
            debug_ipmovie("video resolution: %d x %d\n",
396
                s->video_width, s->video_height);
397
            break;
398

    
399
        case OPCODE_UNKNOWN_06:
400
        case OPCODE_UNKNOWN_0E:
401
        case OPCODE_UNKNOWN_10:
402
        case OPCODE_UNKNOWN_12:
403
        case OPCODE_UNKNOWN_13:
404
        case OPCODE_UNKNOWN_14:
405
        case OPCODE_UNKNOWN_15:
406
            debug_ipmovie("unknown (but documented) opcode %02X\n", opcode_type);
407
            url_fseek(pb, opcode_size, SEEK_CUR);
408
            break;
409

    
410
        case OPCODE_SEND_BUFFER:
411
            debug_ipmovie("send buffer\n");
412
            url_fseek(pb, opcode_size, SEEK_CUR);
413
            break;
414

    
415
        case OPCODE_AUDIO_FRAME:
416
            debug_ipmovie("audio frame\n");
417

    
418
            /* log position and move on for now */
419
            s->audio_chunk_offset = url_ftell(pb);
420
            s->audio_chunk_size = opcode_size;
421
            url_fseek(pb, opcode_size, SEEK_CUR);
422
            break;
423

    
424
        case OPCODE_SILENCE_FRAME:
425
            debug_ipmovie("silence frame\n");
426
            url_fseek(pb, opcode_size, SEEK_CUR);
427
            break;
428

    
429
        case OPCODE_INIT_VIDEO_MODE:
430
            debug_ipmovie("initialize video mode\n");
431
            url_fseek(pb, opcode_size, SEEK_CUR);
432
            break;
433

    
434
        case OPCODE_CREATE_GRADIENT:
435
            debug_ipmovie("create gradient\n");
436
            url_fseek(pb, opcode_size, SEEK_CUR);
437
            break;
438

    
439
        case OPCODE_SET_PALETTE:
440
            debug_ipmovie("set palette\n");
441
            /* check for the logical maximum palette size
442
             * (3 * 256 + 4 bytes) */
443
            if (opcode_size > 0x304) {
444
                debug_ipmovie("demux_ipmovie: set_palette opcode too large\n");
445
                chunk_type = CHUNK_BAD;
446
                break;
447
            }
448
            if (get_buffer(pb, scratch, opcode_size) != opcode_size) {
449
                chunk_type = CHUNK_BAD;
450
                break;
451
            }
452

    
453
            /* load the palette into internal data structure */
454
            first_color = LE_16(&scratch[0]);
455
            last_color = first_color + LE_16(&scratch[2]) - 1;
456
            /* sanity check (since they are 16 bit values) */
457
            if ((first_color > 0xFF) || (last_color > 0xFF)) {
458
                debug_ipmovie("demux_ipmovie: set_palette indices out of range (%d -> %d)\n",
459
                    first_color, last_color);
460
                chunk_type = CHUNK_BAD;
461
                break;
462
            }
463
            j = 4;  /* offset of first palette data */
464
            for (i = first_color; i <= last_color; i++) {
465
                /* the palette is stored as a 6-bit VGA palette, thus each
466
                 * component is shifted up to a 8-bit range */
467
                r = scratch[j++] * 4;
468
                g = scratch[j++] * 4;
469
                b = scratch[j++] * 4;
470
                s->palette_control.palette[i] = (r << 16) | (g << 8) | (b);
471
            }
472
            /* indicate a palette change */
473
            s->palette_control.palette_changed = 1;
474
            break;
475

    
476
        case OPCODE_SET_PALETTE_COMPRESSED:
477
            debug_ipmovie("set palette compressed\n");
478
            url_fseek(pb, opcode_size, SEEK_CUR);
479
            break;
480

    
481
        case OPCODE_SET_DECODING_MAP:
482
            debug_ipmovie("set decoding map\n");
483

    
484
            /* log position and move on for now */
485
            s->decode_map_chunk_offset = url_ftell(pb);
486
            s->decode_map_chunk_size = opcode_size;
487
            url_fseek(pb, opcode_size, SEEK_CUR);
488
            break;
489

    
490
        case OPCODE_VIDEO_DATA:
491
            debug_ipmovie("set video data\n");
492

    
493
            /* log position and move on for now */
494
            s->video_chunk_offset = url_ftell(pb);
495
            s->video_chunk_size = opcode_size;
496
            url_fseek(pb, opcode_size, SEEK_CUR);
497
            break;
498

    
499
        default:
500
            debug_ipmovie("*** unknown opcode type\n");
501
            chunk_type = CHUNK_BAD;
502
            break;
503

    
504
        }
505
    }
506

    
507
    /* make a note of where the stream is sitting */
508
    s->next_chunk_offset = url_ftell(pb);
509

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

    
514
    return chunk_type;
515
}
516

    
517
static int ipmovie_probe(AVProbeData *p)
518
{
519
    if (p->buf_size < IPMOVIE_SIGNATURE_SIZE)
520
        return 0;
521
    if (strncmp(p->buf, IPMOVIE_SIGNATURE, IPMOVIE_SIGNATURE_SIZE) != 0)
522
        return 0;
523

    
524
    return AVPROBE_SCORE_MAX;
525
}
526

    
527
static int ipmovie_read_header(AVFormatContext *s,
528
                               AVFormatParameters *ap)
529
{
530
    IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data;
531
    ByteIOContext *pb = &s->pb;
532
    AVPacket pkt;
533
    AVStream *st;
534
    unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
535
    int chunk_type;
536

    
537
    /* initialize private context members */
538
    ipmovie->video_pts = ipmovie->audio_frame_count = 0;
539
    ipmovie->audio_chunk_offset = ipmovie->video_chunk_offset =
540
    ipmovie->decode_map_chunk_offset = 0;
541

    
542
    /* on the first read, this will position the stream at the first chunk */
543
    ipmovie->next_chunk_offset = IPMOVIE_SIGNATURE_SIZE + 6;
544

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

    
549
    /* peek ahead to the next chunk-- if it is an init audio chunk, process
550
     * it; if it is the first video chunk, this is a silent file */
551
    if (get_buffer(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
552
        CHUNK_PREAMBLE_SIZE)
553
        return -EIO;
554
    chunk_type = LE_16(&chunk_preamble[2]);
555
    url_fseek(pb, -CHUNK_PREAMBLE_SIZE, SEEK_CUR);
556

    
557
    if (chunk_type == CHUNK_VIDEO)
558
        ipmovie->audio_type = 0;  /* no audio */
559
    else if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO)
560
        return AVERROR_INVALIDDATA;
561

    
562
    /* set the pts reference (1 pts = 1/90000) */
563
    s->pts_num = 1;
564
    s->pts_den = 90000;
565

    
566
    /* initialize the stream decoders */
567
    st = av_new_stream(s, 0);
568
    if (!st)
569
        return AVERROR_NOMEM;
570
    ipmovie->video_stream_index = st->index;
571
    st->codec.codec_type = CODEC_TYPE_VIDEO;
572
    st->codec.codec_id = CODEC_ID_INTERPLAY_VIDEO;
573
    st->codec.codec_tag = 0;  /* no fourcc */
574
    st->codec.width = ipmovie->video_width;
575
    st->codec.height = ipmovie->video_height;
576

    
577
    /* palette considerations */
578
    st->codec.palctrl = &ipmovie->palette_control;
579

    
580
    if (ipmovie->audio_type) {
581
        st = av_new_stream(s, 0);
582
        if (!st)
583
            return AVERROR_NOMEM;
584
        ipmovie->audio_stream_index = st->index;
585
        st->codec.codec_type = CODEC_TYPE_AUDIO;
586
        st->codec.codec_id = ipmovie->audio_type;
587
        st->codec.codec_tag = 0;  /* no tag */
588
        st->codec.channels = ipmovie->audio_channels;
589
        st->codec.sample_rate = ipmovie->audio_sample_rate;
590
        st->codec.bits_per_sample = ipmovie->audio_bits;
591
        st->codec.bit_rate = st->codec.channels * st->codec.sample_rate *
592
            st->codec.bits_per_sample;
593
        if (st->codec.codec_id == CODEC_ID_INTERPLAY_DPCM)
594
            st->codec.bit_rate /= 2;
595
        st->codec.block_align = st->codec.channels * st->codec.bits_per_sample;
596
    }
597

    
598
    return 0;
599
}
600

    
601
static int ipmovie_read_packet(AVFormatContext *s,
602
                               AVPacket *pkt)
603
{
604
    IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data;
605
    ByteIOContext *pb = &s->pb;
606
    int ret;
607

    
608
    ret = process_ipmovie_chunk(ipmovie, pb, pkt);
609
    if (ret == CHUNK_BAD)
610
        ret = AVERROR_INVALIDDATA;
611
    else if (ret == CHUNK_EOF)
612
        ret = -EIO;
613
    else if (ret == CHUNK_NOMEM)
614
        ret = AVERROR_NOMEM;
615
    else
616
        ret = 0;
617

    
618
    return ret;
619
}
620

    
621
static int ipmovie_read_close(AVFormatContext *s)
622
{
623
//    IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data;
624

    
625
    return 0;
626
}
627

    
628
static AVInputFormat ipmovie_iformat = {
629
    "ipmovie",
630
    "Interplay MVE format",
631
    sizeof(IPMVEContext),
632
    ipmovie_probe,
633
    ipmovie_read_header,
634
    ipmovie_read_packet,
635
    ipmovie_read_close,
636
};
637

    
638
int ipmovie_init(void)
639
{
640
    av_register_input_format(&ipmovie_iformat);
641
    return 0;
642
}
643