]> git.sesse.net Git - ffmpeg/blob - libavformat/wc3movie.c
Quote path expression to take care of $(prefix) possibly containing spaces.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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                 return -1;
174             wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
175             break;
176
177         case BNAM_TAG:
178             /* load up the name */
179             if (size < 512)
180                 bytes_to_read = size;
181             else
182                 bytes_to_read = 512;
183             if ((ret = get_buffer(pb, s->title, bytes_to_read)) != bytes_to_read)
184                 return AVERROR_IO;
185             break;
186
187         case SIZE_TAG:
188             /* video resolution override */
189             if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) != 
190                 WC3_PREAMBLE_SIZE)
191                 return AVERROR_IO;
192             wc3->width = LE_32(&preamble[0]);
193             wc3->height = LE_32(&preamble[4]);
194             break;
195
196         case PALT_TAG:
197             /* one of several palettes */
198             if (current_palette >= wc3->palette_count)
199                 return AVERROR_INVALIDDATA;
200             if ((ret = get_buffer(pb, 
201                 &wc3->palettes[current_palette * PALETTE_SIZE], 
202                 PALETTE_SIZE)) != PALETTE_SIZE)
203                 return AVERROR_IO;
204
205             /* transform the current palette in place */
206             for (i = current_palette * PALETTE_SIZE;
207                  i < (current_palette + 1) * PALETTE_SIZE; i++) {
208                 /* rotate each palette component left by 2 and use the result
209                  * as an index into the color component table */
210                 rotate = ((wc3->palettes[i] << 2) & 0xFF) | 
211                          ((wc3->palettes[i] >> 6) & 0xFF);
212                 wc3->palettes[i] = wc3_pal_lookup[rotate];
213             }
214             current_palette++;
215             break;
216
217         default:
218             av_log(s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
219                 preamble[0], preamble[1], preamble[2], preamble[3],
220                 preamble[0], preamble[1], preamble[2], preamble[3]);
221             return AVERROR_INVALIDDATA;
222             break;
223         }
224
225         if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) != 
226             WC3_PREAMBLE_SIZE)
227             return AVERROR_IO;
228         fourcc_tag = LE_32(&preamble[0]);
229         /* chunk sizes are 16-bit aligned */
230         size = (BE_32(&preamble[4]) + 1) & (~1);
231
232     } while (fourcc_tag != BRCH_TAG);
233
234     /* initialize the decoder streams */
235     st = av_new_stream(s, 0);
236     if (!st)
237         return AVERROR_NOMEM;
238     av_set_pts_info(st, 33, 1, 90000);
239     wc3->video_stream_index = st->index;
240     st->codec.codec_type = CODEC_TYPE_VIDEO;
241     st->codec.codec_id = CODEC_ID_XAN_WC3;
242     st->codec.codec_tag = 0;  /* no fourcc */
243     st->codec.width = wc3->width;
244     st->codec.height = wc3->height;
245
246     /* palette considerations */
247     st->codec.palctrl = &wc3->palette_control;
248
249     st = av_new_stream(s, 0);
250     if (!st)
251         return AVERROR_NOMEM;
252     av_set_pts_info(st, 33, 1, 90000);
253     wc3->audio_stream_index = st->index;
254     st->codec.codec_type = CODEC_TYPE_AUDIO;
255     st->codec.codec_id = CODEC_ID_PCM_S16LE;
256     st->codec.codec_tag = 1;
257     st->codec.channels = WC3_AUDIO_CHANNELS;
258     st->codec.bits_per_sample = WC3_AUDIO_BITS;
259     st->codec.sample_rate = WC3_SAMPLE_RATE;
260     st->codec.bit_rate = st->codec.channels * st->codec.sample_rate *
261         st->codec.bits_per_sample;
262     st->codec.block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
263
264     return 0;
265 }
266
267 static int wc3_read_packet(AVFormatContext *s,
268                            AVPacket *pkt)
269 {
270     Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data;
271     ByteIOContext *pb = &s->pb;
272     unsigned int fourcc_tag;
273     unsigned int size;
274     int packet_read = 0;
275     int ret = 0;
276     unsigned char preamble[WC3_PREAMBLE_SIZE];
277     unsigned char text[1024];
278     unsigned int palette_number;
279     int i;
280     unsigned char r, g, b;
281     int base_palette_index;
282
283     while (!packet_read) {
284
285         /* get the next chunk preamble */
286         if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
287             WC3_PREAMBLE_SIZE)
288             ret = AVERROR_IO;
289
290         fourcc_tag = LE_32(&preamble[0]);
291         /* chunk sizes are 16-bit aligned */
292         size = (BE_32(&preamble[4]) + 1) & (~1);
293
294         switch (fourcc_tag) {
295
296         case BRCH_TAG:
297             /* no-op */
298             break;
299
300         case SHOT_TAG:
301             /* load up new palette */
302             if ((ret = get_buffer(pb, preamble, 4)) != 4)
303                 return AVERROR_IO;
304             palette_number = LE_32(&preamble[0]);
305             if (palette_number >= wc3->palette_count)
306                 return AVERROR_INVALIDDATA;
307             base_palette_index = palette_number * PALETTE_COUNT * 3;
308             for (i = 0; i < PALETTE_COUNT; i++) {
309                 r = wc3->palettes[base_palette_index + i * 3 + 0];
310                 g = wc3->palettes[base_palette_index + i * 3 + 1];
311                 b = wc3->palettes[base_palette_index + i * 3 + 2];
312                 wc3->palette_control.palette[i] = (r << 16) | (g << 8) | (b);
313             }
314             wc3->palette_control.palette_changed = 1;
315             break;
316
317         case VGA__TAG:
318             /* send out video chunk */
319             if (av_new_packet(pkt, size))
320                 ret = AVERROR_IO;
321             pkt->stream_index = wc3->video_stream_index;
322             pkt->pts = wc3->pts;
323             ret = get_buffer(pb, pkt->data, size);
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 ((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             if (av_new_packet(pkt, size))
351                 ret = AVERROR_IO;
352             pkt->stream_index = wc3->audio_stream_index;
353             pkt->pts = wc3->pts;
354             ret = get_buffer(pb, pkt->data, size);
355             if (ret != size)
356                 ret = AVERROR_IO;
357
358             /* time to advance pts */
359             wc3->pts += WC3_FRAME_PTS_INC;
360
361             packet_read = 1;
362             break;
363
364         default:
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;
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 static AVInputFormat wc3_iformat = {
387     "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 };
395
396 int wc3_init(void)
397 {
398     av_register_input_format(&wc3_iformat);
399     return 0;
400 }