Statistics
| Branch: | Revision:

ffmpeg / libavformat / wc3movie.c @ f59d8ff8

History | View | Annotate | Download (8.97 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
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

    
61
typedef struct Wc3DemuxContext {
62
    int width;
63
    int height;
64
    int64_t pts;
65
    int video_stream_index;
66
    int audio_stream_index;
67

    
68
    AVPacket vpkt;
69

    
70
} Wc3DemuxContext;
71

    
72
static int wc3_probe(AVProbeData *p)
73
{
74
    if (p->buf_size < 12)
75
        return 0;
76

    
77
    if ((AV_RL32(&p->buf[0]) != FORM_TAG) ||
78
        (AV_RL32(&p->buf[8]) != MOVE_TAG))
79
        return 0;
80

    
81
    return AVPROBE_SCORE_MAX;
82
}
83

    
84
static int wc3_read_header(AVFormatContext *s,
85
                           AVFormatParameters *ap)
86
{
87
    Wc3DemuxContext *wc3 = s->priv_data;
88
    AVIOContext *pb = s->pb;
89
    unsigned int fourcc_tag;
90
    unsigned int size;
91
    AVStream *st;
92
    int ret = 0;
93
    char *buffer;
94

    
95
    /* default context members */
96
    wc3->width = WC3_DEFAULT_WIDTH;
97
    wc3->height = WC3_DEFAULT_HEIGHT;
98
    wc3->pts = 0;
99
    wc3->video_stream_index = wc3->audio_stream_index = 0;
100
    av_init_packet(&wc3->vpkt);
101
    wc3->vpkt.data = NULL; wc3->vpkt.size = 0;
102

    
103
    /* skip the first 3 32-bit numbers */
104
    avio_seek(pb, 12, SEEK_CUR);
105

    
106
    /* traverse through the chunks and load the header information before
107
     * the first BRCH tag */
108
    fourcc_tag = avio_rl32(pb);
109
    size = (avio_rb32(pb) + 1) & (~1);
110

    
111
    do {
112
        switch (fourcc_tag) {
113

    
114
        case SOND_TAG:
115
        case INDX_TAG:
116
            /* SOND unknown, INDX unnecessary; ignore both */
117
            avio_seek(pb, size, SEEK_CUR);
118
            break;
119

    
120
        case PC__TAG:
121
            /* number of palettes, unneeded */
122
            avio_seek(pb, 12, SEEK_CUR);
123
            break;
124

    
125
        case BNAM_TAG:
126
            /* load up the name */
127
            buffer = av_malloc(size+1);
128
            if (!buffer)
129
                return AVERROR(ENOMEM);
130
            if ((ret = avio_read(pb, buffer, size)) != size)
131
                return AVERROR(EIO);
132
            buffer[size] = 0;
133
            av_metadata_set2(&s->metadata, "title", buffer,
134
                                   AV_METADATA_DONT_STRDUP_VAL);
135
            break;
136

    
137
        case SIZE_TAG:
138
            /* video resolution override */
139
            wc3->width  = avio_rl32(pb);
140
            wc3->height = avio_rl32(pb);
141
            break;
142

    
143
        case PALT_TAG:
144
            /* one of several palettes */
145
            avio_seek(pb, -8, SEEK_CUR);
146
            av_append_packet(pb, &wc3->vpkt, 8 + PALETTE_SIZE);
147
            break;
148

    
149
        default:
150
            av_log(s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
151
                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24),
152
                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24));
153
            return AVERROR_INVALIDDATA;
154
            break;
155
        }
156

    
157
        fourcc_tag = avio_rl32(pb);
158
        /* chunk sizes are 16-bit aligned */
159
        size = (avio_rb32(pb) + 1) & (~1);
160
        if (url_feof(pb))
161
            return AVERROR(EIO);
162

    
163
    } while (fourcc_tag != BRCH_TAG);
164

    
165
    /* initialize the decoder streams */
166
    st = av_new_stream(s, 0);
167
    if (!st)
168
        return AVERROR(ENOMEM);
169
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
170
    wc3->video_stream_index = st->index;
171
    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
172
    st->codec->codec_id = CODEC_ID_XAN_WC3;
173
    st->codec->codec_tag = 0;  /* no fourcc */
174
    st->codec->width = wc3->width;
175
    st->codec->height = wc3->height;
176

    
177
    st = av_new_stream(s, 0);
178
    if (!st)
179
        return AVERROR(ENOMEM);
180
    av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
181
    wc3->audio_stream_index = st->index;
182
    st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
183
    st->codec->codec_id = CODEC_ID_PCM_S16LE;
184
    st->codec->codec_tag = 1;
185
    st->codec->channels = WC3_AUDIO_CHANNELS;
186
    st->codec->bits_per_coded_sample = WC3_AUDIO_BITS;
187
    st->codec->sample_rate = WC3_SAMPLE_RATE;
188
    st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
189
        st->codec->bits_per_coded_sample;
190
    st->codec->block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
191

    
192
    return 0;
193
}
194

    
195
static int wc3_read_packet(AVFormatContext *s,
196
                           AVPacket *pkt)
197
{
198
    Wc3DemuxContext *wc3 = s->priv_data;
199
    AVIOContext *pb = s->pb;
200
    unsigned int fourcc_tag;
201
    unsigned int size;
202
    int packet_read = 0;
203
    int ret = 0;
204
    unsigned char text[1024];
205

    
206
    while (!packet_read) {
207

    
208
        fourcc_tag = avio_rl32(pb);
209
        /* chunk sizes are 16-bit aligned */
210
        size = (avio_rb32(pb) + 1) & (~1);
211
        if (url_feof(pb))
212
            return AVERROR(EIO);
213

    
214
        switch (fourcc_tag) {
215

    
216
        case BRCH_TAG:
217
            /* no-op */
218
            break;
219

    
220
        case SHOT_TAG:
221
            /* load up new palette */
222
            avio_seek(pb, -8, SEEK_CUR);
223
            av_append_packet(pb, &wc3->vpkt, 8 + 4);
224
            break;
225

    
226
        case VGA__TAG:
227
            /* send out video chunk */
228
            avio_seek(pb, -8, SEEK_CUR);
229
            ret= av_append_packet(pb, &wc3->vpkt, 8 + size);
230
            // ignore error if we have some data
231
            if (wc3->vpkt.size > 0)
232
                ret = 0;
233
            *pkt = wc3->vpkt;
234
            wc3->vpkt.data = NULL; wc3->vpkt.size = 0;
235
            pkt->stream_index = wc3->video_stream_index;
236
            pkt->pts = wc3->pts;
237
            packet_read = 1;
238
            break;
239

    
240
        case TEXT_TAG:
241
            /* subtitle chunk */
242
#if 0
243
            avio_seek(pb, size, SEEK_CUR);
244
#else
245
            if ((unsigned)size > sizeof(text) || (ret = avio_read(pb, text, size)) != size)
246
                ret = AVERROR(EIO);
247
            else {
248
                int i = 0;
249
                av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
250
                av_log (s, AV_LOG_DEBUG, "  inglish: %s\n", &text[i + 1]);
251
                i += text[i] + 1;
252
                av_log (s, AV_LOG_DEBUG, "  doytsch: %s\n", &text[i + 1]);
253
                i += text[i] + 1;
254
                av_log (s, AV_LOG_DEBUG, "  fronsay: %s\n", &text[i + 1]);
255
            }
256
#endif
257
            break;
258

    
259
        case AUDI_TAG:
260
            /* send out audio chunk */
261
            ret= av_get_packet(pb, pkt, size);
262
            pkt->stream_index = wc3->audio_stream_index;
263
            pkt->pts = wc3->pts;
264

    
265
            /* time to advance pts */
266
            wc3->pts++;
267

    
268
            packet_read = 1;
269
            break;
270

    
271
        default:
272
            av_log (s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
273
                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24),
274
                (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24));
275
            ret = AVERROR_INVALIDDATA;
276
            packet_read = 1;
277
            break;
278
        }
279
    }
280

    
281
    return ret;
282
}
283

    
284
static int wc3_read_close(AVFormatContext *s)
285
{
286
    Wc3DemuxContext *wc3 = s->priv_data;
287

    
288
    if (wc3->vpkt.size > 0)
289
        av_free_packet(&wc3->vpkt);
290

    
291
    return 0;
292
}
293

    
294
AVInputFormat ff_wc3_demuxer = {
295
    "wc3movie",
296
    NULL_IF_CONFIG_SMALL("Wing Commander III movie format"),
297
    sizeof(Wc3DemuxContext),
298
    wc3_probe,
299
    wc3_read_header,
300
    wc3_read_packet,
301
    wc3_read_close,
302
};