我记得之前写过这篇帖子,找不到了现在,知道从别处粘贴过来
我现在做的一款游戏使用 Libgdx ,其中需要播放小段视频过度游戏场景,想到传统的办法是跳转 Activity ,显然这样做不是我会选择的!
我想直接在当前游戏 Activity 中插播视频。
播放视频其实只需要:MediaPlayer 和 SurfaceView
刚开始在网上找到了一段这样的实例代码,拿来用没问题:
1 package com.thirdparty;
2
3 public class AAA {
4 public class VideoPlayerActivity extends Activity implements MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, SurfaceHolder.Callback, OnClickListener {
5
6 private SurfaceView surfaceView;
7 private MediaPlayer mPlayer; // MediaPlayer对象
8 private SurfaceHolder mSurfaceHolder; // SurfaceHolder对象
9
10 private Button mSkipVideoBtn;
11
12 @Override
13 protected void onCreate(Bundle savedInstanceState) {
14 super.onCreate(savedInstanceState);
15 requestWindowFeature(Window.FEATURE_NO_TITLE);
16 getWindow().setFlags(0x400, 0x400);
17
18 setContentView(R.layout.video_player);
19
20 surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
21
22 /* 初始化mSurfaceHolder */
23 mSurfaceHolder = surfaceView.getHolder();
24 mSurfaceHolder.addCallback(this); // 设置回调接口
25 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 设置为Buffer类型(播放视频&Camera预览)
26
27 /* 初始化MediaPlayer */
28 mPlayer = MediaPlayer.create(this, getIntent().getIntExtra("resId", R.raw.video2));
29 mPlayer.setOnPreparedListener(this);
30 mPlayer.setOnCompletionListener(this);
31
32 mSkipVideoBtn = (Button) findViewById(R.id.button1);
33 mSkipVideoBtn.setOnClickListener(this);
34 }
35
36 @Override
37 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
38 }
39
40 @Override
41 public void surfaceCreated(SurfaceHolder holder) {
42 mPlayer.setDisplay(holder); // 指定SurfaceHolder
43 // mPlayer.prepareAsync(); // 异步准备(将回调OnPreparedListener接口)
44 }
45
46 @Override
47 public void surfaceDestroyed(SurfaceHolder holder) {
48 // TODO Auto-generated method stub
49
50 }
51
52 @Override
53 public void onPrepared(MediaPlayer player) {
54 /* 获得窗口宽长 */
55 Display display = getWindowManager().getDefaultDisplay();
56 int wWidth = display.getWidth();
57 int wHeight = display.getHeight();
58
59 /* 获得视频宽长 */
60 int vWidth = mPlayer.getVideoWidth();
61 int vHeight = mPlayer.getVideoHeight();
62
63 /* 最适屏幕 */
64 float wRatio = (float) vWidth / (float) wWidth; // 宽度比
65 float hRatio = (float) vHeight / (float) wHeight; // 高度比
66 float ratio = Math.max(wRatio, hRatio); // 较大的比
67 vWidth = (int) Math.ceil((float) vWidth / ratio); // 新视频宽度
68 vHeight = (int) Math.ceil((float) vHeight / ratio); // 新视频高度
69
70 // 改变SurfaceHolder大小
71 mSurfaceHolder.setFixedSize(vWidth, vHeight);
72 // 设置新布局参数(这在samsung i9088上出现stretch的错误==)
73 // surfaceView.setLayoutParams(new LinearLayout.LayoutParams(vWidth,
74 // vHeight));
75 // 启动播放
76 mPlayer.start();
77 }
78 }
79 }
这里最主要的就是: MediaPlayer.setDisplay(),新建一个SurfaceView,将 SurfaceView 的 SurfaceHolder 设置给 MediaPlayer 然后设置播放视频,prepare() 、 start() 就可以正常播放视频了,不过据说只支持 .mp4 .3gp,我没亲测。
起初这段源代码给我带来帮助,在感谢原作者之余他也在代码里设下了一个陷阱,作者当时估计没测试到就是!
如果你使用这段代码,在有些手机上是可以正常播放视频的,而有些手机就是不行(你只能听见声音、看不到画面),系统没给任何提示,只有2个警告信息,如下图:
于是百度“mediaPlayer错误信息”得知 35 在 native 层是这样定义的:const PVMFStatus PVMFInfoTrackDisable = 35;
于是 Google “PVMFInfoTrackDisable ” 果然有人跟我遇到同样的问题,在 stackoverflow 论坛有一篇这样的帖子:
这里不得不说下,stackoverflow 论坛能够找到你遇到的各种疑难杂症,嘿嘿!
这里面说法很多,但没找到根本原因,倒是在另外一篇帖子找到了答案:
这哥们才发现了问题的根本,大概意思就是:在 surfaceCreated 没被系统调用之前,SurfaceView 的 SurfaceHolder 是无效的,而我们一般习惯在 MediaPlayer 构造完后就给他设置数据,而我在 surfaceCreated 才调用了 mPlayer.setDisplay(holder); 这样 MediaPlayer 就没有设置显示器就开始播放了,这样自然看不到画面,而后来系统调用 surfaceCreated 的时候是于事无补的!
这也难怪看到有些人回复说第二次在播放视频的时候就可以,因为前面第一次设置了 holder 嘛!
知道了问题的根本就好办了, 在 surfaceCreated 里设置 holder,然后设置视频数据,然后调用 prepare,这样总是没问题了吧!