媒体播放引擎
v 在opencore中由PVPlayerEngine负责媒体播放功能的实现;
v 在PVPlayerEngine中负责创建各个节点来完成媒体文件格式解析(SourceNode)、媒体数据编解码(DecodeNode/EncNode)以及媒体数据的输出(MediaOutputNode);
v 由PlayerDriver负责opencore与android媒体框架的适配;
v 由AndroidAudioOutput负责音频数据输出到android-audioflinger服务输出,由AndroidSurfaceOutput来负责将视频数据输出到android-surfaceflinger服务输出;
媒体播放引擎-驱动层
v 驱动层包括:PVPlayer和PlayerDriver组成;
v PVPlayer负责将上层应用的命令转换成PlayerDriver可以内部命令加入到其命令队列中,由PlayerDriver负责执行,并负责将命令执行的结果回送给上层媒体框架以及JAVA程序;
v 在PlayerDriver中有一个消息循环负责处理PVPlayer发送过来的命令,调用PVPlayerEngine相应的接口来完成媒体控制;
v 在创建PlayerDriver对象时会生成opencore主线程,并调用OsclExecScheduler.StartScheduler来开始opencore主线程循环;
v 源码文件:
v android/playerdriver.cpp
v android/playerdriver.h
媒体播放引擎-文件格式识别
v 在opencore中由PVPlayerRecognizerRegistry负责文件格式识别,并将结果返回给PVPlayerEngine;
v PVPlayerEngine根据类型来创建对应的文件解析节点ParseNode;
v opencore中对文件格式的识别时通过读取文件头的方式进行的,而不是根据文件扩展名;
v opencore中通过向系统中注册文件识别插件的方式来提供文件格式识别的功能,系统通过循环调用每个注册插件的Recognize()函数来进行格式识别;
v 在创建媒体播放引擎的时候会通过PVPlayerRegistryPopulator::Populate()函数来注册所有的文件识别插件到系统中
v 源码文件:
v pvmi/recognizer/src/pvmf_recognizer_registry.cpp
v pvmi/recognizer/src/pvmf_recognizer_registry_impl.cpp
v pvmi/recognizer/plugins/目录下所有的子目录中存放着文件识别插件的代码;
媒体播放引擎-文件格式解析节点
v 在opencore中通过文件解析节点(ParseNode)来完成音视频文件格式的解析,并将文件中的音频、视频数据送到对应的解码节点进行解码;
v PVPlayerEngine通过PVMFNodeInterface接口来完成对ParseNode的操作;ParseNode通过提供扩展接口来实现通用Node接口不能实现的功能;
v 常用的扩展接口如:PvmiCapabilityAndConfig;
v opencore中通过注册的方式向系统中注册文件格式解析节点
媒体播放引擎-节点注册
v 1、每个节点都有一个对应的PVMFXXXXFactrory来负责创建;
v 2、系统中通过PVPlayerRegistryPopulator. RegisterAllNodes()来注册所有支持的节点;
v 3、opencore首先调用PVPlayerNodeRegistry-> QueryRegistry()函数查询对于指定的输入&输出格式的Node的UUID,然后通过PVPlayerNodeRegistry-> CreateNode ()创建指定的Node。
v 4、PVPlayerEngine就是通过文件格式识别插件返回的媒体类型来创建对应的文件解析节点的
void PVMFMP4FFParserNode::Run()
{
//Process commands.
if (!iInputCommands.empty())
{
ProcessCommand();
}
while (!iPortActivityQueue.empty() && (iInterfaceState == EPVMFNodeStarted || FlushPending()))
{
ProcessPortActivity();
}
if (iInterfaceState == EPVMFNodeStarted && !FlushPending())
{
HandleTrackState();
}
//Check for completion of a flush command...
if (FlushPending() && iPortActivityQueue.empty())
{
//Flush is complete.
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
}
}
void PVMFMP4FFParserNode::HandleTrackState()
{
for (uint32 i = 0; i < iNodeTrackPortList.size(); ++i)
{
switch (iNodeTrackPortList[i].iState)
{
case PVMP4FFNodeTrackPortInfo::TRACKSTATE_UNINITIALIZED:
……
case PVMP4FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA:
……
if (!RetrieveTrackData(iNodeTrackPortList[i]))
{
……
}
……
case PVMP4FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_SENDDATA:
if (SendTrackData(iNodeTrackPortList[i]))
{
……
}
break;
……
}
}
}
媒体播放引擎-解码节点
v opencore中由DecNode节点负责媒体数据的解码工作;
v DecNode通过调用底层的opencoreMAX通用接口实现媒体数据的解码;
v 对于一个普通的视频文件,存在2个解码节点:音频解码节点和视频解码节点;
bool PVMFOMXBaseDecNode::SendInputBufferToOMXComponent()
{
……
OMX_EmptyThisBuffer(iOMXDecoder, input_buf->pBufHdr);
……
}
PVMFOMXBaseDecNode::SendOutputBufferToOMXComponent()
{
……
OMX_FillThisBuffer(iOMXDecoder, output_buf->pBufHdr);
……
}
OMX_ERRORTYPE PVMFOMXBaseDecNode::EmptyBufferDoneProcessing(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
……
}
OMX_ERRORTYPE PVMFOMXBaseDecNode::FillBufferDoneProcessing(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
……
}
v 源码文件:
v nodes/pvomxbasedecnode/
v nodes/pvomxvideodecnode/
v codecs_v2/omx/
媒体播放引擎-媒体输出节点
v MediaOutputNode负责接收DecNode的解码后数据,并将数据输出到MIO;同时在输出前作视频的同步;
v MIO负责将数据输出到surfaceFlinger和AudioFlinger;
v 视频数据在输出前需要做颜色空间的转换(YUV->RGB)和缩放,这部分的工作也在MIO中完成;
v 节点源码:
v nodes/pvmediaoutputnode/
v MIO源码:
v android/android_surface_output.cpp
v android/android_audio_output.cpp
v android/android_audio_mio.cpp
v http://zhaixishan.cublog.cn
附录:
具体的代码阅读: