2 * Wing Commander III Movie (.mve) File Demuxer
3 * Copyright (c) 2003 The ffmpeg Project
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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/
32 #define WC3_PREAMBLE_SIZE 8
34 #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')
48 /* video resolution unless otherwise specified */
49 #define WC3_DEFAULT_WIDTH 320
50 #define WC3_DEFAULT_HEIGHT 165
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
57 /* nice, constant framerate */
58 #define WC3_FRAME_FPS 15
60 #define PALETTE_SIZE (256 * 3)
61 #define PALETTE_COUNT 256
63 typedef struct Wc3DemuxContext
{
66 unsigned char *palettes
;
69 int video_stream_index
;
70 int audio_stream_index
;
72 AVPaletteControl palette_control
;
76 /* bizarre palette lookup table */
77 static const unsigned char wc3_pal_lookup
[] = {
78 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E,
79 0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1A,
80 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25,
81 0x27, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E, 0x2F,
82 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
83 0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
84 0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B,
85 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
86 0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
87 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
88 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C,
89 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74,
90 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
91 0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
92 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
93 0x8C, 0x8D, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
94 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x99,
95 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1,
96 0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
97 0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
98 0xB0, 0xB1, 0xB2, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
99 0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
100 0xBE, 0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4,
101 0xC5, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB,
102 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD0, 0xD1,
103 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 0xE6, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEB, 0xEC,
107 0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2,
108 0xF3, 0xF4, 0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9,
109 0xFA, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD
113 static int wc3_probe(AVProbeData
*p
)
115 if (p
->buf_size
< 12)
118 if ((AV_RL32(&p
->buf
[0]) != FORM_TAG
) ||
119 (AV_RL32(&p
->buf
[8]) != MOVE_TAG
))
122 return AVPROBE_SCORE_MAX
;
125 static int wc3_read_header(AVFormatContext
*s
,
126 AVFormatParameters
*ap
)
128 Wc3DemuxContext
*wc3
= s
->priv_data
;
129 ByteIOContext
*pb
= s
->pb
;
130 unsigned int fourcc_tag
;
133 unsigned char preamble
[WC3_PREAMBLE_SIZE
];
135 int current_palette
= 0;
138 unsigned char rotate
;
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;
146 wc3
->video_stream_index
= wc3
->audio_stream_index
= 0;
148 /* skip the first 3 32-bit numbers */
149 url_fseek(pb
, 12, SEEK_CUR
);
151 /* traverse through the chunks and load the header information before
152 * the first BRCH tag */
153 if ((ret
= get_buffer(pb
, preamble
, WC3_PREAMBLE_SIZE
)) !=
156 fourcc_tag
= AV_RL32(&preamble
[0]);
157 size
= (AV_RB32(&preamble
[4]) + 1) & (~1);
160 switch (fourcc_tag
) {
164 /* SOND unknown, INDX unnecessary; ignore both */
165 url_fseek(pb
, size
, SEEK_CUR
);
169 /* need the number of palettes */
170 url_fseek(pb
, 8, SEEK_CUR
);
171 if ((ret
= get_buffer(pb
, preamble
, 4)) != 4)
173 wc3
->palette_count
= AV_RL32(&preamble
[0]);
174 if((unsigned)wc3
->palette_count
>= UINT_MAX
/ PALETTE_SIZE
){
175 wc3
->palette_count
= 0;
178 wc3
->palettes
= av_malloc(wc3
->palette_count
* PALETTE_SIZE
);
182 /* load up the name */
183 if ((unsigned)size
< 512)
184 bytes_to_read
= size
;
187 if ((ret
= get_buffer(pb
, s
->title
, bytes_to_read
)) != bytes_to_read
)
192 /* video resolution override */
193 if ((ret
= get_buffer(pb
, preamble
, WC3_PREAMBLE_SIZE
)) !=
196 wc3
->width
= AV_RL32(&preamble
[0]);
197 wc3
->height
= AV_RL32(&preamble
[4]);
201 /* one of several palettes */
202 if ((unsigned)current_palette
>= wc3
->palette_count
)
203 return AVERROR_INVALIDDATA
;
204 if ((ret
= get_buffer(pb
,
205 &wc3
->palettes
[current_palette
* PALETTE_SIZE
],
206 PALETTE_SIZE
)) != PALETTE_SIZE
)
209 /* transform the current palette in place */
210 for (i
= current_palette
* PALETTE_SIZE
;
211 i
< (current_palette
+ 1) * PALETTE_SIZE
; i
++) {
212 /* rotate each palette component left by 2 and use the result
213 * as an index into the color component table */
214 rotate
= ((wc3
->palettes
[i
] << 2) & 0xFF) |
215 ((wc3
->palettes
[i
] >> 6) & 0xFF);
216 wc3
->palettes
[i
] = wc3_pal_lookup
[rotate
];
222 av_log(s
, AV_LOG_ERROR
, " unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
223 preamble
[0], preamble
[1], preamble
[2], preamble
[3],
224 preamble
[0], preamble
[1], preamble
[2], preamble
[3]);
225 return AVERROR_INVALIDDATA
;
229 if ((ret
= get_buffer(pb
, preamble
, WC3_PREAMBLE_SIZE
)) !=
232 fourcc_tag
= AV_RL32(&preamble
[0]);
233 /* chunk sizes are 16-bit aligned */
234 size
= (AV_RB32(&preamble
[4]) + 1) & (~1);
236 } while (fourcc_tag
!= BRCH_TAG
);
238 /* initialize the decoder streams */
239 st
= av_new_stream(s
, 0);
241 return AVERROR(ENOMEM
);
242 av_set_pts_info(st
, 33, 1, WC3_FRAME_FPS
);
243 wc3
->video_stream_index
= st
->index
;
244 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
;
250 /* palette considerations */
251 st
->codec
->palctrl
= &wc3
->palette_control
;
253 st
= av_new_stream(s
, 0);
255 return AVERROR(ENOMEM
);
256 av_set_pts_info(st
, 33, 1, WC3_FRAME_FPS
);
257 wc3
->audio_stream_index
= st
->index
;
258 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
;
271 static int wc3_read_packet(AVFormatContext
*s
,
274 Wc3DemuxContext
*wc3
= s
->priv_data
;
275 ByteIOContext
*pb
= s
->pb
;
276 unsigned int fourcc_tag
;
280 unsigned char preamble
[WC3_PREAMBLE_SIZE
];
281 unsigned char text
[1024];
282 unsigned int palette_number
;
284 unsigned char r
, g
, b
;
285 int base_palette_index
;
287 while (!packet_read
) {
289 /* get the next chunk preamble */
290 if ((ret
= get_buffer(pb
, preamble
, WC3_PREAMBLE_SIZE
)) !=
294 fourcc_tag
= AV_RL32(&preamble
[0]);
295 /* chunk sizes are 16-bit aligned */
296 size
= (AV_RB32(&preamble
[4]) + 1) & (~1);
298 switch (fourcc_tag
) {
305 /* load up new palette */
306 if ((ret
= get_buffer(pb
, preamble
, 4)) != 4)
308 palette_number
= AV_RL32(&preamble
[0]);
309 if (palette_number
>= wc3
->palette_count
)
310 return AVERROR_INVALIDDATA
;
311 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
);
318 wc3
->palette_control
.palette_changed
= 1;
322 /* send out video chunk */
323 ret
= av_get_packet(pb
, pkt
, size
);
324 pkt
->stream_index
= wc3
->video_stream_index
;
334 url_fseek(pb
, size
, SEEK_CUR
);
336 if ((unsigned)size
> sizeof(text
) || (ret
= get_buffer(pb
, text
, size
)) != size
)
340 av_log (s
, AV_LOG_DEBUG
, "Subtitle time!\n");
341 av_log (s
, AV_LOG_DEBUG
, " inglish: %s\n", &text
[i
+ 1]);
343 av_log (s
, AV_LOG_DEBUG
, " doytsch: %s\n", &text
[i
+ 1]);
345 av_log (s
, AV_LOG_DEBUG
, " fronsay: %s\n", &text
[i
+ 1]);
351 /* send out audio chunk */
352 ret
= av_get_packet(pb
, pkt
, size
);
353 pkt
->stream_index
= wc3
->audio_stream_index
;
358 /* time to advance pts */
365 av_log (s
, AV_LOG_ERROR
, " unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
366 preamble
[0], preamble
[1], preamble
[2], preamble
[3],
367 preamble
[0], preamble
[1], preamble
[2], preamble
[3]);
368 ret
= AVERROR_INVALIDDATA
;
377 static int wc3_read_close(AVFormatContext
*s
)
379 Wc3DemuxContext
*wc3
= s
->priv_data
;
381 av_free(wc3
->palettes
);
386 AVInputFormat wc3_demuxer
= {
388 NULL_IF_CONFIG_SMALL("Wing Commander III movie format"),
389 sizeof(Wc3DemuxContext
),