cocos2d-x 播放视频 on Android

应一个朋友需求,研究了下 cocos2d-x 引擎在 android 平台上播放视频的方法,因为之前研究 Libgdx 播视频的时候有了经验,于是依葫芦画瓢

首先你不要想到去用系统的 VideoView 控件,他不适合我们

我们来用强大 SurfaceView 和 MediaPlayer 来组装一下,android 框架设计的很好啊

其原理就是:

MediaPlayer.setDisplay (SurfaceHolder sh)

sh 来自于SurfaceView,这样MediaPlayer就可以看到画面了。

不过这里面有几个细节需要注意:

  • 1.何时调用 setDisplay :

  一般可能会在构造函数里面就调用,这样系统会报错即使没报错也可能会出现 闻其声而不见其画面 的现象(大多数人遇到过),告诉你 Holder 无效,SurfaceHolder 是有一组回调接口的,通过 

  addCallback(SurfaceHolder.Callback callback)

设置,Callback 里面有个函数:

  surfaceCreated(final SurfaceHolder holder)

其参数是 SurfaceHolder 所以我们可以猜到这个接口用来告诉我们 SurfaceHolder 创建好啦,所以我们在这个回调里面调用 MediaPlayer.setDisplay 就没问题啦!

  • 2.如何播放视频文件:

在 coco2d-x 中,资源文件肯定都在 assets 目录下,所以我们首先想到通过 URI 引用 assets 下文件,Like:

Uri uri = Uri.parse("file:///android_asset/" + name); //不可取

但是这样是不行的,播放不出来,于是我就上 StackOverFlow 上搜搜,还是有前辈解决了,所以我要说一句:StackOverFlow 是一个神奇的网站。

正确的做法是调用这个接口:

setDataSource (FileDescriptor fd, long offset, long length)

assets 下可以通过:AssetFileDescriptor afd = getAssets().openFd(name); 方法得到 AssetFileDescriptor 对象,然后这样调用就OK:

mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());

你可能会想到:

//直接调用 fd.getFileDescriptor() 是不行的mPlayer.setDataSource(fd.getFileDescriptor());

这样也是不行的,具体原因没深入研究,此外再介绍用 res/raw 下资源的方法:

Uri uri = Uri.parse("android.resource://" + this.getPackageName() + "/" + R.raw.video2); //可取

这样一个 android 层视频播放器就封装好了,实现细节可以看源代码:

View Code

下面介绍如何调用这个播放器:

  • 1.native 层:native 调 java 我们肯定要用到 jni 技术,cocos2d-x 封装了一个 jni 帮助类在:cocos2dx/platform/android/jni/JniHelper.h ,我们需要在 Java 层定义一个静态方法,然后通过 jni->CallStaticVoidMethod 调用:
View Code
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
  JniMethodInfo t;
  if (JniHelper::getStaticMethodInfo(t, "com/yichou/demo/video/VideoDemo",       
    "playVideo", "(Ljava/lang/String;)V"))
  {
    t.env->CallStaticVoidMethod(t.classID, t.methodID, t.env->NewStringUTF("video
      2.mp4"));
  }
#endif
  • 2.这样重点还是来到 Java 层:
View Code
VideoView videoView;
private void a(String name)
{
  Log.i("", "name=" + name);//Uri uri = Uri.parse("file:///android_asset/" + name
    ); //不可取//
  Uri uri = Uri.parse("android.resource://" + this.getPackageName() + "/" +
    R.raw.video2); //可取
  videoView = new VideoView(this);
  videoView.setOnFinishListener(this);//videoView.setVideo(uri);
  try{
    AssetFileDescriptor afd = getAssets().openFd(name);
    videoView.setVideo(afd);
  }catch (IOException e){
      e.printStackTrace();
    }
    group.addView(videoView);
    videoView.setZOrderMediaOverlay(true);
}
public static void playVideo(final String name)
{
    if (instance != null){
      instance.runOnUiThread(new Runnable(){
        @Override
        public void run(){
              instance.a(name);
         }
       });
    }
}

为了方便起见,我们把方法定义为 static 这样我们就需要一个当前 activity 的实例,这里用了一个 instance 静态全局变量,类似于单例设计模式。

完整代码:

View Code
1 public class VideoDemo extends Cocos2dxActivity implements OnFinishListener {
2     ViewGroup group;
3     static VideoDemo instance;
4     
5
6     protected void onCreate(Bundle savedInstanceState){
7         super.onCreate(savedInstanceState);
8         instance = this;
9         
10         group = (ViewGroup)getWindow().getDecorView();
11    }
12    
13    
14     VideoView videoView;
15     
16     private void a(String name) {
17         Log.i("", "name=" + name);
18         
19 //        Uri uri = Uri.parse("file:///android_asset/" + name); //不可取
20 //        Uri uri = Uri.parse("android.resource://" + this.getPackageName() + "/" + R.raw.video2); //可取
21         videoView = new VideoView(this);
22         videoView.setOnFinishListener(this);
23 //        videoView.setVideo(uri);
24         try {
25             AssetFileDescriptor afd = getAssets().openFd(name);
26             videoView.setVideo(afd);
27         } catch (IOException e) {
28             e.printStackTrace();
29         }
30         group.addView(videoView);
31         videoView.setZOrderMediaOverlay(true);
32     }
33     
34     public static void playVideo(final String name) {
35         if (instance != null) {
36             instance.runOnUiThread(new Runnable() {
37                 @Override
38                 public void run() {
39                     instance.a(name); 
40                 }
41             });
42         }
43     }
44     
45     static {
46          System.loadLibrary("game");
47     }
48 
49     @Override
50     public void onVideoFinish() {
51         group.removeView(videoView);
52         videoView = null;
53     }
54 }

OK,核心方法介绍完毕,具体实现细节可以看我提供的 Demo 源码

http://pan.baidu.com/share/link?shareid=505934&uk=4061068395

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值