Originally committed as revision 3529 to svn://svn.ffmpeg.org/ffmpeg/trunk
Mike Melanson authored on 2004/09/28 12:09:49... | ... |
@@ -676,6 +676,8 @@ library: |
676 | 676 |
@tab .fli/.flc files |
677 | 677 |
@item Sierra VMD @tab @tab X |
678 | 678 |
@tab used in Sierra CD-ROM games |
679 |
+@item Sierra Online @tab @tab X |
|
680 |
+@tab .sol files used in Sierra Online games |
|
679 | 681 |
@item Matroska @tab @tab X |
680 | 682 |
@end multitable |
681 | 683 |
|
... | ... |
@@ -742,6 +744,7 @@ following image formats are supported: |
742 | 742 |
@item Apple Animation @tab @tab X @tab fourcc: 'rle ' |
743 | 743 |
@item Apple Graphics @tab @tab X @tab fourcc: 'smc ' |
744 | 744 |
@item Apple Video @tab @tab X @tab fourcc: rpza |
745 |
+@item Apple QuickDraw @tab @tab X @tab fourcc: qdrw |
|
745 | 746 |
@item Cinepak @tab @tab X |
746 | 747 |
@item Microsoft RLE @tab @tab X |
747 | 748 |
@item Microsoft Video-1 @tab @tab X |
... | ... |
@@ -812,6 +815,8 @@ solutions. |
812 | 812 |
@tab used in various Interplay computer games |
813 | 813 |
@item Xan DPCM @tab @tab X |
814 | 814 |
@tab used in Origin's Wing Commander IV AVI files |
815 |
+@item Sierra Online DPCM @tab @tab X |
|
816 |
+@tab used in Sierra Online game audio files |
|
815 | 817 |
@item Apple MACE 3 @tab @tab X |
816 | 818 |
@item Apple MACE 6 @tab @tab X |
817 | 819 |
@item FLAC @tab @tab X |
... | ... |
@@ -20,7 +20,8 @@ OBJS= common.o utils.o mem.o allcodecs.o \ |
20 | 20 |
roqvideo.o dpcm.o interplayvideo.o xan.o rpza.o cinepak.o msrle.o \ |
21 | 21 |
msvideo1.o vqavideo.o idcinvideo.o adx.o rational.o faandct.o 8bps.o \ |
22 | 22 |
smc.o parser.o flicvideo.o truemotion1.o vmdav.o lcl.o qtrle.o g726.o \ |
23 |
- flac.o vp3dsp.o integer.o snow.o tscc.o sonic.o ulti.o h264idct.o |
|
23 |
+ flac.o vp3dsp.o integer.o snow.o tscc.o sonic.o ulti.o h264idct.o \ |
|
24 |
+ qdrw.o |
|
24 | 25 |
|
25 | 26 |
ifeq ($(AMR_NB),yes) |
26 | 27 |
ifeq ($(AMR_NB_FIXED),yes) |
... | ... |
@@ -108,6 +108,7 @@ void avcodec_register_all(void) |
108 | 108 |
register_avcodec(&indeo3_decoder); |
109 | 109 |
register_avcodec(&tscc_decoder); |
110 | 110 |
register_avcodec(&ulti_decoder); |
111 |
+ register_avcodec(&qdraw_decoder); |
|
111 | 112 |
#ifdef CONFIG_FAAD |
112 | 113 |
register_avcodec(&aac_decoder); |
113 | 114 |
register_avcodec(&mpeg4aac_decoder); |
... | ... |
@@ -169,6 +170,7 @@ void avcodec_register_all(void) |
169 | 169 |
register_avcodec(&roq_dpcm_decoder); |
170 | 170 |
register_avcodec(&interplay_dpcm_decoder); |
171 | 171 |
register_avcodec(&xan_dpcm_decoder); |
172 |
+ register_avcodec(&sol_dpcm_decoder); |
|
172 | 173 |
register_avcodec(&qtrle_decoder); |
173 | 174 |
register_avcodec(&flac_decoder); |
174 | 175 |
#endif /* CONFIG_DECODERS */ |
... | ... |
@@ -103,6 +103,7 @@ enum CodecID { |
103 | 103 |
CODEC_ID_SNOW, |
104 | 104 |
CODEC_ID_TSCC, |
105 | 105 |
CODEC_ID_ULTI, |
106 |
+ CODEC_ID_QDRAW, |
|
106 | 107 |
|
107 | 108 |
/* various pcm "codecs" */ |
108 | 109 |
CODEC_ID_PCM_S16LE, |
... | ... |
@@ -140,6 +141,7 @@ enum CodecID { |
140 | 140 |
CODEC_ID_ROQ_DPCM, |
141 | 141 |
CODEC_ID_INTERPLAY_DPCM, |
142 | 142 |
CODEC_ID_XAN_DPCM, |
143 |
+ CODEC_ID_SOL_DPCM, |
|
143 | 144 |
|
144 | 145 |
CODEC_ID_FLAC, |
145 | 146 |
|
... | ... |
@@ -1878,11 +1880,13 @@ extern AVCodec ra_288_decoder; |
1878 | 1878 |
extern AVCodec roq_dpcm_decoder; |
1879 | 1879 |
extern AVCodec interplay_dpcm_decoder; |
1880 | 1880 |
extern AVCodec xan_dpcm_decoder; |
1881 |
+extern AVCodec sol_dpcm_decoder; |
|
1881 | 1882 |
extern AVCodec sonic_decoder; |
1882 | 1883 |
extern AVCodec qtrle_decoder; |
1883 | 1884 |
extern AVCodec flac_decoder; |
1884 | 1885 |
extern AVCodec tscc_decoder; |
1885 | 1886 |
extern AVCodec ulti_decoder; |
1887 |
+extern AVCodec qdraw_decoder; |
|
1886 | 1888 |
|
1887 | 1889 |
/* pcm codecs */ |
1888 | 1890 |
#define PCM_CODEC(id, name) \ |
... | ... |
@@ -24,6 +24,7 @@ |
24 | 24 |
* Xan DPCM decoder by Mario Brito (mbrito@student.dei.uc.pt) |
25 | 25 |
* for more information on the specific data formats, visit: |
26 | 26 |
* http://www.pcisys.net/~melanson/codecs/simpleaudio.html |
27 |
+ * SOL DPCMs implemented by Konstantin Shishkov |
|
27 | 28 |
* |
28 | 29 |
* Note about using the Xan DPCM decoder: Xan DPCM is used in AVI files |
29 | 30 |
* found in the Wing Commander IV computer game. These AVI files contain |
... | ... |
@@ -39,6 +40,8 @@ |
39 | 39 |
typedef struct DPCMContext { |
40 | 40 |
int channels; |
41 | 41 |
short roq_square_array[256]; |
42 |
+ long sample[2];//for SOL_DPCM |
|
43 |
+ int *sol_table;//for SOL_DPCM |
|
42 | 44 |
} DPCMContext; |
43 | 45 |
|
44 | 46 |
#define SATURATE_S16(x) if (x < -32768) x = -32768; \ |
... | ... |
@@ -81,6 +84,32 @@ static int interplay_delta_table[] = { |
81 | 81 |
|
82 | 82 |
}; |
83 | 83 |
|
84 |
+static int sol_table_old[16] = |
|
85 |
+ { 0x0, 0x1, 0x2 , 0x3, 0x6, 0xA, 0xF, 0x15, |
|
86 |
+ -0x15, -0xF, -0xA, -0x6, -0x3, -0x2, -0x1, 0x0}; |
|
87 |
+ |
|
88 |
+static int sol_table_new[16] = |
|
89 |
+ { 0x0, 0x1, 0x2, 0x3, 0x6, 0xA, 0xF, 0x15, |
|
90 |
+ 0x0, -0x1, -0x2, -0x3, -0x6, -0xA, -0xF, -0x15}; |
|
91 |
+ |
|
92 |
+static int sol_table_16[128] = { |
|
93 |
+ 0x000, 0x008, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070, 0x080, |
|
94 |
+ 0x090, 0x0A0, 0x0B0, 0x0C0, 0x0D0, 0x0E0, 0x0F0, 0x100, 0x110, 0x120, |
|
95 |
+ 0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, |
|
96 |
+ 0x1D0, 0x1E0, 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230, |
|
97 |
+ 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, 0x278, 0x280, |
|
98 |
+ 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8, 0x2C0, 0x2C8, 0x2D0, |
|
99 |
+ 0x2D8, 0x2E0, 0x2E8, 0x2F0, 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, |
|
100 |
+ 0x328, 0x330, 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370, |
|
101 |
+ 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0, 0x3B8, 0x3C0, |
|
102 |
+ 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0, 0x3F8, 0x400, 0x440, 0x480, |
|
103 |
+ 0x4C0, 0x500, 0x540, 0x580, 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, |
|
104 |
+ 0x740, 0x780, 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00, |
|
105 |
+ 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 |
|
106 |
+}; |
|
107 |
+ |
|
108 |
+ |
|
109 |
+ |
|
84 | 110 |
static int dpcm_decode_init(AVCodecContext *avctx) |
85 | 111 |
{ |
86 | 112 |
DPCMContext *s = avctx->priv_data; |
... | ... |
@@ -88,6 +117,7 @@ static int dpcm_decode_init(AVCodecContext *avctx) |
88 | 88 |
short square; |
89 | 89 |
|
90 | 90 |
s->channels = avctx->channels; |
91 |
+ s->sample[0] = s->sample[1] = 0; |
|
91 | 92 |
|
92 | 93 |
switch(avctx->codec->id) { |
93 | 94 |
|
... | ... |
@@ -100,6 +130,26 @@ static int dpcm_decode_init(AVCodecContext *avctx) |
100 | 100 |
} |
101 | 101 |
break; |
102 | 102 |
|
103 |
+ |
|
104 |
+ case CODEC_ID_SOL_DPCM: |
|
105 |
+ switch(avctx->codec_tag){ |
|
106 |
+ case 1: |
|
107 |
+ s->sol_table=sol_table_old; |
|
108 |
+ s->sample[0] = s->sample[1] = 0x80; |
|
109 |
+ break; |
|
110 |
+ case 2: |
|
111 |
+ s->sol_table=sol_table_new; |
|
112 |
+ s->sample[0] = s->sample[1] = 0x80; |
|
113 |
+ break; |
|
114 |
+ case 3: |
|
115 |
+ s->sol_table=sol_table_16; |
|
116 |
+ break; |
|
117 |
+ default: |
|
118 |
+ av_log(avctx, AV_LOG_ERROR, "Unknown SOL subcodec\n"); |
|
119 |
+ return -1; |
|
120 |
+ } |
|
121 |
+ break; |
|
122 |
+ |
|
103 | 123 |
default: |
104 | 124 |
break; |
105 | 125 |
} |
... | ... |
@@ -203,6 +253,35 @@ static int dpcm_decode_frame(AVCodecContext *avctx, |
203 | 203 |
channel_number ^= s->channels - 1; |
204 | 204 |
} |
205 | 205 |
break; |
206 |
+ case CODEC_ID_SOL_DPCM: |
|
207 |
+ in = 0; |
|
208 |
+ if (avctx->codec_tag != 3) { |
|
209 |
+ while (in < buf_size) { |
|
210 |
+ int n1, n2; |
|
211 |
+ n1 = (buf[in] >> 4) & 0xF; |
|
212 |
+ n2 = buf[in++] & 0xF; |
|
213 |
+ s->sample[0] += s->sol_table[n1]; |
|
214 |
+ if (s->sample[0] < 0) s->sample[0] = 0; |
|
215 |
+ if (s->sample[0] > 255) s->sample[0] = 255; |
|
216 |
+ output_samples[out++] = (s->sample[0] - 128) << 8; |
|
217 |
+ s->sample[s->channels - 1] += s->sol_table[n2]; |
|
218 |
+ if (s->sample[s->channels - 1] < 0) s->sample[s->channels - 1] = 0; |
|
219 |
+ if (s->sample[s->channels - 1] > 255) s->sample[s->channels - 1] = 255; |
|
220 |
+ output_samples[out++] = (s->sample[s->channels - 1] - 128) << 8; |
|
221 |
+ } |
|
222 |
+ } else { |
|
223 |
+ while (in < buf_size) { |
|
224 |
+ int n; |
|
225 |
+ n = buf[in++]; |
|
226 |
+ if (n & 0x80) s->sample[channel_number] -= s->sol_table[n & 0x7F]; |
|
227 |
+ else s->sample[channel_number] += s->sol_table[n & 0x7F]; |
|
228 |
+ SATURATE_S16(s->sample[channel_number]); |
|
229 |
+ output_samples[out++] = s->sample[channel_number]; |
|
230 |
+ /* toggle channel */ |
|
231 |
+ channel_number ^= s->channels - 1; |
|
232 |
+ } |
|
233 |
+ } |
|
234 |
+ break; |
|
206 | 235 |
} |
207 | 236 |
|
208 | 237 |
*data_size = out * sizeof(short); |
... | ... |
@@ -241,3 +320,14 @@ AVCodec xan_dpcm_decoder = { |
241 | 241 |
NULL, |
242 | 242 |
dpcm_decode_frame, |
243 | 243 |
}; |
244 |
+ |
|
245 |
+AVCodec sol_dpcm_decoder = { |
|
246 |
+ "sol_dpcm", |
|
247 |
+ CODEC_TYPE_AUDIO, |
|
248 |
+ CODEC_ID_SOL_DPCM, |
|
249 |
+ sizeof(DPCMContext), |
|
250 |
+ dpcm_decode_init, |
|
251 |
+ NULL, |
|
252 |
+ NULL, |
|
253 |
+ dpcm_decode_frame, |
|
254 |
+}; |
244 | 255 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,153 @@ |
0 |
+/* |
|
1 |
+ * QuickDraw (qdrw) codec |
|
2 |
+ * Copyright (c) 2004 Konstantin Shishkov |
|
3 |
+ * |
|
4 |
+ * This library is free software; you can redistribute it and/or |
|
5 |
+ * modify it under the terms of the GNU Lesser General Public |
|
6 |
+ * License as published by the Free Software Foundation; either |
|
7 |
+ * version 2 of the License, or (at your option) any later version. |
|
8 |
+ * |
|
9 |
+ * This library is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 |
+ * Lesser General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU Lesser General Public |
|
15 |
+ * License along with this library; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 |
+ * |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+/** |
|
21 |
+ * @file qdrw.c |
|
22 |
+ * Apple QuickDraw codec. |
|
23 |
+ */ |
|
24 |
+ |
|
25 |
+#include "avcodec.h" |
|
26 |
+#include "mpegvideo.h" |
|
27 |
+ |
|
28 |
+typedef struct QdrawContext{ |
|
29 |
+ AVCodecContext *avctx; |
|
30 |
+ AVFrame pic; |
|
31 |
+ uint8_t palette[256*3]; |
|
32 |
+} QdrawContext; |
|
33 |
+ |
|
34 |
+static int decode_frame(AVCodecContext *avctx, |
|
35 |
+ void *data, int *data_size, |
|
36 |
+ uint8_t *buf, int buf_size) |
|
37 |
+{ |
|
38 |
+ QdrawContext * const a = avctx->priv_data; |
|
39 |
+ AVFrame * const p= (AVFrame*)&a->pic; |
|
40 |
+ uint8_t* outdata; |
|
41 |
+ int colors; |
|
42 |
+ int i; |
|
43 |
+ |
|
44 |
+ /* special case for last picture */ |
|
45 |
+ if (buf_size == 0) { |
|
46 |
+ return 0; |
|
47 |
+ } |
|
48 |
+ |
|
49 |
+ if(p->data[0]) |
|
50 |
+ avctx->release_buffer(avctx, p); |
|
51 |
+ |
|
52 |
+ p->reference= 0; |
|
53 |
+ if(avctx->get_buffer(avctx, p) < 0){ |
|
54 |
+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); |
|
55 |
+ return -1; |
|
56 |
+ } |
|
57 |
+ p->pict_type= I_TYPE; |
|
58 |
+ p->key_frame= 1; |
|
59 |
+ |
|
60 |
+ outdata = a->pic.data[0]; |
|
61 |
+ |
|
62 |
+ buf += 0x68; /* jump to palette */ |
|
63 |
+ colors = BE_32(buf); |
|
64 |
+ buf += 4; |
|
65 |
+ |
|
66 |
+ if(colors < 0 || colors > 256) { |
|
67 |
+ av_log(avctx, AV_LOG_ERROR, "Error color count - %i(0x%X)\n", colors, colors); |
|
68 |
+ return -1; |
|
69 |
+ } |
|
70 |
+ |
|
71 |
+ for (i = 0; i <= colors; i++) { |
|
72 |
+ int idx; |
|
73 |
+ idx = BE_16(buf); /* color index */ |
|
74 |
+ buf += 2; |
|
75 |
+ |
|
76 |
+ a->palette[idx * 3 + 0] = *buf++; |
|
77 |
+ buf++; |
|
78 |
+ a->palette[idx * 3 + 1] = *buf++; |
|
79 |
+ buf++; |
|
80 |
+ a->palette[idx * 3 + 2] = *buf++; |
|
81 |
+ buf++; |
|
82 |
+ } |
|
83 |
+ |
|
84 |
+ if (colors) |
|
85 |
+ a->pic.palette_has_changed = 1; |
|
86 |
+ |
|
87 |
+ buf += 18; /* skip unneeded data */ |
|
88 |
+ for (i = 0; i < avctx->height; i++) { |
|
89 |
+ int size, left, code, pix; |
|
90 |
+ uint8_t *next; |
|
91 |
+ uint8_t *out; |
|
92 |
+ int tsize = 0; |
|
93 |
+ |
|
94 |
+ /* decode line */ |
|
95 |
+ out = outdata; |
|
96 |
+ size = BE_16(buf); /* size of packed line */ |
|
97 |
+ buf += 2; |
|
98 |
+ left = size; |
|
99 |
+ next = buf + size; |
|
100 |
+ while (left > 0) { |
|
101 |
+ code = *buf++; |
|
102 |
+ if (code & 0x80 ) { /* run */ |
|
103 |
+ int i; |
|
104 |
+ pix = *buf++; |
|
105 |
+ for (i = 0; i < 257 - code; i++) { |
|
106 |
+ *out++ = a->palette[pix * 3 + 0]; |
|
107 |
+ *out++ = a->palette[pix * 3 + 1]; |
|
108 |
+ *out++ = a->palette[pix * 3 + 2]; |
|
109 |
+ } |
|
110 |
+ tsize += 257 - code; |
|
111 |
+ left -= 2; |
|
112 |
+ } else { /* copy */ |
|
113 |
+ int i, pix; |
|
114 |
+ for (i = 0; i <= code; i++) { |
|
115 |
+ pix = *buf++; |
|
116 |
+ *out++ = a->palette[pix * 3 + 0]; |
|
117 |
+ *out++ = a->palette[pix * 3 + 1]; |
|
118 |
+ *out++ = a->palette[pix * 3 + 2]; |
|
119 |
+ } |
|
120 |
+ left -= 2 + code; |
|
121 |
+ tsize += code + 1; |
|
122 |
+ } |
|
123 |
+ } |
|
124 |
+ buf = next; |
|
125 |
+ outdata += a->pic.linesize[0]; |
|
126 |
+ } |
|
127 |
+ |
|
128 |
+ *data_size = sizeof(AVFrame); |
|
129 |
+ *(AVFrame*)data = a->pic; |
|
130 |
+ |
|
131 |
+ return buf_size; |
|
132 |
+} |
|
133 |
+ |
|
134 |
+static int decode_init(AVCodecContext *avctx){ |
|
135 |
+// QdrawContext * const a = avctx->priv_data; |
|
136 |
+ |
|
137 |
+ avctx->pix_fmt= PIX_FMT_RGB24; |
|
138 |
+ |
|
139 |
+ return 0; |
|
140 |
+} |
|
141 |
+ |
|
142 |
+AVCodec qdraw_decoder = { |
|
143 |
+ "qdraw", |
|
144 |
+ CODEC_TYPE_VIDEO, |
|
145 |
+ CODEC_ID_QDRAW, |
|
146 |
+ sizeof(QdrawContext), |
|
147 |
+ decode_init, |
|
148 |
+ NULL, |
|
149 |
+ NULL, |
|
150 |
+ decode_frame, |
|
151 |
+ CODEC_CAP_DR1, |
|
152 |
+}; |
... | ... |
@@ -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 |
|
19 |
+ sierravmd.o matroska.o sol.o |
|
20 | 20 |
|
21 | 21 |
ifeq ($(CONFIG_RISKY),yes) |
22 | 22 |
OBJS+= asf.o |
... | ... |
@@ -115,6 +115,7 @@ static const CodecTag mov_video_tags[] = { |
115 | 115 |
{ CODEC_ID_8BPS, MKTAG('8', 'B', 'P', 'S') }, /* Planar RGB (8BPS) */ |
116 | 116 |
{ CODEC_ID_SMC, MKTAG('s', 'm', 'c', ' ') }, /* Apple Graphics (SMC) */ |
117 | 117 |
{ CODEC_ID_QTRLE, MKTAG('r', 'l', 'e', ' ') }, /* Apple Animation (RLE) */ |
118 |
+ { CODEC_ID_QDRAW, MKTAG('q', 'd', 'r', 'w') }, /* QuickDraw */ |
|
118 | 119 |
{ CODEC_ID_NONE, 0 }, |
119 | 120 |
}; |
120 | 121 |
|
121 | 122 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,166 @@ |
0 |
+/* |
|
1 |
+ * Sierra SOL decoder |
|
2 |
+ * Copyright Konstantin Shishkov. |
|
3 |
+ * |
|
4 |
+ * This library is free software; you can redistribute it and/or |
|
5 |
+ * modify it under the terms of the GNU Lesser General Public |
|
6 |
+ * License as published by the Free Software Foundation; either |
|
7 |
+ * version 2 of the License, or (at your option) any later version. |
|
8 |
+ * |
|
9 |
+ * This library is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 |
+ * Lesser General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU Lesser General Public |
|
15 |
+ * License along with this library; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 |
+ */ |
|
18 |
+ |
|
19 |
+/* |
|
20 |
+ * Based on documents from Game Audio Player and own research |
|
21 |
+ */ |
|
22 |
+ |
|
23 |
+#include "avformat.h" |
|
24 |
+#include "avi.h" |
|
25 |
+#include "bswap.h" |
|
26 |
+ |
|
27 |
+/* if we don't know the size in advance */ |
|
28 |
+#define AU_UNKOWN_SIZE ((uint32_t)(~0)) |
|
29 |
+ |
|
30 |
+static int sol_probe(AVProbeData *p) |
|
31 |
+{ |
|
32 |
+ /* check file header */ |
|
33 |
+ uint16_t magic; |
|
34 |
+ if (p->buf_size <= 14) |
|
35 |
+ return 0; |
|
36 |
+ magic=le2me_16(*((uint16_t*)p->buf)); |
|
37 |
+ if ((magic == 0x0B8D || magic == 0x0C0D || magic == 0x0C8D) && |
|
38 |
+ p->buf[2] == 'S' && p->buf[3] == 'O' && |
|
39 |
+ p->buf[4] == 'L' && p->buf[5] == 0) |
|
40 |
+ return AVPROBE_SCORE_MAX; |
|
41 |
+ else |
|
42 |
+ return 0; |
|
43 |
+} |
|
44 |
+ |
|
45 |
+#define SOL_DPCM 1 |
|
46 |
+#define SOL_16BIT 4 |
|
47 |
+#define SOL_STEREO 16 |
|
48 |
+ |
|
49 |
+static int sol_codec_id(int magic, int type) |
|
50 |
+{ |
|
51 |
+ if (magic == 0x0B8D) |
|
52 |
+ { |
|
53 |
+ if (type & SOL_DPCM) return CODEC_ID_SOL_DPCM; |
|
54 |
+ else return CODEC_ID_PCM_U8; |
|
55 |
+ } |
|
56 |
+ if (type & SOL_DPCM) |
|
57 |
+ { |
|
58 |
+ if (type & SOL_16BIT) return CODEC_ID_SOL_DPCM; |
|
59 |
+ else if (magic == 0x0C8D) return CODEC_ID_SOL_DPCM; |
|
60 |
+ else return CODEC_ID_SOL_DPCM; |
|
61 |
+ } |
|
62 |
+ if (type & SOL_16BIT) return CODEC_ID_PCM_S16LE; |
|
63 |
+ return CODEC_ID_PCM_U8; |
|
64 |
+} |
|
65 |
+ |
|
66 |
+static int sol_codec_type(int magic, int type) |
|
67 |
+{ |
|
68 |
+ if (magic == 0x0B8D) return 1;//SOL_DPCM_OLD; |
|
69 |
+ if (type & SOL_DPCM) |
|
70 |
+ { |
|
71 |
+ if (type & SOL_16BIT) return 3;//SOL_DPCM_NEW16; |
|
72 |
+ else if (magic == 0x0C8D) return 1;//SOL_DPCM_OLD; |
|
73 |
+ else return 2;//SOL_DPCM_NEW8; |
|
74 |
+ } |
|
75 |
+ return -1; |
|
76 |
+} |
|
77 |
+ |
|
78 |
+static int sol_channels(int magic, int type) |
|
79 |
+{ |
|
80 |
+ if (magic == 0x0B8D || !(type & SOL_STEREO)) return 1; |
|
81 |
+ return 2; |
|
82 |
+} |
|
83 |
+ |
|
84 |
+static int sol_read_header(AVFormatContext *s, |
|
85 |
+ AVFormatParameters *ap) |
|
86 |
+{ |
|
87 |
+ int size; |
|
88 |
+ unsigned int magic,tag; |
|
89 |
+ ByteIOContext *pb = &s->pb; |
|
90 |
+ unsigned int id, codec, channels, rate, type; |
|
91 |
+ AVStream *st; |
|
92 |
+ |
|
93 |
+ /* check ".snd" header */ |
|
94 |
+ magic = get_le16(pb); |
|
95 |
+ tag = get_le32(pb); |
|
96 |
+ if (tag != MKTAG('S', 'O', 'L', 0)) |
|
97 |
+ return -1; |
|
98 |
+ rate = get_le16(pb); |
|
99 |
+ type = get_byte(pb); |
|
100 |
+ size = get_le32(pb); |
|
101 |
+ if (magic != 0x0B8D) |
|
102 |
+ get_byte(pb); /* newer SOLs contain padding byte */ |
|
103 |
+ |
|
104 |
+ codec = sol_codec_id(magic, type); |
|
105 |
+ channels = sol_channels(magic, type); |
|
106 |
+ |
|
107 |
+ if (codec == CODEC_ID_SOL_DPCM) |
|
108 |
+ id = sol_codec_type(magic, type); |
|
109 |
+ else id = 0; |
|
110 |
+ |
|
111 |
+ /* now we are ready: build format streams */ |
|
112 |
+ st = av_new_stream(s, 0); |
|
113 |
+ if (!st) |
|
114 |
+ return -1; |
|
115 |
+ st->codec.codec_type = CODEC_TYPE_AUDIO; |
|
116 |
+ st->codec.codec_tag = id; |
|
117 |
+ st->codec.codec_id = codec; |
|
118 |
+ st->codec.channels = channels; |
|
119 |
+ st->codec.sample_rate = rate; |
|
120 |
+ return 0; |
|
121 |
+} |
|
122 |
+ |
|
123 |
+#define MAX_SIZE 4096 |
|
124 |
+ |
|
125 |
+static int sol_read_packet(AVFormatContext *s, |
|
126 |
+ AVPacket *pkt) |
|
127 |
+{ |
|
128 |
+ int ret; |
|
129 |
+ |
|
130 |
+ if (url_feof(&s->pb)) |
|
131 |
+ return -EIO; |
|
132 |
+ if (av_new_packet(pkt, MAX_SIZE)) |
|
133 |
+ return -EIO; |
|
134 |
+ pkt->stream_index = 0; |
|
135 |
+ |
|
136 |
+ ret = get_buffer(&s->pb, pkt->data, pkt->size); |
|
137 |
+ if (ret < 0) |
|
138 |
+ av_free_packet(pkt); |
|
139 |
+ /* note: we need to modify the packet size here to handle the last |
|
140 |
+ packet */ |
|
141 |
+ pkt->size = ret; |
|
142 |
+ return 0; |
|
143 |
+} |
|
144 |
+ |
|
145 |
+static int sol_read_close(AVFormatContext *s) |
|
146 |
+{ |
|
147 |
+ return 0; |
|
148 |
+} |
|
149 |
+ |
|
150 |
+static AVInputFormat sol_iformat = { |
|
151 |
+ "sol", |
|
152 |
+ "Sierra SOL Format", |
|
153 |
+ 0, |
|
154 |
+ sol_probe, |
|
155 |
+ sol_read_header, |
|
156 |
+ sol_read_packet, |
|
157 |
+ sol_read_close, |
|
158 |
+ pcm_read_seek, |
|
159 |
+}; |
|
160 |
+ |
|
161 |
+int sol_init(void) |
|
162 |
+{ |
|
163 |
+ av_register_input_format(&sol_iformat); |
|
164 |
+ return 0; |
|
165 |
+} |