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