【发布时间】:2018-07-26 08:41:07
【问题描述】:
目前,我正在使用 JTransforms 对我从 MediaCodecAudioRenderer 复制的音频样本执行 FFT,并使用挂钩自定义复制解码缓冲区,从使用 RTMP MediaSource 的 ExoPlayer 播放器。
我得到的是 4096(或 4608...是的,有些 MP3 奇怪地具有非 2 次方样本大小,我不知道为什么)-长度 ByteBuffer。这就是我必须放入 FloatFFT_1D 或 DoubleFFT_1D 对象的内容,对吗?
现在我的代码如下:
crf.setHook((dupe, format) -> {
if(currentMediaSource == mMediaSourceAudio) {
byte[] data = new byte[dupe.limit()];
dupe.position(0);
dupe.get(data);
if(format != null) {
new FFTTask(data, format).execute();
}
Log.i("straight_from_renderer", data.length+" "+format);
}
});
...
...
private class FFTTask extends AsyncTask<Void, Void, float[]> {
byte[] bufferContents;
MediaFormat format;
FFTTask(byte[] samples, MediaFormat format) {
this.bufferContents = samples;
this.format = format;
}
float[] floatMe(short[] pcms) {
float[] floaters = new float[pcms.length];
for (int i = 0; i < pcms.length; i++) {
floaters[i] = pcms[i];
}
return floaters;
}
short[] shortMe(byte[] bytes) {
short[] out = new short[bytes.length / 2]; // will drop last byte if odd number
ByteBuffer bb = ByteBuffer.wrap(bytes);
for (int i = 0; i < out.length; i++) {
out[i] = bb.getShort();
}
return out;
}
float[] directFloatMe(byte[] bytes) {
float[] out = new float[bytes.length / 2]; // will drop last byte if odd number
ByteBuffer bb = ByteBuffer.wrap(bytes);
for (int i = 0; i < out.length; i++) {
out[i] = bb.getFloat();
}
return out;
}
private double db2(double r, double i, double maxSquared) {
return 5.0 * Math.log10((r * r + i * i) / maxSquared);
}
double[] convertToDb(double[] data, double maxSquared) {
data[0] = db2(data[0], 0.0, maxSquared);
int j = 1;
for (int i=1; i < data.length - 1; i+=2, j++) {
data[j] = db2(data[i], data[i+1], maxSquared);
}
data[j] = data[0];
return data;
}
@Override
protected float[] doInBackground(Void... voids) {
//WARNING: bufferContents is from a 2-channel 48k bitrate audio, so convert to mono first?
/*
byte[] oneChannel = new byte[bufferContents.length/2];
for(int i = 0; i < oneChannel.length; i+=2) {
oneChannel[i] = bufferContents[i*2+2];
oneChannel[i+1] = bufferContents[i*2+3];
}
*/
float[] dataAsFloats = floatMe(shortMe(bufferContents));
int fftLen = dataAsFloats.length/2;
fft = new FloatFFT_1D(fftLen);
fft.complexForward(dataAsFloats);
String log = "";
float[] magnitudes = new float[dataAsFloats.length/2];
float magMax = 0;
int maxIndex = 0;
float dominantFreq = 0;
for(int i = 0; i < dataAsFloats.length/2; i++) {
float re = dataAsFloats[2*i];
float im = dataAsFloats[2*i+1];
magnitudes[i] = (float)(Math.sqrt(re * re + im * im) / 1e7);
//log += re+" "+im+" "+magnitudes[i]+"\n";
if(magnitudes[i] > magMax) {
magMax = (float)(magnitudes[i]);
maxIndex = i;
}
}
dominantFreq = format.getInteger(MediaFormat.KEY_SAMPLE_RATE) * maxIndex / fftLen;
Log.i("fft_results", magMax+" "+dominantFreq);
return magnitudes;
}
@Override
protected void onPostExecute(float[] res) {
super.onPostExecute(res);
//fftListener.onFFTResultsAvailable(res);
caView.feedFFTMagnitudes(res);
}
}
我把通道拆分代码注释掉了,因为我不确定是要批发那个字节数组,还是按通道拆分它,然后把其中一个通道的数据放进去。
但是最终的res 值真的很嘈杂——例如,幅度是混乱的,没有像通常的音频分析图像那样显示出明显的模式——相反,它只是一个紧凑的锯齿形,从频率高于 20000 Hz。
我做错了什么?
【问题讨论】: