Statistics
| Branch: | Revision:

ffmpeg / libavformat / wc3movie.c @ 7ce04209

History | View | Annotate | Download (12.5 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 3a278992 Mike Melanson
#define FORM_TAG MKTAG('F', 'O', 'R', 'M')
34
#define MOVE_TAG MKTAG('M', 'O', 'V', 'E')
35 7fffc879 Michael Niedermayer
#define  PC__TAG MKTAG('_', 'P', 'C', '_')
36 3a278992 Mike Melanson
#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 493645eb Mike Melanson
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 74e21d03 Mike Melanson
#define WC3_FRAME_FPS 15
58 493645eb Mike Melanson
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 ba118447 Mike Melanson
    AVPaletteControl palette_control;
72 493645eb Mike Melanson
73
} Wc3DemuxContext;
74
75 cdbe3798 Reimar Döffinger
/**
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 7e5ef401 Mike Melanson
static const unsigned char wc3_pal_lookup[] = {
88 115329f1 Diego Biurrun
  0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E,
89 493645eb Mike Melanson
  0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1A,
90 115329f1 Diego Biurrun
  0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25,
91 493645eb Mike Melanson
  0x27, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E, 0x2F,
92 115329f1 Diego Biurrun
  0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
93 493645eb Mike Melanson
  0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
94 115329f1 Diego Biurrun
  0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B,
95 493645eb Mike Melanson
  0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
96 115329f1 Diego Biurrun
  0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
97 493645eb Mike Melanson
  0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
98 115329f1 Diego Biurrun
  0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C,
99 493645eb Mike Melanson
  0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74,
100 115329f1 Diego Biurrun
  0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
101 493645eb Mike Melanson
  0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
102 115329f1 Diego Biurrun
  0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
103 493645eb Mike Melanson
  0x8C, 0x8D, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
104 115329f1 Diego Biurrun
  0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x99,
105 493645eb Mike Melanson
  0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1,
106 115329f1 Diego Biurrun
  0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
107 493645eb Mike Melanson
  0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
108 115329f1 Diego Biurrun
  0xB0, 0xB1, 0xB2, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
109 493645eb Mike Melanson
  0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
110 115329f1 Diego Biurrun
  0xBE, 0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4,
111 493645eb Mike Melanson
  0xC5, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB,
112 115329f1 Diego Biurrun
  0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD0, 0xD1,
113 493645eb Mike Melanson
  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 115329f1 Diego Biurrun
  0xE6, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEB, 0xEC,
117 493645eb Mike Melanson
  0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2,
118 115329f1 Diego Biurrun
  0xF3, 0xF4, 0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9,
119 493645eb Mike Melanson
  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 fead30d4 Alex Beregszaszi
    if ((AV_RL32(&p->buf[0]) != FORM_TAG) ||
129
        (AV_RL32(&p->buf[8]) != MOVE_TAG))
130 493645eb Mike Melanson
        return 0;
131
132
    return AVPROBE_SCORE_MAX;
133
}
134
135
static int wc3_read_header(AVFormatContext *s,
136
                           AVFormatParameters *ap)
137
{
138 e4141433 Nicholas Tung
    Wc3DemuxContext *wc3 = s->priv_data;
139 899681cd Björn Axelsson
    ByteIOContext *pb = s->pb;
140 493645eb Mike Melanson
    unsigned int fourcc_tag;
141
    unsigned int size;
142
    AVStream *st;
143 0d2e86d7 Aurelien Jacobs
    char buffer[513];
144 493645eb Mike Melanson
    int ret = 0;
145
    int current_palette = 0;
146
    int bytes_to_read;
147
    int i;
148 7e5ef401 Mike Melanson
    unsigned char rotate;
149 493645eb Mike Melanson
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 f6a708f0 Reimar Döffinger
    fourcc_tag = get_le32(pb);
164
    size = (get_be32(pb) + 1) & (~1);
165 493645eb Mike Melanson
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 7fffc879 Michael Niedermayer
        case PC__TAG:
176 493645eb Mike Melanson
            /* need the number of palettes */
177
            url_fseek(pb, 8, SEEK_CUR);
178 f6a708f0 Reimar Döffinger
            wc3->palette_count = get_le32(pb);
179 0ecca7a4 Michael Niedermayer
            if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){
180
                wc3->palette_count= 0;
181 568e18b1 Michael Niedermayer
                return -1;
182 0ecca7a4 Michael Niedermayer
            }
183 493645eb Mike Melanson
            wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
184
            break;
185
186
        case BNAM_TAG:
187
            /* load up the name */
188 0ecca7a4 Michael Niedermayer
            if ((unsigned)size < 512)
189 493645eb Mike Melanson
                bytes_to_read = size;
190
            else
191
                bytes_to_read = 512;
192 0d2e86d7 Aurelien Jacobs
            if ((ret = get_buffer(pb, buffer, bytes_to_read)) != bytes_to_read)
193 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
194 0d2e86d7 Aurelien Jacobs
            buffer[bytes_to_read] = 0;
195
            av_metadata_set(&s->metadata, "title", buffer);
196 493645eb Mike Melanson
            break;
197
198
        case SIZE_TAG:
199
            /* video resolution override */
200 f6a708f0 Reimar Döffinger
            wc3->width  = get_le32(pb);
201
            wc3->height = get_le32(pb);
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 7ce04209 Reimar Döffinger
                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24),
228
                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24));
229 493645eb Mike Melanson
            return AVERROR_INVALIDDATA;
230
            break;
231
        }
232
233 f6a708f0 Reimar Döffinger
        fourcc_tag = get_le32(pb);
234 493645eb Mike Melanson
        /* chunk sizes are 16-bit aligned */
