Browse code

Electronic Arts Game Multimedia format demuxer (WVE/UV2/etc.)

Originally committed as revision 3600 to svn://svn.ffmpeg.org/ffmpeg/trunk

Mike Melanson authored on 2004/10/17 04:33:57
Showing 6 changed files
... ...
@@ -4,6 +4,7 @@ version <next>
4 4
 - Sierra Online audio file demuxer and decoder
5 5
 - Apple QuickDraw (qdrw) video decoder
6 6
 - Creative ADPCM audio decoder
7
+- Electronic Arts Multimedia (WVE/UV2/etc.) file demuxer
7 8
 
8 9
 version 0.4.9-pre1:
9 10
 
... ...
@@ -687,6 +687,8 @@ library:
687 687
 @tab .sol files used in Sierra Online games
688 688
 @item Matroska         @tab    @tab X
689 689
 @end multitable
690
+@item Electronic Arts Multimedia    @tab    @tab X
691
+@tab used in various EA games; files have extensions like WVE and UV2
690 692
 
691 693
 @code{X} means that the encoding (resp. decoding) is supported.
692 694
 
... ...
@@ -16,7 +16,7 @@ OBJS+=mpeg.o mpegts.o mpegtsenc.o ffm.o crc.o img.o img2.o raw.o rm.o \
16 16
       avienc.o avidec.o wav.o swf.o au.o gif.o mov.o mpjpeg.o dv.o \
17 17
       yuv4mpeg.o 4xm.o flvenc.o flvdec.o movenc.o psxstr.o idroq.o ipmovie.o \
18 18
       nut.o wc3movie.o mp3.o westwood.o segafilm.o idcin.o flic.o \
19
-      sierravmd.o matroska.o sol.o
19
+      sierravmd.o matroska.o sol.o electronicarts.o
20 20
 
21 21
 ifeq ($(CONFIG_RISKY),yes)
22 22
 OBJS+= asf.o
... ...
@@ -105,6 +105,7 @@ void av_register_all(void)
105 105
     nut_init();
106 106
     matroska_init();
107 107
     sol_init();
108
+    ea_init();
108 109
 
109 110
 #ifdef CONFIG_ENCODERS
110 111
     /* image formats */
... ...
@@ -502,6 +502,9 @@ int matroska_init(void);
502 502
 /* sol.c */
503 503
 int sol_init(void);
504 504
 
505
+/* electronicarts.c */
506
+int ea_init(void);
507
+
505 508
 #include "rtp.h"
506 509
 
507 510
 #include "rtsp.h"
