我正在尝试使用android AudioRecord和MediaCodec对aac音频进行编码。我创建了一个非常类似于(使用Android MediaCodec从相机编码H.264)的编码器类。使用此类,我创建了一个AudioRecord实例,并告诉它将其byte[]数据读出到AudioEncoder(audioEncoder.offerEncoder(Data))。
while(isRecording)
{
audioRecord.read(Data, 0, Data.length);
audioEncoder.offerEncoder(Data);
}
这是我的音频记录设置
int audioSource = MediaRecorder.AudioSource.MIC;
int sampleRateInHz = 44100;
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
我成功地收集了一些字节[]数组数据,并将其写入本地文件。不幸的是,该文件无法播放。我在网上做了更多搜索,找到了一篇相关帖子(如何用Android MediaCodec生成AAC ADTS基本流)。因此,其他有类似问题的人表示,主要问题是“MediaCodec编码器生成原始AAC流。原始AAC流需要转换为可播放格式,如ADTS流”。所以我尝试添加ADTS标题。然而,在我添加了ADTS头(我在下面的代码中注释掉了)之后,我的AudioEncoder甚至不会写入输出音频文件。我还缺什么吗?我的设置正确吗?
欢迎提出任何建议、意见和意见,我们将不胜感激。谢谢大家!
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.Environment;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
public class AudioEncoder {
private MediaCodec mediaCodec;
private BufferedOutputStream outputStream;
private String mediaType = "audio/mp4a-latm";
public AudioEncoder() {
File f = new File(Environment.getExternalStorageDirectory(), "Download/audio_encoded.aac");
touch(f);
try {
outputStream = new BufferedOutputStream(new FileOutputStream(f));
Log.e("AudioEncoder", "outputStream initialized");
} catch (Exception e){
e.printStackTrace();
}
mediaCodec = MediaCodec.createEncoderByType(mediaType);
final int kSampleRates[] = { 8000, 11025, 22050, 44100, 48000 };
final int kBitRates[] = { 64000, 128000 };
MediaFormat mediaFormat = MediaFormat.createAudioFormat(mediaType,kSampleRates[3],1);
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[1]);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
}
public void close() {
try {
mediaCodec.stop();
mediaCodec.release();
outputStream.flush();
outputStream.close();
} catch (Exception e){
e.printStackTrace();
}
}
// called AudioRecord's read
public synchronized void offerEncoder(byte[] input) {
Log.e("AudioEncoder", input.length + " is coming");
try {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(input);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
////trying to add a ADTS
// while (outputBufferIndex >= 0) {
// int outBitsSize = bufferInfo.size;
// int outPacketSize = outBitsSize + 7; // 7 is ADTS size
// ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
//
// outputBuffer.position(bufferInfo.offset);
// outputBuffer.limit(bufferInfo.offset + outBitsSize);
//
// byte[] outData = new byte[outPacketSize];
// addADTStoPacket(outData, outPacketSize);
//
// outputBuffer.get(outData, 7, outBitsSize);
// outputBuffer.position(bufferInfo.offset);
//
//// byte[] outData = new byte[bufferInfo.size];
// outputStream.write(outData, 0, outData.length);
// Log.e("AudioEncoder", outData.length + " bytes written");
//
// mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
// outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
//
// }
//Without ADTS header
while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size];
outputBuffer.get(outData);
outputStream.write(outData, 0, outData.length);
Log.e("AudioEncoder", outData.length + " bytes written");
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
/**
* Add ADTS header at the beginning of each and every AAC packet.
* This is needed as MediaCodec encoder generates a packet of raw
* AAC data.
*
* Note the packetLen must count in the ADTS header itself.
**/
private void addADTStoPacket(byte[] packet, int packetLen) {
int profile = 2; //AAC LC
//39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;
int freqIdx = 4; //44.1KHz
int chanCfg = 2; //CPE
// fill in ADTS data
packet[0] = (byte)0xFF;
packet[1] = (byte)0xF9;
packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));
packet[4] = (byte)((packetLen&0x7FF) >> 3);
packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);
packet[6] = (byte)0xFC;
}
public void touch(File f)
{
try {
if(!f.exists())
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
检查“testEncoder”方法,了解如何正确使用MediaCodec作为编码器。
之后在你的代码中,
您的输入(音频记录器)配置为单声道,而您的输出(ADTS数据包头)设置为两个声道(chanCfg=2)。
此外,如果更改输入采样器(当前为44.1khz),还必须更改ADTS数据包头中的freqIdx标志。检查此链接以获取有效值。
并且ADTS头配置文件标志设置为“AAC LC”,您也可以在MediaCodecInfo下找到这个。CodecProfileLevel。您已设置配置文件=2,即MediaCodecInfo。CodecProfileLevel。AACObjectLC
您可以使用Android的MediaMuxer将MediaCodec创建的原始流打包到。mp4文件。奖励:AAC数据包包含在一个。mp4不需要ADTS报头。
我在Github上有一个这种技术的工作示例。
我正在尝试使用使用编解码器对一些音频流进行编码。为此,我使用了google cts ExtractEncodeMust的这个实现。 对于某些aac文件,它会在编码某些帧后抛出。更准确地说,它会在第1030行抛出异常,。 我正在配置如下: 我完全不知道如何解决这个问题。任何形式的帮助都将不胜感激。 带有一些日志的堆栈跟踪: 设备:小米POCO x3 操作系统:Android10 导致溢出的示例文件信
我正在尝试使用Android上的MediaCodec API来解码AAC流。(它是原始AAC。)我尝试使用MediaFormat.createAudioFormat()来创建要传递给MediaCodec.configure()的格式对象,但我在使用AAC(音频/mp4a-latm)时一直出错。(不过它适用于MP3(音频/mpeg)...) 最后,我为一个AAC文件创建了一个MediaExtract
我在Android设备上的相机捕获过程中使用音频记录来记录音频流。由于我想处理帧数据并处理音频/视频样本,所以我不使用MediaRecorder。 我在另一个线程中运行AudioRecord并调用read()来收集原始音频数据。一旦我得到数据流,我就将它们馈送到配置为AAC音频编码器的MediaCodec中。 以下是我关于录音机/编码器的一些代码: 我发现这是第一次录音。read()的返回时间较长
我正在使用MediaCodec将PCM数据转换为AAC,并使用MediaMuxer将此aac数据存储到m4a文件中。没有视频。 该文件会生成,甚至会播放。但是没有声音。如果我将aac文件导入Audacity,它不会显示任何数据。音频的长度甚至是预期的时间。我知道数据正在被编码,尽管我不确定这些数据是否被正确编码。 对pcm数据进行编码: 我已经浏览了大量示例,我所做的一切似乎都是正确的。如果我在o
我正在修改一个Android框架示例,将MediaCodec生成的基本AAC流打包成一个独立的。mp4文件。我使用的是一个实例,其中包含一个由实例生成的AAC曲目。 然而,我总是最终得到一个错误消息调用:
我想修剪现有的aac-mp4音频文件。我第一次想“修剪”0个字节,基本上就是使用MediaCodec/MediaExtractor复制文件。 问题: 标题是固定大小的,我可以从旧文件中复制它?或者它有一些关于音轨持续时间的信息,我需要更新它?如果它有固定大小,那是什么(为了知道我应该从旧文件中复制多少字节)? 我应该只使用提取器的getSampleData(ByteBuffer,偏移量)和进步()