【发布时间】:2014-05-01 12:51:03
【问题描述】:
我正在使用 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 ms。当我记录每次调用 read() 的系统时间并从基本时间中减去它们时,我得到以下序列:
每次 read() 之前的时间:0ms, 345ms, 543ms, 692ms, 891ms, 1093ms, 1244ms, ...
我将这些原始数据以上述时间值作为 PTS 提供给音频编码器,编码器输出具有以下 PTS 的编码音频样本:
编码器输出PTS:0ms, 185ms, 371ms, 557ms, 743ms, 928ms, ...
看起来编码器将数据的每个部分视为具有相同的时间段。我相信编码器可以正常工作,因为我每次都给它相同大小(16384)的原始数据。但是,如果我使用编码器输出 PTS 作为 muxer 的输入,我将获得音频内容比视频内容更快的视频。
我想问一下:
- AudioRecord.read() 的第一次阻塞时间是否更长?我确信函数调用需要超过 300 毫秒,而它只记录 16384 字节为 186 毫秒。这也是取决于设备/Android 版本的问题吗?
- 如何实现音视频同步?我有一个解决方法来测量第一次调用 read() 的延迟时间,然后将音频样本的 PTS 移动延迟。还有其他更好的方法来处理这个问题吗?
【问题讨论】:
-
你试过MediaFormat.KEY_CHANNEL_MASK = AudioFormat.CHANNEL_OUT_MONO吗?
-
我已经通过设置 KEY_CHANNEL_MASK = AudioFormat.CHANNEL_OUT_MONO 配置了音频编码器,但它的行为仍然相同。它仍然尝试按预期持续时间“压缩”输出 PTS。
-
@Mark 你找到解决方案了吗?
标签: android audio encoder audiorecord android-mediacodec