Statistics
| Branch: | Revision:

ffmpeg / libavformat / wc3movie.c @ 20cd83e2

History | View | Annotate | Download (12.7 KB)

1 493645eb Mike Melanson
/*
2
 * Wing Commander III Movie (.mve) File Demuxer
3
 * Copyright (c) 2003 The ffmpeg Project
4
 *
5 b78e7197 Diego Biurrun
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8 493645eb Mike Melanson
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10 b78e7197 Diego Biurrun
 * version 2.1 of the License, or (at your option) any later version.
11 493645eb Mike Melanson
 *
12 b78e7197 Diego Biurrun
 * FFmpeg is distributed in the hope that it will be useful,
13 493645eb Mike Melanson
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18 b78e7197 Diego Biurrun
 * License along with FFmpeg; if not, write to the Free Software
19 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 493645eb Mike Melanson
 */
21
22
/**
23
 * @file wc3movie.c
24
 * Wing Commander III Movie file demuxer
25
 * by Mike Melanson (melanson@pcisys.net)
26
 * for more information on the WC3 .mve file format, visit:
27
 *   http://www.pcisys.net/~melanson/codecs/
28
 */
29
30
#include "avformat.h"
31
32
#define WC3_PREAMBLE_SIZE 8
33
34 3a278992 Mike Melanson
#define FORM_TAG MKTAG('F', 'O', 'R', 'M')
35
#define MOVE_TAG MKTAG('M', 'O', 'V', 'E')
36
#define _PC__TAG MKTAG('_', 'P', 'C', '_')
37
#define SOND_TAG MKTAG('S', 'O', 'N', 'D')
38
#define BNAM_TAG MKTAG('B', 'N', 'A', 'M')
39
#define SIZE_TAG MKTAG('S', 'I', 'Z', 'E')
40
#define PALT_TAG MKTAG('P', 'A', 'L', 'T')
41
#define INDX_TAG MKTAG('I', 'N', 'D', 'X')
42
#define BRCH_TAG MKTAG('B', 'R', 'C', 'H')
43
#define SHOT_TAG MKTAG('S', 'H', 'O', 'T')
44
#define VGA__TAG MKTAG('V', 'G', 'A', ' ')
45
#define TEXT_TAG MKTAG('T', 'E', 'X', 'T')
46
#define AUDI_TAG MKTAG('A', 'U', 'D', 'I')
47 493645eb Mike Melanson
48
/* video resolution unless otherwise specified */
49
#define WC3_DEFAULT_WIDTH 320
50
#define WC3_DEFAULT_HEIGHT 165
51
52
/* always use the same PCM audio parameters */
53
#define WC3_SAMPLE_RATE 22050
54
#define WC3_AUDIO_CHANNELS 1
55
#define WC3_AUDIO_BITS 16
56
57
/* nice, constant framerate */
58
#define WC3_FRAME_PTS_INC (90000 / 15)
59
60
#define PALETTE_SIZE (256 * 3)
61
#define PALETTE_COUNT 256
62
63
typedef struct Wc3DemuxContext {
64
    int width;
65
    int height;
66
    unsigned char *palettes;
67
    int palette_count;
68
    int64_t pts;
69
    int video_stream_index;
70
    int audio_stream_index;
71
72 ba118447 Mike Melanson
    AVPaletteControl palette_control;
73 493645eb Mike Melanson
74
} Wc3DemuxContext;
75
76
/* bizarre palette lookup table */
77 7e5ef401 Mike Melanson
static const unsigned char wc3_pal_lookup[] = {
78 115329f1 Diego Biurrun
  0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E,
79 493645eb Mike Melanson
  0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1A,
80 115329f1 Diego Biurrun
  0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25,
81 493645eb Mike Melanson
  0x27, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E, 0x2F,
82 115329f1 Diego Biurrun
  0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
83 493645eb Mike Melanson
  0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
84 115329f1 Diego Biurrun
  0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B,
85 493645eb Mike Melanson
  0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
86 115329f1 Diego Biurrun
  0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
87 493645eb Mike Melanson
  0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
88 115329f1 Diego Biurrun
  0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C,
89 493645eb Mike Melanson
  0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74,
90 115329f1 Diego Biurrun
  0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
91 493645eb Mike Melanson
  0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
92 115329f1 Diego Biurrun
  0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
93 493645eb Mike Melanson
  0x8C, 0x8D, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
94 115329f1 Diego Biurrun
  0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x99,
95 493645eb Mike Melanson
  0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1,
96 115329f1 Diego Biurrun
  0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
97 493645eb Mike Melanson
  0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
98 115329f1 Diego Biurrun
  0xB0, 0xB1, 0xB2, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
99 493645eb Mike Melanson
  0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
100 115329f1 Diego Biurrun
  0xBE, 0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4,
101 493645eb Mike Melanson
  0xC5, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB,
102 115329f1 Diego Biurrun
  0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD0, 0xD1,
103 493645eb Mike Melanson
  0xD2, 0xD3, 0xD4, 0xD5, 0xD5, 0xD6, 0xD7, 0xD8,
104
  0xD9, 0xDA, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
105
  0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE4, 0xE5,
106 115329f1 Diego Biurrun
  0xE6, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEB, 0xEC,
107 493645eb Mike Melanson
  0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2,
108 115329f1 Diego Biurrun
  0xF3, 0xF4, 0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9,
109 493645eb Mike Melanson
  0xFA, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD
110
};
111
112
113
static int wc3_probe(AVProbeData *p)
114
{
115
    if (p->buf_size < 12)
116
        return 0;
117
118
    if ((LE_32(&p->buf[0]) != FORM_TAG) ||
119
        (LE_32(&p->buf[8]) != MOVE_TAG))
120
        return 0;
121
122
    return AVPROBE_SCORE_MAX;
123
}
124
125
static int wc3_read_header(AVFormatContext *s,
126
                           AVFormatParameters *ap)
