]> git.sesse.net Git - ffmpeg/blob - libavformat/wc3movie.c
allow individual selection of muxers and demuxers
[ffmpeg] / libavformat / wc3movie.c
1 /*
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  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
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 #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
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     AVPaletteControl palette_control;
71
72 } Wc3DemuxContext;
73
74 /* bizarre palette lookup table */
75 static const unsigned char wc3_pal_lookup[] = {
76   0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E,
77   0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1A,
78   0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25,
79   0x27, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E, 0x2F,
80   0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
81   0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
82   0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B,
83   0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
84   0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
85   0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
86   0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C,
87   0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74,
88   0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
89   0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
90   0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
91   0x8C, 0x8D, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
92   0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x99,
93   0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1,
94   0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
95   0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
96   0xB0, 0xB1, 0xB2, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
97   0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
98   0xBE, 0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4,
99   0xC5, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB,
100   0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD0, 0xD1,
101   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   0xE6, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEB, 0xEC,
105   0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2,
106   0xF3, 0xF4, 0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9,
107   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     unsigned char rotate;
137
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     if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
152         WC3_PREAMBLE_SIZE)
153         return AVERROR_IO;
154     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                 return AVERROR_IO;
171             wc3->palette_count = LE_32(&preamble[0]);
172             if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){
173                 wc3->palette_count= 0;
174                 return -1;
175             }
176             wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
177             break;
178
179         case BNAM_TAG:
180             /* load up the name */
181             if ((unsigned)size < 512)
182                 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                 return AVERROR_IO;
187             break;
188
189         case SIZE_TAG:
190             /* video resolution override */
191             if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
192                 WC3_PREAMBLE_SIZE)
193                 return AVERROR_IO;
194             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             if ((unsigned)current_palette >= wc3->palette_count)
201                 return AVERROR_INVALIDDATA;
202             if ((ret = get_buffer(pb,
203                 &wc3->palettes[current_palette * PALETTE_SIZE],
204                 PALETTE_SIZE)) != PALETTE_SIZE)
205                 return AVERROR_IO;
206
207             /* transform the current palette in place */
208             for (i = current_palette * PALETTE_SIZE;
209                  i < (current_palette + 1) * PALETTE_SIZE; i++) {
210                 /* rotate each palette component left by 2 and use the result
211                  * as an index into the color component table */
212                 rotate = ((wc3->palettes[i] << 2) & 0xFF) |
213                          ((wc3->palettes[i] >> 6) & 0xFF);
214                 wc3->palettes[i] = wc3_pal_lookup[rotate];
215             }
216             current_palette++;
217             break;
218
219         default:
220             av_log(s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
221                 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         if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
228             WC3_PREAMBLE_SIZE)
229             return AVERROR_IO;
230         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     av_set_pts_info(st, 33, 1, 90000);
241     wc3->video_stream_index = st->index;
242     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
248     /* palette considerations */
249     st->codec->palctrl = &wc3->palette_control;
250
251     st = av_new_stream(s, 0);
252     if (!st)
253         return AVERROR_NOMEM;
254     av_set_pts_info(st, 33, 1, 90000);
255     wc3->audio_stream_index = st->index;
256     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
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     int i;
282     unsigned char r, g, b;
283     int base_palette_index;
284
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             ret = AVERROR_IO;
291
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                 return AVERROR_IO;
306             palette_number = LE_32(&preamble[0]);
307             if (palette_number >= wc3->palette_count)
308                 return AVERROR_INVALIDDATA;
309             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             wc3->palette_control.palette_changed = 1;
317             break;
318
319         case VGA__TAG:
320             /* send out video chunk */
321             ret= av_get_packet(pb, pkt, size);
322             pkt->stream_index = wc3->video_stream_index;
323             pkt->pts = wc3->pts;
324             if (ret != size)
325                 ret = AVERROR_IO;
326             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             if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size)
335                 ret = AVERROR_IO;
336             else {
337                 int i = 0;
338                 av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
339                 av_log (s, AV_LOG_DEBUG, "  inglish: %s\n", &text[i + 1]);
340                 i += text[i] + 1;
341                 av_log (s, AV_LOG_DEBUG, "  doytsch: %s\n", &text[i + 1]);
342                 i += text[i] + 1;
343                 av_log (s, AV_LOG_DEBUG, "  fronsay: %s\n", &text[i + 1]);
344             }
345 #endif
346             break;
347
348         case AUDI_TAG:
349             /* send out audio chunk */
350             ret= av_get_packet(pb, pkt, size);
351             pkt->stream_index = wc3->audio_stream_index;
352             pkt->pts = wc3->pts;
353             if (ret != size)
354                 ret = AVERROR_IO;
355
356             /* time to advance pts */
357             wc3->pts += WC3_FRAME_PTS_INC;
358
359             packet_read = 1;
360             break;
361
362         default:
363             av_log (s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
364                 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 AVInputFormat wc3_demuxer = {
385     "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 };