508 511
new file mode 100644
... ...
@@ -0,0 +1,299 @@
0
+/* Electronic Arts Multimedia File Demuxer
1
+ * Copyright (c) 2004  The ffmpeg Project
2
+ *
3
+ * This library is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2 of the License, or (at your option) any later version.
7
+ *
8
+ * This library is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with this library; if not, write to the Free Software
15
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
+ */
17
+
18
+/**
19
+ * @file electronicarts.c
20
+ * Electronic Arts Multimedia file demuxer (WVE/UV2/etc.)
21
+ * by Robin Kay (komadori at gekkou.co.uk)
22
+ */
23
+
24
+#include "avformat.h"
25
+
26
+#define SCHl_TAG MKTAG('S', 'C', 'H', 'l')
27
+#define PT00_TAG MKTAG('P', 'T', 0x0, 0x0)
28
+#define SCDl_TAG MKTAG('S', 'C', 'D', 'l')
29
+#define pIQT_TAG MKTAG('p', 'I', 'Q', 'T')
30
+#define SCEl_TAG MKTAG('S', 'C', 'E', 'l')
31
+#define _TAG MKTAG('', '', '', '')
32
+
33
+#define EA_SAMPLE_RATE 22050
34
+#define EA_BITS_PER_SAMPLE 16
35
+#define EA_PREAMBLE_SIZE 8
36
+
37
+typedef struct EaDemuxContext {
38
+    int width;
39
+    int height;
40
+    int video_stream_index;
41
+    int track_count;
42
+
43
+    int audio_stream_index;
44
+    int audio_frame_counter;
45
+
46
+    int64_t audio_pts;
47
+    int64_t video_pts;
48
+    int video_pts_inc;
49
+    float fps;
50
+
51
+    int num_channels;
52
+    int num_samples;
53
+    int compression_type;
54
+} EaDemuxContext;
55
+
56
+static uint32_t read_arbitary(ByteIOContext *pb) {
57
+    uint8_t size, byte;
58
+    int i;
59
+    uint32_t word;
60
+
61
+    size = get_byte(pb);
62
+
63
+    word = 0;
64
+    for (i = 0; i < size; i++) {
65
+        byte = get_byte(pb);
66
+        word <<= 8;
67
+        word |= byte;
68
+    }
69
+
70
+    return word;
71
+}
72
+
73
+/*
74
+ * Process WVE file header
75
+ * Returns 1 if the WVE file is valid and successfully opened, 0 otherwise
76
+ */
77
+static int process_ea_header(AVFormatContext *s) {
78
+    int inHeader;
79
+    uint32_t blockid, size;
80
+    EaDemuxContext *ea = (EaDemuxContext *)s->priv_data;
81
+    ByteIOContext *pb = &s->pb;
82
+
83
+    if (get_buffer(pb, (void*)&blockid, 4) != 4) {
84
+        return 0;
85
+    }
86
+    if (le2me_32(blockid) != SCHl_TAG) {
87
+        return 0;
88
+    }
89
+
90
+    if (get_buffer(pb, (void*)&size, 4) != 4) {
91
+        return 0;
92
+    }
93
+    size = le2me_32(size);
94
+
95
+    if (get_buffer(pb, (void*)&blockid, 4) != 4) {
96
+        return 0;
97
+    }
98
+    if (le2me_32(blockid) != PT00_TAG) {
99
+        av_log (s, AV_LOG_ERROR, "PT header missing\n");
100
+        return 0;
101
+    }
102
+
103
+    inHeader = 1;
104
+    while (inHeader) {
105
+        int inSubheader;
106
+        uint8_t byte;
107
+        byte = get_byte(pb) & 0xFF;
108
+
109
+        switch (byte) {
110
+        case 0xFD:
111
+            av_log (s, AV_LOG_INFO, "entered audio subheader\n");
112
+            inSubheader = 1;
113
+            while (inSubheader) {
114
+                uint8_t subbyte;
115
+                subbyte = get_byte(pb) & 0xFF;
116
+
117
+                switch (subbyte) {
118
+                case 0x82:
119
+                    ea->num_channels = read_arbitary(pb);
120
+                    av_log (s, AV_LOG_INFO, "num_channels (element 0x82) set to 0x%08x\n", ea->num_channels);
121
+                    break;
122
+                case 0x83:
123
+                    ea->compression_type = read_arbitary(pb);
124
+                    av_log (s, AV_LOG_INFO, "compression_type (element 0x83) set to 0x%08x\n", ea->compression_type);
125
+                    break;
126
+                case 0x85:
127
+                    ea->num_samples = read_arbitary(pb);
128
+                    av_log (s, AV_LOG_INFO, "num_samples (element 0x85) set to 0x%08x\n", ea->num_samples);
129
+                    break;
130
+                case 0x8A:
131
+                    av_log (s, AV_LOG_INFO, "element 0x%02x set to 0x%08x\n", subbyte, read_arbitary(pb));
132
+                    av_log (s, AV_LOG_INFO, "exited audio subheader\n");
133
+                    inSubheader = 0;
134
+                    break;
135
+                default:
136
+                    av_log (s, AV_LOG_INFO, "element 0x%02x set to 0x%08x\n", subbyte, read_arbitary(pb));
137
+                    break;
138
+                }
139
+            }
140
+            break;
141
+        case 0xFF:
142
+            av_log (s, AV_LOG_INFO, "end of header block reached\n");
143
+            inHeader = 0;
144
+            break;
145
+        default:
146
+            av_log (s, AV_LOG_INFO, "header element 0x%02x set to 0x%08x\n", byte, read_arbitary(pb));
147
+            break;
148
+        }
149
+    }
150
+
151
+    if ((ea->num_channels != 2) || (ea->compression_type != 7)) {
152
+        av_log (s, AV_LOG_ERROR, "unsupported stream type\n");
153
+        return 0;
154
+    }
155
+
156
+    /* skip to the start of the data */
157
+    url_fseek(pb, size, SEEK_SET);
158
+
159
+    return 1;
160
+}
161
+
162
+
163
+static int ea_probe(AVProbeData *p)
164
+{
165
+    if (p->buf_size < 4)
166
+        return 0;
167
+
168
+    if (LE_32(&p->buf[0]) != SCHl_TAG)
169
+        return 0;
170
+
171
+    return AVPROBE_SCORE_MAX;
172
+}
173
+
174
+static int ea_read_header(AVFormatContext *s,
175
+                          AVFormatParameters *ap)
176
+{
177
+    EaDemuxContext *ea = (EaDemuxContext *)s->priv_data;
178
+    AVStream *st;
179
+
180
+    if (!process_ea_header(s))
181
+        return AVERROR_IO;
182
+
183
+#if 0
184
+    /* initialize the video decoder stream */
185
+    st = av_new_stream(s, 0);
186
+    if (!st)
187
+        return AVERROR_NOMEM;
188
+    av_set_pts_info(st, 33, 1, 90000);
189
+    ea->video_stream_index = st->index;
190
+    st->codec.codec_type = CODEC_TYPE_VIDEO;
191
+    st->codec.codec_id = CODEC_ID_EA_MJPEG;
192
+    st->codec.codec_tag = 0;  /* no fourcc */
193
+#endif    
194
+
195
+    /* initialize the audio decoder stream */
196
+    st = av_new_stream(s, 0);
197
+    if (!st)
198
+        return AVERROR_NOMEM;
199
+    av_set_pts_info(st, 33, 1, EA_SAMPLE_RATE);
200
+    st->codec.codec_type = CODEC_TYPE_AUDIO;
201
+    st->codec.codec_id = CODEC_ID_ADPCM_EA;
202
+    st->codec.codec_tag = 0;  /* no tag */
203
+    st->codec.channels = ea->num_channels;
204
+    st->codec.sample_rate = EA_SAMPLE_RATE;
205
+    st->codec.bits_per_sample = EA_BITS_PER_SAMPLE;
206
+    st->codec.bit_rate = st->codec.channels * st->codec.sample_rate *
207
+        st->codec.bits_per_sample / 4;
208
+    st->codec.block_align = st->codec.channels * st->codec.bits_per_sample;
209
+
210
+    ea->audio_stream_index = st->index;
211
+    ea->audio_frame_counter = 0;
212
+
213
+    return 1;
214
+}
215
+
216
+static int ea_read_packet(AVFormatContext *s,
217
+                          AVPacket *pkt)
218
+{
219
+    EaDemuxContext *ea = s->priv_data;
220
+    ByteIOContext *pb = &s->pb;
221
+    int ret = 0;
222
+    int packet_read = 0;
223
+    unsigned char preamble[EA_PREAMBLE_SIZE];
224
+    unsigned int chunk_type, chunk_size;
225
+
226
+    while (!packet_read) {
227
+
228
+        if (get_buffer(pb, preamble, EA_PREAMBLE_SIZE) != EA_PREAMBLE_SIZE)
229
+            return AVERROR_IO;
230
+        chunk_type = LE_32(&preamble[0]);
231
+        chunk_size = LE_32(&preamble[4]) - EA_PREAMBLE_SIZE;
232
+
233
+        switch (chunk_type) {
234
+        /* audio data */
235
+        case SCDl_TAG:
236
+            if (av_new_packet(pkt, chunk_size))
237
+                ret = AVERROR_IO;
238
+            else {
239
+                ret = get_buffer(pb, pkt->data, chunk_size);
240
+                if (ret != chunk_size)
241
+                    ret = AVERROR_IO;
242
+                else {
243
+                    pkt->stream_index = ea->audio_stream_index;
244
+                    pkt->pts = 90000;
245
+                    pkt->pts *= ea->audio_frame_counter;
246
+                    pkt->pts /= EA_SAMPLE_RATE;
247
+
248
+                    /* 2 samples/byte, 1 or 2 samples per frame depending 
249
+                     * on stereo; chunk also has 12-byte header */
250
+                    ea->audio_frame_counter += ((chunk_size - 12) * 2) /
251
+                        ea->num_channels;
252
+                }
253
+            }
254
+
255
+            packet_read = 1;
256
+            break;
257
+
258
+        /* ending tag */
259
+        case SCEl_TAG:
260
+            ret = AVERROR_IO;
261
+            packet_read = 1;
262
+            break;
263
+
264
+        default:
265
+            url_fseek(pb, chunk_size, SEEK_CUR);
266
+            break;
267
+        }
268
+
269
+        /* ending packet */
270
+        if (chunk_type == SCEl_TAG) {
271
+        }
272
+    }
273
+
274
+    return ret;
275
+}
276
+
277
+static int ea_read_close(AVFormatContext *s)
278
+{
279
+//    EaDemuxContext *ea = (EaDemuxContext *)s->priv_data;
280
+
281
+    return 0;
282
+}
283
+
284
+static AVInputFormat ea_iformat = {
285
+    "ea",
286
+    "Electronic Arts Multimedia Format",
287
+    sizeof(EaDemuxContext),
288
+    ea_probe,
289
+    ea_read_header,
290
+    ea_read_packet,
291
+    ea_read_close,
292
+};
293
+
294
+int ea_init(void)
295
+{
296
+    av_register_input_format(&ea_iformat);
297
+    return 0;
298
+}