~ubuntu-branches/ubuntu/jaunty/xvidcap/jaunty-proposed

« back to all changes in this revision

Viewing changes to ffmpeg/libavformat/ipmovie.c

  • Committer: Bazaar Package Importer
  • Author(s): Christian Marillat
  • Date: 2004-08-29 10:53:42 UTC
  • Revision ID: james.westby@ubuntu.com-20040829105342-qgmnry37eadfkoxx
Tags: upstream-1.1.3
ImportĀ upstreamĀ versionĀ 1.1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
    int 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
        s->video_pts += s->frame_pts_inc;
 
203
 
 
204
        chunk_type = CHUNK_VIDEO;
 
205
 
 
206
    } else {
 
207
 
 
208
        url_fseek(pb, s->next_chunk_offset, SEEK_SET);
 
209
        chunk_type = CHUNK_DONE;
 
210
 
 
211
    }
 
212
 
 
213
    return chunk_type;
 
214
}
 
215
 
 
216
/* This function loads and processes a single chunk in an IP movie file.
 
217
 * It returns the type of chunk that was processed. */
 
218
static int process_ipmovie_chunk(IPMVEContext *s, ByteIOContext *pb, 
 
219
    AVPacket *pkt)
 
220
{
 
221
    unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
 
222
    int chunk_type;
 
223
    int chunk_size;
 
224
    unsigned char opcode_preamble[OPCODE_PREAMBLE_SIZE];
 
225
    unsigned char opcode_type;
 
226
    unsigned char opcode_version;
 
227
    int opcode_size;
 
228
    unsigned char scratch[1024];
 
229
    int i, j;
 
230
    int first_color, last_color;
 
231
    int audio_flags;
 
232
 
 
233
    /* see if there are any pending packets */
 
234
    chunk_type = load_ipmovie_packet(s, pb, pkt);
 
235
    if ((chunk_type == CHUNK_VIDEO) && (chunk_type != CHUNK_DONE))
 
236
        return chunk_type;
 
237
 
 
238
    /* read the next chunk, wherever the file happens to be pointing */
 
239
    if (url_feof(pb))
 
240
        return CHUNK_EOF;
 
241
    if (get_buffer(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
 
242
        CHUNK_PREAMBLE_SIZE)
 
243
        return CHUNK_BAD;
 
244
    chunk_size = LE_16(&chunk_preamble[0]);
 
245
    chunk_type = LE_16(&chunk_preamble[2]);
 
246
 
 
247
    debug_ipmovie("chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size);
 
248
 
 
249
    switch (chunk_type) {
 
250
 
 
251
    case CHUNK_INIT_AUDIO:
 
252
        debug_ipmovie("initialize audio\n");
 
253
        break;
 
254
 
 
255
    case CHUNK_AUDIO_ONLY:
 
256
        debug_ipmovie("audio only\n");
 
257
        break;
 
258
 
 
259
    case CHUNK_INIT_VIDEO:
 
260
        debug_ipmovie("initialize video\n");
 
261
        break;
 
262
 
 
263
    case CHUNK_VIDEO:
 
264
        debug_ipmovie("video (and audio)\n");
 
265
        break;
 
266
 
 
267
    case CHUNK_SHUTDOWN:
 
268
        debug_ipmovie("shutdown\n");
 
269
        break;
 
270
 
 
271
    case CHUNK_END:
 
272
        debug_ipmovie("end\n");
 
273
        break;
 
274
 
 
275
    default:
 
276
        debug_ipmovie("invalid chunk\n");
 
277
        chunk_type = CHUNK_BAD;
 
278
        break;
 
279
 
 
280
    }
 
281
 
 
282
    while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) {
 
283
 
 
284
        /* read the next chunk, wherever the file happens to be pointing */
 
285
       if (url_feof(pb)) {
 
286
            chunk_type = CHUNK_EOF;
 
287
            break;
 
288
        }
 
289
        if (get_buffer(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) !=
 
290
            CHUNK_PREAMBLE_SIZE) {
 
291
            chunk_type = CHUNK_BAD;
 
292
            break;
 
293
        }
 
294
 
 
295
        opcode_size = LE_16(&opcode_preamble[0]);
 
296
        opcode_type = opcode_preamble[2];
 
297
        opcode_version = opcode_preamble[3];
 
298
 
 
299
        chunk_size -= OPCODE_PREAMBLE_SIZE;
 
300
        chunk_size -= opcode_size;
 
301
        if (chunk_size < 0) {
 
302
            debug_ipmovie("chunk_size countdown just went negative\n");
 
303
            chunk_type = CHUNK_BAD;
 
304
            break;
 
305
        }
 
306
 
 
307
        debug_ipmovie("  opcode type %02X, version %d, 0x%04X bytes: ",
 
308
            opcode_type, opcode_version, opcode_size);
 
309
        switch (opcode_type) {
 
310
 
 
311
        case OPCODE_END_OF_STREAM:
 
312
            debug_ipmovie("end of stream\n");
 
313
            url_fseek(pb, opcode_size, SEEK_CUR);
 
314
            break;
 
315
 
 
316
        case OPCODE_END_OF_CHUNK:
 
317
            debug_ipmovie("end of chunk\n");
 
318
            url_fseek(pb, opcode_size, SEEK_CUR);
 
319
            break;
 
320
 
 
321
        case OPCODE_CREATE_TIMER:
 
322
            debug_ipmovie("create timer\n");
 
323
            if ((opcode_version > 0) || (opcode_size > 6)) {
 
324
                debug_ipmovie("bad create_timer opcode\n");
 
325
                chunk_type = CHUNK_BAD;
 
326
                break;
 
327
            }
 
328
            if (get_buffer(pb, scratch, opcode_size) !=
 
329
                opcode_size) {
 
330
                chunk_type = CHUNK_BAD;
 
331
                break;
 
332
            }
 
333
            s->fps = 1000000 / (LE_32(&scratch[0]) * LE_16(&scratch[4]));
 
334
            s->fps++;  /* above calculation usually yields 14.9; we need 15 */
 
335
            s->frame_pts_inc = 90000 / s->fps;
 
336
            debug_ipmovie("%d frames/second (timer div = %d, subdiv = %d)\n",
 
337
                s->fps, LE_32(&scratch[0]), LE_16(&scratch[4]));
 
338
            break;
 
339
 
 
340
        case OPCODE_INIT_AUDIO_BUFFERS:
 
341
            debug_ipmovie("initialize audio buffers\n");
 
342
            if ((opcode_version > 1) || (opcode_size > 10)) {
 
343
                debug_ipmovie("bad init_audio_buffers opcode\n");
 
344
                chunk_type = CHUNK_BAD;
 
345
                break;
 
346
            }
 
347
            if (get_buffer(pb, scratch, opcode_size) !=
 
348
                opcode_size) {
 
349
                chunk_type = CHUNK_BAD;
 
350
                break;
 
351
            }
 
352
            s->audio_sample_rate = LE_16(&scratch[4]);
 
353
            audio_flags = LE_16(&scratch[2]);
 
354
            /* bit 0 of the flags: 0 = mono, 1 = stereo */
 
355
            s->audio_channels = (audio_flags & 1) + 1;
 
356
            /* bit 1 of the flags: 0 = 8 bit, 1 = 16 bit */
 
357
            s->audio_bits = (((audio_flags >> 1) & 1) + 1) * 8;
 
358
            /* bit 2 indicates compressed audio in version 1 opcode */
 
359
            if ((opcode_version == 1) && (audio_flags & 0x4))
 
360
                s->audio_type = CODEC_ID_INTERPLAY_DPCM;
 
361
            else if (s->audio_bits == 16)
 
362
                s->audio_type = CODEC_ID_PCM_S16LE;
 
363
            else
 
364
                s->audio_type = CODEC_ID_PCM_U8;
 
365
            debug_ipmovie("audio: %d bits, %d Hz, %s, %s format\n",
 
366
                s->audio_bits,
 
367
                s->audio_sample_rate,
 
368
                (s->audio_channels == 2) ? "stereo" : "mono",
 
369
                (s->audio_type == CODEC_ID_INTERPLAY_DPCM) ? 
 
370
                "Interplay audio" : "PCM");
 
371
            break;
 
372
 
 
373
        case OPCODE_START_STOP_AUDIO:
 
374
            debug_ipmovie("start/stop audio\n");
 
375
            url_fseek(pb, opcode_size, SEEK_CUR);
 
376
            break;
 
377
 
 
378
        case OPCODE_INIT_VIDEO_BUFFERS:
 
379
            debug_ipmovie("initialize video buffers\n");
 
380
            if ((opcode_version > 2) || (opcode_size > 8)) {
 
381
                debug_ipmovie("bad init_video_buffers opcode\n");
 
382
                chunk_type = CHUNK_BAD;
 
383
                break;
 
384
            }
 
385
            if (get_buffer(pb, scratch, opcode_size) !=
 
386
                opcode_size) {
 
387
                chunk_type = CHUNK_BAD;
 
388
                break;
 
389
            }
 
390
            s->video_width = LE_16(&scratch[0]) * 8;
 
391
            s->video_height = LE_16(&scratch[2]) * 8;
 
392
            debug_ipmovie("video resolution: %d x %d\n",
 
393
                s->video_width, s->video_height);
 
394
            break;
 
395
 
 
396
        case OPCODE_UNKNOWN_06:
 
397
        case OPCODE_UNKNOWN_0E:
 
398
        case OPCODE_UNKNOWN_10:
 
399
        case OPCODE_UNKNOWN_12:
 
400
        case OPCODE_UNKNOWN_13:
 
401
        case OPCODE_UNKNOWN_14:
 
402
        case OPCODE_UNKNOWN_15:
 
403
            debug_ipmovie("unknown (but documented) opcode %02X\n", opcode_type);
 
404
            url_fseek(pb, opcode_size, SEEK_CUR);
 
405
            break;
 
406
 
 
407
        case OPCODE_SEND_BUFFER:
 
408
            debug_ipmovie("send buffer\n");
 
409
            url_fseek(pb, opcode_size, SEEK_CUR);
 
410
            break;
 
411
 
 
412
        case OPCODE_AUDIO_FRAME:
 
413
            debug_ipmovie("audio frame\n");
 
414
 
 
415
            /* log position and move on for now */
 
416
            s->audio_chunk_offset = url_ftell(pb);
 
417
            s->audio_chunk_size = opcode_size;
 
418
            url_fseek(pb, opcode_size, SEEK_CUR);
 
419
            break;
 
420
 
 
421
        case OPCODE_SILENCE_FRAME:
 
422
            debug_ipmovie("silence frame\n");
 
423
            url_fseek(pb, opcode_size, SEEK_CUR);
 
424
            break;
 
425
 
 
426
        case OPCODE_INIT_VIDEO_MODE:
 
427
            debug_ipmovie("initialize video mode\n");
 
428
            url_fseek(pb, opcode_size, SEEK_CUR);
 
429
            break;
 
430
 
 
431
        case OPCODE_CREATE_GRADIENT:
 
432
            debug_ipmovie("create gradient\n");
 
433
            url_fseek(pb, opcode_size, SEEK_CUR);
 
434
            break;
 
435
 
 
436
        case OPCODE_SET_PALETTE:
 
437
            debug_ipmovie("set palette\n");
 
438
            /* check for the logical maximum palette size
 
439
             * (3 * 256 + 4 bytes) */
 
440
            if (opcode_size > 0x304) {
 
441
                debug_ipmovie("demux_ipmovie: set_palette opcode too large\n");
 
442
                chunk_type = CHUNK_BAD;
 
443
                break;
 
444
            }
 
445
            if (get_buffer(pb, scratch, opcode_size) != opcode_size) {
 
446
                chunk_type = CHUNK_BAD;
 
447
                break;
 
448
            }
 
449
 
 
450
            /* load the palette into internal data structure */
 
451
            first_color = LE_16(&scratch[0]);
 
452
            last_color = first_color + LE_16(&scratch[2]);
 
453
            /* sanity check (since they are 16 bit values) */
 
454
            if ((first_color > 0xFF) || (last_color > 0xFF)) {
 
455
                debug_ipmovie("demux_ipmovie: set_palette indices out of range (%d -> %d)\n",
 
456
                    first_color, last_color);
 
457
                chunk_type = CHUNK_BAD;
 
458
                break;
 
459
            }
 
460
            j = 4;  /* offset of first palette data */
 
461
            for (i = first_color; i <= last_color; i++) {
 
462
                /* the palette is stored as a 6-bit VGA palette, thus each
 
463
                 * component is shifted up to a 8-bit range */
 
464
                s->palette_control.palette[i * 3 + 0] = scratch[j++] * 4;
 
465
                s->palette_control.palette[i * 3 + 1] = scratch[j++] * 4;
 
466
                s->palette_control.palette[i * 3 + 2] = scratch[j++] * 4;
 
467
            }
 
468
            /* indicate a palette change */
 
469
            s->palette_control.palette_changed = 1;
 
470
            break;
 
471
 
 
472
        case OPCODE_SET_PALETTE_COMPRESSED:
 
473
            debug_ipmovie("set palette compressed\n");
 
474
            url_fseek(pb, opcode_size, SEEK_CUR);
 
475
            break;
 
476
 
 
477
        case OPCODE_SET_DECODING_MAP:
 
478
            debug_ipmovie("set decoding map\n");
 
479
 
 
480
            /* log position and move on for now */
 
481
            s->decode_map_chunk_offset = url_ftell(pb);
 
482
            s->decode_map_chunk_size = opcode_size;
 
483
            url_fseek(pb, opcode_size, SEEK_CUR);
 
484
            break;
 
485
 
 
486
        case OPCODE_VIDEO_DATA:
 
487
            debug_ipmovie("set video data\n");
 
488
 
 
489
            /* log position and move on for now */
 
490
            s->video_chunk_offset = url_ftell(pb);
 
491
            s->video_chunk_size = opcode_size;
 
492
            url_fseek(pb, opcode_size, SEEK_CUR);
 
493
            break;
 
494
 
 
495
        default:
 
496
            debug_ipmovie("*** unknown opcode type\n");
 
497
            chunk_type = CHUNK_BAD;
 
498
            break;
 
499
 
 
500
        }
 
501
    }
 
502
 
 
503
    /* make a note of where the stream is sitting */
 
504
    s->next_chunk_offset = url_ftell(pb);
 
505
 
 
506
    /* dispatch the first of any pending packets */
 
507
    if ((chunk_type == CHUNK_VIDEO) || (chunk_type == CHUNK_AUDIO_ONLY))
 
508
        chunk_type = load_ipmovie_packet(s, pb, pkt);
 
509
 
 
510
    return chunk_type;
 
511
}
 
512
 
 
513
static int ipmovie_probe(AVProbeData *p)
 
514
{
 
515
    if (p->buf_size < IPMOVIE_SIGNATURE_SIZE)
 
516
        return 0;
 
517
    if (strncmp(p->buf, IPMOVIE_SIGNATURE, IPMOVIE_SIGNATURE_SIZE) != 0)
 
518
        return 0;
 
519
 
 
520
    return AVPROBE_SCORE_MAX;
 
521
}
 
522
 
 
523
static int ipmovie_read_header(AVFormatContext *s,
 
524
                               AVFormatParameters *ap)
 
525
{
 
526
    IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data;
 
527
    ByteIOContext *pb = &s->pb;
 
528
    AVPacket pkt;
 
529
    AVStream *st;
 
530
 
 
531
    /* initialize private context members */
 
532
    ipmovie->video_pts = ipmovie->audio_frame_count = 0;
 
533
    ipmovie->audio_chunk_offset = ipmovie->video_chunk_offset =
 
534
    ipmovie->decode_map_chunk_offset = 0;
 
535
 
 
536
    /* on the first read, this will position the stream at the first chunk */
 
537
    ipmovie->next_chunk_offset = IPMOVIE_SIGNATURE_SIZE + 6;
 
538
 
 
539
    /* process the first chunk which should be CHUNK_INIT_VIDEO */
 
540
    if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO)
 
541
        return AVERROR_INVALIDDATA;
 
542
 
 
543
    /* process the next chunk which should be CHUNK_INIT_AUDIO */
 
544
    if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO)
 
