1 package com.quadcap.http.client; 2 3 import java.io.BufferedOutputStream ; 4 import java.io.ByteArrayOutputStream ; 5 import java.io.FileInputStream ; 6 import java.io.FileOutputStream ; 7 import java.io.IOException ; 8 import java.io.OutputStream ; 9 10 import com.quadcap.util.Debug; 11 12 import com.quadcap.io.IO; 13 14 18 public class Mp3FrameStream extends OutputStream { 19 ByteArrayOutputStream frame = new ByteArrayOutputStream (); 20 OutputStream frameData; 21 OutputStream nonFrameData; 22 int state = 0; 23 24 int id = 0; 25 int layer = 0; 26 int protection = 0; 27 int bitrateEnc = 0; 28 int frequency = 0; 29 int pad = 0; 30 int priv = 0; 31 int mode = 0; 32 int modeExt = 0; 33 int copy = 0; 34 int home = 0; 35 int emph = 0; 36 37 double bitrate = 0; 38 double samplerate = 0; 39 int framesize = 0; 40 int count = 0; 41 42 int totalBytes = 0; 43 int nonFrameCount = 0; 44 45 boolean started = false; 46 int bitrateEncStart = 0; 47 int frequencyStart = 0; 48 49 public Mp3FrameStream() {} 50 51 public void init(OutputStream frameData, OutputStream nonFrameData) { 52 this.frameData = frameData; 53 this.nonFrameData = nonFrameData; 54 started = false; 55 } 56 57 public void write(int b) throws IOException { 58 totalBytes++; 59 if (false && (totalBytes % 100000) == 99999) { 60 msg("totalBytes: " + totalBytes + ", state: " + state + 61 ", count: " + count + ", framesize: " + framesize); 62 } 63 64 b &= 0xff; 65 switch (state) { 66 case 0: 67 if (b == 0xff) { 68 state = 1; 69 } else { 70 nonFrameData.write(b); 71 nonFrameCount++; 72 } 73 break; 74 case 1: 75 if ((b & 0xe0) == 0xe0) { 76 if (nonFrameCount > 0) { 77 msg("" + nonFrameCount + " non frame bytes @ " + 78 totalBytes); 79 } 80 nonFrameCount = 0; 81 frame.reset(); 83 frame.write(0xff); 84 frame.write(b); 85 id = (b & 0x8) >> 3; 86 layer = (b & 0x6) >> 1; 87 protection = (b & 0x1); 88 state = 2; 89 } else { 90 nonFrameData.write(0xff); 91 nonFrameData.write(b); 92 nonFrameCount++; 93 state = 0; 94 } 95 break; 96 case 2: 97 frame.write(b); 98 bitrateEnc = (b & 0xf0) >> 4; 99 frequency = (b & 0xc) >> 2; 100 pad = (b & 0x2) >> 1; 101 priv = (b & 0x1); 102 state = 3; 103 break; 104 case 3: 105 frame.write(b); 106 mode = (b & 0xc0) >> 6; 107 modeExt = (b & 0x3) >> 4; 108 copy = (b & 0x8) >> 3; 109 home = (b & 0x4) >> 2; 110 emph = (b & 0x3); 111 bitrate = bitrates[bitrateEnc][(id << 2) | layer] * 1000; 112 samplerate = samplerates[(id << 2) | frequency]; 113 if (samplerate == 0) { 114 state = 0; 115 nonFrameData.write(frame.toByteArray()); 116 nonFrameCount += 4; 117 } else if (started && bitrateEnc != bitrateEncStart || 118 frequency != frequencyStart) { 119 nonFrameData.write(frame.toByteArray()); 120 nonFrameCount += 4; 121 state = 0; 122 } else { 123 framesize = (int) (144 * (bitrate / samplerate) + pad); 124 if (!started) { 125 msg("bitrate: " + bitrate + ", samplerate: " + samplerate + 126 ", framesize: " + framesize + " brEnc: " + bitrateEnc + 127 " id: " + id + " layer: " + layer + " freq: " + 128 frequency); 129 started = true; 130 } 131 bitrateEncStart = bitrateEnc; 132 frequencyStart = frequency; 133 count = 4; 134 state = 4; 135 } 136 break; 137 case 4: 138 frame.write(b); 139 if (++count >= framesize) { 140 byte[] data = frame.toByteArray(); 141 frameData.write(data); 142 state = 0; 143 } 144 break; 145 } 146 } 147 148 int[] samplerates = { 149 22050, 24000, 16000, 0, 44100, 48000, 32000, 0 }; 152 153 int[][] bitrates = { 154 {0, 8, 32, 32, 0, 32, 32, 32}, {0, 8, 32, 32, 0, 32, 32, 32}, {0, 16, 48, 64, 0, 40, 48, 64}, {0, 24, 56, 96, 0, 48, 56, 96}, {0, 32, 64, 128, 0, 56, 64, 128}, {0, 64, 80, 160, 0, 64, 80, 160}, {0, 80, 96, 192, 0, 80, 96, 192}, {0, 96, 112, 224, 0, 96, 112, 224}, {0, 112, 128, 256, 0, 112, 128, 256}, {0, 128, 160, 288, 0, 128, 160, 288}, {0, 160, 192, 320, 0, 160, 192, 320}, {0, 112, 224, 352, 0, 192, 224, 352}, {0, 128, 256, 384, 0, 224, 256, 384}, {0, 256, 320, 416, 0, 256, 320, 416}, {0, 320, 384, 448, 0, 320, 384, 448}, {0, 320, 384, 448, 0, 320, 384, 448} }; 174 175 void msg(String s) { 176 Debug.println(s); 177 } 178 179 public static void main(String [] args) { 180 Mp3FrameStream mp = new Mp3FrameStream(); 181 for (int i = 0; i < args.length; i++) { 182 String s = args[i]; 183 try { 184 if (false) { 185 FileInputStream fi = new FileInputStream (s); 186 int b; 187 int state = 0; 188 int count = 0; 189 while ((b = fi.read()) >= 0) { 190 count++; 191 switch (state) { 192 case 0: 193 if (b == 0xff) { 194 state = 1; 195 } 196 break; 197 case 1: 198 if (b == 251) { 199 state = 2; 200 } else if (b != 0xff) { 201 state = 0; 202 } 203 break; 204 case 2: 205 if (b == 146) { 206 mp.msg("Sync at " + (count-3)); 207 } 208 state = 0; 209 break; 210 } 211 } 212 fi.close(); 213 } 214 FileInputStream fis = new FileInputStream (s); 215 try { 216 FileOutputStream raw = new FileOutputStream (s + ".out"); 217 FileOutputStream skp = new FileOutputStream (s + ".skp"); 218 mp.init(raw, skp); 219 try { 220 IO.copyStream(fis, mp); 221 } finally { 222 mp.close(); 223 } 224 } finally { 225 fis.close(); 226 } 227 } catch (Throwable t) { 228 Debug.print(t); 229 } 230 } 231 } 232 233 public void close() throws IOException { 234 Debug.println("close()"); 235 frameData.close(); 236 nonFrameData.close(); 237 if (nonFrameCount > 0) { 238 Debug.println("" + nonFrameCount + " trailing bytes no sync"); 239 } 240 } 241 } 242 | Popular Tags |