KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > iv > flash > util > MP3Helper


1 /*
2  * $Id: MP3Helper.java,v 1.4 2002/06/24 13:51:55 awason Exp $
3  *
4  * ===========================================================================
5  *
6  */

7
8 package org.openlaszlo.iv.flash.util;
9
10 import org.openlaszlo.iv.flash.parser.*;
11 import org.openlaszlo.iv.flash.util.*;
12 import org.openlaszlo.iv.flash.url.*;
13 import org.openlaszlo.iv.flash.api.*;
14
15 import java.io.*;
16
17 /**
18  * Class for parsing MP3 files, but only accepts those which the flash player
19  * understands.
20  *
21  * @author James Taylor
22  *
23  */

24
25 public class MP3Helper
26 {
27     private InputStream in;
28
29     private boolean isSynched = false;
30
31     // Per frame porperties ( but should be constant except pad and framesize )
32

33     private int mode;
34     private int layer;
35     private int bitrate;
36     private int frequency;
37     private int pad;
38     private int frameSize;
39
40     private int samplesPerFrame;
41
42     // Counts samples read _so far_
43

44     private int samples = 0;
45
46     private boolean stereo;
47
48     /* MP3 has a constant number of samples per frame */
49
50     private static int SAMPLES_PER_FRAME_V1 = 1152;
51     private static int SAMPLES_PER_FRAME_V2 = 576;
52
53
54     /* Flash only supports mpeg audio layer 3, so only the bitrates for layer 3
55      * are included here. Row 1 is for version 1, row 2 is for version 2 and 2.5
56      */

57
58     private static int bitrates[][] =
59     {
60         { -1, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 },
61         { -1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }
62     };
63
64     /* Frequencies that flash supports. Probably a waste to use a 2d array here
65      * since flash only allows the first column ( 00 for frequency ).
66      *
67      */

68
69     private static int frequencies[][] =
70     {
71         { 11025, -1, -1, -1 },
72         { -1, -1, -1, -1 },
73         { 22050, -1, -1, -1 },
74         { 44100, -1, -1, -1 }
75     };
76
77     /**
78      * Creates a new MP3Helper which reads MP3Frames from the supplied buffer.
79      *
80      */

81
82     public MP3Helper( FlashBuffer fob ) throws IOException, IVException
83     {
84         in = fob.getInputStream();
85         skipID3(fob);
86     }
87
88     /*
89      * Skip ID3 header.
90      * If it is not using an "unsynchronization scheme", it can confuse sync()
91      * http://www.id3.org/develop.html
92      */

93     private void skipID3( FlashBuffer fob ) throws IOException {
94         int b1, b2, b3, b4;
95         // Do nothing if no valid ID3 header
96
if (fob.getSize() < 10
97             || fob.getByteAt(0) != 'I' || fob.getByteAt(1) != 'D' || fob.getByteAt(2) != '3'
98             || fob.getUByteAt(3) >= 0xff || fob.getUByteAt(4) >= 0xff
99             || (b1 = fob.getUByteAt(6)) >= 0x80 || (b2 = fob.getUByteAt(7)) >= 0x80
100             || (b3 = fob.getUByteAt(8)) >= 0x80 || (b4 = fob.getUByteAt(9)) >= 0x80)
101             return;
102
103         // Skip ID3 data - size is a 28bit integer, with high bit of each byte ignored
104
in.skip(10 + (b1<<21 | b2<<14 | b3<<7 | b4));
105     }
106
107     /**
108      * Reads the header of the next MP3 frame, synchronzing the stream first
109      * if that has not yet been done.
110      *
111      * @return the 4 byte header, or null if there are no more frames.
112      *
113      */

114
115     public byte[] readHeader() throws IOException, IVException
116     {
117         byte[] header;
118
119         if ( isSynched == false )
120         {
121             header = sync();
122         }
123         else
124         {
125             header = new byte[ 4 ];
126
127             if ( in.read( header, 0, 4 ) != 4 )
128             {
129                 return null;
130             }
131
132         }
133
134         // Verify the header
135

136         if ( ( ( header[0] & 0xFF ) != 0xFF ) )
137         {
138             return null;
139         }
140
141         // Parse header data
142

143         mode = ( header[1] >>> 3 ) & 0x03;
144
145         samplesPerFrame = ( mode == 3 ) ? SAMPLES_PER_FRAME_V1 : SAMPLES_PER_FRAME_V2;
146
147         layer = ( header[1] >>> 1 ) & 0x03;
148
149         // Only layer 3 files are valid for the flash player
150

151         if ( layer != 1 )
152         {
153             throw new IVException( Resource.INVLMP3LAYER );
154         }
155
156         // Get bitrate from bitrates array -- varies with mode
157

158         bitrate = bitrates[ ( mode == 3 ) ? 0 : 1][ ( header[2] >>> 4 ) & 0x0F ];
159
160         // Get frequency -- also varies with mode
161

162         frequency = frequencies[ mode ][ ( header[2] >>> 2 ) & 0x03 ];
163
164         if ( frequency == -1 )
165         {
166             throw new IVException( Resource.INVLMP3FREQUENCY );
167         }
168
169         // Channel mode
170

171         stereo = ( ( ( header[3] >>> 6 ) & 0x03 ) != 3 );
172
173         // Determine is this frame is padded
174

175         pad = ( ( header[2] >>> 1 ) & 0x01 );
176
177         // Increment the sample counter
178

179         samples += samplesPerFrame;
180
181         // Calculate the frame size
182

183         frameSize = ( ( ( mode == 3 ) ? 144 : 72 ) * bitrate * 1000 / frequency + pad );
184
185         return header;
186     }
187
188     /**
189      * Reads from the input stream until it finds an MP3 header.
190      *
191      * @return the 4 byte header.
192      *
193      */

194
195     private byte[] sync() throws IOException, IVException
196     {
197         byte[] header = new byte[ 4 ];
198
199         while ( in.read( header, 0, 1 ) == 1 )
200         {
201             if ( (header[0] & 0xFF) == 0xFF )
202             {
203                 if ( in.read( header, 1, 1 ) != 1 )
204                     throw new IVException( Resource.INVLMP3 );
205                 if ( (header[1] & 0xE0) == 0xE0 )
206                     break;
207             }
208         }
209
210         // Read remainder of header
211

212         if ( in.read( header, 2, 2 ) != 2 )
213         {
214             throw new IVException( Resource.INVLMP3 );
215         }
216
217         isSynched = true;
218
219         return header;
220     }
221
222     /**
223      * Processes the next frame in the stream, and sets the frame properties
224      * ( mode, layer, bitrate, frequency, framesize, pad )
225      *
226      * @return the contents of the frame.
227      *
228      */

229
230     public byte[] nextFrame() throws IOException, IVException
231     {
232         byte[] header;
233         byte[] frame;
234
235         header = readHeader();
236
237         if ( header == null )
238         {
239             return null;
240         }
241
242         int datasize = frameSize - header.length;
243
244         frame = new byte[ frameSize ];
245
246         System.arraycopy( header, 0, frame, 0, header.length );
247
248         if( in.read( frame, header.length, datasize ) == -1 )
249         {
250             throw new IVException( Resource.INVLMP3 );
251         }
252
253         return frame;
254     }
255
256     /** Frequency accessor */
257
258     public int getFrequency() { return frequency; }
259
260     /** Stereo accessor */
261
262     public boolean getStereo() { return stereo; }
263
264     /** Samples accessor */
265
266     public int getSamples() { return samples; }
267
268     /** SamplesPerFrame accessor */
269
270     public int getSamplesPerFrame() { return samplesPerFrame; }
271 }
272
Popular Tags