1 /*
2     Ming, an SWF output library
3     Copyright (C) 2002  Opaque Industries - http://www.opaque.net/
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.1 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 /* $Id$ */
21 
22 #include "libming.h"
23 #include "input.h"
24 #include "mp3.h"
25 #include "error.h"
26 #include "sound.h"
27 
28 
29 // [version][idx]
30 static unsigned short mp3_samplingrate_tbl[4][4] =
31 {
32 	// mpeg 2.5
33 	{ 11025, 12000, 8000, 0},
34 	// reserved
35 	{ 0, 0, 0, 0},
36 	// mpeg 2
37 	{ 22050, 24000, 16000, 0},
38 	// mpeg 1
39 	{ 44100, 48000, 32000, 0}
40 };
41 
42 // [version][layer][idx]
43 static unsigned short mp3_bitrate_tbl[4][4][16] =
44 {
45 	// mpeg 2.5
46 	{
47 		// reserved
48 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
49 		// layer 3
50 		{ 0, 8, 16, 24,	32, 40,	48, 56, 64, 80, 96, 112, 128, 144, 160, 0},
51 		// layer 2
52 		{ 0, 8, 16, 24,	32, 40,	48, 56, 64, 80, 96, 112, 128, 144, 160, 0},
53 		// layer 1
54 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
55 	},
56 
57 	// reserved
58 	{
59 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
60 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
61 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
62 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
63 	},
64 
65 	// mpeg version 2
66 	{
67 		// reserved
68 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
69 		// layer 3
70 		{ 0, 8, 16, 24,	32, 40,	48, 56, 64, 80, 96, 112, 128, 144, 160, 0},
71 		// layer 2
72 		{ 0, 8, 16, 24,	32, 40,	48, 56, 64, 80, 96, 112, 128, 144, 160, 0},
73 		// layer 1
74 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
75 
76 	},
77 	// mpeg version 1
78 	{
79 		// reserved
80 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
81 		// layer 3
82 		{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0},
83 		// layer 2
84 		{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 },
85 		// layer 1
86 		{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 382, 416, 448, 0}
87 	}
88 };
89 
90 
91 #define CHECK_STREAM(__in)			\
92 	do {					\
93 		if(SWFInput_eof(__in))		\
94 			return 0;		\
95 	} while(0);
96 
97 
98 /*
99  * reads a MP3 header
100  * returns:
101  * 	0 if EOF
102  * 	-1 if invalid header; stream is unaltered
103  * 	1 on success
104  */
readMP3Header(SWFInput input,struct mp3_header * mp3h)105 int readMP3Header(SWFInput input, struct mp3_header *mp3h)
106 {
107 	int frameSync, br, sr;
108 	if(SWFInput_length(input) - SWFInput_tell(input) < 4)
109 		return 0;
110 
111 	frameSync = SWFInput_readBits(input, 11);
112 	CHECK_STREAM(input);
113 
114 	mp3h->version = SWFInput_readBits(input, 2);
115 	mp3h->layer = SWFInput_readBits(input, 2);
116 	SWFInput_readBits(input, 1); // protect bit
117 	CHECK_STREAM(input);
118 
119 	br = SWFInput_readBits(input, 4);
120 	sr = SWFInput_readBits(input, 2);
121 	mp3h->bitrate = mp3_bitrate_tbl[mp3h->version][mp3h->layer][br];
122 	mp3h->samplingRate = mp3_samplingrate_tbl[mp3h->version][sr];
123 	mp3h->padding = SWFInput_readBits(input, 1);
124 	SWFInput_readBits(input, 1); // private bit
125 	CHECK_STREAM(input);
126 
127 	mp3h->channelMode = SWFInput_readBits(input, 2);
128 	SWFInput_readBits(input, 2); // extension
129 	SWFInput_readBits(input, 3); // copyright, orig, emphasis
130 	CHECK_STREAM(input);
131 	SWFInput_byteAlign(input);
132 	if((frameSync & 0x7ff) != 0x7ff)
133 	{
134 		SWFInput_seek(input, -4, SEEK_CUR);
135 		return -1;
136 	}
137 
138 	if(mp3h->version == 1 || mp3h->layer == 0)
139 	{
140 		SWFInput_seek(input, -4, SEEK_CUR);
141 		return -1;
142 	}
143 	return 1;
144 }
145 
nextMP3Frame(SWFInput input)146 int nextMP3Frame(SWFInput input)
147 {
148 	int frameLen, ret;
149 	struct mp3_header mp3h;
150 
151 	ret = readMP3Header(input, &mp3h);
152 
153 	if(ret < 0)
154 		return -1;
155 
156 	if(ret == 0 || SWFInput_eof(input))
157 		return 0;
158 
159 	if(mp3h.samplingRate == 0 || mp3h.bitrate == 0)
160 		SWF_error("invalid mp3 file\n");
161 	if(mp3h.version == MP3_VERSION_1)
162 	{
163 		frameLen = 144 * mp3h.bitrate * 1000
164 				/ mp3h.samplingRate + mp3h.padding;
165 	}
166 	else
167 		frameLen = 72 * mp3h.bitrate * 1000
168 			/ mp3h.samplingRate + mp3h.padding;
169 
170 	SWFInput_seek(input, frameLen-4, SEEK_CUR);
171 	return frameLen;
172 }
173 
174 /*
175  * returns the sound flags used within ming
176  * stream is set to the first mp3 frame header.
177  */
getMP3Flags(SWFInput input,byte * flags)178 int getMP3Flags(SWFInput input, byte *flags)
179 {
180 	struct mp3_header mp3h;
181 	int rate=0, channels, start = 0;
182 	int ret;
183 
184 	/*
185 	 * skip stream until first MP3 header which starts with 0xffe
186 	 */
187 	while((ret = readMP3Header(input, &mp3h)) < 0)
188 	{
189 		SWFInput_seek(input, 1, SEEK_CUR);
190 		start++;
191 	}
192 
193 	if(ret == 0 || SWFInput_eof(input))
194 		return -1;
195 
196 	SWFInput_seek(input, start, SEEK_SET);
197 	if (mp3h.channelMode == MP3_CHANNEL_MONO )
198 		channels = SWF_SOUND_MONO;
199 	else
200 		channels = SWF_SOUND_STEREO;
201 
202 	switch ( mp3h.version )
203 	{
204 		case MP3_VERSION_1:
205 			rate = SWF_SOUND_44KHZ;
206 			break;
207 
208 		case MP3_VERSION_2:
209 			rate = SWF_SOUND_22KHZ;
210 			break;
211 
212 		case MP3_VERSION_25:
213 			rate = SWF_SOUND_11KHZ;
214 			break;
215 	}
216 
217 	*flags =
218 		SWF_SOUND_MP3_COMPRESSED | rate | SWF_SOUND_16BITS | channels;
219 	return start;
220 }
221 
222 /*
223  * Read at most the wanted number of samples from the input mp3 stream
224  * The stream read pointer is advanced.
225  * The actual number of samples read is written in *wanted and their
226  * total length is returned.
227  * If *wanted is < 0 read all there is in the stream.
228  */
getMP3Samples(SWFInput input,int flags,int * wanted)229 int getMP3Samples(SWFInput input, int flags, int *wanted)
230 {
231 	int frameSize, length;
232 	int numSamples = 0;
233 	int totalLength = 0;
234 
235 	switch(flags & SWF_SOUND_RATE)
236 	{
237 	case SWF_SOUND_44KHZ:
238 		frameSize = 1152;
239 		break;
240 	case SWF_SOUND_22KHZ:
241 	case SWF_SOUND_11KHZ:
242 		frameSize = 576;
243 		break;
244 	default:
245 		*wanted = 0;
246 		return -1;
247 	}
248 
249 	while(*wanted < 0 || numSamples < *wanted - frameSize)
250 	{
251 		length = nextMP3Frame(input);
252 		if(length <= 0)
253 			break; /* EOF */
254 		totalLength += length;
255 		numSamples += frameSize;
256 	}
257 
258 	*wanted = numSamples;
259 	return totalLength;
260 }
261 
262 /*
263  * Returns the length of a mp3 stream in ms. The duration is
264  * measured in ms. The stream is unaltered.
265  */
getMP3Duration(SWFInput input)266 unsigned int getMP3Duration(SWFInput input)
267 {
268 	int start, flags, samples = -1;
269 	int sampleRate;
270 
271 	start = SWFInput_tell(input);
272 	if(getMP3Flags(input, (byte *)&flags) < 0)
273 		return 0;
274 	if(getMP3Samples(input, flags, &samples) <= 0)
275 		return 0;
276 
277 	sampleRate = SWFSound_getSampleRate(flags);
278 	SWFInput_seek(input, start, SEEK_SET);
279 	return samples * 1000.0	/ sampleRate;
280 }
281 /*
282  * Local variables:
283  * tab-width: 2
284  * c-basic-offset: 2
285  * End:
286  */
287