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("video2.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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM