Statistics
| Branch: | Revision:

ffmpeg / libavformat / wc3movie.c @ 2874c81c

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 f28c4e75 Reimar Döffinger
 * 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 cdbe3798 Reimar Döffinger
 * 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
    int ret = 0;
144
    int current_palette = 0;
145 12ad6671 Michael Niedermayer
    char *buffer;
146 493645eb Mike Melanson
    int i;
147 7e5ef401 Mike Melanson
    unsigned char rotate;
148 493645eb Mike Melanson
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 f6a708f0 Reimar Döffinger
    fourcc_tag = get_le32(pb);
163
    size = (get_be32(pb) + 1) & (~1);
164 493645eb Mike Melanson
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 7fffc879 Michael Niedermayer
        case PC__TAG:
175 493645eb Mike Melanson
            /* need the number of palettes */
176
            url_fseek(pb, 8, SEEK_CUR);
177 f6a708f0 Reimar Döffinger
            wc3->palette_count = get_le32(pb);
178 0ecca7a4 Michael Niedermayer
            if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){
179
                wc3->palette_count= 0;
180 568e18b1 Michael Niedermayer
                return -1;
181 0ecca7a4 Michael Niedermayer
            }
182 493645eb Mike Melanson
            wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
183
            break;
184
185
        case BNAM_TAG:
186
            /* load up the name */
187 12ad6671 Michael Niedermayer
            buffer = av_malloc(size+1);
188
            if (!buffer)
189 2874c81c Stefano Sabatini
                return AVERROR(ENOMEM);
190 12ad6671 Michael Niedermayer
            if ((ret = get_buffer(pb, buffer, size)) != size)
191 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
192 12ad6671 Michael Niedermayer
            buffer[size] = 0;
193
            av_metadata_set2(&s->metadata, "title", buffer,
194
                                   AV_METADATA_DONT_STRDUP_VAL);
195 493645eb Mike Melanson
            break;
196
197
        case SIZE_TAG:
198
            /* video resolution override */
199 f6a708f0 Reimar Döffinger
            wc3->width  = get_le32(pb);
200
            wc3->height = get_le32(pb);
201 493645eb Mike Melanson
            break;
202
203
        case PALT_TAG:
204
            /* one of several palettes */
205 0ecca7a4 Michael Niedermayer
            if ((unsigned)current_palette >= wc3->palette_count)
206 493645eb Mike Melanson
                return AVERROR_INVALIDDATA;
207 115329f1 Diego Biurrun
            if ((ret = get_buffer(pb,
208
                &wc3->palettes[current_palette * PALETTE_SIZE],
209 493645eb Mike Melanson
                PALETTE_SIZE)) != PALETTE_SIZE)
210 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
211 493645eb Mike Melanson
212
            /* transform the current palette in place */
213
            for (i = current_palette * PALETTE_SIZE;
214
                 i < (current_palette + 1) * PALETTE_SIZE; i++) {
215 7e5ef401 Mike Melanson
                /* rotate each palette component left by 2 and use the result
216
                 * as an index into the color component table */
217 115329f1 Diego Biurrun
                rotate = ((wc3->palettes[i] << 2) & 0xFF) |
218 7e5ef401 Mike Melanson
                         ((wc3->palettes[i] >> 6) & 0xFF);
219
                wc3->palettes[i] = wc3_pal_lookup[rotate];
220 493645eb Mike Melanson
            }
221
            current_palette++;
222
            break;
223
224
        default:
225 bc874dae Michel Bardiaux
            av_log(s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
226 7ce04209 Reimar Döffinger
                (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 493645eb Mike Melanson
            return AVERROR_INVALIDDATA;
229
            break;
230
        }
231
232 f6a708f0 Reimar Döffinger
        fourcc_tag = get_le32(pb);
233 493645eb Mike Melanson
        /* chunk sizes are 16-bit aligned */
234 f6a708f0 Reimar Döffinger
        size = (get_be32(pb) + 1) & (~1);
235
        if (url_feof(pb))
236
            return AVERROR(EIO);
237 493645eb Mike Melanson
238
    } while (fourcc_tag != BRCH_TAG);
239
240
    /* initialize the decoder streams */
241
    st = av_new_stream(s, 0);
242
    if (!st)
243 769e10f0 Panagiotis Issaris
        return AVERROR(ENOMEM);
244 74e21d03 Mike Melanson
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
245 493645eb Mike Melanson
    wc3->video_stream_index = st->index;
246 72415b2a Stefano Sabatini
    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
247 01f4895c Michael Niedermayer
    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 493645eb Mike Melanson
252
    /* palette considerations */
253 01f4895c Michael Niedermayer
    st->codec->palctrl = &wc3->palette_control;
254 493645eb Mike Melanson
255
    st = av_new_stream(s, 0);
256
    if (!st)
