00001
package com.quadcap.http.client;
00002
00003
import java.io.BufferedOutputStream;
00004
import java.io.ByteArrayOutputStream;
00005
import java.io.FileInputStream;
00006
import java.io.FileOutputStream;
00007
import java.io.IOException;
00008
import java.io.OutputStream;
00009
00010
import com.quadcap.util.Debug;
00011
00012
import com.quadcap.io.IO;
00013
00014
00015
00016
00017
00018 public class Mp3FrameStream extends OutputStream {
00019 ByteArrayOutputStream
frame =
new ByteArrayOutputStream();
00020 OutputStream
frameData;
00021 OutputStream
nonFrameData;
00022 int state = 0;
00023
00024 int id = 0;
00025 int layer = 0;
00026 int protection = 0;
00027 int bitrateEnc = 0;
00028 int frequency = 0;
00029 int pad = 0;
00030 int priv = 0;
00031 int mode = 0;
00032 int modeExt = 0;
00033 int copy = 0;
00034 int home = 0;
00035 int emph = 0;
00036
00037 double bitrate = 0;
00038 double samplerate = 0;
00039 int framesize = 0;
00040 int count = 0;
00041
00042 int totalBytes = 0;
00043 int nonFrameCount = 0;
00044
00045 boolean started =
false;
00046 int bitrateEncStart = 0;
00047 int frequencyStart = 0;
00048
00049 public Mp3FrameStream() {}
00050
00051 public void init(OutputStream frameData, OutputStream nonFrameData) {
00052
this.frameData = frameData;
00053
this.nonFrameData = nonFrameData;
00054
started =
false;
00055 }
00056
00057 public void write(
int b)
throws IOException {
00058
totalBytes++;
00059
if (
false && (
totalBytes % 100000) == 99999) {
00060
msg(
"totalBytes: " +
totalBytes +
", state: " +
state +
00061
", count: " +
count +
", framesize: " +
framesize);
00062 }
00063
00064 b &= 0xff;
00065
switch (
state) {
00066
case 0:
00067
if (b == 0xff) {
00068
state = 1;
00069 }
else {
00070
nonFrameData.write(b);
00071
nonFrameCount++;
00072 }
00073
break;
00074
case 1:
00075
if ((b & 0xe0) == 0xe0) {
00076
if (
nonFrameCount > 0) {
00077
msg(
"" +
nonFrameCount +
" non frame bytes @ " +
00078
totalBytes);
00079 }
00080
nonFrameCount = 0;
00081
00082
frame.reset();
00083
frame.write(0xff);
00084
frame.write(b);
00085
id = (b & 0x8) >> 3;
00086
layer = (b & 0x6) >> 1;
00087
protection = (b & 0x1);
00088
state = 2;
00089 }
else {
00090
nonFrameData.write(0xff);
00091
nonFrameData.write(b);
00092
nonFrameCount++;
00093
state = 0;
00094 }
00095
break;
00096
case 2:
00097
frame.write(b);
00098
bitrateEnc = (b & 0xf0) >> 4;
00099
frequency = (b & 0xc) >> 2;
00100
pad = (b & 0x2) >> 1;
00101
priv = (b & 0x1);
00102
state = 3;
00103
break;
00104
case 3:
00105
frame.write(b);
00106
mode = (b & 0xc0) >> 6;
00107
modeExt = (b & 0x3) >> 4;
00108
copy = (b & 0x8) >> 3;
00109
home = (b & 0x4) >> 2;
00110
emph = (b & 0x3);
00111
bitrate =
bitrates[
bitrateEnc][(
id << 2) |
layer] * 1000;
00112
samplerate =
samplerates[(
id << 2) |
frequency];
00113
if (
samplerate == 0) {
00114
state = 0;
00115
nonFrameData.write(
frame.toByteArray());
00116
nonFrameCount += 4;
00117 }
else if (
started &&
bitrateEnc !=
bitrateEncStart ||
00118
frequency !=
frequencyStart) {
00119
nonFrameData.write(
frame.toByteArray());
00120
nonFrameCount += 4;
00121
state = 0;
00122 }
else {
00123
framesize = (
int) (144 * (
bitrate /
samplerate) +
pad);
00124
if (!
started) {
00125
msg(
"bitrate: " +
bitrate +
", samplerate: " +
samplerate +
00126
", framesize: " +
framesize +
" brEnc: " +
bitrateEnc +
00127
" id: " +
id +
" layer: " +
layer +
" freq: " +
00128
frequency);
00129
started =
true;
00130 }
00131
bitrateEncStart =
bitrateEnc;
00132
frequencyStart =
frequency;
00133
count = 4;
00134
state = 4;
00135 }
00136
break;
00137
case 4:
00138
frame.write(b);
00139
if (++
count >=
framesize) {
00140 byte[] data =
frame.toByteArray();
00141
frameData.write(data);
00142
state = 0;
00143 }
00144
break;
00145 }
00146 }
00147
00148 int[]
samplerates = {
00149 22050, 24000, 16000, 0,
00150 44100, 48000, 32000, 0
00151 };
00152
00153 int[][]
bitrates = {
00154
00155
00156
00157 {0, 8, 32, 32, 0, 32, 32, 32},
00158 {0, 8, 32, 32, 0, 32, 32, 32},
00159 {0, 16, 48, 64, 0, 40, 48, 64},
00160 {0, 24, 56, 96, 0, 48, 56, 96},
00161 {0, 32, 64, 128, 0, 56, 64, 128},
00162 {0, 64, 80, 160, 0, 64, 80, 160},
00163 {0, 80, 96, 192, 0, 80, 96, 192},
00164 {0, 96, 112, 224, 0, 96, 112, 224},
00165 {0, 112, 128, 256, 0, 112, 128, 256},
00166 {0, 128, 160, 288, 0, 128, 160, 288},
00167 {0, 160, 192, 320, 0, 160, 192, 320},
00168 {0, 112, 224, 352, 0, 192, 224, 352},
00169 {0, 128, 256, 384, 0, 224, 256, 384},
00170 {0, 256, 320, 416, 0, 256, 320, 416},
00171 {0, 320, 384, 448, 0, 320, 384, 448},
00172 {0, 320, 384, 448, 0, 320, 384, 448}
00173 };
00174
00175 void msg(String s) {
00176
Debug.println(s);
00177 }
00178
00179 public static void main(String[] args) {
00180
Mp3FrameStream mp =
new Mp3FrameStream();
00181
for (
int i = 0; i < args.length; i++) {
00182 String s = args[i];
00183
try {
00184
if (
false) {
00185 FileInputStream fi =
new FileInputStream(s);
00186
int b;
00187
int state = 0;
00188
int count = 0;
00189
while ((b = fi.read()) >= 0) {
00190 count++;
00191
switch (state) {
00192
case 0:
00193
if (b == 0xff) {
00194 state = 1;
00195 }
00196
break;
00197
case 1:
00198
if (b == 251) {
00199 state = 2;
00200 }
else if (b != 0xff) {
00201 state = 0;
00202 }
00203
break;
00204
case 2:
00205
if (b == 146) {
00206 mp.
msg(
"Sync at " + (count-3));
00207 }
00208 state = 0;
00209
break;
00210 }
00211 }
00212 fi.close();
00213 }
00214 FileInputStream fis =
new FileInputStream(s);
00215
try {
00216 FileOutputStream raw =
new FileOutputStream(s +
".out");
00217 FileOutputStream skp =
new FileOutputStream(s +
".skp");
00218 mp.
init(raw, skp);
00219
try {
00220
IO.copyStream(fis, mp);
00221 } finally {
00222 mp.
close();
00223 }
00224 } finally {
00225 fis.close();
00226 }
00227 }
catch (Throwable t) {
00228
Debug.print(t);
00229 }
00230 }
00231 }
00232
00233 public void close() throws IOException {
00234
Debug.println(
"close()");
00235
frameData.close();
00236
nonFrameData.close();
00237
if (
nonFrameCount > 0) {
00238
Debug.println(
"" +
nonFrameCount +
" trailing bytes no sync");
00239 }
00240 }
00241 }