MediaPlayer(九)--reset()流程

作者: llm_5243 | 来源:发表于2020-04-20 16:11 被阅读0次

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

        /**
         * 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

    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

    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

    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();
    }
    
    
    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缓存中的命令数据

    相关文章

      网友评论

        本文标题:MediaPlayer(九)--reset()流程

        本文链接:https://www.haomeiwen.com/subject/extdihtx.html