Statistics
| Branch: | Revision:

ffmpeg / libavformat / wc3movie.c @ 7ce04209

History | View | Annotate | Download (12.5 KB)

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 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

    
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
    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 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
static 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

    
123
static 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

    
135
static 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
    char buffer[513];
144
    int ret = 0;
145
    int current_palette = 0;
146
    int bytes_to_read;
147
    int i;
148
    unsigned char rotate;
149

    
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
    fourcc_tag = get_le32(pb);
164
    size = (get_be32(pb) + 1) & (~1);
165

    
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
        case PC__TAG:
176
            /* need the number of palettes */
177
            url_fseek(pb, 8, SEEK_CUR);
178
            wc3->palette_count = get_le32(pb);
179
            if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){
180
                wc3->palette_count= 0;
181
                return -1;
182
            }
183
            wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
184
            break;
185

    
186
        case BNAM_TAG:
187
            /* load up the name */
188
            if ((unsigned)size < 512)
189
                bytes_to_read = size;
190
            else
191
                bytes_to_read = 512;
192
            if ((ret = get_buffer(pb, buffer, bytes_to_read)) != bytes_to_read)
193
                return AVERROR(EIO);
194
            buffer[bytes_to_read] = 0;
195
            av_metadata_set(&s->metadata, "title", buffer);
196
            break;
197

    
198
        case SIZE_TAG:
199
            /* video resolution override */
200
            wc3->width  = get_le32(pb);
201
            wc3->height = get_le32(pb);
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
                (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
            return AVERROR_INVALIDDATA;
230
            break;
231
        }
232

    
233
        fourcc_tag = get_le32(pb);
234
        /* chunk sizes are 16-bit aligned */
235
        size = (get_be32(pb) + 1) & (~1);
236
        if (url_feof(pb))
237
            return AVERROR(EIO);
238

    
239
    } while (fourcc_tag != BRCH_TAG);
240

    
241
    /* initialize the decoder streams */
242
    st = av_new_stream(s, 0);
243
    if (!st)
244
        return AVERROR(ENOMEM);
245
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
246
    wc3->video_stream_index = st->index;
247
    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

    
253
    /* palette considerations */
254
    st->codec->palctrl = &wc3->palette_control;
255

    
256
    st = av_new_stream(s, 0);
257
    if (!st)
258
        return AVERROR(ENOMEM);
259
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
260
    wc3->audio_stream_index = st->index;
261
    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
    st->codec->bits_per_coded_sample = WC3_AUDIO_BITS;
266
    st->codec->sample_rate = WC3_SAMPLE_RATE;
267
    st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
268
        st->codec->bits_per_coded_sample;
269
    st->codec->block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
270

    
271
    return 0;
272
}
273

    
274
static int wc3_read_packet(AVFormatContext *s,
275
                           AVPacket *pkt)
276
{
277
    Wc3DemuxContext *wc3 = s->priv_data;
278
    ByteIOContext *pb = s->pb;
279
    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
    int i;
286
    unsigned char r, g, b;
287
    int base_palette_index;
288

    
289
    while (!packet_read) {
290

    
291
        fourcc_tag = get_le32(pb);
292
        /* chunk sizes are 16-bit aligned */
293
        size = (get_be32(pb) + 1) & (~1);
294
        if (url_feof(pb))
295
            return AVERROR(EIO);
296

    
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
            palette_number = get_le32(pb);
306
            if (palette_number >= wc3->palette_count)
307
                return AVERROR_INVALIDDATA;
308
            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
            wc3->palette_control.palette_changed = 1;
316
            break;
317

    
318
        case VGA__TAG:
319
            /* send out video chunk */
320
            ret= av_get_packet(pb, pkt, size);
321
            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
            if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size)
332
                ret = AVERROR(EIO);
333
            else {
334
                int i = 0;
335
                av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
336
                av_log (s, AV_LOG_DEBUG, "  inglish: %s\n", &text[i + 1]);
337
                i += text[i] + 1;
338
                av_log (s, AV_LOG_DEBUG, "  doytsch: %s\n", &text[i + 1]);
339
                i += text[i] + 1;
340
                av_log (s, AV_LOG_DEBUG, "  fronsay: %s\n", &text[i + 1]);
341
            }
342
#endif
343
            break;
344

    
345
        case AUDI_TAG:
346
            /* send out audio chunk */
347
            ret= av_get_packet(pb, pkt, size);
348
            pkt->stream_index = wc3->audio_stream_index;
349
            pkt->pts = wc3->pts;
350

    
351
            /* time to advance pts */
352
            wc3->pts++;
353

    
354
            packet_read = 1;
355
            break;
356

    
357
        default:
358
            av_log (s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
359
                (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
            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
    Wc3DemuxContext *wc3 = s->priv_data;
373

    
374
    av_free(wc3->palettes);
375

    
376
    return 0;
377
}
378

    
379
AVInputFormat wc3_demuxer = {
380
    "wc3movie",
381
    NULL_IF_CONFIG_SMALL("Wing Commander III movie format"),
382
    sizeof(Wc3DemuxContext),
383
    wc3_probe,
384
    wc3_read_header,
385
    wc3_read_packet,
386
    wc3_read_close,
387
};