前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MediaPlayer(九)--reset()流程

MediaPlayer(九)--reset()流程

作者头像
小蚂蚁与大象
发布2020-04-21 11:40:42
1.7K0
发布2020-04-21 11:40:42
举报

frameworks/base/media/java/android/media/MediaPlayer.java

代码语言:javascript
复制
    /**
     * Resets the MediaPlayer to its uninitialized state. After calling
     * this method, you will have to initialize it again by setting the
     * data source and calling prepare().
     */
    public void reset() {
        mSelectedSubtitleTrackIndex = -1;
        synchronized(mOpenSubtitleSources) {
            for (final InputStream is: mOpenSubtitleSources) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
            mOpenSubtitleSources.clear();
        }
        if (mSubtitleController != null) {
            mSubtitleController.reset();
        }
        if (mTimeProvider != null) {
            mTimeProvider.close();
            mTimeProvider = null;
        }

        stayAwake(false);
        _reset();
        // make sure none of the listeners get called anymore
        if (mEventHandler != null) {
            mEventHandler.removeCallbacksAndMessages(null);
        }

        synchronized (mIndexTrackPairs) {
            mIndexTrackPairs.clear();
            mInbandTrackIndices.clear();
        };

        resetDrmState();
    }

    private native void _reset();

主要步骤

  • 销毁 Subtitle相关处理
  • 销毁 mTimeProvider
  • stayAwake(false),不保持屏幕长开的的状态
  • _reset(),调用到jni层,下面分析
  • 销毁 mEventHandler所有消息,不再向播放器应用发送任何消息

frameworks/base/media/jni/android_media_MediaPlayer.cpp

代码语言:javascript
复制
static void
android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
{
    ALOGV("reset");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }
    process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
}

frameworks/av/media/libmedia/mediaplayer.cpp

代码语言:javascript
复制
status_t MediaPlayer::reset_l()
{
    mLoop = false;
    if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
    mPrepareSync = false;
    if (mPlayer != 0) {
        status_t ret = mPlayer->reset();
        if (ret != NO_ERROR) {
            ALOGE("reset() failed with return code (%d)", ret);
            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
        } else {
            mPlayer->disconnect();
            mCurrentState = MEDIA_PLAYER_IDLE;
        }
        // setDataSource has to be called again to create a
        // new mediaplayer.
        mPlayer = 0;
        mCurrentBufferingSettings = BufferingSettings();
        return ret;
    }
    clear_l();
    return NO_ERROR;
}

主要步骤:

  • 调用MediaPlayerService 的reset方法 这一步主要执行到NuPlayer的reset
  • 调用MediaPlayerService 的disconnect 这一步会销毁MediaPlayerService 保存的服务端mediaplayer binder实例mClient 和NuPlayer的实例
  • 将mPlayer销毁 mPlayer是mediaplayer 同服务端MediaPlayerService

frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

代码语言:javascript
复制
status_t MediaPlayerService::Client::reset()
{
    ALOGV("[%d] reset", mConnId);
    mMaybeVideoAlive = false;
    mRetransmitEndpointValid = false;
    sp<MediaPlayerBase> p = getPlayer();
    if (p == 0) return UNKNOWN_ERROR;
    return p->reset();
}
代码语言:javascript
复制
void MediaPlayerService::Client::disconnect()
{
    ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
    // grab local reference and clear main reference to prevent future
    // access to object
    sp<MediaPlayerBase> p;
    {
        Mutex::Autolock l(mLock);
       //使用了一个局部变量对mPlayer引用,即对底层播放器的引用。
       //会使强引用计数加1。在这个函数退出后,p的生命周期也结束,智能指针会自动销毁底层播放器实例
        p = mPlayer;

       //调用了智能指针的clear方法,将强引用计数减1,并m_ptr = 0 
       //mClient 为sp<IMediaPlayerClient>,即是对mediaplayer的引用
       //mPlayer 为sp<MediaPlayerBase>
       //mClient和mPlayer为全局的引用变量,使用clear后, mClient和mPlayer将无法再被使用
        mClient.clear();      
        mPlayer.clear();
    }

    // clear the notification to prevent callbacks to dead client
    // and reset the player. We assume the player will serialize
    // access to itself if necessary.
    if (p != 0) {
        p->setNotifyCallback(0, 0);
#if CALLBACK_ANTAGONIZER
        ALOGD("kill Antagonizer");
        mAntagonizer->kill();
#endif
        p->reset();
    }

    {
        Mutex::Autolock l(mLock);
        disconnectNativeWindow_l();
    }

    IPCThreadState::self()->flushCommands();
}

disconnect步骤稍微有点绕。先用一个局部变量p 指向了mPlayer,即增加了对NuPlayer的强引用计数,接着销毁了全局变量mClient和mPlayer引用。mClient计数应该会为0,所以对应的实例也会被销毁。而NuPlayer的引用计数由于局部变量p,引用计数不会为0。接着通过p 将NuPlayer的回调函数置为0,并调用到NuPlayer的reset方法,这里是重复调用了reset方法,因为release流程只会调用mediaplayer的disconnect方法,不会调用到reset方法。在函数执行完后,局部变量p会自动销毁,同时也会自动销毁NuPlayer实例 主要步骤:

  • 销毁mClient和mPlayer的引用
  • 设置NuPlayer的回调函数为0
  • 调用NuPlayer reset方法
  • disconnectNativeWindow_l(没详细研究,应该是涉及到显示的window,跟surface和wms相关)
  • flushCommands() 调用talkWithDriver(false)立即发送mOut缓存中的命令数据
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档