127
{
128
    Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data;
129
    ByteIOContext *pb = &s->pb;
130
    unsigned int fourcc_tag;
131
    unsigned int size;
132
    AVStream *st;
133
    unsigned char preamble[WC3_PREAMBLE_SIZE];
134
    int ret = 0;
135
    int current_palette = 0;
136
    int bytes_to_read;
137
    int i;
138 7e5ef401 Mike Melanson
    unsigned char rotate;
139 493645eb Mike Melanson
140
    /* default context members */
141
    wc3->width = WC3_DEFAULT_WIDTH;
142
    wc3->height = WC3_DEFAULT_HEIGHT;
143
    wc3->palettes = NULL;
144
    wc3->palette_count = 0;
145
    wc3->pts = 0;
146
    wc3->video_stream_index = wc3->audio_stream_index = 0;
147
148
    /* skip the first 3 32-bit numbers */
149
    url_fseek(pb, 12, SEEK_CUR);
150
151
    /* traverse through the chunks and load the header information before
152
     * the first BRCH tag */
153 115329f1 Diego Biurrun
    if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
154 493645eb Mike Melanson
        WC3_PREAMBLE_SIZE)
155 0bd586c5 Mike Melanson
        return AVERROR_IO;
156 493645eb Mike Melanson
    fourcc_tag = LE_32(&preamble[0]);
157
    size = (BE_32(&preamble[4]) + 1) & (~1);
158
159
    do {
160
        switch (fourcc_tag) {
161
162
        case SOND_TAG:
163
        case INDX_TAG:
164
            /* SOND unknown, INDX unnecessary; ignore both */
165
            url_fseek(pb, size, SEEK_CUR);
166
            break;
167
168
        case _PC__TAG:
169
            /* need the number of palettes */
170
            url_fseek(pb, 8, SEEK_CUR);
171
            if ((ret = get_buffer(pb, preamble, 4)) != 4)
172 0bd586c5 Mike Melanson
                return AVERROR_IO;
173 493645eb Mike Melanson
            wc3->palette_count = LE_32(&preamble[0]);
174 0ecca7a4 Michael Niedermayer
            if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){
175
                wc3->palette_count= 0;
176 568e18b1 Michael Niedermayer
                return -1;
177 0ecca7a4 Michael Niedermayer
            }
178 493645eb Mike Melanson
            wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
179
            break;
180
181
        case BNAM_TAG:
182
            /* load up the name */
183 0ecca7a4 Michael Niedermayer
            if ((unsigned)size < 512)
184 493645eb Mike Melanson
                bytes_to_read = size;
185
            else
186
                bytes_to_read = 512;
187
            if ((ret = get_buffer(pb, s->title, bytes_to_read)) != bytes_to_read)
188 0bd586c5 Mike Melanson
                return AVERROR_IO;
189 493645eb Mike Melanson
            break;
190
191
        case SIZE_TAG:
192
            /* video resolution override */
193 115329f1 Diego Biurrun
            if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
194 493645eb Mike Melanson
                WC3_PREAMBLE_SIZE)
195 0bd586c5 Mike Melanson
                return AVERROR_IO;
196 493645eb Mike Melanson
            wc3->width = LE_32(&preamble[0]);
