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