如何使用Android AudioRecord和MediaCodec作为音频编码器来正确处理PTS?

3
我正在使用AudioRecord在Android设备上记录相机捕获过程中的音频流。由于我想处理帧数据并处理音视频样本,所以我不使用MediaRecorder。
我在另一个线程中运行AudioRecord,并调用read()来收集原始音频数据。一旦我得到数据流,我将它们提供给配置为AAC音频编码器的MediaCodec。
以下是关于音频录制器/编码器的一些代码:
m_encode_audio_mime = "audio/mp4a-latm";
m_audio_sample_rate = 44100;
m_audio_channels = AudioFormat.CHANNEL_IN_MONO;
m_audio_channel_count = (m_audio_channels == AudioFormat.CHANNEL_IN_MONO ? 1 : 2);

int audio_bit_rate = 64000;
int audio_data_format = AudioFormat.ENCODING_PCM_16BIT;

m_audio_buffer_size = AudioRecord.getMinBufferSize(m_audio_sample_rate, m_audio_channels, audio_data_format) * 2;
m_audio_recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, m_audio_sample_rate,
                                   m_audio_channels, audio_data_format, m_audio_buffer_size);

m_audio_encoder = MediaCodec.createEncoderByType(m_encode_audio_mime);
MediaFormat audio_format = new MediaFormat();
audio_format.setString(MediaFormat.KEY_MIME, m_encode_audio_mime);
audio_format.setInteger(MediaFormat.KEY_BIT_RATE, audio_bit_rate);
audio_format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, m_audio_channel_count);
audio_format.setInteger(MediaFormat.KEY_SAMPLE_RATE, m_audio_sample_rate);
audio_format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
audio_format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, m_audio_buffer_size);
m_audio_encoder.configure(audio_format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

我发现第一次调用AudioRecord.read()方法需要更长的时间才能返回,而随后的read()方法则具有更接近音频实际数据实时性的时间间隔。例如,我的音频格式为44100Hz 16Bit 1Channel,而AudioRecord的缓冲区大小为16384,因此完整的缓冲区表示185.76毫秒。当我记录每个read()调用之前的系统时间并从基准时间中减去它们时,我获得以下序列:
每个read()之前的时间:0毫秒,345毫秒,543毫秒,692毫秒,891毫秒,1093毫秒,1244毫秒,...
我将这些原始数据作为PTS传递给音频编码器,并使用上述时间值作为PTS,编码器输出编码音频样本,并具有以下PTS:
编码器输出PTS:0毫秒,185毫秒,371毫秒,557毫秒,743毫秒,928毫秒,...
看起来编码器将数据的每个部分视为具有相同的时间周期。我相信编码器工作正确,因为我每次都给它相同大小(16384)的原始数据。但是,如果我将编码器输出PTS用作复用器的输入,则会获得一个音频内容比视频内容快的视频。
我想询问以下问题:
1. 第一次调用AudioRecord.read()是否预计会阻止更长时间?我确信函数调用需要超过300毫秒,而只记录了16384字节作为186毫秒。这也是一个依赖于设备/Android版本的问题吗?
2. 我该怎么做才能实现音频/视频同步?我有一种解决方法可以测量第一次read()调用的延迟时间,然后将音频样本的PTS通过这个延迟进行移动。是否有另一种更好的处理方式?

你尝试过使用 MediaFormat.KEY_CHANNEL_MASK = AudioFormat.CHANNEL_OUT_MONO 吗? - Marlon
我已经通过设置KEY_CHANNEL_MASK = AudioFormat.CHANNEL_OUT_MONO来配置音频编码器,但它的行为仍然是相同的。它仍然试图通过预期持续时间来“压缩”输出PTS。 - Mark
@Mark,你找到解决方案了吗? - Vadim Eksler
1个回答

0

将单声道输入转换为立体声。在我意识到MediaCoder提供的AAC编码器仅适用于立体声输入之前,我已经抓狂了一段时间。


2
你能提供一些代码吗?我觉得我遇到了同样的问题,但不知道该如何解决它 :( - chris6523

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接