• 【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: }
  • 相关阅读:
    第二章 第二节 安装Eclipse
    windows10下成功安装docker splash及遇到问题的解决方案
    关于.net程序员面试的问题
    ajax更新时 updatepanel 更新问题
    关于分页问题解决方法
    2条路 代码生成 or 配置
    Accordion控件之仿OutLookBar
    《C#3.0 in a Nutshell,3rd Edition》之C#3.0和.net3.5基本介绍篇
    ERP之我见
    2009岁末之复用系统框架(B/S)
  • 原文地址:https://www.cnblogs.com/yichouangle/p/2736281.html
Copyright © 2020-2023  润新知