专栏首页构建FFmpeg Android播放器MediaPlayer(九)--reset()流程

MediaPlayer(九)--reset()流程

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • rk3399 wifi和eth0共存 调试

    项目中Android 板通过有线连接poe摄像头, android app通过wifi跟外部通讯。采用的Android 8.1的代码。

    小蚂蚁与大象
  • FFmpeg--简介

    FFmpeg 是基于GNU General Public License 协议的开源多媒体软件项目。 FF意思是 Fast Forward - 播放器上的快进按...

    小蚂蚁与大象
  • MeidaPlayer(六)--setDisplay流程

    在Activity 的OnSurfaceCreate回调后,表示Surface已经创建成功,可以将surface传到native层player

    小蚂蚁与大象
  • if 语句

    每条if语句的核心都是一个值为Ture或False的表达式,这种表达式被称为条件测试。Python根据条件测试的值为Ture还是False来决定是否执行if语句...

    于小勇
  • 1024 科学计数法 (20 分)

    科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式 [+-][1-9].[0-9]+E[+-][0-9]+,即数字的整数部分只有 1 ...

    可爱见见
  • Python代码找bug(2)

    (1)三个for循环迭代的range的参数应该是(1,5),这样才能循环1-4次嘛;

    高一峰
  • 被迫重构代码,这次我干掉了 if-else

    我们看下边的伪代码,大致就是重构前下单逻辑的代码,由于来源比较少,简单的做if-else逻辑判断足以满足需求。

    程序员内点事
  • leetcode-788-Rotated Digits(使用vector替代if else的逐个判断)

    chenjx85
  • 如何优雅的用策略模式,取代臃肿的 if-else 嵌套,看这篇就够了

    Java的二十几种设计模式背的滚瓜烂熟,为什么这个时候不想着尝试用一下?说不定能轻松的解决掉哦

    程序员内点事
  • 2016广东工业大学新生杯决赛网络同步赛暨全国新生邀请赛 题解&源码

    Problem A: pigofzhou的巧克力棒 Description 众所周知,pigofzhou有许多妹子。有一天,pigofzhou得到了一根巧克力棒...

    Angel_Kitty

扫码关注云+社区

领取腾讯云代金券