545
        return AVERROR_INVALIDDATA;
 
546
 
 
547
    /* set the pts reference (1 pts = 1/90000) */
 
548
    s->pts_num = 1;
 
549
    s->pts_den = 90000;
 
550
 
 
551
    /* initialize the stream decoders */
 
552
    st = av_new_stream(s, 0);
 
553
    if (!st)
 
554
        return AVERROR_NOMEM;
 
555
    ipmovie->video_stream_index = st->index;
 
556
    st->codec.codec_type = CODEC_TYPE_VIDEO;
 
557
    st->codec.codec_id = CODEC_ID_INTERPLAY_VIDEO;
 
558
    st->codec.codec_tag = 0;  /* no fourcc */
 
559
    st->codec.width = ipmovie->video_width;
 
560
    st->codec.height = ipmovie->video_height;
 
561
 
 
562
    /* palette considerations */
 
563
    st->codec.extradata_size = sizeof(AVPaletteControl);
 
564
    st->codec.extradata = &ipmovie->palette_control;
 
565
 
 
566
    st = av_new_stream(s, 0);
 
567
    if (!st)
 
568
        return AVERROR_NOMEM;
 
569
    ipmovie->audio_stream_index = st->index;
 
570
    st->codec.codec_type = CODEC_TYPE_AUDIO;
 