197
            wc3->height = LE_32(&preamble[4]);
198
            break;
199
200
        case PALT_TAG:
201
            /* one of several palettes */
202 0ecca7a4 Michael Niedermayer
            if ((unsigned)current_palette >= wc3->palette_count)
203 493645eb Mike Melanson
                return AVERROR_INVALIDDATA;
204 115329f1 Diego Biurrun
            if ((ret = get_buffer(pb,
205
                &wc3->palettes[current_palette * PALETTE_SIZE],
206 493645eb Mike Melanson
                PALETTE_SIZE)) != PALETTE_SIZE)
207 0bd586c5 Mike Melanson
                return AVERROR_IO;
208 493645eb Mike Melanson
209
            /* transform the current palette in place */
210
            for (i = current_palette * PALETTE_SIZE;
211
                 i < (current_palette + 1) * PALETTE_SIZE; i++) {
212 7e5ef401 Mike Melanson
                /* rotate each palette component left by 2 and use the result
213
                 * as an index into the color component table */
214 115329f1 Diego Biurrun
                rotate = ((wc3->palettes[i] << 2) & 0xFF) |
215 7e5ef401 Mike Melanson
                         ((wc3->palettes[i] >> 6) & 0xFF);
216
                wc3->palettes[i] = wc3_pal_lookup[rotate];
217 493645eb Mike Melanson
            }
218
            current_palette++;
219
            break;
220
221
        default:
222 bc874dae Michel Bardiaux
            av_log(s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
223 493645eb Mike Melanson
                preamble[0], preamble[1], preamble[2], preamble[3],
224
                preamble[0], preamble[1], preamble[2], preamble[3]);
225
            return AVERROR_INVALIDDATA;
226
            break;
227
        }
228
229 115329f1 Diego Biurrun
        if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
230 493645eb Mike Melanson
            WC3_PREAMBLE_SIZE)
231 0bd586c5 Mike Melanson
            return AVERROR_IO;
232 493645eb Mike Melanson
        fourcc_tag = LE_32(&preamble[0]);
233
        /* chunk sizes are 16-bit aligned */
234
        size = (BE_32(&preamble[4]) + 1) & (~1);
235
236
    } while (fourcc_tag != BRCH_TAG);
237
238
    /* initialize the decoder streams */
239
    st = av_new_stream(s, 0);
240
    if (!st)
241
        return AVERROR_NOMEM;
242 9ee91c2f Michael Niedermayer
    av_set_pts_info(st, 33, 1, 90000);
243 493645eb Mike Melanson
    wc3->video_stream_index = st->index;
244 01f4895c Michael Niedermayer
    st->codec->codec_type = CODEC_TYPE_VIDEO;
245
    st->codec->codec_id = CODEC_ID_XAN_WC3;
246
    st->codec->codec_tag = 0;  /* no fourcc */
247
    st->codec->width = wc3->width;
248
    st->codec->height = wc3->height;
249 493645eb Mike Melanson
250
    /* palette considerations */
251 01f4895c Michael Niedermayer
    st->codec->palctrl = &wc3->palette_control;
252 493645eb Mike Melanson
253
    st = av_new_stream(s, 0);
254
    if (!st)
255
        return AVERROR_NOMEM;
256 9ee91c2f Michael Niedermayer
    av_set_pts_info(st, 33, 1, 90000);
257 493645eb Mike Melanson
    wc3->audio_stream_index = st->index;
258 01f4895c Michael Niedermayer
    st->codec->codec_type = CODEC_TYPE_AUDIO;
259
    st->codec->codec_id = CODEC_ID_PCM_S16LE;
260
    st->codec->codec_tag = 1;
261
    st->codec->channels = WC3_AUDIO_CHANNELS;
262
    st->codec->bits_per_sample = WC3_AUDIO_BITS;
263
    st->codec->sample_rate = WC3_SAMPLE_RATE;
264
    st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
265
        st->codec->bits_per_sample;
266
    st->codec->block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
267 493645eb Mike Melanson
268
    return 0;
269
}
270
271
static int wc3_read_packet(AVFormatContext *s,
272
                           AVPacket *pkt)
