Mercurial > libavformat.hg
comparison sol.c @ 533:59da52e5f5a5 libavformat
support for Sierra Online audio files and Apple QuickDraw codec,
courtesy of Konstantin Shishkov
author | melanson |
---|---|
date | Tue, 28 Sep 2004 03:09:49 +0000 |
parents | |
children | 23b915bb10f5 |
comparison
equal
deleted
inserted
replaced
532:772247018ade | 533:59da52e5f5a5 |
---|---|
1 /* | |
2 * Sierra SOL decoder | |
3 * Copyright Konstantin Shishkov. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 /* | |
21 * Based on documents from Game Audio Player and own research | |
22 */ | |
23 | |
24 #include "avformat.h" | |
25 #include "avi.h" | |
26 #include "bswap.h" | |
27 | |
28 /* if we don't know the size in advance */ | |
29 #define AU_UNKOWN_SIZE ((uint32_t)(~0)) | |
30 | |
31 static int sol_probe(AVProbeData *p) | |
32 { | |
33 /* check file header */ | |
34 uint16_t magic; | |
35 if (p->buf_size <= 14) | |
36 return 0; | |
37 magic=le2me_16(*((uint16_t*)p->buf)); | |
38 if ((magic == 0x0B8D || magic == 0x0C0D || magic == 0x0C8D) && | |
39 p->buf[2] == 'S' && p->buf[3] == 'O' && | |
40 p->buf[4] == 'L' && p->buf[5] == 0) | |
41 return AVPROBE_SCORE_MAX; | |
42 else | |
43 return 0; | |
44 } | |
45 | |
46 #define SOL_DPCM 1 | |
47 #define SOL_16BIT 4 | |
48 #define SOL_STEREO 16 | |
49 | |
50 static int sol_codec_id(int magic, int type) | |
51 { | |
52 if (magic == 0x0B8D) | |
53 { | |
54 if (type & SOL_DPCM) return CODEC_ID_SOL_DPCM; | |
55 else return CODEC_ID_PCM_U8; | |
56 } | |
57 if (type & SOL_DPCM) | |
58 { | |
59 if (type & SOL_16BIT) return CODEC_ID_SOL_DPCM; | |
60 else if (magic == 0x0C8D) return CODEC_ID_SOL_DPCM; | |
61 else return CODEC_ID_SOL_DPCM; | |
62 } | |
63 if (type & SOL_16BIT) return CODEC_ID_PCM_S16LE; | |
64 return CODEC_ID_PCM_U8; | |
65 } | |
66 | |
67 static int sol_codec_type(int magic, int type) | |
68 { | |
69 if (magic == 0x0B8D) return 1;//SOL_DPCM_OLD; | |
70 if (type & SOL_DPCM) | |
71 { | |
72 if (type & SOL_16BIT) return 3;//SOL_DPCM_NEW16; | |
73 else if (magic == 0x0C8D) return 1;//SOL_DPCM_OLD; | |
74 else return 2;//SOL_DPCM_NEW8; | |
75 } | |
76 return -1; | |
77 } | |
78 | |
79 static int sol_channels(int magic, int type) | |
80 { | |
81 if (magic == 0x0B8D || !(type & SOL_STEREO)) return 1; | |
82 return 2; | |
83 } | |
84 | |
85 static int sol_read_header(AVFormatContext *s, | |
86 AVFormatParameters *ap) | |
87 { | |
88 int size; | |
89 unsigned int magic,tag; | |
90 ByteIOContext *pb = &s->pb; | |
91 unsigned int id, codec, channels, rate, type; | |
92 AVStream *st; | |
93 | |
94 /* check ".snd" header */ | |
95 magic = get_le16(pb); | |
96 tag = get_le32(pb); | |
97 if (tag != MKTAG('S', 'O', 'L', 0)) | |
98 return -1; | |
99 rate = get_le16(pb); | |
100 type = get_byte(pb); | |
101 size = get_le32(pb); | |
102 if (magic != 0x0B8D) | |
103 get_byte(pb); /* newer SOLs contain padding byte */ | |
104 | |
105 codec = sol_codec_id(magic, type); | |
106 channels = sol_channels(magic, type); | |
107 | |
108 if (codec == CODEC_ID_SOL_DPCM) | |
109 id = sol_codec_type(magic, type); | |
110 else id = 0; | |
111 | |
112 /* now we are ready: build format streams */ | |
113 st = av_new_stream(s, 0); | |
114 if (!st) | |
115 return -1; | |
116 st->codec.codec_type = CODEC_TYPE_AUDIO; | |
117 st->codec.codec_tag = id; | |
118 st->codec.codec_id = codec; | |
119 st->codec.channels = channels; | |
120 st->codec.sample_rate = rate; | |
121 return 0; | |
122 } | |
123 | |
124 #define MAX_SIZE 4096 | |
125 | |
126 static int sol_read_packet(AVFormatContext *s, | |
127 AVPacket *pkt) | |
128 { | |
129 int ret; | |
130 | |
131 if (url_feof(&s->pb)) | |
132 return -EIO; | |
133 if (av_new_packet(pkt, MAX_SIZE)) | |
134 return -EIO; | |
135 pkt->stream_index = 0; | |
136 | |
137 ret = get_buffer(&s->pb, pkt->data, pkt->size); | |
138 if (ret < 0) | |
139 av_free_packet(pkt); | |
140 /* note: we need to modify the packet size here to handle the last | |
141 packet */ | |
142 pkt->size = ret; | |
143 return 0; | |
144 } | |
145 | |
146 static int sol_read_close(AVFormatContext *s) | |
147 { | |
148 return 0; | |
149 } | |
150 | |
151 static AVInputFormat sol_iformat = { | |
152 "sol", | |
153 "Sierra SOL Format", | |
154 0, | |
155 sol_probe, | |
156 sol_read_header, | |
157 sol_read_packet, | |
158 sol_read_close, | |
159 pcm_read_seek, | |
160 }; | |
161 | |
162 int sol_init(void) | |
163 { | |
164 av_register_input_format(&sol_iformat); | |
165 return 0; | |
166 } |