571
    st->codec.codec_id = ipmovie->audio_type;
 
572
    st->codec.codec_tag = 0;  /* no tag */
 
573
    st->codec.channels = ipmovie->audio_channels;
 
574
    st->codec.sample_rate = ipmovie->audio_sample_rate;
 
575
    st->codec.bits_per_sample = ipmovie->audio_bits;
 
576
    st->codec.bit_rate = st->codec.channels * st->codec.sample_rate *
 
577
        st->codec.bits_per_sample;
 
578
    if (st->codec.codec_id == CODEC_ID_INTERPLAY_DPCM)
 
579
        st->codec.bit_rate /= 2;
 
580
    st->codec.block_align = st->codec.channels * st->codec.bits_per_sample;
 
581
 
 
582
    return 0;
 
583
}
 
584
 
 
585
static int ipmovie_read_packet(AVFormatContext *s,
 
586
                               AVPacket *pkt)
 
587
{
 
588
    IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data;
 
589
    ByteIOContext *pb = &s->pb;
 
590
    int ret;
 
591
 
 
592
    ret = process_ipmovie_chunk(ipmovie, pb, pkt);
 
593
    if (ret == CHUNK_BAD)
 
594
        ret = AVERROR_INVALIDDATA;
 
595
    else if (ret == CHUNK_EOF)
 
596
        ret = -EIO;
 
597
    else if (ret == CHUNK_NOMEM)
 
598
        ret = AVERROR_NOMEM;
 
599
    else
 
600
        ret = 0;
 
601
 
 
602
    return ret;
 
603
}
 
604
 
 
605
static int ipmovie_read_close(AVFormatContext *s)
 
606
{
 
607
//    IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data;
 
608
 
 
609
    return 0;
 
610
}
 
611
 
 
612
static AVInputFormat ipmovie_iformat = {
 
613
    "ipmovie",
 
614
    "Interplay MVE format",
 
615
    sizeof(IPMVEContext),
 
616
    ipmovie_probe,
 
617
    ipmovie_read_header,
 
618
    ipmovie_read_packet,
 
619
    ipmovie_read_close,
 
620
};
 
621
 
 
622
int ipmovie_init(void)
 
623
{
 
624
    av_register_input_format(&ipmovie_iformat);
 
625
    return 0;
 
626
}
 
627