我想做的是:使用Android的MediaCodec将原始PCM音频样本编码到原始AAC文件中。
我的问题是:当我使用FFMPEG将生成的原始AAC文件打包到M4A容器中时,FFMPEG抱怨文件中缺少编解码器参数。
细节:
因为我找不到任何用于生成输出AAC文件的音频编码器的MediaCodec示例代码,所以我尝试将视频编码器修改为音频编码器。原始代码如下:源代码
我对音频编码器的配置如下:
mEncoderFormat = MediaFormat.createAudioFormat("audio/mp4a-latm", (int)mAudioSampleRate, 2);
// redundant?
mEncoderFormat.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
mEncoderFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,
MediaCodecInfo.CodecProfileLevel.AACObjectELD);
mEncoderFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, kSampleRates);
mEncoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates);
mEncoderFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
testEncoderWithFormat("audio/mp4a-latm", mEncoderFormat);
try {
codec.configure(
mEncoderFormat,
null /* surface */,
null /* crypto */,
MediaCodec.CONFIGURE_FLAG_ENCODE);
} catch (IllegalStateException e) {
Log.e(TAG, "codec '" + componentName + "' failed configuration.");
return;
}
Log.d(TAG, " testEncoder configured with format = " + format);
然后我向编码器提供每帧10ms的PCM样本。编码器获取每帧,生成一帧比特流,然后我将比特流写入FileOutputStream。循环一直持续到输入文件的末尾。
代码一直运行到最后。我使用“adb pull”将生成的AAC文件从设备中获取到我的PC,并使用FFMPEG读取它。下面是FFMPEG发出的命令和错误:
$ ffmpeg -f aac -i BlessedNoColor_nexus7_api18.aac
ffmpeg version N-45739-g04bf2e7 Copyright (c) 2000-2012 the FFmpeg developers
built on Oct 20 2012 00:20:36 with gcc 4.7.2 (GCC)
configuration: --enable-gpl --enable-version3 --disable-pthreads --enable-runt
ime-cpudetect --enable-avisynth --enable-bzlib --enable-frei0r --enable-libass -
-enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libfreetype --enab
le-libgsm --enable-libmp3lame --enable-libnut --enable-libopenjpeg --enable-libo
pus --enable-librtmp --enable-libschroedinger --enable-libspeex --enable-libtheo
ra --enable-libutvideo --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-li
bvorbis --enable-libvpx --enable-libx264 --enable-libxavs --enable-libxvid --ena
ble-zlib
libavutil 51. 76.100 / 51. 76.100
libavcodec 54. 67.100 / 54. 67.100
libavformat 54. 33.100 / 54. 33.100
libavdevice 54. 3.100 / 54. 3.100
libavfilter 3. 19.103 / 3. 19.103
libswscale 2. 1.101 / 2. 1.101
libswresample 0. 16.100 / 0. 16.100
libpostproc 52. 1.100 / 52. 1.100
[aac @ 00000000002efae0] channel element 2.0 is not allocated
[aac @ 00000000003cf520] decoding for stream 0 failed
[aac @ 00000000003cf520] Could not find codec parameters for stream 0 (Audio: aac, 0 channels, s16): unspecified sample rate
Consider increasing the value for the 'analyzeduration' and 'probesize' options
[aac @ 00000000003cf520] Estimating duration from bitrate, this may be inaccurate
BlessedNoColor_nexus7_api18.aac: could not find codec parameters
我的问题:
任何帮助都将不胜感激。如果有一个示例项目可以完成我在这里尝试做的事情,那就太好了。如果我的源代码可以帮助您帮助我,我会发布它。我需要做一些清理。谢谢!
编辑:将标题从“MediaCodec生成的基本AAC文件缺少编解码器参数”更改为“如何使用Android MediaCodec生成AAC ADTS基本流”
我终于生成了可以在Android设备和Windows主机上播放的AAC文件。我在这里发布我的解决方案,希望它可以帮助其他人。
首先,我之前关于Android MediaCodec编码器生成基本AAC流的假设并不准确。MediaCodec编码器生成原始AAC流。这就是文件无法播放的原因。原始AAC流需要转换为可播放的格式,例如ADTS流。我改变了这篇文章的标题,以反映我的新理解。还有一篇帖子问了一个类似的问题,并且给出了很好的答案。然而,新手可能不一定理解那里的简短描述。我第一次读那篇文章时还没完全明白。
因此,为了生成可以由媒体播放器播放的AAC比特流,我从fadden在他的第1条评论中给出的EncoderTest示例开始,但修改了原始代码以在每个输出帧(访问单元)中添加ADTS标头,并将生成的流写入文件(将原始代码的第248行到第267行替换为以下代码片段):
if (index >= 0) {
int outBitsSize = info.size;
int outPacketSize = outBitsSize + 7; // 7 is ADTS size
ByteBuffer outBuf = codecOutputBuffers[index];
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);
mFileStream.write(data, 0, outPacketSize); //open FileOutputStream beforehand
} catch (IOException e) {
Log.e(TAG, "failed writing bitstream data to file");
e.printStackTrace();
}
numBytesDequeued += info.size;
outBuf.clear();
codec.releaseOutputBuffer(index, false /* render */);
Log.d(TAG, " dequeued " + outBitsSize + " bytes of output data.");
Log.d(TAG, " wrote " + outPacketSize + " bytes into output file.");
}
else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
}
else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
codecOutputBuffers = codec.getOutputBuffers();
}
在循环之外,我定义了addADTStoPacket函数,如下所示:
/**
* 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;
}
我还添加了控制如何停止生成AAC ADTS流的代码,但这是特定于应用程序的,因此我将不在这里详述。通过所有这些更改,生成的AAC文件可以在Android设备上、在我的Windows PC上播放,ffmpeg对此感到满意。
问题内容: 我们正在尝试找到一种语法,以从日期函数的第三个参数生成DAY | WEEK | MONTH选项。 您知道在DECLARE中使用什么正确的语法,并且应该将其转换为有效的SQL。 问题答案: 以下是BigQuery标准SQL 这些都是文字,无法进行参数化 而且,您知道-动态SQL尚不可用 因此,不幸的是,以下是我今天能想到的唯一解决方案
问题内容: 我之前从未使用过JSON,并且尝试使用以下javascript:http : //jqueryselectcombo.googlecode.com/files/jquery.selectCombo1.2.6.js 它需要以下格式的JSON输出: 您能否指导我举一个有关如何使用PHP生成上述JSON输出的示例? 问题答案: 最简单的方法可能是从所需的对的关联数组开始: 然后使用forea
我正在从事一个使用8.5.9版Tomcat的Spring Boot开发的项目。 该应用程序在JAX RS中提供RESTfull web服务。在Prod环境中,有时我会得到一个错误503服务不可用,但我无法复制它,因为我使用本地模拟。 有没有办法在本地重现错误?比如把雄猫暂时搁置?
假设我们有以下方法。 如何使用这两个参数创建单个IntStream? 它似乎很冗长。我们有什么简明的成语吗?
我知道这似乎已经讨论过了,答案是肯定的,可以为不同的字符串生成相同的值,但不太可能(Java的hashCode可以为不同的字符串生成相同的值吗?)。然而,它确实发生在我的应用程序中。 以下代码将生成相同的hashcode:-347019262(jave 1.7.25) 在这种情况下,我确实需要hashcode,我希望使用它为字符串生成唯一的主键。看来我做得不对。有什么建议吗? 多谢!
如何生成版本1(基于时间的)UUID?是否有一个单独的库,或者它是如何在Java7 API中提供的,我错过了它。