文章目录
前言
通过 文2,我们知道 MediaRecorder 相关接口是在 StagefrightRecorder.cpp 中实现,本文进一步分析音频采集、编码、写入文件详细流程。
音频采集
音频初始化
通过前文,我们知道 setupAudioEncoder 在 setupMPEG4orWEBMRecording 中初始化,相关源码如下
// frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
status_t StagefrightRecorder::setupAudioEncoder() {
sp<MediaCodecSource> audioEncoder = createAudioSource();
return OK;
}
sp<MediaCodecSource> StagefrightRecorder::createAudioSource() {
...
// 通过 AVFactory 工厂创建 AudioSource,并初始化
sp<AudioSource> audioSource = AVFactory::get()->createAudioSource(
&attr,
mAttributionSource,
sourceSampleRate,
mAudioChannels,
mSampleRate,
mSelectedDeviceId,
mSelectedMicDirection,
mSelectedMicFieldDimension);
}
那 AudioSource 是如何初始化的呢
// frameworks/av/media/libstagefright/AudioSource.cpp
void AudioSource::set(const audio_attributes_t *attr, const AttributionSourceState& attributionSource,
uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
audio_port_handle_t selectedDeviceId,
audio_microphone_direction_t selectedMicDirection,
float selectedMicFieldDimension)
{
...
// 构造了 一个 AudioRecord cpp 对象
mRecord = new AudioRecord(
AUDIO_SOURCE_DEFAULT, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
audio_channel_in_mask_from_count(channelCount),
attributionSource,
(size_t) (bufCount * frameCount),
// 采集的音频数据回调
wp<AudioRecord::IAudioRecordCallback>{
this},
frameCount /*notificationFrames*/,
AUDIO_SESSION_ALLOCATE,
AudioRecord::TRANSFER_DEFAULT,
AUDIO_INPUT_FLAG_NONE,
attr,
selectedDeviceId,
selectedMicDirection,
selectedMicFieldDimension);
...
}
AudioRecord.java 底层的实现也是 AudioSource.cpp
AudioRecord 主要是负责从麦克风设备采集音频 PCM 帧
AudioRecord 分析
// frameworks/av/media/libaudioclient/AudioRecord.cpp
status_t AudioRecord::set(...) {
...
if (mCallback != nullptr) {
// 启动录制的线程
mAudioRecordThread = new AudioRecordThread(*this);
mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
}
...
}
bool AudioRecord::AudioRecordThread::threadLoop() {
...
nsecs_t ns = mReceiver.processAudioBuffer();
...
}
nsecs_t AudioRecord::processAudioBuffer() {
...
// 回调 AudioRecord::IAudioRecordCallback
if (newOverrun) {
callback->onOverrun();
}
if (markerReached) {
callback->onMarker(markerPosition.value());
}
while (newPosCount > 0) {
callback->onNewPos(newPosition.value());
newPosition += updatePeriod;
newPosCount--;
}
if (mObservedSequence != sequence) {
mObservedSequence = sequence;
callback->onNewIAudioRecord();
}
while (mRemainingFrames > 0) {
// 获取 audioBuffer
status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
// 回调 取到的 buffer 到 AudioSource 中 onMoreData
const size_t readSize = callback->onMoreData(*buffer);
// 释放 buffer
releaseBuffer(&audioBuffer);
}
}
AudioSource 采集到音频
// frameworks/av/media/libstagefright/AudioSource.cpp
size_t AudioSource::onMoreData(const AudioRecord::Buffer& audioBuffer) {
...
// 将AudioRecord::Buffer 放入 MediaBuffer
MediaBuffer *buffer = new MediaBuffer(audioBuffer.size());
memcpy((uint8_t *) buffer->data(),
audioBuffer.data(), audioBuffer.size());
buffer->set_range(0, audioBuffer.size());
// 将 buffer 放入缓存
queueInputBuffer_l(buffer, timeUs);
return audioBuffer.size();
}
void AudioSource::queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs) {
...
// 将 buffer 放入缓存 mBuffersReceived 中
mBuffersReceived.push_back(buffer);
mFrameAvailableCondition.signal();
}
// 如下接口可以读取采集到的 buffer
status_t

本文深入分析了MediaRecorder音频采集、编码、写入文件的详细流程。介绍了音频初始化、AudioRecord分析及AudioSource采集音频的过程,阐述了音频编码及编码后数据的处理方式,还说明了MPEG4Writer写入音频编码后数据到文件和取编码后音频数据的流程。
最低0.47元/天 解锁文章
3675

被折叠的 条评论
为什么被折叠?



