如何生成 AAC ADTS 基本流与 Android MediaCodec

标签:  Android 发布时间: 2013/12/10 20:29:50 本文来自:  http://stackoverflow.com/questions/18862715/how-to-generate-the-aac-adts-elementary-stream-with-android-mediacodec 注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

想做什么:使用 Android 的 MediaCodec 将编码到原始的 AAC 文件的原始 PCM 音频采样。

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

详细信息:

由于生成的输出 AAC 文件的音频编码器为找不到任何 MediaCodec 的示例代码,我试着修改到音频编码器的视频编码器。这里的原始代码是: source_code

我配置的音频编码器,像这样:

    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);

然后我喂编码器与价值的 PCM 样品每帧 10ms年。编码器需要每个帧,将生成的位流,一个框架和 FileOutputStream 位流写入。循环继续直到输入文件的末尾。

代码运行到终点。我做 '亚行拉' 生成的 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

我的问题:

  1. 我已经在调用 codec.start() 之前配置编码器。所生成的 AAC 文件为什么缺少的编解码器参数?
  2. 在原始的视频编解码器示例中,参数"惩教署-0"从编码器传递到解码器,但不是会写到码流文件中明确。我需要显式地将它们写入到 AAC 文件吗?
  3. 我把输入的 PCM 样本分为每个框架,不一定会产生一个完整的输出数据包 10ms年。为每个输入的帧,我只是写不管编码器输出到文件中。那是令人担忧吗?

任何可以帮助将深为感激。如果有一个示例项目,不会想在这里做什么,那就再好不过。如果我的源代码可以帮你帮助我,我就把它寄。我需要做一些清理。谢谢 !

编辑: 从"初级 AAC 文件由 MediaCodec 缺少的编解码器的参数生成"更改标题为"如何生成 AAC ADTS 基本流与 Android MediaCodec"

解决方法 1:

我最后生成的 android 系统的设备和 Windows 主机计算机上可播放的 AAC 文件。我张贴我的解决方案在这里,希望它能帮助其他人。

首先,Android MediaCodec 编码器生成基本的 AAC 流我先前假设不是准确的。MediaCodec 编码器生成的原始的 AAC 流。这就是为什么无法播放文件。原始的 AAC 流需要转换成一个可播放格式,例如ADTS流。我已更改以反映我的新认识这篇文章的标题。有另一篇文章,问了一个类似的问题,并有一个优秀的答案。然而,一个新手未必了解那里的简要说明。我相当没我阅读这篇文章的第一次。

所以,为了生成 AAC 码流可以发挥的一个媒体播放器,我开始给出的 EncoderTest 示例由法登在他第一次的意见,但修改的原代码添加 ADTS 头每输出帧 (访问单位),并将结果流写入到一个文件中 (更换线路通过 267 248 的原代码与下面的代码段):

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 是和他们一起快乐。

更多相关文章

  1. [Android Studio] 使用本地 aar 文件
  2. Android Studio 实时显示布局文件Preview窗口
  3. Android 学习 之 资源文件 动态修改strings.xml中的字符资源
  4. Android手势操作示例(上/下/左/右的判断)
  5. android FTP上传下载文件
  6. Android ApiDemos示例解析(18):App->Activity->Wallpaper
  7. Android Studio添加so文件并打包到APK的lib文件夹中
  8. android studio打包 so文件

随机推荐

  1. Android(安卓)Fragment+tabHost应用实战
  2. Android(安卓)使用GSM定位
  3. 如何通过网页打开Android(安卓)APP
  4. Android和J2ME按钮接口之简单对比
  5. Android7.0 系统启动流程---system_serve
  6. 如何使用android sdk开发应用
  7. 如何使Android应用程序获取系统权限来修
  8. android Canvas用法
  9. android传输视频到PC
  10. Android中的网络时间同步