android 视频 surface view,Android下的视频播放编程-SurfaceView重显时的问题

尽管网上有不少Android下视频播放的例子代码,好似很简单;但试着写一个时,遇到了不少的麻烦。

我的目标是正在播放时可以通过另一个Activity来选择另一个文件来播放,而在选择过程中原文件并不停播(可以想象的是由于存在Activity切换,原文件的播放会出现停顿,只要时间不长就行)。

发现的问题是在选文件时仍能听到原文件的声音(图像自然看不到了),但文件选择后返回到原Activity时,原文件仍在播放,但图像区空白。经查,发现SurfaceHolder.Callback.surfaceChanged()并未触发,或者其中的width/height参数为0。在返回到原Activity时主动刷新(update)SurfaceView也无济于事。

查了一下SurfaceView的源码,仍然没有发现让SurfaceView主动调用surfaceChanged()的方法(update,resize,setFormat,hide/reshow等都试过,未果。)

后来的解决方案是:在MediaPlayer的onPrepared(MediaPlayer

mp)中检查MediaPlayer的width/height,如果其值为0(因为SurfaceHolder.Callback.surfaceChanged()并未触发),就释放当前的MediaPlayer对象,重新一次播放(需先保留一些参数,如文件名,当前位置,当前屏幕方向,...)。这里的重新播放并不是就地执行,而是向Activity发送一个消息,在主线程里执行重放。其中的原因是在执行MediaPlayer.setDisplay(surfaceHolder)时会调用刷新surfaceHolder:

public

void MediaPlayer.setDisplay(SurfaceHolder sh) {

mSurfaceHolder = sh;

if (sh != null) {

mSurface = sh.getSurface();

} else {

mSurface = null;

}

//以下两行用于刷新:

_setVideoSurface();

updateSurfaceScreenOn();

}

部分代码如下,其中monitorThread只是获得MediaPlayer的当前位置,并相应更新SeekBar的位置。

boolean mSurfaceExists =

true; //调试用!

private SurfaceHolder.Callback surfaceHolderCallback = new

SurfaceHolder.Callback() {

@Override

public void

surfaceChanged(SurfaceHolder holder, int format, int width, int

height) {

// Do

nothing

Log.e(LOG_TAG,

"surfaceChanged: width="+width+", height="+height);

if(width!=0

&& height!=0) {

holder.setFixedSize(width,

height);

}

}

@Override

public void

surfaceCreated(SurfaceHolder holder) {

// Do

nothing

Log.d(LOG_TAG,

"surfaceCreated.");

mSurfaceExists

= true;

}

@Override

public void

surfaceDestroyed(SurfaceHolder holder) {

// Do

nothing

Log.d(LOG_TAG,

"surfaceDestroyed.");

mSurfaceExists

= false;

}

};

private MediaPlayer getPlayer() {

// we need

get a new Player in case the old one comes to END or ERROR

state(reset() won't help).

surfaceHolder =

surfaceView.getHolder();

surfaceHolder.addCallback(surfaceHolderCallback);

surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

MediaPlayer

player = new MediaPlayer();

player.reset(); // new() and

reset() lead to different mPlayer status.

player.setDisplay(surfaceHolder);

player.setOnErrorListener(new

MediaPlayer.OnErrorListener(){

@Override

public boolean onError(MediaPlayer mp, int what, int extra) {

Log.e(LOG_TAG, "MplayerError: what="+what+", extra="+extra);

if(state!=VideoPlayerState.PREPARING) {

btnPlay.setEnabled(true);

}

return false;

}

});

player.setOnBufferingUpdateListener(new

MediaPlayer.OnBufferingUpdateListener(){

@Override

public void onBufferingUpdate(MediaPlayer mp, int percent) {

Log.e(LOG_TAG, "MplayerError: percent="+percent);

}

});

player.setOnPreparedListener(new

MediaPlayer.OnPreparedListener(){

@Override

public void onPrepared(MediaPlayer mp) {

// Only now we can invoke mPlayer.isPlaying(),

mPlayer.getPosition(), ...

int width = mp.getVideoWidth();

int height = mp.getVideoHeight();

Log.e(LOG_TAG, "onPrepared(): width="+width+",

height="+height);

if(width<=0 || height<=0) {

// restart playing:

saved_old_pos = CurrentPosition;

stopPlayer();

postMessage(MSG_VIDEO_PLAY);

return;

}

surfaceHolder.setFixedSize(width, height);

doRealPlay();

}

});

player.setOnCompletionListener(new OnCompletionListener() {

@Override

public void onCompletion(MediaPlayer mp) {

stop();

if(arg_once==true) { //如果只需播放一个文件,播完就退出。

finish();

}

}

});

return player;

}

@Override

protected void onActivityResult(int requestCode,

int resultCode, Intent data) {

switch(requestCode){

case SharedConstants.REQ_FILECHOOSER:

toLoadNewFile = false;

File videoFile = null;

if(resultCode == RESULT_OK) {

String retPath =

data.getStringExtra(SharedConstants.CHOSENFILE_KEY);

videoFile = new

File(retPath);

}

if(videoFile!=null &&

!videoFile.getAbsolutePath().equals(currFile_Long)

&& videoFile.canRead()) {

Log.e(LOG_TAG, "For new file: pos="+CurrentPosition + ",

mSurfaceExists="+mSurfaceExists);

// For a new and readable file:

currFile_Long = videoFile.getAbsolutePath();

currFile_Short = videoFile.getName();

saved_old_pos = 0; // start from beginning!

stop(); // new Pos will become

0.

postMessage(MSG_VIDEO_PLAY);

} else {

Log.e(LOG_TAG, "For no-new file: pos="+CurrentPosition + ",

mSurfaceExists="+mSurfaceExists);

// Weird: SurfaceView will NOT show up!

// to restore SurfaceView:

if(mPlayer!=null &&

state==VideoPlayerState.PLAYING) {

saved_old_pos = CurrentPosition;

stop(); // new Pos will become

0.

postMessage(MSG_VIDEO_PLAY);

}

}

Log.e(LOG_TAG,

" onActivityResult() done.");

break;

default:

break;

}

}

private void stopPlayer() {

if(monitorThread!=null) {

monitorThread.interrupt();

boolean retry = true;

while(retry==true) {

try {

monitorThread.join();

retry = false;

} catch(InterruptedException e) {

// Do nothing.

}

}

monitorThread=null;

}

if(mPlayer!=null

&& state!=VideoPlayerState.STOPPED)

{

mPlayer.release();

mPlayer = null; // to avoid

IllegalStateException

state =

VideoPlayerState.STOPPED;

}

CurrentPosition=0;

}

private void stop() {

stopPlayer();

btnPlay.setEnabled(true);

btnStop.setEnabled(false);

btnPlay.setText(lblPlay);

showCurrentPosition();

showPlayingInfoViews(View.VISIBLE);

lbl_video_playing_file.setText(currFile_Short);

rotateScreen(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值