273
{
274
    Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data;
275
    ByteIOContext *pb = &s->pb;
276
    unsigned int fourcc_tag;
277
    unsigned int size;
278
    int packet_read = 0;
279
    int ret = 0;
280
    unsigned char preamble[WC3_PREAMBLE_SIZE];
281
    unsigned char text[1024];
282
    unsigned int palette_number;
283 2a2bbcb0 Mike Melanson
    int i;
284
    unsigned char r, g, b;
285
    int base_palette_index;
286 493645eb Mike Melanson
287
    while (!packet_read) {
288
289
        /* get the next chunk preamble */
290
        if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
291
            WC3_PREAMBLE_SIZE)
292 0bd586c5 Mike Melanson
            ret = AVERROR_IO;
293 493645eb Mike Melanson
294
        fourcc_tag = LE_32(&preamble[0]);
295
        /* chunk sizes are 16-bit aligned */
296
        size = (BE_32(&preamble[4]) + 1) & (~1);
297
298
        switch (fourcc_tag) {
299
300
        case BRCH_TAG:
301
            /* no-op */
302
            break;
303
304
        case SHOT_TAG:
305
            /* load up new palette */
306
            if ((ret = get_buffer(pb, preamble, 4)) != 4)
307 0bd586c5 Mike Melanson
                return AVERROR_IO;
308 493645eb Mike Melanson
            palette_number = LE_32(&preamble[0]);
309
            if (palette_number >= wc3->palette_count)
310
                return AVERROR_INVALIDDATA;
311 2a2bbcb0 Mike Melanson
            base_palette_index = palette_number * PALETTE_COUNT * 3;
312
            for (i = 0; i < PALETTE_COUNT; i++) {
313
                r = wc3->palettes[base_palette_index + i * 3 + 0];
314
                g = wc3->palettes[base_palette_index + i * 3 + 1];
315
                b = wc3->palettes[base_palette_index + i * 3 + 2];
316
                wc3->palette_control.palette[i] = (r << 16) | (g << 8) | (b);
317
            }
318 ba118447 Mike Melanson
            wc3->palette_control.palette_changed = 1;
319 493645eb Mike Melanson
            break;
320
321
        case VGA__TAG:
322
            /* send out video chunk */
323 2692067a Michael Niedermayer
            ret= av_get_packet(pb, pkt, size);
324 493645eb Mike Melanson
            pkt->stream_index = wc3->video_stream_index;
325
            pkt->pts = wc3->pts;
326
            if (ret != size)
327 0bd586c5 Mike Melanson
                ret = AVERROR_IO;
328 493645eb Mike Melanson
            packet_read = 1;
329
            break;
330
331
        case TEXT_TAG:
332
            /* subtitle chunk */
333
#if 0
334
            url_fseek(pb, size, SEEK_CUR);
335
#else
336 0ecca7a4 Michael Niedermayer
            if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size)
337 0bd586c5 Mike Melanson
                ret = AVERROR_IO;
338 493645eb Mike Melanson
            else {
339
                int i = 0;
340 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
341
                av_log (s, AV_LOG_DEBUG, "  inglish: %s\n", &text[i + 1]);
342 493645eb Mike Melanson
                i += text[i] + 1;
343 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "  doytsch: %s\n", &text[i + 1]);
344 493645eb Mike Melanson
                i += text[i] + 1;
345 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "  fronsay: %s\n", &text[i + 1]);
346 493645eb Mike Melanson
            }
347
#endif
348
            break;
349
350
        case AUDI_TAG:
351
            /* send out audio chunk */
352 2692067a Michael Niedermayer
            ret= av_get_packet(pb, pkt, size);
353 493645eb Mike Melanson
            pkt->stream_index = wc3->audio_stream_index;
354
            pkt->pts = wc3->pts;
355
            if (ret != size)
356 0bd586c5 Mike Melanson
                ret = AVERROR_IO;
357 493645eb Mike Melanson
358
            /* time to advance pts */
359
            wc3->pts += WC3_FRAME_PTS_INC;
360
361
            packet_read = 1;
362
            break;
363
364
        default:
365 bb270c08 Diego Biurrun
            av_log (s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
366 493645eb Mike Melanson
                preamble[0], preamble[1], preamble[2], preamble[3],
367
                preamble[0], preamble[1], preamble[2], preamble[3]);
368
            ret = AVERROR_INVALIDDATA;
369
            packet_read = 1;
370
            break;
371
        }
372
    }
373
374
    return ret;
375
}
376
377
static int wc3_read_close(AVFormatContext *s)
378
{
379
    Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data;
380
381
    av_free(wc3->palettes);
382
383
    return 0;
384
}
385
386 ff70e601 Måns Rullgård
AVInputFormat wc3_demuxer = {
387 493645eb Mike Melanson
    "wc3movie",
388
    "Wing Commander III movie format",
389
    sizeof(Wc3DemuxContext),
390
    wc3_probe,
391
    wc3_read_header,
392
    wc3_read_packet,
393
    wc3_read_close,
394
};