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

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

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

   1: public class VideoPlayerActivity extends Activity implements 
   2:         MediaPlayer.OnCompletionListener, 
   3:         MediaPlayer.OnPreparedListener, 
   4:         SurfaceHolder.Callback, 
   5:         OnClickListener {
   6:  
   7:     private SurfaceView surfaceView;
   8:     private MediaPlayer mPlayer; // MediaPlayer对象
   9:     private SurfaceHolder mSurfaceHolder; // SurfaceHolder对象
  10:  
  11:     private Button mSkipVideoBtn;
  12:  
  13:     @Override
  14:     protected void onCreate(Bundle savedInstanceState) {
  15:         super.onCreate(savedInstanceState);
  16:         requestWindowFeature(Window.FEATURE_NO_TITLE);
  17:         getWindow().setFlags(0x400, 0x400);
  18:  
  19:         setContentView(R.layout.video_player);
  20:  
  21:         surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
  22:  
  23:         /* 初始化mSurfaceHolder */
  24:         mSurfaceHolder = surfaceView.getHolder();
  25:         mSurfaceHolder.addCallback(this); // 设置回调接口
  26:         mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 设置为Buffer类型(播放视频&Camera预览)
  27:  
  28:         /* 初始化MediaPlayer */
  29:         mPlayer = MediaPlayer.create(this, getIntent().getIntExtra("resId", R.raw.video2));
  30:         mPlayer.setOnPreparedListener(this);
  31:         mPlayer.setOnCompletionListener(this);
  32:  
  33:         mSkipVideoBtn = (Button) findViewById(R.id.button1);
  34:         mSkipVideoBtn.setOnClickListener(this);
  35:     }
  36:  
  37:     @Override
  38:     protected void onDestroy() {
  39:         mPlayer.release();
  40:         super.onDestroy();
  41:     }
  42:  
  43:     @Override
  44:     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  45:         // TODO Auto-generated method stub
  46:  
  47:         String s = "#E0D8C8";
  48:          int c = Integer.parseInt(s, 16);
  49:          surfaceView.setBackgroundColor(Color.rgb(c>>24, (c>>16)&0x0000ff00, c&0x000000ff));
  50:     }
  51:  
  52:     @Override
  53:     public void surfaceCreated(SurfaceHolder holder) {
  54:         mPlayer.setDisplay(holder); // 指定SurfaceHolder
  55:         // mPlayer.prepareAsync(); // 异步准备(将回调OnPreparedListener接口)
  56:     }
  57:  
  58:     @Override
  59:     public void surfaceDestroyed(SurfaceHolder holder) {
  60:         // TODO Auto-generated method stub
  61:  
  62:     }
  63:  
  64:     @Override
  65:     public void onPrepared(MediaPlayer player) {
  66:         /* 获得窗口宽长 */
  67:         Display display = getWindowManager().getDefaultDisplay();
  68:         int wWidth = display.getWidth();
  69:         int wHeight = display.getHeight();
  70:  
  71:         /* 获得视频宽长 */
  72:         int vWidth = mPlayer.getVideoWidth();
  73:         int vHeight = mPlayer.getVideoHeight();
  74:  
  75:         /* 最适屏幕 */
  76:         float wRatio = (float) vWidth / (float) wWidth; // 宽度比
  77:         float hRatio = (float) vHeight / (float) wHeight; // 高度比
  78:         float ratio = Math.max(wRatio, hRatio); // 较大的比
  79:         vWidth = (int) Math.ceil((float) vWidth / ratio); // 新视频宽度
  80:         vHeight = (int) Math.ceil((float) vHeight / ratio); // 新视频高度
  81:  
  82:         // 改变SurfaceHolder大小
  83:         mSurfaceHolder.setFixedSize(vWidth, vHeight);
  84:         // 设置新布局参数(这在samsung i9088上出现stretch的错误==)
  85:         // surfaceView.setLayoutParams(new LinearLayout.LayoutParams(vWidth,
  86:         // vHeight));
  87:         // 启动播放
  88:         mPlayer.start();
  89:     }
  90:  
  91:     @Override
  92:     public void onCompletion(MediaPlayer mp) {
  93:         // mSkipVideoBtn.setText("开始游戏");
  94:         // Toast.makeText(this, "播放完毕!", Toast.LENGTH_SHORT).show();
  95:         finish();
  96:     }
  97:  
  98:     @Override
  99:     public void onClick(View v) {
 100:         mPlayer.stop();
 101:         finish();
 102:     }
 103: }

