承接上一章节分析:【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】【03】
本系列文章分析的安卓源码版本:【Android 10.0 版本】
推荐涉及到的知识点:
Binder机制实现原理:Android C++底层Binder通信机制原理分析总结【通俗易懂】
ALooper机制实现原理:Android native层媒体通信架构AHandler/ALooper机制实现源码分析
Binder异常关闭监听:Android native层DeathRecipient对关联进程(如相关Service服务进程)异常关闭通知事件的监听实现源码分析
【此章节小节编号将重新排序】
onOMXEvent()接收处理执行:
前面小节已分析过该方法可以是BaseState父类状态的具体子类状态实现者进行重写,处理自身业务。但也会有默认父类该方法处理。而对于该方法的所有涉及到的该方法实现的状态实现,如下截图中
从上面的实现可知,有这么多个状态实现了该方法,而目前我们只会按照程序执行流程来分析,因此将会分析mLoadedToIdleState状态实现者的【onOMXEvent】方法实现流程,如下
备注:其它流程实现将会在后续有涉及时分析。并且注意,分析该方法时我将会默认为读者已看过8.3小节的分析了。
// [frameworks/av/media/libstagefright/ACodec.cpp]
bool ACodec::LoadedToIdleState::onOMXEvent(
OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
switch (event) {
// 此处就是接收底层组件对于【OMX_StateIdle】该状态命令处理完成事件的处理
case OMX_EventCmdComplete:
{
status_t err = OK;
// 从此处检查状态值有效性也可看出,若不是这两个事件类型参数,即表明底层组件处理发生错误
if (data1 != (OMX_U32)OMX_CommandStateSet
|| data2 != (OMX_U32)OMX_StateIdle) {
ALOGE("Unexpected command completion in LoadedToIdleState: %s(%u) %s(%u)",
asString((OMX_COMMANDTYPE)data1), data1,
asString((OMX_STATETYPE)data2), data2);
// 底层组件状态扭转处理失败
err = FAILED_TRANSACTION;
}
if (err == OK) {
// 成功时,则将会再次发送另一个【OMX_StateExecuting】编解码器执行命令状态事件扭转处理
// 非常需要注意该状态扭转请求事件将会影响下面【changeState】状态机扭转之后的执行流程。
// 该事件如前面流程分析可知,将是底层组件异步回调通知最终执行ACodec的当前状态的【onOMXEvent】方法实现
err = mCodec->mOMXNode->sendCommand(
OMX_CommandStateSet, OMX_StateExecuting);
}
if (err != OK) {
// 底层组件失败则通知MediaCodec的callback回调监听类接收该错误
// 该方法见此前已有分析
mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
} else {
// 成功时,将当前状态机状态扭转到【IdleToExecutingState】状态实现者
// 见下面的分析
mCodec->changeState(mCodec->mIdleToExecutingState);
}
return true;
}
default:
return BaseState::onOMXEvent(event, data1, data2);
}
}
mCodec->changeState(mCodec->mIdleToExecutingState)实现分析:
将当前状态机状态扭转到【IdleToExecutingState】状态实现者
由前面状态分析可知,它将会执行该状态实现者的状态进入方法,如下
// [frameworks/av/media/libstagefright/ACodec.cpp]
void ACodec::IdleToExecutingState::stateEntered() {
ALOGV("[%s] Now Idle->Executing", mCodec->mComponentName.c_str());
}
其实可以看到它啥事没做,只是将当前状态机扭转到该状态实现者而已。
但需要注意,上面发送了【OMX_StateExecuting】编解码器执行命令状态事件扭转处理事件,该事件如前面流程分析可知,将是底层组件异步回调通知最终执行ACodec的当前状态【IdleToExecutingState】实现类的【onOMXEvent】方法实现,如下
// [frameworks/av/media/libstagefright/ACodec.cpp]
bool ACodec::IdleToExecutingState::onOMXEvent(
OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
switch (event) {
case OMX_EventCmdComplete:
{
// 检查必须是请求扭转到【OMX_StateExecuting】正在执行状态的回调
if (data1 != (OMX_U32)OMX_CommandStateSet
|| data2 != (OMX_U32)OMX_StateExecuting) {
ALOGE("Unexpected command completion in IdleToExecutingState: %s(%u) %s(%u)",
asString((OMX_COMMANDTYPE)data1), data1,
asString((OMX_STATETYPE)data2), data2);
mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
return true;
}
// 正在执行状态实现者执行启动(恢复)工作即编解码器真正开始工作了
// 见第1小节分析
mCodec->mExecutingState->resume();
// 切换到该正在执行编解码工作实现者状态
// 见第2小节分析
mCodec->changeState(mCodec->mExecutingState);
return true;
}
default:
return BaseState::onOMXEvent(event, data1, data2);
}
}
1、mCodec->mExecutingState->resume()实现分析:
正在执行状态实现者执行启动(恢复)工作即编解码器真正开始工作了
一句话总结它的工作任务就是:
递交输出缓冲区Buffer给编解码器(去填充已解码或已编码音视频数据),递交输入Buffer给客户端去填充(待解码或待编码的原始音频或视频)数据。
另外接下来的章节分析中,请记住关于Buffer ID和Buffer Index的概念和区别,ID就是为每个Buffer自动生成的唯一的ID,逐渐递增值。 Buffer Index其实就是Buffer在队列中的索引,即列表item索引。因此ID 和 Index是有区别的。
// [frameworks/av/media/libstagefright/ACodec.cpp]
void ACodec::ExecutingState::resume() {
// mActive标志位表示:如果输入和输出缓冲