如何生成的AAC ADTS基本流与Android媒体codeC [英] How to generate the AAC ADTS elementary stream with Android MediaCodec

查看:1253
本文介绍了如何生成的AAC ADTS基本流与Android媒体codeC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要做的:使用Android的媒体codeC为en code原始的PCM音频采样成原始的AAC文件

What I am trying to do: use Android's MediaCodec to encode raw PCM audio samples into a raw AAC file.

我的问题:当我使用FFMPEG收拾产生的原始AAC文件到M4A容器,FFMPEG抱怨在文件中缺少codeC参数

The problem I have: when I use FFMPEG to pack the generated raw AAC file into an M4A container, FFMPEG complains about missing codec parameters in the file.

详细信息:

因为我无法找到任何媒体$ C $毫升样品code的音频连接codeR产生一个输出AAC文件,我试图修改视频连接codeR成音频连接codeR。原来的code是在这里:<一href="https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/En$c$cDe$c$cTest.java">source_$c$c

Since I can't find any MediaCodec sample code for the audio encoder that generates an output AAC file, I tried to modify the video encoder into an audio encoder. The original code is here: source_code

我配置了音频连接codeR这样的:

I configured the audio encoder like this:

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

然后我喂EN codeR具有10ms的价值每帧的PCM样本。带连接codeR需要每一帧,生成比特流的帧,而我写的比特流成一个FileOutputStream中。该循环继续,直到输入文件的末尾。

Then I feed the encoder with 10ms worth of PCM samples per frame. The encoder takes each frame, generates a frame of bitstream, and I write the bitstream into an FileOutputStream. The loop continues until the end of the input file.

在code运行到终点。我做'亚行拉到从设备生成的AAC文件,我的电脑,并使用FFMPEG阅读。下面是命令和错误FFMPEG吐出来的:

The code runs to the finish. I do 'adb pull' to get the generated AAC file from the device to my PC, and use FFMPEG to read it. Below is the command and the error FFMPEG spits out:

$ 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之前配置的EN codeR()。为什么生成的AAC文件中缺少codeC参数?
  2. 在原始视频codeC的例子,参数CSD-0从EN codeR传递给脱codeR,但不写入比特流文件中明确。我需要他们明确地写入到AAC文件?
  3. 我将输入PCM样本到10ms的每帧,这并不一定产生完整的输出分组。对于每一个输入框,我就写什么的EN codeR输出到文件中。那是一个令人关注的原因是什么?

任何帮助会深深AP preciated。这将会是巨大的,如果有一个示例项目,做什么,我想在这里做。如果我的源$ C ​​$ C可以帮助你帮我,我会后它。我需要做一些清理工作。谢谢!

Any helps will be deeply appreciated. It'd be great if there is a sample project that does what I'm trying to do here. If my source code can help you help me, I'll post it. I need to do some cleanup. Thanks!

修改:从如何生成AAC ADTS基本流与Android媒体$ C $由媒体codeC生成缺少codeC参数基本AAC文件中更改标题CC

Edit: Changed the title from "Elementary AAC file generated by MediaCodec missing codec parameters" to "How to generate the AAC ADTS elementary stream with Android MediaCodec"

推荐答案

我最后生成的AAC文件,这些文件可播放Android设备和Windows主机上都。我张贴我的解决方案在这里,希望它可以帮助别人。

I finally generated AAC files that are playable on both the Android device and the Windows host computer. I am posting my solution here, hoping it could help others.

首先,我的previous假设Android的媒体codeC连接codeR产生的基本AAC流是不准确的。媒体codeC连接codeR产生的原始AAC流。这就是为什么文件无法播放。需要原始的AAC流被转换成一个可播放的格式,如 ADTS 的流。我已经改变了这个帖子的标题,以反映我的新的认识。有<一个href="http://stackoverflow.com/questions/14934305/pcm-to-aac-conversion-using-media$c$cc?rq=1">another帖子说问过类似的问题,并有一个很好的答案。然而,新手未必了解简要说明那里。我并没有完全得到它的第一时间我看了那个帖子。

First, my previous assumption that the Android MediaCodec encoder generates the elementary AAC stream was not accurate. The MediaCodec encoder generates the raw AAC stream. That's why the files could not be played. The raw AAC stream needs to be converted into a playable format, such as the ADTS stream. I have changed the title of this post to reflect my new understanding. There was another post that asked a similar question, and had an excellent answer. However, a novice may not necessarily understand the brief descriptions there. I didn't quite get it the 1st time I read that post.

因此​​,为了产生能由媒体播放器播放一个AAC比特流中,我从由法登在他的第一评论给出的恩coderTest例如启动,但修改了原始code键添加每输出帧(接入单元)ADTS头标,并(通过267的初始code具有以下code段更换线路248)写的结果流进一个文件:

So, in order to generate an AAC bitstream that can be played by a media player, I started from the EncoderTest example given by fadden in his 1st comment, but modified the original code to add the ADTS header per output frame (access unit), and to write the resulting stream into a file (replaced lines 248 through 267 of the original code with the following code snippet):

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是这样的:

Outside the loop, I defined the function addADTStoPacket like this:

/**
 *  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;
}

我还添加了code控制如何停止产生AAC ADTS流,但这是特定的应用程序,所以我不会在这里详细。所有这些变化,生成的AAC文件可以播放在Android设备上,我的Windows电脑上,并ffmpeg的是满意。

I also added code to control how to stop generating the AAC ADTS stream, but that's application specific, so I won't detail here. With all these changes, the generated AAC files can be played on the Android device, on my Windows PC, and ffmpeg is happy with them.

这篇关于如何生成的AAC ADTS基本流与Android媒体codeC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