android 播放视频文件格式,Android视频文件格式解析相关分析

目录结构

OpenCore的代码在如下目录中:external/opencore/。这个目录是OpenCore的根目录,其中包含的子目录以下所示:

* android:这里面是一个上层的库,它基于PVPlayer和PVAuthor的SDK实现了一个为Android使用的Player和Author。

* baselibs:包含数据结构和线程安全等内容的底层库

* codecs_v2:这是一个内容较多的库,主要包含编解码的实现,以及一个OpenMAX的实现

* engines:包含PVPlayer和PVAuthor引擎的实现

* extern_libs_v2:包含了khronos的OpenMAX的头文件

* fileformats:文件格式的据具体解析(parser)类

* nodes:编解码和文件解析的各个node类。

* oscl:操做系统兼容库

* pvmi: 输入输出控制的抽象接口

* protocols:主要是与网络相关的RTSP、RTP、HTTP等协议的相关内容

* pvcommon:pvcommon库文件的Android.mk文件,没有源文件。

* pvplayer:pvplayer库文件的Android.mk文件,没有源文件。

* pvauthor:pvauthor库文件的Android.mk文件,没有源文件。

* tools_v2:编译工具以及一些可注册的模块。

Splitter的定义与初始化

以wav的splitter为例,在fileformats目录下有解析wav文件格式的pvwavfileparser.cpp文件,在nodes目录 下有pvmf_wavffparser_factory.cpp,pvmf_wavffparser_node.h, pvmf_wavffparser_port.h等文件。

咱们由底往上看,vwavfileparser.cpp中的PV_Wav_Parser类有InitWavParser(),GetPCMData(),RetrieveFileInfo()等解析wav格式的成员函数,此类应该就是最终的解析类。咱们搜索PV_Wav_Parser类被用到的地方可知,在PVMFWAVFFParserNode类中有PV_Wav_Parser的一个指针成员变量。再搜索可知,PVMFWAVFFParserNode类是经过PVMFWAVFFParserNodeFactory的CreatePVMFWAVFFParserNode()成员函数生成的。而CreatePVMFWAVFFParserNode()函数是在PVPlayerNodeRegistry::PVPlayerNodeRegistry()类构造函数中经过PVPlayerNodeInfo类被注册到Oscl_Vector 的vector中,在这个构造函数中,AMR,mp3等node也是一样被注册的。

由上可知,Opencore中对splitter的管理也是与ffmpeg等相似,都是在框架的初始化时注册的,只不过Opencore注册的是每一个splitter的factory函数。

综述一下splitter的定义与初始化过程:

每一个splitter都在fileformats目录下有个对应的子目录,其下有各自的解析类。

每一个splitter都在nodes目录下有关对应的子目录,其下有各自的统一接口的node类和node factory类。

播放引擎PVPlayerEngine类中有PVPlayerNodeRegistry iPlayerNodeRegistry成员变量。

在PVPlayerNodeRegistry的构造函数中,将 AMR, AAC, MP3等splitter的输入与输出类型标示和node factory类中的create node与release delete接口经过PVPlayerNodeInfo类push到Oscl_Vector iType成员变量中。

当前Splitter的匹配过程

PVMFStatus PVPlayerNodeRegistry::QueryRegistry(PVMFFormatType& aInputType, PVMFFormatType& aOutputType, Oscl_Vector& aUuids)函数的功能是根据输入类型和输出类型,在已注册的node vector中寻找是否有匹配的node,有的话传回其惟一识别标识PVUuid。

从QueryRegistry这个函数至底向上搜索可获得,在android中splitter的匹配过程以下:

android_media_MediaPlayer.cpp之中定义了一个JNINativeMethod(JAVA本地调用方法)类型的数组gMethods,供java代码中调用MultiPlayer类的setDataSource成员函数时找到对应的c++函数

{"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},

static void android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)

此函数中先获得当前的MediaPlayer实例,而后调用其setDataSource函数,传入路径

status_t MediaPlayer::setDataSource(const char *url)

此函数经过调getMediaPlayerService()先获得当前的MediaPlayerService, const sp& service(getMediaPlayerService());

而后新建一个IMediaPlayer变量, sp player(service->create(getpid(), this, fd, offset, length));

在sp MediaPlayerService::create(pid_t pid, const sp& client, const char* url)中

调status_t MediaPlayerService::Client::setDataSource(const char *url)函数,Client是MediaPlayerService的一个内部类。

在MediaPlayerService::Client::setDataSource中,调sp MediaPlayerService::Client::createPlayer(player_type playerType)

生成一个继承自MediaPlayerBase的PVPlayer实例,

PVPlayer的继承关系以下:

PVPlayer-->MediaPlayerInterface-->MediaPlayerBase

最后调PVPlayer的setDataSource()函数

status_t PVPlayer::setDataSource(const char *url)

status_t PVPlayer::prepare()

此函数开头执行ret = mPlayerDriver->enqueueCommand(new PlayerSetDataSource(mDataSourcePath,0,0));

将PlayerSetDataSource 的command类加入到PlayerDriver的command处理队列中,

在void PlayerDriver::Run()函数中处理此command,调用下面的handleSetDataSource函数。

void PlayerDriver::handleSetDataSource(PlayerSetDataSource* ec)

PVCommandId PVPlayerEngine::AddDataSource(PVPlayerDataSource& aDataSource, const OsclAny* aContextData)

This function allows a player data source to be specified for playback. This function must be called

PVMFStatus PVPlayerEngine::DoAddDataSource(PVPlayerEngineCommand& aCmd)

PVMFStatus PVPlayerEngine::DoSetupSourceNode(PVCommandId aCmdId, OsclAny* aCmdContext) java

以上,是前辈摸索出的一条线索,可是不全面,至少对我如今的工做来讲如此.node

其以WAV格式为突破口,止步于CreatePVMFWAVFFParserNode().最后这段代码位置是在 external/opencore/engines/player/config/linux_nj/pv_player_node_registry.cpp中.linux

咱们已经知道3gp格式是支持的,可是android代码中并无明确的有关3gp的文件解析node或者代码,在PVPlayer的方法中enqueueCommand(),再在playerdriver的Run()中,dequeueCommand()而且根据command->code(),作相应的操做.android

其中就有handleSetDataSource(),这个方法看上去与文件格式解析相关.c++

handleSetDataSource()中会调用pv_player_engine.cpp中的AddDataSource()方法,发出一个Command:“PVP_ENGINE_COMMAND_ADD_DATA_SOURCE”到队列中,数组

接着在Run()中的switch(...)语句中,执行DoAddDataSource(),在这里安全

if(iSourceFormat=SOURCEFORMAT_UNKNOWN)网络

{数据结构

retval = DoQuerySourceFormat(...);

}

else

{

...

}

在DoQuerySourceFormat()中,参数iPlayerRecognizerRegistry闪亮登场,其类型为PVPlayerRecognizerRegistry,经过

iPlayerRecognizerRegistry.QueryFormatType(iDataSource->GetDataSourceURL(), *this, (OsclAny*) context));

在QueryFormatType()中,会使用传入的文件路径建立一个PVMIDataStreamSyncInterfaceRefFactory对象,并强制转换成PVMFDataStreamFactory*.再使用PVMFRecognizerRegistry::Recognize(iRecSessionId, *iFileDataStreamFactory, NULL, iRecognizerResult, NULL);它会继续向下调用PVMFRecognizerRegistryImpl::Recognize(...),将参数保存,再生成一个CMD:PVMFRECREG_COMMAND_RECOGNIZE,再在PVMFRecognizerRegistryImpl::Run()中,经过switch(...)执行doRecognize().

能够理解为全部解析的node都保存在iRecognizerPluginFactoryList中,再在doRecognaize()中遍历,以得到合适的node(I am not sure!XD)

如下能够忽略

/*******************************************************************************************

初始化位置是在PVPlayerEngine::PopulateRecognizerRegistry(...)中,这个函数是被PopulateAllRegistries(...)调用,而PopulateAllRegistries(...)在PlayerEngine的Construct()中调用,而且其在调用PopulateRecognizerRegistry(...)以前,还会调用一个PopulateNodeRegistry(...),暂且把PopulateAllRegistries(...)放下不谈,回到PopulateRecognizerRegistry(...)中,首先经过读取config文件(/system/etc/pvplayer.conf),将其中与PV_RECOGNIZER_INTERFACE相同Uuid的动态库加载进来...(这里为何会指定一个Uuid呢?这个Uuid在config文件中对应的正是 libopencoremp4reg.so,也就是说,格式为UNKNOWN的,都用这个库来识别?...继续看). 这个库自己就是opencore的一个node,生成它的Android.mk位于"external/opencore/tools_v2/build/modules/linux_mp4/node_registry",能够看出,他其实就是nodes/pvmp4ffparsernode,到此,文件解析的动态库也已加载.明天来继续往下看,今天再温习一下流程,思索下...

*********************************************************************************************/

好吧,其实android 1.5不支持.MP4的现象是由于个人.mp4文件的声音部分是用的aac编码,而android自己只支持wav的音频编码...so,虽然可以识别出是video/mp4,可是却会致使播放器die(由于个人播放器没作纠错)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值