257 769e10f0 Panagiotis Issaris
        return AVERROR(ENOMEM);
258 74e21d03 Mike Melanson
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
259 493645eb Mike Melanson
    wc3->audio_stream_index = st->index;
260 72415b2a Stefano Sabatini
    st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
261 01f4895c Michael Niedermayer
    st->codec->codec_id = CODEC_ID_PCM_S16LE;
262
    st->codec->codec_tag = 1;
263
    st->codec->channels = WC3_AUDIO_CHANNELS;
264 dd1c8f3e Luca Abeni
    st->codec->bits_per_coded_sample = WC3_AUDIO_BITS;
265 01f4895c Michael Niedermayer
    st->codec->sample_rate = WC3_SAMPLE_RATE;
266
    st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
267 dd1c8f3e Luca Abeni
        st->codec->bits_per_coded_sample;
268 01f4895c Michael Niedermayer
    st->codec->block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
269 493645eb Mike Melanson
270
    return 0;
271
}
272
273
static int wc3_read_packet(AVFormatContext *s,
274
                           AVPacket *pkt)
275
{
276 e4141433 Nicholas Tung
    Wc3DemuxContext *wc3 = s->priv_data;
277 899681cd Björn Axelsson
    ByteIOContext *pb = s->pb;
278 493645eb Mike Melanson
    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 2a2bbcb0 Mike Melanson
    int i;
285
    unsigned char r, g, b;
286
    int base_palette_index;
287 493645eb Mike Melanson
288
    while (!packet_read) {
289
290 f6a708f0 Reimar Döffinger
        fourcc_tag = get_le32(pb);
291 493645eb Mike Melanson
        /* chunk sizes are 16-bit aligned */
292 f6a708f0 Reimar Döffinger
        size = (get_be32(pb) + 1) & (~1);
293
        if (url_feof(pb))
294
            return AVERROR(EIO);
295 493645eb Mike Melanson
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 f6a708f0 Reimar Döffinger
            palette_number = get_le32(pb);
305 493645eb Mike Melanson
            if (palette_number >= wc3->palette_count)
306
                return AVERROR_INVALIDDATA;
307 2a2bbcb0 Mike Melanson
            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 ba118447 Mike Melanson
            wc3->palette_control.palette_changed = 1;
315 493645eb Mike Melanson
            break;
316
317
        case VGA__TAG:
318
            /* send out video chunk */
319 2692067a Michael Niedermayer
            ret= av_get_packet(pb, pkt, size);
320 493645eb Mike Melanson
            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 0ecca7a4 Michael Niedermayer
            if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size)
331 6f3e0b21 Panagiotis Issaris
                ret = AVERROR(EIO);
332 493645eb Mike Melanson
            else {
333
                int i = 0;
334 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
335
                av_log (s, AV_LOG_DEBUG, "  inglish: %s\n", &text[i + 1]);
336 493645eb Mike Melanson
                i += text[i] + 1;
337 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "  doytsch: %s\n", &text[i + 1]);
338 493645eb Mike Melanson
                i += text[i] + 1;
339 bc874dae Michel Bardiaux
                av_log (s, AV_LOG_DEBUG, "  fronsay: %s\n", &text[i + 1]);
340 493645eb Mike Melanson
            }
341
#endif
342
            break;
343
344
        case AUDI_TAG:
345
            /* send out audio chunk */
346 2692067a Michael Niedermayer
            ret= av_get_packet(pb, pkt, size);
347 493645eb Mike Melanson
            pkt->stream_index = wc3->audio_stream_index;
348
            pkt->pts = wc3->pts;
349
350
            /* time to advance pts */
351 74e21d03 Mike Melanson
            wc3->pts++;
352 493645eb Mike Melanson
353
            packet_read = 1;
354
            break;
355
356
        default:
357 bb270c08 Diego Biurrun
            av_log (s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
358 7ce04209 Reimar Döffinger
                (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 493645eb Mike Melanson
            ret = AVERROR_INVALIDDATA;
361
            packet_read = 1;
362
            break;
363
        }
364
    }
365
366
    return ret;
367
}
368
369
static int wc3_read_close(AVFormatContext *s)
370
{
371 e4141433 Nicholas Tung
    Wc3DemuxContext *wc3 = s->priv_data;
372 493645eb Mike Melanson
373
    av_free(wc3->palettes);
374
375
    return 0;
376
}
377
378 ff70e601 Måns Rullgård
AVInputFormat wc3_demuxer = {
379 493645eb Mike Melanson
    "wc3movie",
380 bde15e74 Stefano Sabatini
    NULL_IF_CONFIG_SMALL("Wing Commander III movie format"),
381 493645eb Mike Melanson
    sizeof(Wc3DemuxContext),
382
    wc3_probe,
383
    wc3_read_header,
384
    wc3_read_packet,
385
    wc3_read_close,
386
};