您的位置:首页 > 其它

【Libgdx 原创】在 Libgdx 中播放视频实例

2012-10-23 22:03 351 查看
我现在做的一款游戏使用 Libgdx ,其中需要播放小段视频过度游戏场景,想到传统的办法是跳转 Activity ,显然这样做不是我会选择的!
我想直接在当前游戏 Activity 中插播视频。
播放视频其实只需要:MediaPlayer 和 SurfaceView 

刚开始在网上找到了一段这样的实例代码,拿来用没问题

[code] public class VideoPlayerActivity extends Activity implements


MediaPlayer.OnCompletionListener,


MediaPlayer.OnPreparedListener,


SurfaceHolder.Callback,


OnClickListener {




 private SurfaceView surfaceView;


 private MediaPlayer mPlayer; // MediaPlayer对象


 private SurfaceHolder mSurfaceHolder; // SurfaceHolder对象




 private Button mSkipVideoBtn;




 @Override


 protected void onCreate(Bundle savedInstanceState) {


 super.onCreate(savedInstanceState);


 requestWindowFeature(Window.FEATURE_NO_TITLE);


 getWindow().setFlags(0x400, 0x400);




 setContentView(R.layout.video_player);




 surfaceView = (SurfaceView) findViewById(R.id.surfaceView);




 /* 初始化mSurfaceHolder */


 mSurfaceHolder = surfaceView.getHolder();


 mSurfaceHolder.addCallback(this); // 设置回调接口


 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 设置为Buffer类型(播放视频&Camera预览)




 /* 初始化MediaPlayer */


 mPlayer = MediaPlayer.create(this, getIntent().getIntExtra("resId", R.raw.video2));


 mPlayer.setOnPreparedListener(this);


 mPlayer.setOnCompletionListener(this);




 mSkipVideoBtn = (Button) findViewById(R.id.button1);


 mSkipVideoBtn.setOnClickListener(this);


}




 @Override


 protected void onDestroy() {


 mPlayer.release();


 super.onDestroy();


}




 @Override


 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {


 // TODO Auto-generated method stub




 String s = "#E0D8C8";


int c = Integer.parseInt(s, 16);


surfaceView.setBackgroundColor(Color.rgb(c>>24, (c>>16)&0x0000ff00, c&0x000000ff));


}




 @Override


 public void surfaceCreated(SurfaceHolder holder) {


 mPlayer.setDisplay(holder); // 指定SurfaceHolder


 // mPlayer.prepareAsync(); // 异步准备(将回调OnPreparedListener接口)


}




 @Override


 public void surfaceDestroyed(SurfaceHolder holder) {


 // TODO Auto-generated method stub




}




 @Override


 public void onPrepared(MediaPlayer player) {


 /* 获得窗口宽长 */


 Display display = getWindowManager().getDefaultDisplay();


 int wWidth = display.getWidth();


 int wHeight = display.getHeight();




 /* 获得视频宽长 */


 int vWidth = mPlayer.getVideoWidth();


 int vHeight = mPlayer.getVideoHeight();




 /* 最适屏幕 */


 float wRatio = (float) vWidth / (float) wWidth; // 宽度比


 float hRatio = (float) vHeight / (float) wHeight; // 高度比


 float ratio = Math.max(wRatio, hRatio); // 较大的比


 vWidth = (int) Math.ceil((float) vWidth / ratio); // 新视频宽度


 vHeight = (int) Math.ceil((float) vHeight / ratio); // 新视频高度




 // 改变SurfaceHolder大小


 mSurfaceHolder.setFixedSize(vWidth, vHeight);


 // 设置新布局参数(这在samsung i9088上出现stretch的错误==)


 // surfaceView.setLayoutParams(new LinearLayout.LayoutParams(vWidth,


 // vHeight));


 // 启动播放


 mPlayer.start();


}




 @Override


 public void onCompletion(MediaPlayer mp) {


 // mSkipVideoBtn.setText("开始游戏");


 // Toast.makeText(this, "播放完毕!", Toast.LENGTH_SHORT).show();


 finish();


}




 @Override


 public void onClick(View v) {


 mPlayer.stop();


 finish();


}


}