这里最主要的就是: 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 论坛能够找到你遇到的各种疑难杂症,嘿嘿!

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

QQ截图20121023215101

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

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

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

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

   1: public class VideoPlayer implements 
   2:             MediaPlayer.OnCompletionListener, 
   3:             SurfaceHolder.Callback,
   4:             OnClickListener,
   5:             OnErrorListener,
   6:             OnInfoListener,
   7:             OnTouchListener,
   8:             OnKeyListener,
   9:             MediaPlayer.OnPreparedListener {
  10:     private SurfaceView surfaceView;
  11:     private MediaPlayer mPlayer; // MediaPlayer对象
  12:     private SurfaceHolder mSurfaceHolder; // SurfaceHolder对象
  13:     private ViewGroup viewGroup;
  14:     private GameActivity gameActivity;
  15:     private ImageButton button;
  16:     
  17:     private boolean surfaceCreated = false;
  18:  
  19:     
  20:     public VideoPlayer(GameActivity gameActivity) {
  21:         this.gameActivity = gameActivity;
  22:         
  23:         LayoutInflater inflater = (LayoutInflater) gameActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  24: //        LayoutInflater inflater = context.getLayoutInflater();
  25:         viewGroup =  (ViewGroup) inflater.inflate(R.layout.video_player, null);
  26:         
  27:         button = (ImageButton) viewGroup.findViewById(R.id.button1);
  28:         button.setOnClickListener(this);
  29:         button.setVisibility(View.INVISIBLE);
  30:         
  31:         surfaceView = (SurfaceView) viewGroup.findViewById(R.id.surfaceView);
  32:         surfaceView.setOnTouchListener(this);
  33:         surfaceView.setOnKeyListener(this);
  34:         surfaceView.setFocusableInTouchMode(true);
  35:         surfaceView.requestFocus();
  36:         
  37:         mSurfaceHolder = surfaceView.getHolder();
  38:         mSurfaceHolder.addCallback(this); // 设置回调接口
  39:         mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 设置为Buffer类型(播放视频&Camera预览)
  40:         
  41:         mPlayer = new MediaPlayer();
  42:         mPlayer.setScreenOnWhilePlaying(true);
  43:         
  44:         mPlayer.setOnPreparedListener(this);
  45:         mPlayer.setOnCompletionListener(this);
  46:         mPlayer.setOnErrorListener(this);
  47:         mPlayer.setOnInfoListener(this);
  48:     }
  49:     
  50:     public void pause() {
  51:         mPlayer.pause();
  52:     }
  53:     
  54:     public void resume() {
  55:         mPlayer.start();
  56:     }
  57:     
  58:     private int resId;
  59:     public void setVideo(int resId) {
  60:         Log.i(PobabyGame.TAG, "== setVideo ! == ");
  61:  
  62:         this.resId = resId;
  63:         Uri uri = Uri.parse("android.resource://" 
  64:                 + gameActivity.getPackageName() 
  65:                 + "/" + resId);
  66:         
  67:         try {
  68:             mPlayer.setDataSource(gameActivity, uri);
  69: //            mPlayer.prepare();
  70:         } catch (IllegalArgumentException e) {
  71:         } catch (SecurityException e) {
  72:         } catch (IllegalStateException e) {
  73:         } catch (IOException e) {
  74:         }
  75:     }
  76:     
  77:     public SurfaceView getSurfaceView() {
  78:         return surfaceView;
  79:     }
  80:     
  81:     public ViewGroup getViewGroup() {
  82:         return viewGroup;
  83:     }
  84:     
  85:     @Override
  86:     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  87:     }
  88:  
  89:     @Override
  90:     public void surfaceCreated(final SurfaceHolder holder) {
  91:         Log.i(PobabyGame.TAG, "== surfaceCreated ! == " + "holder" + holder.toString() + ", h2" + mSurfaceHolder);
  92:         
  93:         gameActivity.handler.post(new Runnable() {
  94:             @Override
  95:             public void run() {
  96:                 mPlayer.setDisplay(holder); // 指定SurfaceHolder
  97:                 surfaceCreated = true;
  98:                 
  99: //                Uri uri = Uri.parse("android.resource://" 
 100: //                        + gameActivity.getPackageName() 
 101: //                        + "/" + resId);
 102:                 
 103:                 try {
 104: //                    mPlayer.setDataSource(gameActivity, uri);
 105:                     mPlayer.prepare();
 106:                 } catch (IllegalArgumentException e) {
 107:                 } catch (SecurityException e) {
 108:                 } catch (IllegalStateException e) {
 109:                 } catch (IOException e) {
 110:                 }
 111:             }
 112:         });
 113:     }
 114:  
 115:     @Override
 116:     public void surfaceDestroyed(SurfaceHolder holder) {
 117:         surfaceCreated = false;
 118:     }
 119:  
 120:     @Override
 121:     public void onPrepared(MediaPlayer player) {
 122:         int wWidth = Gdx.graphics.getWidth();
 123:         int wHeight = Gdx.graphics.getHeight();
 124:  
 125:         /* 获得视频宽长 */
 126:         int vWidth = mPlayer.getVideoWidth();
 127:         int vHeight = mPlayer.getVideoHeight();
 128:  
 129:         /* 最适屏幕 */
 130:         float wRatio = (float) vWidth / (float) wWidth; // 宽度比
 131:         float hRatio = (float) vHeight / (float) wHeight; // 高度比
 132:         float ratio = Math.max(wRatio, hRatio); // 较大的比
 133:         vWidth = (int) Math.ceil((float) vWidth / ratio); // 新视频宽度
 134:         vHeight = (int) Math.ceil((float) vHeight / ratio); // 新视频高度
 135:  
 136:         // 改变SurfaceHolder大小
 137:         mSurfaceHolder.setFixedSize(vWidth, vHeight);
 138:         mPlayer.start();
 139:         
 140:         gameActivity.gameView.setVisibility(View.INVISIBLE);
 141:     }
 142:  
 143:     @Override
 144:     public void onCompletion(MediaPlayer mp) {
 145:         gameActivity.videoFinish(resId);
 146:     }
 147:  
 148:     @Override
 149:     public void onClick(View v) {
 150:         gameActivity.videoFinish(resId);
 151:         mPlayer.release();
 152:     }
 153:  
 154:     @Override
 155:     public boolean onInfo(MediaPlayer mp, int what, int extra) {
 156:         Log.i(PobabyGame.TAG, String.format("onInfo(%d, %d)", what, extra));
 157:         return true;
 158:     }
 159:  
 160:     @Override
 161:     public boolean onError(MediaPlayer mp, int what, int extra) {
 162:         Log.e(PobabyGame.TAG, String.format("onError(%d, %d)", what, extra));
 163:         return true;
 164:     }
 165:  
 166:     @Override
 167:     public boolean onTouch(View v, MotionEvent event) {
 168:         if(event.getAction() == MotionEvent.ACTION_DOWN){
 169:             button.setVisibility(View.VISIBLE);
 170:             return true;
 171:         }
 172:         
 173:         return false;
 174:     }
 175:  
 176:     @Override
 177:     public boolean onKey(View v, int keyCode, KeyEvent event) {
 178:         if(event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
 179:             gameActivity.videoFinish(resId);
 180:             mPlayer.release();
 181:         }
 182:         
 183:         return true;
 184:     }
 185: }
原文地址:https://www.cnblogs.com/yichouangle/p/2736281.html