如何使用Android MediaCodec生成AAC ADTS基本stream

我想要做的是:使用Android的MediaCodec将原始PCMaudio样本编码为原始AAC文件。

遇到的问题是:当我使用FFMPEG将生成的原始AAC文件打包到M4A容器中时,FFMPEG抱怨文件中缺less编解码参数。

细节:

由于我找不到生成输出AAC文件的audio编码器的任何MediaCodec示例代码,我试图将video编码器修改为audio编码器。 原代码在这里: source_code

我configuration了这样的audio编码器:

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采样的编码器。 编码器需要每帧,生成一个比特stream帧,然后将比特stream写入FileOutputStream。 循环一直继续到input文件的结尾。

代码运行结束。 我做'adb pull'把从设备生成的AAC文件传到我的电脑,然后用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 

我的问题:

  1. 我在调用codec.start()之前configuration了编码器。 为什么生成的AAC文件缺less编解码器参数?
  2. 在原始video编解码器示例中,参数“csd-0”从编码器传递到解码器,但不会显式写入比特stream文件。 我需要将它们明确写入AAC文件吗?
  3. 我把input的PCM采样分成每帧10ms,不一定产生完整的输出数据包。 对于每个input帧,我只是将任何编码器输出写入文件。 这是一个令人担忧的原因吗?

任何帮助将深受赞赏。 如果有一个示例项目能够完成我在这里要做的事情,那将会很棒。 如果我的源代码可以帮助你,我会发布它。 我需要做一些清理。 谢谢!

编辑 :将标题从“由MediaCodec缺less编解码器参数生成的基本AAC文件”更改为“如何使用Android MediaCodec生成AAC ADTS基本stream”

Solutions Collecting From Web of "如何使用Android MediaCodec生成AAC ADTS基本stream"

我终于生成了可在Android设备和Windows主机上播放的AAC文件。 我在这里张贴我的解决scheme,希望能帮助别人。

首先,我之前假设Android MediaCodec编码器生成基本AACstream是不准确的。 MediaCodec编码器生成原始AACstream。 这就是文件无法播放的原因。 原始的AACstream需要被转换成可播放的格式,例如ADTSstream。 我已经改变了这篇文章的标题,以反映我的新理解。 还有一个post提出了类似的问题,并有一个很好的答案。 但是,新手可能不一定了解那里的简要说明。 我第一次读这篇文章的时候并不是很了解。

因此,为了生成媒体播放器可以播放的AAC比特stream,我从Fadden在他的第一条评论中给出的EncoderTest示例开始,但是修改了原始代码以在每个输出帧(访问单元)上添加ADTS报头,并将结果stream写入一个文件(用下面的代码片段replace原始代码的第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 ADTSstream,但这是应用程序特定的,所以我不会在这里详细介绍。 随着所有这些变化,生成的AAC文件可以在Android设备上,在我的Windows PC上播放,ffmpeg很满意。