235 f6a708f0 Reimar Döffinger
        size = (get_be32(pb) + 1) & (~1);
236
        if (url_feof(pb))
237
            return AVERROR(EIO);
238 493645eb Mike Melanson
239
    } while (fourcc_tag != BRCH_TAG);
240
241
    /* initialize the decoder streams */
242
    st = av_new_stream(s, 0);
243
    if (!st)
244 769e10f0 Panagiotis Issaris
        return AVERROR(ENOMEM);
245 74e21d03 Mike Melanson
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
246 493645eb Mike Melanson
    wc3->video_stream_index = st->index;
247 01f4895c Michael Niedermayer
    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 493645eb Mike Melanson
253
    /* palette considerations */
254 01f4895c Michael Niedermayer
    st->codec->palctrl = &wc3->palette_control;
255 493645eb Mike Melanson
256
    st = av_new_stream(s, 0);
257
    if (!st)
258 769e10f0 Panagiotis Issaris
        return AVERROR(ENOMEM);
259 74e21d03 Mike Melanson
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
260 493645eb Mike Melanson
    wc3->audio_stream_index = st->index;
261 01f4895c Michael Niedermayer
    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 dd1c8f3e Luca Abeni
    st->codec->bits_per_coded_sample = WC3_AUDIO_BITS;
266 01f4895c Michael Niedermayer
    st->codec->sample_rate = WC3_SAMPLE_RATE;
267
    st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
268 dd1c8f3e Luca Abeni
        st->codec->bits_per_coded_sample;
269 01f4895c Michael Niedermayer
    st->codec->block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
270 493645eb Mike Melanson
271
    return 0;
272
}
273
274
static int wc3_read_packet(AVFormatContext *s,
275
                           AVPacket *pkt)
276
{
277 e4141433 Nicholas Tung
    Wc3DemuxContext *wc3 = s->priv_data;
278 899681cd Björn Axelsson
    ByteIOContext *pb = s->pb;
279 493645eb Mike Melanson
    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 2a2bbcb0 Mike Melanson
    int i;
286
    unsigned char r, g, b;
287
    int base_palette_index;
288 493645eb Mike Melanson
289
    while (!packet_read) {
290
291 f6a708f0 Reimar Döffinger
        fourcc_tag = get_le32(pb);
292 493645eb Mike Melanson
        /* chunk sizes are 16-bit aligned */
293 f6a708f0 Reimar Döffinger
        size = (get_be32(pb) + 1) & (~1);
294
        if (url_feof(pb))
295
            return AVERROR(EIO);
296 493645eb Mike Melanson
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 f6a708f0 Reimar Döffinger
            palette_number = get_le32(pb);
306 493645eb Mike Melanson
            if (palette_number >= wc3->palette_count)
307
                return AVERROR_INVALIDDATA;
308 2a2bbcb0 Mike Melanson
            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 ba118447 Mike Melanson
            wc3->palette_control.palette_changed = 1;
316 493645eb Mike Melanson
            break;
317
318
        case VGA__TAG:
319
            /* send out video chunk */
320 2692067a Michael Niedermayer
            ret= av_get_packet(pb, pkt, size);
321 493645eb Mike Melanson
            pkt->stream_index = wc3->video_stream_index;
322
            pkt->pts = wc3->pts;
323
            packet_read = 1;
324
            break;
325
326
        case TEXT_TAG:
327
            /* subtitle chunk */
328
#if 0
329
            url_fseek(pb, size, SEEK_CUR);
330
#else
331 0ecca7a4 Michael Niedermayer
            if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size)
332 6f3e0b21 Panagiotis Issaris
                ret = AVERROR(EIO);
333 493645eb Mike Melanson
            else {
334
                int i = 0;
335 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
336
                av_log (s, AV_LOG_DEBUG, "  inglish: %s\n", &text[i + 1]);
337 493645eb Mike Melanson
                i += text[i] + 1;
338 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "  doytsch: %s\n", &text[i + 1]);
339 493645eb Mike Melanson
                i += text[i] + 1;
340 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "  fronsay: %s\n", &text[i + 1]);
341 493645eb Mike Melanson
            }
342
#endif
343
            break;
344
345
        case AUDI_TAG:
346
            /* send out audio chunk */
347 2692067a Michael Niedermayer
            ret= av_get_packet(pb, pkt, size);
348 493645eb Mike Melanson
            pkt->stream_index = wc3->audio_stream_index;
349
            pkt->pts = wc3->pts;
350
351
            /* time to advance pts */
352 74e21d03 Mike Melanson
            wc3->pts++;
353 493645eb Mike Melanson
354
            packet_read = 1;
355
            break;
356
357
        default:
358 bb270c08 Diego Biurrun
            av_log (s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
359 7ce04209 Reimar Döffinger
                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24),
360
                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24));
361 493645eb Mike Melanson
            ret = AVERROR_INVALIDDATA;
362
            packet_read = 1;
363
            break;
364
        }
365
    }
366
367
    return ret;
368
}
369
370
static int wc3_read_close(AVFormatContext *s)
371
{
372 e4141433 Nicholas Tung
    Wc3DemuxContext *wc3 = s->priv_data;
373 493645eb Mike Melanson
374
    av_free(wc3->palettes);
375
376
    return 0;
377
}
378
379 ff70e601 Måns Rullgård
AVInputFormat wc3_demuxer = {
380 493645eb Mike Melanson
    "wc3movie",
381 bde15e74 Stefano Sabatini
    NULL_IF_CONFIG_SMALL("Wing Commander III movie format"),
382 493645eb Mike Melanson
    sizeof(Wc3DemuxContext),
383
    wc3_probe,
384
    wc3_read_header,
385
    wc3_read_packet,
386
    wc3_read_close,
387
};