2 * Wing Commander III Movie (.mve) File Demuxer
3 * Copyright (c) 2003 The ffmpeg Project
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.
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.
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
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/
30 #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
31 #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \
32 (((uint8_t*)(x))[2] << 16) | \
33 (((uint8_t*)(x))[1] << 8) | \
35 #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])
36 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \
37 (((uint8_t*)(x))[1] << 16) | \
38 (((uint8_t*)(x))[2] << 8) | \
41 #define WC3_PREAMBLE_SIZE 8
43 #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \
44 ( (long)(unsigned char)(ch0) | \
45 ( (long)(unsigned char)(ch1) << 8 ) | \
46 ( (long)(unsigned char)(ch2) << 16 ) | \
47 ( (long)(unsigned char)(ch3) << 24 ) )
49 #define FORM_TAG FOURCC_TAG('F', 'O', 'R', 'M')
50 #define MOVE_TAG FOURCC_TAG('M', 'O', 'V', 'E')
51 #define _PC__TAG FOURCC_TAG('_', 'P', 'C', '_')
52 #define SOND_TAG FOURCC_TAG('S', 'O', 'N', 'D')
53 #define BNAM_TAG FOURCC_TAG('B', 'N', 'A', 'M')
54 #define SIZE_TAG FOURCC_TAG('S', 'I', 'Z', 'E')
55 #define PALT_TAG FOURCC_TAG('P', 'A', 'L', 'T')
56 #define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X')
57 #define BRCH_TAG FOURCC_TAG('B', 'R', 'C', 'H')
58 #define SHOT_TAG FOURCC_TAG('S', 'H', 'O', 'T')
59 #define VGA__TAG FOURCC_TAG('V', 'G', 'A', ' ')
60 #define TEXT_TAG FOURCC_TAG('T', 'E', 'X', 'T')
61 #define AUDI_TAG FOURCC_TAG('A', 'U', 'D', 'I')
63 /* video resolution unless otherwise specified */
64 #define WC3_DEFAULT_WIDTH 320
65 #define WC3_DEFAULT_HEIGHT 165
67 /* always use the same PCM audio parameters */
68 #define WC3_SAMPLE_RATE 22050
69 #define WC3_AUDIO_CHANNELS 1
70 #define WC3_AUDIO_BITS 16
72 /* nice, constant framerate */
73 #define WC3_FRAME_PTS_INC (90000 / 15)
75 #define PALETTE_SIZE (256 * 3)
76 #define PALETTE_COUNT 256
78 typedef struct Wc3DemuxContext {
81 unsigned char *palettes;
84 int video_stream_index;
85 int audio_stream_index;
87 AVPaletteControl palette_control;
91 /* bizarre palette lookup table */
92 static const unsigned char wc3_pal_lookup[] = {
93 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E,
94 0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1A,
95 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25,
96 0x27, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E, 0x2F,
97 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
98 0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
99 0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B,
100 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
101 0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
102 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
103 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C,
104 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74,
105 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
106 0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
107 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
108 0x8C, 0x8D, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
109 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x99,
110 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1,
111 0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
112 0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
113 0xB0, 0xB1, 0xB2, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
114 0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
115 0xBE, 0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4,
116 0xC5, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB,
117 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD0, 0xD1,
118 0xD2, 0xD3, 0xD4, 0xD5, 0xD5, 0xD6, 0xD7, 0xD8,
119 0xD9, 0xDA, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
120 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE4, 0xE5,
121 0xE6, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEB, 0xEC,
122 0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2,
123 0xF3, 0xF4, 0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9,
124 0xFA, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD
128 static int wc3_probe(AVProbeData *p)
130 if (p->buf_size < 12)
133 if ((LE_32(&p->buf[0]) != FORM_TAG) ||
134 (LE_32(&p->buf[8]) != MOVE_TAG))
137 return AVPROBE_SCORE_MAX;
140 static int wc3_read_header(AVFormatContext *s,
141 AVFormatParameters *ap)
143 Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data;
144 ByteIOContext *pb = &s->pb;
145 unsigned int fourcc_tag;
148 unsigned char preamble[WC3_PREAMBLE_SIZE];
150 int current_palette = 0;
153 unsigned char rotate;
155 /* default context members */
156 wc3->width = WC3_DEFAULT_WIDTH;
157 wc3->height = WC3_DEFAULT_HEIGHT;
158 wc3->palettes = NULL;
159 wc3->palette_count = 0;
161 wc3->video_stream_index = wc3->audio_stream_index = 0;
163 /* skip the first 3 32-bit numbers */
164 url_fseek(pb, 12, SEEK_CUR);
166 /* traverse through the chunks and load the header information before
167 * the first BRCH tag */
168 if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
171 fourcc_tag = LE_32(&preamble[0]);
172 size = (BE_32(&preamble[4]) + 1) & (~1);
175 switch (fourcc_tag) {
179 /* SOND unknown, INDX unnecessary; ignore both */
180 url_fseek(pb, size, SEEK_CUR);
184 /* need the number of palettes */
185 url_fseek(pb, 8, SEEK_CUR);
186 if ((ret = get_buffer(pb, preamble, 4)) != 4)
188 wc3->palette_count = LE_32(&preamble[0]);
189 wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
193 /* load up the name */
195 bytes_to_read = size;
198 if ((ret = get_buffer(pb, s->title, bytes_to_read)) != bytes_to_read)
203 /* video resolution override */
204 if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
207 wc3->width = LE_32(&preamble[0]);
208 wc3->height = LE_32(&preamble[4]);
212 /* one of several palettes */
213 if (current_palette >= wc3->palette_count)
214 return AVERROR_INVALIDDATA;
215 if ((ret = get_buffer(pb,
216 &wc3->palettes[current_palette * PALETTE_SIZE],
217 PALETTE_SIZE)) != PALETTE_SIZE)
220 /* transform the current palette in place */
221 for (i = current_palette * PALETTE_SIZE;
222 i < (current_palette + 1) * PALETTE_SIZE; i++) {
223 /* rotate each palette component left by 2 and use the result
224 * as an index into the color component table */
225 rotate = ((wc3->palettes[i] << 2) & 0xFF) |
226 ((wc3->palettes[i] >> 6) & 0xFF);
227 wc3->palettes[i] = wc3_pal_lookup[rotate];
233 printf (" unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
234 preamble[0], preamble[1], preamble[2], preamble[3],
235 preamble[0], preamble[1], preamble[2], preamble[3]);
236 return AVERROR_INVALIDDATA;
240 if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
243 fourcc_tag = LE_32(&preamble[0]);
244 /* chunk sizes are 16-bit aligned */
245 size = (BE_32(&preamble[4]) + 1) & (~1);
247 } while (fourcc_tag != BRCH_TAG);
249 /* initialize the decoder streams */
250 st = av_new_stream(s, 0);
252 return AVERROR_NOMEM;
253 wc3->video_stream_index = st->index;
254 st->codec.codec_type = CODEC_TYPE_VIDEO;
255 st->codec.codec_id = CODEC_ID_XAN_WC3;
256 st->codec.codec_tag = 0; /* no fourcc */
257 st->codec.width = wc3->width;
258 st->codec.height = wc3->height;
260 /* palette considerations */
261 st->codec.extradata_size = sizeof(AVPaletteControl);
262 st->codec.extradata = &wc3->palette_control;
264 st = av_new_stream(s, 0);
266 return AVERROR_NOMEM;
267 wc3->audio_stream_index = st->index;
268 st->codec.codec_type = CODEC_TYPE_AUDIO;
269 st->codec.codec_id = CODEC_ID_PCM_S16LE;
270 st->codec.codec_tag = 1;
271 st->codec.channels = WC3_AUDIO_CHANNELS;
272 st->codec.bits_per_sample = WC3_AUDIO_BITS;
273 st->codec.sample_rate = WC3_SAMPLE_RATE;
274 st->codec.bit_rate = st->codec.channels * st->codec.sample_rate *
275 st->codec.bits_per_sample;
276 st->codec.block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
278 /* set the pts reference (1 pts = 1/90000) */
285 static int wc3_read_packet(AVFormatContext *s,
288 Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data;
289 ByteIOContext *pb = &s->pb;
290 unsigned int fourcc_tag;
294 unsigned char preamble[WC3_PREAMBLE_SIZE];
295 unsigned char text[1024];
296 unsigned int palette_number;
298 while (!packet_read) {
300 /* get the next chunk preamble */
301 if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
305 fourcc_tag = LE_32(&preamble[0]);
306 /* chunk sizes are 16-bit aligned */
307 size = (BE_32(&preamble[4]) + 1) & (~1);
309 switch (fourcc_tag) {
316 /* load up new palette */
317 if ((ret = get_buffer(pb, preamble, 4)) != 4)
319 palette_number = LE_32(&preamble[0]);
320 if (palette_number >= wc3->palette_count)
321 return AVERROR_INVALIDDATA;
322 memcpy(wc3->palette_control.palette,
323 &wc3->palettes[palette_number * PALETTE_COUNT * 3],
325 wc3->palette_control.palette_changed = 1;
329 /* send out video chunk */
330 if (av_new_packet(pkt, size))
332 pkt->stream_index = wc3->video_stream_index;
334 ret = get_buffer(pb, pkt->data, size);
343 url_fseek(pb, size, SEEK_CUR);
345 if ((ret = get_buffer(pb, text, size)) != size)
349 printf ("Subtitle time!\n");
350 printf (" inglish: %s\n", &text[i + 1]);
352 printf (" doytsch: %s\n", &text[i + 1]);
354 printf (" fronsay: %s\n", &text[i + 1]);
360 /* send out audio chunk */
361 if (av_new_packet(pkt, size))
363 pkt->stream_index = wc3->audio_stream_index;
365 ret = get_buffer(pb, pkt->data, size);
369 /* time to advance pts */
370 wc3->pts += WC3_FRAME_PTS_INC;
376 printf (" unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
377 preamble[0], preamble[1], preamble[2], preamble[3],
378 preamble[0], preamble[1], preamble[2], preamble[3]);
379 ret = AVERROR_INVALIDDATA;
388 static int wc3_read_close(AVFormatContext *s)
390 Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data;
392 av_free(wc3->palettes);
397 static AVInputFormat wc3_iformat = {
399 "Wing Commander III movie format",
400 sizeof(Wc3DemuxContext),
409 av_register_input_format(&wc3_iformat);