Lame编码的mp3音频速度变慢-Android
我一直在关注在Android和jni上使用LAME mp3。录音似乎是工作,我得到了一个mp3输出,但在播放音频已放慢和音调 我试着把所有相关的代码放在下面。有关于为什么会发生这种情况的指导吗?提前感谢你的帮助 编辑:好的,只是为了检查一下,我将原始数据导入Audacity,播放效果很好,所以这在编码阶段一定是个问题 Java类:Lame编码的mp3音频速度变慢-Android,android,java-native-interface,audiorecord,lame,slowdown,Android,Java Native Interface,Audiorecord,Lame,Slowdown,我一直在关注在Android和jni上使用LAME mp3。录音似乎是工作,我得到了一个mp3输出,但在播放音频已放慢和音调 我试着把所有相关的代码放在下面。有关于为什么会发生这种情况的指导吗?提前感谢你的帮助 编辑:好的,只是为了检查一下,我将原始数据导入Audacity,播放效果很好,所以这在编码阶段一定是个问题 Java类: 公共类记录扩展活动实现OnClickListener{ 静止的{ 系统加载库(“mp3lame”); } 私有本机void initEncoder(int numCh
公共类记录扩展活动实现OnClickListener{
静止的{
系统加载库(“mp3lame”);
}
私有本机void initEncoder(int numChannels、int sampleRate、int比特率、int模式、int质量);
私有本机void destroycoder();
私有本机int encodeFile(字符串sourcePath、字符串targetPath);
专用静态最终整数记录器_BPP=16;
专用静态最终字符串音频\u记录器\u文件\u EXT\u WAV=“.WAV”;
私有静态最终字符串音频\u记录器\u文件夹=“AberdeenSoundsites”;
专用静态最终字符串音频\u记录器\u TEMP\u FILE=“录制\u TEMP.raw”;
专用静态最终int[]记录器_SAMPLERATES={4410022050110258000};
专用静态最终整数记录器\u通道=立体声中的AudioFormat.CHANNEL\u;
专用静态最终整数记录器\u音频\u编码=AudioFormat.ENCODING\u PCM\u 16位;
公共静态最终int NUM_通道=2;
公共静态最终整数抽样率=44100;
公共静态最终整数比特率=320;
公共静态最终整数模式=1;
公共静态最终整数质量=2;
私人卖空者;
私有文件;
私有文件编码文件;
私人int采样器;
私有字符串文件名;
专用录音机=空;
私有int bufferSize=0;
私有线程recordingThread=null;
私有布尔值isRecording=false;
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.record);
initEncoder(通道数、采样率、比特率、模式、质量);
stopButton=(按钮)findViewById(R.id.stop_按钮);
stopButton.setOnClickListener(此);
计时器=(TextView)findViewById(R.id.记录时间);
bufferSize=AudioRecord.getMinBufferSize(44100,记录器通道,记录器音频编码);
}
私有无效开始记录(){
停止=错误;
stopButton.setText(R.string.stop\u按钮\u标签);
//设置并启动音频录制
记录器=findAudioRecord();
记录器。开始记录();
isRecording=true;
rawFile=getFile(“原始”);
mBuffer=新短[缓冲区大小];
startBufferedWrite(原始文件);
}
私有void stopRecording(){
mHandler.removeCallbacks(startTimer);
停止=真;
if(记录器!=null){
isRecording=false;
录音机。停止();
记录器。释放();
记录器=空;
recordingThread=null;
}
encodedFile=getFile(“mp3”);
int result=encodeFile(rawFile.getAbsolutePath(),encodedFile.getAbsolutePath());
如果(结果==0){
Toast.makeText(Record.this,“编码为”+encodedFile.getName(),Toast.LENGTH\u SHORT)
.show();
}
}
私有void startBufferedWrite(最终文件){
新线程(newrunnable()){
@凌驾
公开募捐{
Looper.prepare();
DataOutputStream输出=null;
试一试{
输出=新的DataOutputStream(新的BufferedOutputStream(新的FileOutputStream(文件)));
while(isRecording){
int readSize=recorder.read(mBuffer,0,mBuffer.length);
对于(int i=0;ipublic class Record extends Activity implements OnClickListener {
static {
System.loadLibrary("mp3lame");
}
private native void initEncoder(int numChannels, int sampleRate, int bitRate, int mode, int quality);
private native void destroyEncoder();
private native int encodeFile(String sourcePath, String targetPath);
private static final int RECORDER_BPP = 16;
private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav";
private static final String AUDIO_RECORDER_FOLDER = "AberdeenSoundsites";
private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw";
private static final int[] RECORDER_SAMPLERATES = {44100, 22050, 11025, 8000};
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
public static final int NUM_CHANNELS = 2;
public static final int SAMPLE_RATE = 44100;
public static final int BITRATE = 320;
public static final int MODE = 1;
public static final int QUALITY = 2;
private short[] mBuffer;
private File rawFile;
private File encodedFile;
private int sampleRate;
private String filename;
private AudioRecord recorder = null;
private int bufferSize = 0;
private Thread recordingThread = null;
private boolean isRecording = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.record);
initEncoder(NUM_CHANNELS, SAMPLE_RATE, BITRATE, MODE, QUALITY);
stopButton = (Button) findViewById(R.id.stop_button);
stopButton.setOnClickListener(this);
timer = (TextView) findViewById(R.id.recording_time);
bufferSize = AudioRecord.getMinBufferSize(44100, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);
}
private void startRecording() {
stopped = false;
stopButton.setText(R.string.stop_button_label);
// Set up and start audio recording
recorder = findAudioRecord();
recorder.startRecording();
isRecording = true;
rawFile = getFile("raw");
mBuffer = new short[bufferSize];
startBufferedWrite(rawFile);
}
private void stopRecording() {
mHandler.removeCallbacks(startTimer);
stopped = true;
if(recorder != null){
isRecording = false;
recorder.stop();
recorder.release();
recorder = null;
recordingThread = null;
}
encodedFile = getFile("mp3");
int result = encodeFile(rawFile.getAbsolutePath(), encodedFile.getAbsolutePath());
if (result == 0) {
Toast.makeText(Record.this, "Encoded to " + encodedFile.getName(), Toast.LENGTH_SHORT)
.show();
}
}
private void startBufferedWrite(final File file) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
DataOutputStream output = null;
try {
output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
while (isRecording) {
int readSize = recorder.read(mBuffer, 0, mBuffer.length);
for (int i = 0; i < readSize; i++) {
output.writeShort(mBuffer[i]);
}
}
} catch (IOException e) {
Toast.makeText(Record.this, e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (output != null) {
try {
output.flush();
} catch (IOException e) {
Toast.makeText(Record.this, e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
try {
output.close();
} catch (IOException e) {
Toast.makeText(Record.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
}
}).start();
}
private File getFile(final String suffix) {
Time time = new Time();
time.setToNow();
return new File(Environment.getExternalStorageDirectory()+"/MyAppFolder", time.format("%Y%m%d%H%M%S") + "." + suffix);
}
public AudioRecord findAudioRecord() {
for (int rate : RECORDER_SAMPLERATES) {
for (short audioFormat : new short[] { AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_PCM_8BIT }) {
for (short channelConfig : new short[] { AudioFormat.CHANNEL_IN_STEREO, AudioFormat.CHANNEL_IN_MONO }) {
try {
Log.d("AberdeenSoundsites", "Attempting rate " + rate + "Hz, bits: " + audioFormat + ", channel: "
+ channelConfig);
int bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat);
if (bufferSize != AudioRecord.ERROR_BAD_VALUE) {
// check if we can instantiate and have a success
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, rate, channelConfig, audioFormat, bufferSize);
sampleRate = rate;
if (recorder.getState() == AudioRecord.STATE_INITIALIZED)
return recorder;
}
} catch (Exception e) {
Log.e("MyApp", rate + "Exception, keep trying.",e);
}
}
}
}
Log.e("MyApp", "No settings worked :(");
return null;
}
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <android/log.h>
#include "libmp3lame/lame.h"
#define LOG_TAG "LAME ENCODER"
#define LOGD(format, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, format, ##args);
#define BUFFER_SIZE 8192
#define be_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8))
lame_t lame;
int read_samples(FILE *input_file, short *input) {
int nb_read;
nb_read = fread(input, 1, sizeof(short), input_file) / sizeof(short);
int i = 0;
while (i < nb_read) {
input[i] = be_short(input[i]);
i++;
}
return nb_read;
}
void Java_myPacakage_myApp_Record_initEncoder(JNIEnv *env,
jobject jobj, jint in_num_channels, jint in_samplerate, jint in_brate,
jint in_mode, jint in_quality) {
lame = lame_init();
LOGD("Init parameters:");
lame_set_num_channels(lame, in_num_channels);
LOGD("Number of channels: %d", in_num_channels);
lame_set_in_samplerate(lame, in_samplerate);
LOGD("Sample rate: %d", in_samplerate);
lame_set_brate(lame, in_brate);
LOGD("Bitrate: %d", in_brate);
lame_set_mode(lame, in_mode);
LOGD("Mode: %d", in_mode);
lame_set_quality(lame, in_quality);
LOGD("Quality: %d", in_quality);
int res = lame_init_params(lame);
LOGD("Init returned: %d", res);
}
void Java_myPacakage_myApp_Record_destroyEncoder(
JNIEnv *env, jobject jobj) {
int res = lame_close(lame);
LOGD("Deinit returned: %d", res);
}
void Java_myPacakage_myApp_Record_encodeFile(JNIEnv *env,
jobject jobj, jstring in_source_path, jstring in_target_path) {
const char *source_path, *target_path;
source_path = (*env)->GetStringUTFChars(env, in_source_path, NULL);
target_path = (*env)->GetStringUTFChars(env, in_target_path, NULL);
FILE *input_file, *output_file;
input_file = fopen(source_path, "rb");
output_file = fopen(target_path, "wb");
short input[BUFFER_SIZE];
char output[BUFFER_SIZE];
int nb_read = 0;
int nb_write = 0;
int nb_total = 0;
LOGD("Encoding started");
while (nb_read = read_samples(input_file, input)) {
nb_write = lame_encode_buffer(lame, input, input, nb_read, output,
BUFFER_SIZE);
fwrite(output, nb_write, 1, output_file);
nb_total += nb_write;
}
LOGD("Encoded %d bytes", nb_total);
nb_write = lame_encode_flush(lame, output, BUFFER_SIZE);
fwrite(output, nb_write, 1, output_file);
LOGD("Flushed %d bytes", nb_write);
fclose(input_file);
fclose(output_file);
}
lame_set_in_samplerate(lame, 48000);
lame_set_out_samplerate(lame, 44100);
if (lame_get_num_channels(glf) == 2)
{
result = lame_encode_buffer_interleaved(glf, j_buffer_l, samples/2, j_mp3buf, mp3buf_size);
}
else
{
result = lame_encode_buffer(glf, j_buffer_l, j_buffer_r, samples, j_mp3buf, mp3buf_size);
}
nb_write = lame_encode_buffer(lame, input, input, nb_read, output, BUFFER_SIZE);
int CDECL lame_encode_buffer (
lame_global_flags* gfp, /* global context handle */
const short int buffer_l [], /* PCM data for left channel */
const short int buffer_r [], /* PCM data for right channel */
const int nsamples, /* number of samples per channel */
unsigned char* mp3buf, /* pointer to encoded MP3 stream */
const int mp3buf_size ); /* number of valid octets in this
stream */
nb_write = lame_encode_buffer(lame, input, input, nb_read, output, BUFFER_SIZE);
nb_write = lame_encode_buffer(lame, input1, input2, nb_read, output, BUFFER_SIZE);