Android12 MultiMedia框架之NuPlayerDriver

目录:Android12 MultiMedia框架

NuPlayerDriver的创建也是在setDataSource()中发生的,那么我们继续前文分析,这次我们换个本地播放的setDataSource()方法来看看,稍微简单点:

//frameworks/av/media/libmedia/mediaplayer.cpp  
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)  
{  
    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);  
  
    status_t err = UNKNOWN_ERROR;  
    const sp<IMediaPlayerService> service(getMediaPlayerService());  
    if (service != 0) {  
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mAttributionSource));  
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||  
            (NO_ERROR != player->setDataSource(fd, offset, length))) {  
            player.clear();  
        }  
        err = attachNewPlayer(player);  
    }  
  
    return err;  
}  

create()前文已经看过了,接着看今天的正题:

//frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp  
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)  
{  
    ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",  
            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);  
    struct stat sb;  
    int ret = fstat(fd, &sb);  
    //省略  
  
    if (offset >= sb.st_size) {  
        ALOGE("offset error");  
        return UNKNOWN_ERROR;  
    }  
    if (offset + length > sb.st_size) {  
        length = sb.st_size - offset;  
        ALOGV("calculated length = %lld", (long long)length);  
    }  
  
    player_type playerType = MediaPlayerFactory::getPlayerType(this,  
                                                               fd,  
                                                               offset,  
                                                               length);  
    sp<MediaPlayerBase> p = setDataSource_pre(playerType);  
    if (p == NULL) {  
        return NO_INIT;  
    }  
  
    // now set data source  
    return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));  
}  

先通过getPlayerType()方法来确定player的类型(其实在当前版本中,只有一种player:NU_PLAYER类型),我们来看看getPlayerType()的原理是啥:

//frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp  
player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,  
                                              int fd,  
                                              int64_t offset,  
                                              int64_t length) {  
    GET_PLAYER_TYPE_IMPL(client, fd, offset, length);  
}  
  
#define GET_PLAYER_TYPE_IMPL(a...)                      \  
    Mutex::Autolock lock_(&sLock);                      \  
                                                        \  
    player_type ret = STAGEFRIGHT_PLAYER;               \  
    float bestScore = 0.0;                              \  
                                                        \  
    for (size_t i = 0; i < sFactoryMap.size(); ++i) {   \  
                                                        \  
        IFactory* v = sFactoryMap.valueAt(i);           \  
        float thisScore;                                \  
        CHECK(v != NULL);                               \  
        thisScore = v->scoreFactory(a, bestScore);      \  
        if (thisScore > bestScore) {                    \  
            ret = sFactoryMap.keyAt(i);                 \  
            bestScore = thisScore;                      \  
        }                                               \  
    }                                                   \  
                                                        \  
    if (0.0 == bestScore) {                             \  
        ret = getDefaultPlayerType();                   \  
    }                                                   \  
                                                        \  
    return ret;  

这段代码定义了一个宏 GET_PLAYER_TYPE_IMPL,用于确定最佳播放器类型。这个宏的作用是在多个工厂对象中选择得分最高的播放器类型。设计这个宏的人估计喜欢打球。

在讲MediaPlayerService章节的时候,其实有一个player没讲,即:TEST_PLAYER。sFactoryMap里面存储了两个Factory类型:NuPlayerFactory和TestPlayerFactory,看名字就知道后者是测试用的。而这两个Factory都没有实现本地播放类型的scoreFactory()方法,所以它的返回值就是父类的初始实现的值:0.0。所以最终返回的还是getDefaultPlayerType()类型:NU_PLAYER。话说回来,当前Android12版本只保留了NU_PLAYER类型,根本不需要这一通分析,哈哈。

那么,继续看setDataSource_pre()方法在操办什么大事情:

//frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp  
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) {  
        return p;  
    }  
  
    //监听三个服务的死亡情况:media.extractor服务、OMX服务、Codec2服务  
    //省略  
  
    mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);  
  
    if (!p->hardwareOutput()) {  
        mAudioOutput = new AudioOutput(mAudioSessionId, mAttributionSource,  
                mAudioAttributes, mAudioDeviceUpdatedListener);  
        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);  
    }  
  
    return p;  
}  

这段代码里应题的内容都在createPlayer()内,死亡通知我直接省略了,AudioOutput不是本次的主题也不看了。我们来看看createPlayer()的实现吧:

//frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp  
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)  
{  
    // determine if we have the right player type  
    sp<MediaPlayerBase> p = getPlayer();  
    if ((p != NULL) && (p->playerType() != playerType)) {  
        ALOGV("delete player");  
        p.clear();  
    }  
    if (p == NULL) {  
        p = MediaPlayerFactory::createPlayer(playerType, mListener,  
            VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAttributionSource.pid)));  
    }  
  
    if (p != NULL) {  
        p->setUID(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAttributionSource.uid)));  
    }  
  
    return p;  
}  
  
//frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp  
sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(  
        player_type playerType,  
        const sp<MediaPlayerBase::Listener> &listener,  
        pid_t pid) {  
    sp<MediaPlayerBase> p;  
    IFactory* factory;  
    status_t init_result;  
    Mutex::Autolock lock_(&sLock);  
  
    if (sFactoryMap.indexOfKey(playerType) < 0) {  
        ALOGE("Failed to create player object of type %d, no registered"  
              " factory", playerType);  
        return p;  
    }  
  
    factory = sFactoryMap.valueFor(playerType);  
    CHECK(NULL != factory);  
    p = factory->createPlayer(pid);  
  
    if (p == NULL) {  
        ALOGE("Failed to create player object of type %d, create failed",  
               playerType);  
        return p;  
    }  
  
    init_result = p->initCheck();  
    if (init_result == NO_ERROR) {  
        p->setNotifyCallback(listener);  
    } else {  
        ALOGE("Failed to create player object of type %d, initCheck failed"  
              " (res = %d)", playerType, init_result);  
        p.clear();  
    }  
  
    return p;  
}  

