Statistics
| Branch: | Revision:

ffmpeg / libavformat / wc3movie.c @ bd51c013

History | View | Annotate | Download (12.9 KB)

1 493645eb Mike Melanson
/*
2
 * Wing Commander III Movie (.mve) File Demuxer
3
 * Copyright (c) 2003 The ffmpeg Project
4
 *
5 b78e7197 Diego Biurrun
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8 493645eb Mike Melanson
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10 b78e7197 Diego Biurrun
 * version 2.1 of the License, or (at your option) any later version.
11 493645eb Mike Melanson
 *
12 b78e7197 Diego Biurrun
 * FFmpeg is distributed in the hope that it will be useful,
13 493645eb Mike Melanson
 * 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 b78e7197 Diego Biurrun
 * License along with FFmpeg; if not, write to the Free Software
19 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 493645eb Mike Melanson
 */
21
22
/**
23 bad5537e Diego Biurrun
 * @file libavformat/wc3movie.c
24 493645eb Mike Melanson
 * 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 6a5d31ac Diego Biurrun
#include "libavutil/intreadwrite.h"
31 493645eb Mike Melanson
#include "avformat.h"
32
33
#define WC3_PREAMBLE_SIZE 8
34
35 3a278992 Mike Melanson
#define FORM_TAG MKTAG('F', 'O', 'R', 'M')
36
#define MOVE_TAG MKTAG('M', 'O', 'V', 'E')
37 7fffc879 Michael Niedermayer
#define  PC__TAG MKTAG('_', 'P', 'C', '_')
38 3a278992 Mike Melanson
#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 493645eb Mike Melanson
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 74e21d03 Mike Melanson
#define WC3_FRAME_FPS 15
60 493645eb Mike Melanson
61
#define PALETTE_SIZE (256 * 3)
62
#define PALETTE_COUNT 256
63
64
typedef 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 ba118447 Mike Melanson
    AVPaletteControl palette_control;
74 493645eb Mike Melanson
75
} Wc3DemuxContext;
76
77
/* bizarre palette lookup table */
78 7e5ef401 Mike Melanson
static const unsigned char wc3_pal_lookup[] = {
79 115329f1 Diego Biurrun
  0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E,
80 493645eb Mike Melanson
  0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1A,
81 115329f1 Diego Biurrun
  0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25,
82 493645eb Mike Melanson
  0x27, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E, 0x2F,
83 115329f1 Diego Biurrun
  0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
84 493645eb Mike Melanson
  0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
85 115329f1 Diego Biurrun
  0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B,
86 493645eb Mike Melanson
  0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
87 115329f1 Diego Biurrun
  0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
88 493645eb Mike Melanson
  0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
89 115329f1 Diego Biurrun
  0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C,
90 493645eb Mike Melanson
  0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74,
91 115329f1 Diego Biurrun
  0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
92 493645eb Mike Melanson
  0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
93 115329f1 Diego Biurrun
  0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
94 493645eb Mike Melanson
  0x8C, 0x8D, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
95 115329f1 Diego Biurrun
  0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x99,
96 493645eb Mike Melanson
  0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1,
97 115329f1 Diego Biurrun
  0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
98 493645eb Mike Melanson
  0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
99 115329f1 Diego Biurrun
  0xB0, 0xB1, 0xB2, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
100 493645eb Mike Melanson
  0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
101 115329f1 Diego Biurrun
  0xBE, 0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4,
102 493645eb Mike Melanson
  0xC5, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB,
103 115329f1 Diego Biurrun
  0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD0, 0xD1,
104 493645eb Mike Melanson
  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 115329f1 Diego Biurrun
  0xE6, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEB, 0xEC,
108 493645eb Mike Melanson
  0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2,
109 115329f1 Diego Biurrun
  0xF3, 0xF4, 0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9,
110 493645eb Mike Melanson
  0xFA, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD
111
};
112
113
114
static int wc3_probe(AVProbeData *p)
115
{
116
    if (p->buf_size < 12)
117
        return 0;
118
119 fead30d4 Alex Beregszaszi
    if ((AV_RL32(&p->buf[0]) != FORM_TAG) ||
120
        (AV_RL32(&p->buf[8]) != MOVE_TAG))
121 493645eb Mike Melanson
        return 0;
122
123
    return AVPROBE_SCORE_MAX;
124
}
125
126
static int wc3_read_header(AVFormatContext *s,
127
                           AVFormatParameters *ap)
128
{
129 e4141433 Nicholas Tung
    Wc3DemuxContext *wc3 = s->priv_data;
130 899681cd Björn Axelsson
    ByteIOContext *pb = s->pb;
131 493645eb Mike Melanson
    unsigned int fourcc_tag;
132
    unsigned int size;
133
    AVStream *st;
134
    unsigned char preamble[WC3_PREAMBLE_SIZE];
135 0d2e86d7 Aurelien Jacobs
    char buffer[513];
136 493645eb Mike Melanson
    int ret = 0;
137
    int current_palette = 0;
138
    int bytes_to_read;
139
    int i;
140 7e5ef401 Mike Melanson
    unsigned char rotate;
141 493645eb Mike Melanson
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 115329f1 Diego Biurrun
    if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
156 493645eb Mike Melanson
        WC3_PREAMBLE_SIZE)
