在 Libgdx 中播放视频(一)

我记得之前写过这篇帖子,找不到了现在,知道从别处粘贴过来

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

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

View Code
 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 论坛有一篇这样的帖子:

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,这样总是没问题了吧!

原文地址:https://www.cnblogs.com/yichouangle/p/3046073.html