第一次进createPlayer()必然会调用MediaPlayerFactory::createPlayer(),根据player_type从sFactoryMap中取出Factory,这里就进入了NuPlayerFactory的createPlayer()方法:

//frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp
virtual sp<MediaPlayerBase> createPlayer(pid_t pid) {
	ALOGV(" create NuPlayer");
	return new NuPlayerDriver(pid);
}

今天的主角来了,此处直接new了一个NuPlayerDriver:

//frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
NuPlayerDriver::NuPlayerDriver(pid_t pid)
    : mState(STATE_IDLE),
      mIsAsyncPrepare(false),
      mAsyncResult(UNKNOWN_ERROR),
      mSetSurfaceInProgress(false),
      mDurationUs(-1),
      mPositionUs(-1),
      mSeekInProgress(false),
      mPlayingTimeUs(0),
      mRebufferingTimeUs(0),
      mRebufferingEvents(0),
      mRebufferingAtExit(false),
      mLooper(new ALooper),
      mMediaClock(new MediaClock),
      mPlayer(new NuPlayer(pid, mMediaClock)),
      mPlayerFlags(0),
      mMetricsItem(NULL),
      mClientUid(-1),
      mAtEOS(false),
      mLooping(false),
      mAutoLoop(false) {
    ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
    mLooper->setName("NuPlayerDriver Looper");

    mMediaClock->init();

    // set up an analytics record
    mMetricsItem = mediametrics::Item::create(kKeyPlayer);

    mLooper->start(
            false, /* runOnCallingThread */
            true,  /* canCallJava */
            PRIORITY_AUDIO);

    mLooper->registerHandler(mPlayer);

    mPlayer->init(this);
}

看其构造函数还是一目了然的,分别创建了ALooper、MediaClock和Nuplayer并做一些初始化操作。这里就不挨个分析了,我直接把new NuPlayerDriver()生成的内容以图的方法展现出来:

本来想把所有的模块画在一起,但是因为连线的原因不好处理,连接的乱七八糟,怎么调整都不好看,所以干脆就分割成了几个小块,也就是图中的3个小方框。需要注意的是:颜色相同的模块是同一个实例,大家自行在脑海里去把他们连接成一个整体。

值得一提的是:NuPlayerDriver中已经把NuPlayer的消息通知机制(ALooper/AHandler/AMessage,AMessage是随用随创建的)给建立起来了。这个消息通知机制我将在下一章节来分析。

回过头来,创建完NuPlayerDriver以后,调用setNotifyCallback()将Client构造时(参见:Android12 MultiMedia框架之MediaPlayerService::Client)创建的Listener保存到它的父类MediaPlayerBase的mListener成员中。

至此,setDataSource_pre()分析结束。接下来进入setDataSource_post()了,它的第二个参数传入的是NuPlayerDriver的setDataSource()的执行结果,这个函数就是在创建source了,我们后面的章节再看,这里跳过。setDataSource_post()其实就是将创建的NuPlayerDriver保存到mPlayer。

最后,来整体看下执行完MediaPlayer的setDataSource()后,生成的大概的框图是什么样子的:

### 关于ArcGIS License Server无法启动的解决方案 当遇到ArcGIS License Server无法启动的情况,可以从以下几个方面排查并解决问题: #### 1. **检查网络配置** 确保License Server所在的计算机能够被其他客户端正常访问。如果是在局域网环境中部署了ArcGIS Server Local,则需要确认该环境下的网络设置是否允许远程连接AO组件[^1]。 #### 2. **验证服务状态** 检查ArcGIS Server Object Manager (SOM) 的运行情况。通常情况下,在Host SOM机器上需将此服务更改为由本地系统账户登录,并重启相关服务来恢复其正常工作流程[^2]。 #### 3. **审查日志文件** 查看ArcGIS License Manager的日志记录,寻找任何可能指示错误原因的信息。这些日志可以帮助识别具体是什么阻止了许可服务器的成功初始化。 #### 4. **权限问题** 确认用于启动ArcGIS License Server的服务账号具有足够的权限执行所需操作。这包括但不限于读取/写入特定目录的权利以及与其他必要进程通信的能力。 #### 5. **软件版本兼容性** 保证所使用的ArcGIS产品及其依赖项之间存在良好的版本匹配度。不一致可能会导致意外行为完全失败激活license server的功能。 #### 示例代码片段:修改服务登录身份 以下是更改Windows服务登录凭据的一个简单PowerShell脚本例子: ```powershell $serviceName = "ArcGISServerObjectManager" $newUsername = ".\LocalSystemUser" # 替换为实际用户名 $newPassword = ConvertTo-SecureString "" -AsPlainText -Force Set-Service -Name $serviceName -StartupType Automatic New-ServiceCredential -ServiceName $serviceName -Account $newUsername -Password $newPassword Restart-Service -Name $serviceName ``` 上述脚本仅作为示范用途,请依据实际情况调整参数值后再实施。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值