如何在Android上编写音频文件,最好是.3gp
我研究这个已经有一段时间了,但仍然没有乐趣 我知道MediaRecorder将以几种格式之一读取音频源并直接写入文件。我也知道AudioRecord会读取音频源并让你处理原始数据,但是有没有办法从你的应用程序中写入数据如何在Android上编写音频文件,最好是.3gp,android,audio,audio-recording,Android,Audio,Audio Recording,我研究这个已经有一段时间了,但仍然没有乐趣 我知道MediaRecorder将以几种格式之一读取音频源并直接写入文件。我也知道AudioRecord会读取音频源并让你处理原始数据,但是有没有办法从你的应用程序中写入数据 例如,我想读取音频,以某种简单的方式对其进行过滤,然后写入.3gp文件。有没有办法做到这一点?搜索示例时,我只能找到一种通过手动写入头来生成.wav文件的方法。编写自己的编码器或使用现有的编码器,如using JNI 这个问题也可能有用。 您查看了MediaCodec类了吗 .a
例如,我想读取音频,以某种简单的方式对其进行过滤,然后写入.3gp文件。有没有办法做到这一点?搜索示例时,我只能找到一种通过手动写入头来生成.wav文件的方法。编写自己的编码器或使用现有的编码器,如using JNI 这个问题也可能有用。
您查看了MediaCodec类了吗
.aac
对你有用吗?如果是,请检查以下内容:
使用管理器类以新线程运行此runnable。在开始录制按钮上,单击:
.aac
的文件导入android.media.AudioFormat;
导入android.media.AudioRecord;
导入android.media.MediaCodec;
导入android.media.mediacodeinfo;
导入android.media.MediaFormat;
导入android.media.MediaRecorder;
导入android.os.Build;
导入android.util.Log;
导入java.io.IOException;
导入java.io.OutputStream;
导入java.nio.ByteBuffer;
公共类AudioRecordThread实现可运行{
私有静态最终字符串标记=AudioRecordThread.class.getSimpleName();
私有静态最终整数抽样率=44100;
私有静态最终整数抽样率指数=4;
专用静态最终整数通道=1;
专用静态最终整数比特率=32000;
私有最终整数缓冲大小;
专用最终MediaCodec MediaCodec;
私人最终录音;
私有最终输出流OutputStream;
私有OnRecorderFailedListener OnRecorderFailedListener;
AudioRecordThread(OutputStream OutputStream,OnRecorderFailedListener OnRecorderFailedListener)抛出IOException{
this.bufferSize=AudioRecord.getMinBufferSize(采样率,单声道中的AudioFormat.CHANNEL,AudioFormat.ENCODING,PCM,16位);
this.audioRecord=createAudioRecord(this.bufferSize);
this.mediaCodec=createMediaCodec(this.bufferSize);
this.outputStream=outputStream;
this.onRecorderFailedListener=onRecorderFailedListener;
this.mediaCodec.start();
试一试{
录音。开始录制();
}捕获(例外e){
Log.w(TAG,e);
mediaCodec.release();
抛出新的IOException(e);
}
}
@凌驾
公开募捐{
if(onRecorderFailedListener!=null){
Log.d(标签“onRecorderStarted”);
onRecorderFailedListener.onRecorderStarted();
}
MediaCodec.BufferInfo BufferInfo=新的MediaCodec.BufferInfo();
ByteBuffer[]CodeInputBuffers=mediaCodec.getInputBuffers();
ByteBuffer[]codecOutputBuffers=mediaCodec.getOutputBuffers();
试一试{
而(!Thread.interrupted()){
boolean success=handleCodecInput(音频录制、mediaCodec、CodeInputBuffers、Thread.currentThread().isAlive());
如果(成功)
handleCodecOutput(mediaCodec、CodeOutputBuffers、bufferInfo、outputStream);
}
}捕获(IOE异常){
Log.w(TAG,e);
}最后{
mediaCodec.stop();
录音。停止();
mediaCodec.release();
audioRecord.release();
试一试{
outputStream.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
专用布尔HandleCodeInput(录音、录音、,
MediaCodec MediaCodec,ByteBuffer[]CodeInputBuffers,
布尔运行)抛出IOException{
byte[]audioRecordData=新字节[bufferSize];
int length=audioRecord.read(audioRecordData,0,audioRecordData.length);
if(length==AudioRecord.ERROR\u BAD\u值||
长度==AudioRecord.ERROR\u无效\u操作||
长度!=缓冲区大小){
如果(长度!=缓冲区大小){
if(onRecorderFailedListener!=null){
Log.d(标记“length!=BufferSize调用onRecordFailed”);
onRecorderFailedListener.onRecorderFailed();
}
返回false;
}
}
int codecInputBufferIndex=mediaCodec.dequeueInputBuffer(10*1000);
如果(CodeInputBufferIndex>=0){
ByteBuffer codecBuffer=codecInputBuffers[codecInputBufferIndex];
codecBuffer.clear();
codecBuffer.put(audioRecordData);
mediaCodec.queueInputBuffer(CodeInputBufferIndex,0,长度,0,正在运行?0:mediaCodec.BUFFER\u标志\u流的结束\u);
}
返回true;
}
私有无效handleCodecOutput(MediaCodec MediaCodec,
ByteBuffer[]编码输出缓冲区,
MediaCodec.BufferInfo BufferInfo,
OutputStream(输出流)
抛出IOException{
int codecOutputBufferIndex=mediaCodec.dequeueOutputBuffer(bufferInfo,0);
while(codecOutputBufferIndex!=MediaCodec.INFO\u请稍后重试){
如果(codecOutputBufferIndex>=0){
ByteBuffer encoderOutputBuffer=codecOutputBuffers[codecOutputBufferIndex];
编码Buffer.position(bufferInfo.offset);
encoderOutputBuffer.limit(bufferInfo.offset+bufferInfo
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaRecorder;
import android.os.Build;
import android.util.Log;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
public class AudioRecordThread implements Runnable {
private static final String TAG = AudioRecordThread.class.getSimpleName();
private static final int SAMPLE_RATE = 44100;
private static final int SAMPLE_RATE_INDEX = 4;
private static final int CHANNELS = 1;
private static final int BIT_RATE = 32000;
private final int bufferSize;
private final MediaCodec mediaCodec;
private final AudioRecord audioRecord;
private final OutputStream outputStream;
private OnRecorderFailedListener onRecorderFailedListener;
AudioRecordThread(OutputStream outputStream, OnRecorderFailedListener onRecorderFailedListener) throws IOException {
this.bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
this.audioRecord = createAudioRecord(this.bufferSize);
this.mediaCodec = createMediaCodec(this.bufferSize);
this.outputStream = outputStream;
this.onRecorderFailedListener = onRecorderFailedListener;
this.mediaCodec.start();
try {
audioRecord.startRecording();
} catch (Exception e) {
Log.w(TAG, e);
mediaCodec.release();
throw new IOException(e);
}
}
@Override
public void run() {
if (onRecorderFailedListener != null) {
Log.d(TAG, "onRecorderStarted");
onRecorderFailedListener.onRecorderStarted();
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
ByteBuffer[] codecInputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] codecOutputBuffers = mediaCodec.getOutputBuffers();
try {
while (!Thread.interrupted()) {
boolean success = handleCodecInput(audioRecord, mediaCodec, codecInputBuffers, Thread.currentThread().isAlive());
if (success)
handleCodecOutput(mediaCodec, codecOutputBuffers, bufferInfo, outputStream);
}
} catch (IOException e) {
Log.w(TAG, e);
} finally {
mediaCodec.stop();
audioRecord.stop();
mediaCodec.release();
audioRecord.release();
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private boolean handleCodecInput(AudioRecord audioRecord,
MediaCodec mediaCodec, ByteBuffer[] codecInputBuffers,
boolean running) throws IOException {
byte[] audioRecordData = new byte[bufferSize];
int length = audioRecord.read(audioRecordData, 0, audioRecordData.length);
if (length == AudioRecord.ERROR_BAD_VALUE ||
length == AudioRecord.ERROR_INVALID_OPERATION ||
length != bufferSize) {
if (length != bufferSize) {
if (onRecorderFailedListener != null) {
Log.d(TAG, "length != BufferSize calling onRecordFailed");
onRecorderFailedListener.onRecorderFailed();
}
return false;
}
}
int codecInputBufferIndex = mediaCodec.dequeueInputBuffer(10 * 1000);
if (codecInputBufferIndex >= 0) {
ByteBuffer codecBuffer = codecInputBuffers[codecInputBufferIndex];
codecBuffer.clear();
codecBuffer.put(audioRecordData);
mediaCodec.queueInputBuffer(codecInputBufferIndex, 0, length, 0, running ? 0 : MediaCodec.BUFFER_FLAG_END_OF_STREAM);
}
return true;
}
private void handleCodecOutput(MediaCodec mediaCodec,
ByteBuffer[] codecOutputBuffers,
MediaCodec.BufferInfo bufferInfo,
OutputStream outputStream)
throws IOException {
int codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
while (codecOutputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
if (codecOutputBufferIndex >= 0) {
ByteBuffer encoderOutputBuffer = codecOutputBuffers[codecOutputBufferIndex];
encoderOutputBuffer.position(bufferInfo.offset);
encoderOutputBuffer.limit(bufferInfo.offset + bufferInfo.size);
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
byte[] header = createAdtsHeader(bufferInfo.size - bufferInfo.offset);
outputStream.write(header);
byte[] data = new byte[encoderOutputBuffer.remaining()];
encoderOutputBuffer.get(data);
outputStream.write(data);
}
encoderOutputBuffer.clear();
mediaCodec.releaseOutputBuffer(codecOutputBufferIndex, false);
} else if (codecOutputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
codecOutputBuffers = mediaCodec.getOutputBuffers();
}
codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
}
private byte[] createAdtsHeader(int length) {
int frameLength = length + 7;
byte[] adtsHeader = new byte[7];
adtsHeader[0] = (byte) 0xFF; // Sync Word
adtsHeader[1] = (byte) 0xF1; // MPEG-4, Layer (0), No CRC
adtsHeader[2] = (byte) ((MediaCodecInfo.CodecProfileLevel.AACObjectLC - 1) << 6);
adtsHeader[2] |= (((byte) SAMPLE_RATE_INDEX) << 2);
adtsHeader[2] |= (((byte) CHANNELS) >> 2);
adtsHeader[3] = (byte) (((CHANNELS & 3) << 6) | ((frameLength >> 11) & 0x03));
adtsHeader[4] = (byte) ((frameLength >> 3) & 0xFF);
adtsHeader[5] = (byte) (((frameLength & 0x07) << 5) | 0x1f);
adtsHeader[6] = (byte) 0xFC;
return adtsHeader;
}
private AudioRecord createAudioRecord(int bufferSize) {
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize * 10);
if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.d(TAG, "Unable to initialize AudioRecord");
throw new RuntimeException("Unable to initialize AudioRecord");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (android.media.audiofx.NoiseSuppressor.isAvailable()) {
android.media.audiofx.NoiseSuppressor noiseSuppressor = android.media.audiofx.NoiseSuppressor
.create(audioRecord.getAudioSessionId());
if (noiseSuppressor != null) {
noiseSuppressor.setEnabled(true);
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (android.media.audiofx.AutomaticGainControl.isAvailable()) {
android.media.audiofx.AutomaticGainControl automaticGainControl = android.media.audiofx.AutomaticGainControl
.create(audioRecord.getAudioSessionId());
if (automaticGainControl != null) {
automaticGainControl.setEnabled(true);
}
}
}
return audioRecord;
}
private MediaCodec createMediaCodec(int bufferSize) throws IOException {
MediaCodec mediaCodec = MediaCodec.createEncoderByType("audio/mp4a-latm");
MediaFormat mediaFormat = new MediaFormat();
mediaFormat.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE);
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNELS);
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, bufferSize);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
try {
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
} catch (Exception e) {
Log.w(TAG, e);
mediaCodec.release();
throw new IOException(e);
}
return mediaCodec;
}
interface OnRecorderFailedListener {
void onRecorderFailed();
void onRecorderStarted();
}
}