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