[/code]

这里最主要的就是: MediaPlayer.setDisplay(),新建一个SurfaceView,将 SurfaceView 的 SurfaceHolder 设置给 MediaPlayer 然后设置播放视频,prepare() 、 start() 就可以正常播放视频了,不过据说只支持 .mp4 .3gp,我没亲测。

起初这段源代码给我带来帮助,在感谢原作者之余他也在代码里设下了一个陷阱,作者当时估计没测试到就是!

如果你使用这段代码,在有些手机上是可以正常播放视频的,而有些手机就是不行(你只能听见声音、看不到画面),系统没给任何提示,只有2个警告信息,如下图:





于是百度“mediaPlayer错误信息”得知 35 在 native 层是这样定义的:const PVMFStatus PVMFInfoTrackDisable = 35;

于是 Google “PVMFInfoTrackDisable ” 果然有人跟我遇到同样的问题,在 stackoverflow 论坛有一篇这样的帖子:

http://stackoverflow.com/questions/7509818/android-mediaplayer-sometimes-no-video-is-played-even-though-audio-plays

这里不得不说下,stackoverflow 论坛能够找到你遇到的各种疑难杂症,嘿嘿!

 

这里面说法很多,但没找到根本原因,倒是在另外一篇帖子找到了答案:





这哥们才发现了问题的根本,大概意思就是:在 surfaceCreated 没被系统调用之前,SurfaceView 的 SurfaceHolder 是无效的,而我们一般习惯在 MediaPlayer 构造完后就给他设置数据,而我在 surfaceCreated 才调用了 mPlayer.setDisplay(holder); 这样 MediaPlayer 就没有设置显示器就开始播放了,这样自然看不到画面,而后来系统调用 surfaceCreated 的时候是于事无补的!

这也难怪看到有些人回复说第二次在播放视频的时候就可以,因为前面第一次设置了 holder 嘛!

知道了问题的根本就好办了, 在 surfaceCreated 里设置 holder,然后设置视频数据,然后调用 prepare,这样总是没问题了吧!

下面贴上我封装的一个 VideoPlayer :

[code] public class VideoPlayer implements


