Statistics
| Branch: | Revision:

ffmpeg / libavformat / wc3movie.c @ 4b65d88f

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