157 6f3e0b21 Panagiotis Issaris
        return AVERROR(EIO);
158 fead30d4 Alex Beregszaszi
    fourcc_tag = AV_RL32(&preamble[0]);
159
    size = (AV_RB32(&preamble[4]) + 1) & (~1);
160 493645eb Mike Melanson
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 7fffc879 Michael Niedermayer
        case PC__TAG:
171 493645eb Mike Melanson
            /* need the number of palettes */
172
            url_fseek(pb, 8, SEEK_CUR);
173
            if ((ret = get_buffer(pb, preamble, 4)) != 4)
174 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
175 fead30d4 Alex Beregszaszi
            wc3->palette_count = AV_RL32(&preamble[0]);
176 0ecca7a4 Michael Niedermayer
            if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){
177
                wc3->palette_count= 0;
178 568e18b1 Michael Niedermayer
                return -1;
179 0ecca7a4 Michael Niedermayer
            }
180 493645eb Mike Melanson
            wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
181
            break;
182
183
        case BNAM_TAG:
184
            /* load up the name */
185 0ecca7a4 Michael Niedermayer
            if ((unsigned)size < 512)
186 493645eb Mike Melanson
                bytes_to_read = size;
187
            else
188
                bytes_to_read = 512;
189 0d2e86d7 Aurelien Jacobs
            if ((ret = get_buffer(pb, buffer, bytes_to_read)) != bytes_to_read)
190 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
191 0d2e86d7 Aurelien Jacobs
            buffer[bytes_to_read] = 0;
192
            av_metadata_set(&s->metadata, "title", buffer);
193 493645eb Mike Melanson
            break;
194
195
        case SIZE_TAG:
196
            /* video resolution override */
197 115329f1 Diego Biurrun
            if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
198 493645eb Mike Melanson
                WC3_PREAMBLE_SIZE)
199 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
200 fead30d4 Alex Beregszaszi
            wc3->width = AV_RL32(&preamble[0]);
201
            wc3->height = AV_RL32(&preamble[4]);
202 493645eb Mike Melanson
            break;
203
204
        case PALT_TAG:
205
            /* one of several palettes */
206 0ecca7a4 Michael Niedermayer
            if ((unsigned)current_palette >= wc3->palette_count)
207 493645eb Mike Melanson
                return AVERROR_INVALIDDATA;
208 115329f1 Diego Biurrun
            if ((ret = get_buffer(pb,
209
                &wc3->palettes[current_palette * PALETTE_SIZE],
210 493645eb Mike Melanson
                PALETTE_SIZE)) != PALETTE_SIZE)
211 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
212 493645eb Mike Melanson
213
            /* transform the current palette in place */
214
            for (i = current_palette * PALETTE_SIZE;
215
                 i < (current_palette + 1) * PALETTE_SIZE; i++) {
216 7e5ef401 Mike Melanson
                /* rotate each palette component left by 2 and use the result
217
                 * as an index into the color component table */
218 115329f1 Diego Biurrun
                rotate = ((wc3->palettes[i] << 2) & 0xFF) |
219 7e5ef401 Mike Melanson
                         ((wc3->palettes[i] >> 6) & 0xFF);
220
                wc3->palettes[i] = wc3_pal_lookup[rotate];
221 493645eb Mike Melanson
            }
222
            current_palette++;
223
            break;
224
225
        default:
226 bc874dae Michel Bardiaux
            av_log(s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
227 493645eb Mike Melanson
                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 115329f1 Diego Biurrun
        if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) !=
234 493645eb Mike Melanson
            WC3_PREAMBLE_SIZE)
235 6f3e0b21 Panagiotis Issaris
            return AVERROR(EIO);
236 fead30d4 Alex Beregszaszi
        fourcc_tag = AV_RL32(&preamble[0]);
237 493645eb Mike Melanson
        /* chunk sizes are 16-bit aligned */
238 fead30d4 Alex Beregszaszi
        size = (AV_RB32(&preamble[4]) + 1) & (~1);
239 493645eb Mike Melanson
240
    } while (fourcc_tag != BRCH_TAG);
241
242
    /* initialize the decoder streams */
243
    st = av_new_stream(s, 0);
244
    if (!st)
245 769e10f0 Panagiotis Issaris
        return AVERROR(ENOMEM);
246 74e21d03 Mike Melanson
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
247 493645eb Mike Melanson
    wc3->video_stream_index = st->index;
248 01f4895c Michael Niedermayer
    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 493645eb Mike Melanson
254
    /* palette considerations */
255 01f4895c Michael Niedermayer
    st->codec->palctrl = &wc3->palette_control;
