问题很简单,但我没有任何解决方法:
我写了一行代码来在我的Nexus 4(Android 4.4.2)上创建一个AAC编码器
MediaCodec codec = MediaCodec.createEncoderByType("audio/mp4a-latm");
保存在“codec”中的返回值不为null,但我在Logcat中收到一条红色错误消息:
03-20 15:25:08.985: E/OMXMaster(24517): A component of name 'OMX.qcom.audio.decoder.aac' already exists, ignoring this one.
我还尝试了另一条线:
MediaCodec codec = MediaCodec.createByCodecName("OMX.google.aac.encoder");
并获得相同的错误结果.
在使用MediaCodec之前,我是否错过了任何初始化步骤?我在官方文件中没有找到任何关于此的信息.
有没有人遇到这个问题?
实际上我正在尝试将PCM编码为AAC文件.我读过这个post @hubeir.他似乎已经成功了.我做了同样的事情:(1)设置mediacodec并输入PCM数据以获得编码帧.为此,我阅读了cts的代码.每个编码的帧长度约为371-379. (2)将adts标题添加到框架,然后保存到文件.我一点一点地检查了头部,这是正确的.但该文件仍然无法播放.所以我想也许错误日志就是问题所在.
以下是我的全部代码,供参考:
MediaCodec codec = MediaCodec.createByCodecName("OMX.google.aac.encoder");
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
format.setInteger(MediaFormat.KEY_AAC_PROFILE,
MediaCodecInfo.CodecProfileLevel.AACObjectELD);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, nSamplerate);
format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, nChannels);
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
boolean bEndInput = false;
boolean bEndOutput = false;
while(true)
{
if (!bEndInput)
{
int inputBufferIndex = codec.dequeueInputBuffer(0);
if (inputBufferIndex >= 0)
{
int nLen = app.readPCM(nHandle,inputBuffers[inputBufferIndex]);//This line read PCM, return 0 if end of data.
int nBufLen = inputBuffers[inputBufferIndex].capacity();
if (nLen == nBufLen)
codec.queueInputBuffer(inputBufferIndex, 0, nLen, 0, MediaCodec.BUFFER_FLAG_SYNC_FRAME);
else if (nLen < nBufLen)
{
codec.queueInputBuffer(inputBufferIndex, 0, nLen, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
bEndInput = true;
break;
}
}
}
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
if (!bEndOutput)
{
int outputBufferIndex = codec.dequeueOutputBuffer(info, 0);
if (outputBufferIndex >= 0)
{
int outBitsSize = info.size;
Log.d("test", "Offset:"+info.offset);
Log.d("test", "Size:"+info.size);
Log.d("test", "Time:"+info.presentationTimeUs);
Log.d("test", "Flags:"+info.flags);
if (outBitsSize <= 10)
{
codec.releaseOutputBuffer(outputBufferIndex, false /* render */);
continue;
}
int outPacketSize = outBitsSize + 7; // 7 is ADTS size
ByteBuffer outBuf = outputBuffers[outputBufferIndex];
outBuf.position(info.offset);
outBuf.limit(info.offset + outBitsSize);
try {
byte[] data = new byte[outPacketSize]; //space for ADTS header included
addADTStoPacket(data, outPacketSize);
outBuf.get(data, 7, outBitsSize);
outBuf.position(info.offset);
outputStream.write(data, 0, outPacketSize); //open FileOutputStream beforehand
} catch (IOException e) {
Log.e("test", "failed writing bitstream data to file");
e.printStackTrace();
}
outBuf.clear();
codec.releaseOutputBuffer(outputBufferIndex, false /* render */);
Log.d("test", " dequeued " + outBitsSize + " bytes of output data.");
Log.d("test", " wrote " + outPacketSize + " bytes into output file.");
if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM)
{
bEndOutput = true;
//break;
}
}
else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
{
outputBuffers = codec.getOutputBuffers();
}
else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
{
}
}
if (bEndInput && bEndOutput)
break;
}
解决方法:
我想通了.
(1)媒体格式的错误设置:
format.setInteger(MediaFormat.KEY_AAC_PROFILE,
MediaCodecInfo.CodecProfileLevel.AACObjectELD);
should be format.setInteger(MediaFormat.KEY_AAC_PROFILE,
MediaCodecInfo.CodecProfileLevel.AACObjectLC);
(2)编码帧只能在(info.flags == 0)时用adts文件写入文件
(3)输出文件名后缀应为“aac”. “mp4”或“m4a”可能不适用于某些应用程序.
MediaCodec codec = MediaCodec.createByCodecName("OMX.google.aac.encoder");
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
format.setInteger(MediaFormat.KEY_AAC_PROFILE,
MediaCodecInfo.CodecProfileLevel.AACObjectLC); //fixed version
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, nSamplerate);
format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, nChannels);
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
boolean bEndInput = false;
boolean bEndOutput = false;
while(true)
{
if (!bEndInput)
{
int inputBufferIndex = codec.dequeueInputBuffer(0);
if (inputBufferIndex >= 0)
{
int nLen = app.readPCM(nHandle,inputBuffers[inputBufferIndex]);//This line read PCM, return 0 if end of data.
int nBufLen = inputBuffers[inputBufferIndex].capacity();
if (nLen == nBufLen)
codec.queueInputBuffer(inputBufferIndex, 0, nLen, 0, MediaCodec.BUFFER_FLAG_SYNC_FRAME);
else if (nLen < nBufLen)
{
codec.queueInputBuffer(inputBufferIndex, 0, nLen, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
bEndInput = true;
break;
}
}
}
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
if (!bEndOutput)
{
int outputBufferIndex = codec.dequeueOutputBuffer(info, 0);
if (outputBufferIndex >= 0)
{
int outBitsSize = info.size;
Log.d("test", "Offset:"+info.offset);
Log.d("test", "Size:"+info.size);
Log.d("test", "Time:"+info.presentationTimeUs);
Log.d("test", "Flags:"+info.flags);
if (info.flags != 0) //fixed version
{
codec.releaseOutputBuffer(outputBufferIndex, false /* render */);
continue;
}
int outPacketSize = outBitsSize + 7; // 7 is ADTS size
ByteBuffer outBuf = outputBuffers[outputBufferIndex];
outBuf.position(info.offset);
outBuf.limit(info.offset + outBitsSize);
try {
byte[] data = new byte[outPacketSize]; //space for ADTS header included
addADTStoPacket(data, outPacketSize);
outBuf.get(data, 7, outBitsSize);
outBuf.position(info.offset);
outputStream.write(data, 0, outPacketSize); //open FileOutputStream beforehand
} catch (IOException e) {
Log.e("test", "failed writing bitstream data to file");
e.printStackTrace();
}
outBuf.clear();
codec.releaseOutputBuffer(outputBufferIndex, false /* render */);
Log.d("test", " dequeued " + outBitsSize + " bytes of output data.");
Log.d("test", " wrote " + outPacketSize + " bytes into output file.");
if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM)
{
bEndOutput = true;
//break;
}
}
else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
{
outputBuffers = codec.getOutputBuffers();
}
else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
{
}
}
if (bEndInput && bEndOutput)
break;
}