MediaPlayer.OnCompletionListener,


 SurfaceHolder.Callback,


 OnClickListener,


 OnErrorListener,


 OnInfoListener,


 OnTouchListener,


 OnKeyListener,


 MediaPlayer.OnPreparedListener {


 private SurfaceView surfaceView;


 private MediaPlayer mPlayer; // MediaPlayer对象


 private SurfaceHolder mSurfaceHolder; // SurfaceHolder对象


 private ViewGroup viewGroup;


 private GameActivity gameActivity;


 private ImageButton button;


 


 private boolean surfaceCreated = false;


 


 


 public VideoPlayer(GameActivity gameActivity) {


 this.gameActivity = gameActivity;


 


 LayoutInflater inflater = (LayoutInflater) gameActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);


 //LayoutInflater inflater = context.getLayoutInflater();


 viewGroup =(ViewGroup) inflater.inflate(R.layout.video_player, null);


 


 button = (ImageButton) viewGroup.findViewById(R.id.button1);


 button.setOnClickListener(this);


 button.setVisibility(View.INVISIBLE);


 


 surfaceView = (SurfaceView) viewGroup.findViewById(R.id.surfaceView);


 surfaceView.setOnTouchListener(this);


 surfaceView.setOnKeyListener(this);


 surfaceView.setFocusableInTouchMode(true);


 surfaceView.requestFocus();


 


 mSurfaceHolder = surfaceView.getHolder();


 mSurfaceHolder.addCallback(this); // 设置回调接口


 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 设置为Buffer类型(播放视频&Camera预览)


 


 mPlayer = new MediaPlayer();


 mPlayer.setScreenOnWhilePlaying(true);


 


 mPlayer.setOnPreparedListener(this);


 mPlayer.setOnCompletionListener(this);


 mPlayer.setOnErrorListener(this);


 mPlayer.setOnInfoListener(this);


}


 


 public void pause() {


 mPlayer.pause();


}


 


 public void resume() {


 mPlayer.start();


}


 


 private int resId;


 public void setVideo(int resId) {


 Log.i(PobabyGame.TAG, "== setVideo ! == ");


 


 this.resId = resId;


 Uri uri = Uri.parse("android.resource://" 


 + gameActivity.getPackageName() 


 + "/" + resId);


 


 try {


 mPlayer.setDataSource(gameActivity, uri);


 //mPlayer.prepare();


} catch (IllegalArgumentException e) {


} catch (SecurityException e) {


} catch (IllegalStateException e) {


} catch (IOException e) {


}


}


 


 public SurfaceView getSurfaceView() {


 return surfaceView;


}


 


 public ViewGroup getViewGroup() {


 return viewGroup;


}


 


 @Override


 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {


}


 


 @Override


 public void surfaceCreated(final SurfaceHolder holder) {


 Log.i(PobabyGame.TAG, "== surfaceCreated ! == " + "holder" + holder.toString() + ", h2" + mSurfaceHolder);


 


 gameActivity.handler.post(new Runnable() {


 @Override


 public void run() {


 mPlayer.setDisplay(holder); // 指定SurfaceHolder


 surfaceCreated = true;


 


 //Uri uri = Uri.parse("android.resource://" 


 //+ gameActivity.getPackageName() 


 //+ "/" + resId);


 


 try {


 //mPlayer.setDataSource(gameActivity, uri);


 mPlayer.prepare();


} catch (IllegalArgumentException e) {


} catch (SecurityException e) {


} catch (IllegalStateException e) {


} catch (IOException e) {


}


}


});


}


 


 @Override


 public void surfaceDestroyed(SurfaceHolder holder) {


 surfaceCreated = false;


}


 


 @Override


 public void onPrepared(MediaPlayer player) {


 int wWidth = Gdx.graphics.getWidth();


 int wHeight = Gdx.graphics.getHeight();


 


 /* 获得视频宽长 */


 int vWidth = mPlayer.getVideoWidth();


 int vHeight = mPlayer.getVideoHeight();


 


 /* 最适屏幕 */


 float wRatio = (float) vWidth / (float) wWidth; // 宽度比


 float hRatio = (float) vHeight / (float) wHeight; // 高度比


 float ratio = Math.max(wRatio, hRatio); // 较大的比


 vWidth = (int) Math.ceil((float) vWidth / ratio); // 新视频宽度


 vHeight = (int) Math.ceil((float) vHeight / ratio); // 新视频高度


 


 // 改变SurfaceHolder大小


 mSurfaceHolder.setFixedSize(vWidth, vHeight);


 mPlayer.start();


 


 gameActivity.gameView.setVisibility(View.INVISIBLE);


}


 


 @Override


 public void onCompletion(MediaPlayer mp) {


 gameActivity.videoFinish(resId);


}


 


 @Override


 public void onClick(View v) {


 gameActivity.videoFinish(resId);


 mPlayer.release();


}


 


 @Override


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


 Log.i(PobabyGame.TAG, String.format("onInfo(%d, %d)", what, extra));


 return true;


}


 


 @Override


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


 Log.e(PobabyGame.TAG, String.format("onError(%d, %d)", what, extra));


 return true;


}


 


 @Override


 public boolean onTouch(View v, MotionEvent event) {


 if(event.getAction() == MotionEvent.ACTION_DOWN){


 button.setVisibility(View.VISIBLE);


 return true;


}


 


 return false;


}


 


 @Override


 public boolean onKey(View v, int keyCode, KeyEvent event) {


 if(event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){


 gameActivity.videoFinish(resId);


 mPlayer.release();


}


 


 return true;


}


}

[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: