Statistics
| Branch: | Revision:

ffmpeg / libavformat / wc3movie.c @ 2874c81c

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

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

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

    
378
AVInputFormat 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
};