stagefright
本篇主要介绍一个典型的播放调用过程
下面是一个典型的播放序列:
- mediaplayer player=new MediaPlayer();
- player->setdatasource(url,header);
- player->prepare();
- player->start();
MediaPlayer::MediaPlayer() 主要是基本的初始化,比较简单。
2、setDataSource
status_t MediaPlayer::setDataSource(constchar *url, const Keyedvector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
status_t err = BAD_VALUE;
if(url != NULL) {
constsp<IMediaPlayerservice>& service(getMediaPlayerService());
if(service != 0) {
sp<IMediaPlayer> player(service->create(getpid(),this, mAudiOSessionId));
if((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(url, headers))) {
player.clear();
}
err = attachNewPlayer(player);
}
}
returnerr;
}
先看下 service->create(getpid(), this, mAudiosessionId)操作,代码在mediaplayerservice.cpp中 setDataSource的操作就转成通过与mediaplayerservice的交互来完成了。
sp<IMediaPlayer> MediaPlayerService::create(pid_t pid,const sp<IMediaPlayerClient>& client,
intaudioSessionId)
{
int32_t connId = Android_atomic_inc(&mNextConnId);
sp<Client> c =new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getcallingUid());
ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid());
wp<Client> w = c;
{
mutex::Autolock lock(mLock);
mClients.add(w);
}
returnc;
}
而且,Client类的继承关系为:Client->BnMediaPlayer->IMediaPlayer分析上面代码,可以看出create方法,是构造了一个Client对象,并且将此client对象添加到mediapalyerservice类的全局列表中:mClient
因此在setDataSource中的
1 |
|
语句相当于
1 |
|
即player最终是用Client对象来初始化,可以直接认为player==client,创建Player,真正实现是MediaPlayerService创建的client。
[说明]c++功力较差,此处可能不严谨
紧接着执行player->setDataSource(url, headers),即Clients::setDataSource
status_t MediaPlayerService::Client::setDataSource(intfd, int64_t offset, int64_t length){
ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
struct stat sb;
intret = fstat(fd, &sb);
if(ret != 0) {
ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
returnUNKNOWN_ERROR;
}
ALOGV("st_dev = %llu", sb.st_dev);
ALOGV("st_mode = %u", sb.st_mode);
ALOGV("st_uid = %lu", sb.st_uid);
ALOGV("st_gid = %lu", sb.st_gid);
ALOGV("st_size = %llu", sb.st_size);
if(offset >= sb.st_size) {
ALOGE("offset error");
::close(fd);
returnUNKNOWN_ERROR;
}
if(offset + length > sb.st_size) {
length = sb.st_size - offset;
ALOGV("calculated length = %lld", length);
}
player_type playerType = MediaPlayerFactory::getPlayerType(this,
fd,
offset,
length);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if(p == NULL) {
returnNO_INIT;
}
// now set data source
setDataSource_post(p, p->setDataSource(fd, offset, length));
returnmStatus;
}
2.1 getPlayerType代码比较清晰,首选是选择播放器类型,之后调用setDataSource_pre以及setDataSource_post下面分别来看。
这里有几种类型的播放器,会在mediaplayerservice服务类 的构造函数中来注册,代码如下代码中可以看出,一般情况下,STAGEFRIGHT_PLAYER为默认播放器。
MediaPlayerService::MediaPlayerService()
{
***
MediaPlayerFactory::registerBuiltinFactories();
}
void MediaPlayerFactory::registerBuiltinFactories() {
Mutex::Autolock lock_(&sLock);
if(sInitComplete)
return;
registerFactory_l(newStagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
registerFactory_l(newNuPlayerFactory(), NU_PLAYER);
registerFactory_l(newSonivoxPlayerFactory(), SONIVOX_PLAYER);
registerFactory_l(newTestPlayerFactory(), TEST_PLAYER);
sInitComplete =true;
}
从registerBuiltinFactories的实现可以看出共注册了四个播放器类型。后面会介绍几个播放器的用途等
下面挑选STAGEFRIGHT_PLAYER类型作为例子看下
class StagefrightPlayerFactory :
publicMediaPlayerFactory::IFactory {
public:
virtual float scoreFactory(constsp<IMediaPlayer>& client,
intfd,
int64_t offset,
int64_t length,
float curScore) {
char buf[20];
lseek(fd, offset, SEEK_SET);
read(fd, buf, sizeof(buf));
lseek(fd, offset, SEEK_SET);
long ident = *((long*)buf);
// Ogg vorbis?
if(ident == 0x5367674f)// 'OggS'
return1.0;
return0.0;
}
virtual sp<MediaPlayerBase> createPlayer() {
ALOGV(" create StagefrightPlayer");
returnnew StagefrightPlayer();
}
};
比较简单,就是一些判断条件,这里还提供了createPlayer,返回实际的播放器对象,后面用的着。
2.2 setDataSource_pre
具体代码如下
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(player_type playerType)
{
ALOGV("player type = %d", playerType);
// create the right type of player
sp<MediaPlayerBase> p = createPlayer(playerType);
if(p == NULL) {
returnp;
}
if(!p->hardwareOutput()) {
mAudioOutput =new AudioOutput(mAudioSessionId);
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}
returnp;
}
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
// determine if we have the right player type
sp<MediaPlayerBase> p = mPlayer;
if((p != NULL) && (p->playerType() != playerType)) {
ALOGV("delete player");
p.clear();
}
if(p == NULL) {
p = MediaPlayerFactory::createPlayer(playerType,this, notify);
}
if(p != NULL) {
p->setUID(mUID);
}
returnp;
}
主要是创建播放器
上面看具体StagefrightPlayerFactory 实现的时候,代码中实现了createPlayer,此处就是调用的此方法
因此等价于return (new StagefrightPlayer()) ;
2.3 setDataSource_post
上面的代码的主要目的是找到对应的播放器,下面主要是执行具体的setdatasource操作
这里需要注意的是 实际的工作是在调用的时候完成的
1 |
|
调用的时候,执行了实际播放器的setDataSource方法,而实际的setDataSource_post 仅仅是将播放器保存在本地成员mPlayer中,代码如下
void MediaPlayerService::Client::setDataSource_post(constsp<MediaPlayerBase>& p,
status_t status)
{
ALOGV(" setDataSource");
mStatus = status;
if(mStatus != OK) {
ALOGE(" error: %d", mStatus);
return;
}
// Set the re-transmission endpoint if one was chosen.
if(mRetransmitEndpointvalid) {
mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
if(mStatus != NO_ERROR) {
ALOGE("setRetransmitEndpoint error: %d", mStatus);
}
}
if(mStatus == OK) {
mPlayer = p;
}
}
下面就进入实际播放器stagefritplayer中看具体实现了(此处以stagefrightplayer为例)
通过上面的介绍,熟悉了如何从MediaPlayer(java类)一步一步调用到实际工作的类StageFrigtPlayer
这里只是以setDataSource为例,其他方法如prepare等类似。
下面这张图表示了调用流程
总结下几种播放器的区别
StagefrightPlayer: 默认播放器,本地文件基本都使用其播放
NuPlayerDriver:主要用于播放网络视频,http https rtsp等
SonivoxPlayer:用于播放midi等类型的音乐
下一篇着重分析stagefrigtplayer的主要结构
文章最后发布于: 2015-07-28 16:09:07
相关阅读
项目中需要调用一下第三方地图的API,因为自己一直用的是高德地图,所以优先采用高德地图。事实证明我也没选错,百度地图的API使用起来
关于CoInitialize和CoUninitialize调用的有关问题
本人封装了一个类,里面需要用到ADO连接数据库,所以需要初始化COM环境以及释放COM环境,我打算在构造函数里面执行CoInitialize,在析构
smmUtility::mapIt(LogisticsPostalAddress::findByLocation(logisticsLocation.RecId));
# encoding=utf8 import requests import time def get_verify_code(im, typeid): verify_code = '****' url = 'http://ap
A5创业网(公众号:iadmin5)6月29日报道,日前,有用户称,在vivo NEX手机设备上通过手机QQ浏览器打开某些网页时,手机摄像头会出现“自