• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/ffmpeg/libavformat/
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
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
62typedef 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 251 inclusive:
80 * wc3_pal_lookup[i] = round(pow(i / 256.0, 0.8) * 256);
81 * values 252, 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 */
87static 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
123static 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
135static 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    int ret = 0;
144    int current_palette = 0;
145    char *buffer;
146    int i;
147    unsigned char rotate;
148
149    /* default context members */
150    wc3->width = WC3_DEFAULT_WIDTH;
151    wc3->height = WC3_DEFAULT_HEIGHT;
152    wc3->palettes = NULL;
153    wc3->palette_count = 0;
154    wc3->pts = 0;
155    wc3->video_stream_index = wc3->audio_stream_index = 0;
156
157    /* skip the first 3 32-bit numbers */
158    url_fseek(pb, 12, SEEK_CUR);
159
160    /* traverse through the chunks and load the header information before
161     * the first BRCH tag */
162    fourcc_tag = get_le32(pb);
163    size = (get_be32(pb) + 1) & (~1);
164
165    do {
166        switch (fourcc_tag) {
167
168        case SOND_TAG:
169        case INDX_TAG:
170            /* SOND unknown, INDX unnecessary; ignore both */
171            url_fseek(pb, size, SEEK_CUR);
172            break;
173
174        case PC__TAG:
175            /* need the number of palettes */
176            url_fseek(pb, 8, SEEK_CUR);
177            wc3->palette_count = get_le32(pb);
178            if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){
179                wc3->palette_count= 0;
180                return -1;
181            }
182            wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
183            break;
184
185        case BNAM_TAG:
186            /* load up the name */
187            buffer = av_malloc(size+1);
188            if (!buffer)
189                return AVERROR(ENOMEM);
190            if ((ret = get_buffer(pb, buffer, size)) != size)
191                return AVERROR(EIO);
192            buffer[size] = 0;
193            av_metadata_set2(&s->metadata, "title", buffer,
194                                   AV_METADATA_DONT_STRDUP_VAL);
195            break;
196
197        case SIZE_TAG:
198            /* video resolution override */
199            wc3->width  = get_le32(pb);
200            wc3->height = get_le32(pb);
201            break;
202
203        case PALT_TAG:
204            /* one of several palettes */
205            if ((unsigned)current_palette >= wc3->palette_count)
206                return AVERROR_INVALIDDATA;
207            if ((ret = get_buffer(pb,
208                &wc3->palettes[current_palette * PALETTE_SIZE],
209                PALETTE_SIZE)) != PALETTE_SIZE)
210                return AVERROR(EIO);
211
212            /* transform the current palette in place */
213            for (i = current_palette * PALETTE_SIZE;
214                 i < (current_palette + 1) * PALETTE_SIZE; i++) {
215                /* rotate each palette component left by 2 and use the result
216                 * as an index into the color component table */
217                rotate = ((wc3->palettes[i] << 2) & 0xFF) |
218                         ((wc3->palettes[i] >> 6) & 0xFF);
219                wc3->palettes[i] = wc3_pal_lookup[rotate];
220            }
221            current_palette++;
222            break;
223
224        default:
225            av_log(s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
226                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24),
227                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24));
228            return AVERROR_INVALIDDATA;
229            break;
230        }
231
232        fourcc_tag = get_le32(pb);
233        /* chunk sizes are 16-bit aligned */
234        size = (get_be32(pb) + 1) & (~1);
235        if (url_feof(pb))
236            return AVERROR(EIO);
237
238    } while (fourcc_tag != BRCH_TAG);
239
240    /* initialize the decoder streams */
241    st = av_new_stream(s, 0);
242    if (!st)
243        return AVERROR(ENOMEM);
244    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
245    wc3->video_stream_index = st->index;
246    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
247    st->codec->codec_id = CODEC_ID_XAN_WC3;
248    st->codec->codec_tag = 0;  /* no fourcc */
249    st->codec->width = wc3->width;
250    st->codec->height = wc3->height;
251
252    /* palette considerations */
253    st->codec->palctrl = &wc3->palette_control;
254
255    st = av_new_stream(s, 0);
256    if (!st)
257        return AVERROR(ENOMEM);
258    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
259    wc3->audio_stream_index = st->index;
260    st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
261    st->codec->codec_id = CODEC_ID_PCM_S16LE;
262    st->codec->codec_tag = 1;
263    st->codec->channels = WC3_AUDIO_CHANNELS;
264    st->codec->bits_per_coded_sample = WC3_AUDIO_BITS;
265    st->codec->sample_rate = WC3_SAMPLE_RATE;
266    st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
267        st->codec->bits_per_coded_sample;
268    st->codec->block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
269
270    return 0;
271}
272
273static int wc3_read_packet(AVFormatContext *s,
274                           AVPacket *pkt)
275{
276    Wc3DemuxContext *wc3 = s->priv_data;
277    ByteIOContext *pb = s->pb;
278    unsigned int fourcc_tag;
279    unsigned int size;
280    int packet_read = 0;
281    int ret = 0;
282    unsigned char text[1024];
283    unsigned int palette_number;
284    int i;
285    unsigned char r, g, b;
286    int base_palette_index;
287
288    while (!packet_read) {
289
290        fourcc_tag = get_le32(pb);
291        /* chunk sizes are 16-bit aligned */
292        size = (get_be32(pb) + 1) & (~1);
293        if (url_feof(pb))
294            return AVERROR(EIO);
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            palette_number = get_le32(pb);
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            ret= av_get_packet(pb, pkt, size);
320            pkt->stream_index = wc3->video_stream_index;
321            pkt->pts = wc3->pts;
322            packet_read = 1;
323            break;
324
325        case TEXT_TAG:
326            /* subtitle chunk */
327#if 0
328            url_fseek(pb, size, SEEK_CUR);
329#else
330            if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size)
331                ret = AVERROR(EIO);
332            else {
333                int i = 0;
334                av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
335                av_log (s, AV_LOG_DEBUG, "  inglish: %s\n", &text[i + 1]);
336                i += text[i] + 1;
337                av_log (s, AV_LOG_DEBUG, "  doytsch: %s\n", &text[i + 1]);
338                i += text[i] + 1;
339                av_log (s, AV_LOG_DEBUG, "  fronsay: %s\n", &text[i + 1]);
340            }
341#endif
342            break;
343
344        case AUDI_TAG:
345            /* send out audio chunk */
346            ret= av_get_packet(pb, pkt, size);
347            pkt->stream_index = wc3->audio_stream_index;
348            pkt->pts = wc3->pts;
349
350            /* time to advance pts */
351            wc3->pts++;
352
353            packet_read = 1;
354            break;
355
356        default:
357            av_log (s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
358                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24),
359                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24));
360            ret = AVERROR_INVALIDDATA;
361            packet_read = 1;
362            break;
363        }
364    }
365
366    return ret;
367}
368
369static int wc3_read_close(AVFormatContext *s)
370{
371    Wc3DemuxContext *wc3 = s->priv_data;
372
373    av_free(wc3->palettes);
374
375    return 0;
376}
377
378AVInputFormat wc3_demuxer = {
379    "wc3movie",
380    NULL_IF_CONFIG_SMALL("Wing Commander III movie format"),
381    sizeof(Wc3DemuxContext),
382    wc3_probe,
383    wc3_read_header,
384    wc3_read_packet,
385    wc3_read_close,
386};
387