256 493645eb Mike Melanson
257
    st = av_new_stream(s, 0);
258
    if (!st)
259 769e10f0 Panagiotis Issaris
        return AVERROR(ENOMEM);
260 74e21d03 Mike Melanson
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
261 493645eb Mike Melanson
    wc3->audio_stream_index = st->index;
262 01f4895c Michael Niedermayer
    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 dd1c8f3e Luca Abeni
    st->codec->bits_per_coded_sample = WC3_AUDIO_BITS;
267 01f4895c Michael Niedermayer
    st->codec->sample_rate = WC3_SAMPLE_RATE;
268
    st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
269 dd1c8f3e Luca Abeni
        st->codec->bits_per_coded_sample;
270 01f4895c Michael Niedermayer
    st->codec->block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
271 493645eb Mike Melanson
272
    return 0;
273
}
274
275
static int wc3_read_packet(AVFormatContext *s,
276
                           AVPacket *pkt)
277
{
278 e4141433 Nicholas Tung
    Wc3DemuxContext *wc3 = s->priv_data;
279 899681cd Björn Axelsson
    ByteIOContext *pb = s->pb;
280 493645eb Mike Melanson
    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 2a2bbcb0 Mike Melanson
    int i;
288
    unsigned char r, g, b;
289
    int base_palette_index;
290 493645eb Mike Melanson
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 e584914a Mike Melanson
            return AVERROR(EIO);
297 493645eb Mike Melanson
298 fead30d4 Alex Beregszaszi
        fourcc_tag = AV_RL32(&preamble[0]);
299 493645eb Mike Melanson
        /* chunk sizes are 16-bit aligned */
300 fead30d4 Alex Beregszaszi
        size = (AV_RB32(&preamble[4]) + 1) & (~1);
301 493645eb Mike Melanson
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 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
312 fead30d4 Alex Beregszaszi
            palette_number = AV_RL32(&preamble[0]);
313 493645eb Mike Melanson
            if (palette_number >= wc3->palette_count)
314
                return AVERROR_INVALIDDATA;
315 2a2bbcb0 Mike Melanson
            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 ba118447 Mike Melanson
            wc3->palette_control.palette_changed = 1;
323 493645eb Mike Melanson
            break;
324
325
        case VGA__TAG:
326
            /* send out video chunk */
327 2692067a Michael Niedermayer
            ret= av_get_packet(pb, pkt, size);
328 493645eb Mike Melanson
            pkt->stream_index = wc3->video_stream_index;
329
            pkt->pts = wc3->pts;
330
            if (ret != size)
331 6f3e0b21 Panagiotis Issaris
                ret = AVERROR(EIO);
332 493645eb Mike Melanson
            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 0ecca7a4 Michael Niedermayer
            if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size)
341 6f3e0b21 Panagiotis Issaris
                ret = AVERROR(EIO);
342 493645eb Mike Melanson
            else {
343
                int i = 0;
344 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
345
                av_log (s, AV_LOG_DEBUG, "  inglish: %s\n", &text[i + 1]);
346 493645eb Mike Melanson
                i += text[i] + 1;
347 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "  doytsch: %s\n", &text[i + 1]);
348 493645eb Mike Melanson
                i += text[i] + 1;
349 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "  fronsay: %s\n", &text[i + 1]);
350 493645eb Mike Melanson
            }
351
#endif
352
            break;
353
354
        case AUDI_TAG:
355
            /* send out audio chunk */
356 2692067a Michael Niedermayer
            ret= av_get_packet(pb, pkt, size);
357 493645eb Mike Melanson
            pkt->stream_index = wc3->audio_stream_index;
358
            pkt->pts = wc3->pts;
359
            if (ret != size)
360 6f3e0b21 Panagiotis Issaris
                ret = AVERROR(EIO);
361 493645eb Mike Melanson
362
            /* time to advance pts */
363 74e21d03 Mike Melanson
            wc3->pts++;
364 493645eb Mike Melanson
365
            packet_read = 1;
366
            break;
367
368
        default:
369 bb270c08 Diego Biurrun
            av_log (s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
370 493645eb Mike Melanson
                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
381
static int wc3_read_close(AVFormatContext *s)
382
{
383 e4141433 Nicholas Tung
    Wc3DemuxContext *wc3 = s->priv_data;
384 493645eb Mike Melanson
385
    av_free(wc3->palettes);
386
387
    return 0;
388
}
389
390 ff70e601 Måns Rullgård
AVInputFormat wc3_demuxer = {
391 493645eb Mike Melanson
    "wc3movie",
392 bde15e74 Stefano Sabatini
    NULL_IF_CONFIG_SMALL("Wing Commander III movie format"),
393 493645eb Mike Melanson
    sizeof(Wc3DemuxContext),
394
    wc3_probe,
395
    wc3_read_header,
396
    wc3_read_packet,
397
    wc3_read_close,
398
};