Cocos2d-x Lua 播放视频(iOS&android)

最近刚转了游戏,来公司不久就接到一个任务就是做一个视频播放的功能,自己花了3天时间,暂时实现了一个简易的功能,特写篇博客,以作记录。

参考地址如下:

http://blog.csdn.net/xiaominghimi/article/details/6870259

http://blog.csdn.net/kaitiren/article/details/11832851

http://blog.csdn.net/candyforever/article/details/8905852

实现功能:

Lua与C++的互调,C++与Object-c的互调, C++与Java的互相调用。

iOS视频的播放,android的视频播放。

声明:

pc 环境是 MAC OS 10.9.3

cocos2d-x 是2.2.3版本,其他版本可能部分API不同。

一,iOS实现

1 首先我们创建测试工程,我用的是Lua.

2 打开cocos2d-x 里的projects文件夹找到我们创建的工程打开,我们的工程文件夹,可以看到如下工程

3 打开proj.ios工程,看见xxxx.xcodeproj文件,双击打开,看见如下工程目录:

4.其中Other Sources里放得就是iOS相关的代码,如果是c++语言的工程,应该可以看到一个ios的文件夹,如下图,

5,下载这个文件夹 http://pan.baidu.com/s/1c0vPiuO,放到Other Sources里,如图:

6,添加MediaPlayer.framework类库到iOS工程,如图:

7,在AppController.h里添加如下代码:

 1 #import "CCVideoPlayeriOS/CCVideoPlayer.h"
 2 #import "cocos2d.h"
 3 using namespace cocos2d;
 4
 5 @class RootViewController;
 6
 7 @interface AppController : NSObject <UIAccelerometerDelegate, UIAlertViewDelegate, UITextFieldDelegate,UIApplicationDelegate,CCVideoPlayerDelegate> {
 8     UIWindow *window;
 9     RootViewController    *viewController;
10     CCObject * vedioDelegate;
11 }
12
13 @property(nonatomic,retain)UIWindow * window;
14
15 -(void)playVedio:(const char *)filePath delegate:(CCObject *)delegate skip:(bool)skip;
16
17 @end

代码解释:

1)引入了CCVideoPlayeriOS里的CCVideoPlayer.h然后 AppController实现了CCVideoPlayerDelegate协议

2)引入了cocos2d.h头文件和cocos2d命名空间,目的是,添加CCObject * vedioDelegate 成员变量

3)添加了播放函数 -(void)playVedio:(const char *)filePath delegate:(CCObject *)delegate skip:(bool)skip;

参数 filePath->要播放的文件路劲

  delegate->是播放完的回调代理

8,在AppController.m里添加如下代码

  1 //引入VedioPlatform头文件
  2 #import "VedioPlatform.h"
  3
  4 @implementation AppController
  5
  6 #pragma mark -
  7 #pragma mark Application lifecycle
  8
  9 // cocos2d application instance
 10 static AppDelegate s_sharedApplication;
 11
 12 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 13
 14     // Override point for customization after application launch.
 15
 16     // Add the view controller‘s view to the window and display.
 17     window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
 18     EAGLView *__glView = [EAGLView viewWithFrame: [window bounds]
 19                                      pixelFormat: kEAGLColorFormatRGBA8
 20                                      depthFormat: GL_DEPTH_COMPONENT16
 21                               preserveBackbuffer: NO
 22                                       sharegroup: nil
 23                                    multiSampling: NO
 24                                  numberOfSamples: 0 ];
 25
 26     [__glView setMultipleTouchEnabled:YES];
 27     // Use RootViewController manage EAGLView
 28     viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
 29     viewController.wantsFullScreenLayout = YES;
 30     viewController.view = __glView;
 31
 32     // Set RootViewController to window
 33     if ( [[UIDevice currentDevice].systemVersion floatValue] < 6.0)
 34     {
 35         // warning: addSubView doesn‘t work on iOS6
 36         [window addSubview: viewController.view];
 37     }
 38     else
 39     {
 40         // use this method on ios6
 41         [window setRootViewController:viewController];
 42     }
 43
 44     [window makeKeyAndVisible];
 45
 46     [[UIApplication sharedApplication] setStatusBarHidden: YES];
 47
 48     cocos2d::CCApplication::sharedApplication()->run();
 49
 50     //将自己添加为CCVideoPlayer的播放代理,主要为了播放完成的回调
 51     [CCVideoPlayer setDelegate:self];
 52
 53     return YES;
 54 }
 55
 56
 57 - (void)applicationWillResignActive:(UIApplication *)application {
 58     /*
 59      Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
 60      Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
 61      */
 62     cocos2d::CCDirector::sharedDirector()->pause();
 63 }
 64
 65 - (void)applicationDidBecomeActive:(UIApplication *)application {
 66     /*
 67      Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
 68      */
 69     cocos2d::CCDirector::sharedDirector()->resume();
 70 }
 71
 72 - (void)applicationDidEnterBackground:(UIApplication *)application {
 73     /*
 74      Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
 75      If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
 76      */
 77     cocos2d::CCApplication::sharedApplication()->applicationDidEnterBackground();
 78 }
 79
 80 - (void)applicationWillEnterForeground:(UIApplication *)application {
 81     /*
 82      Called as part of  transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
 83      */
 84     cocos2d::CCApplication::sharedApplication()->applicationWillEnterForeground();
 85 }
 86
 87 - (void)applicationWillTerminate:(UIApplication *)application {
 88     /*
 89      Called when the application is about to terminate.
 90      See also applicationDidEnterBackground:.
 91      */
 92 }
 93
 94
 95 #pragma mark -
 96 #pragma mark Memory management
 97
 98 - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
 99     /*
100      Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
101      */
102      cocos2d::CCDirector::sharedDirector()->purgeCachedData();
103 }
104
105
106 - (void)dealloc {
107     [super dealloc];
108 }
109
110 #pragma mark - Play Vedio(是所有播放相关的代码)
111
112 //播放视频
113 //filePath视频地址,
114 //delegate播完回调代理也就是VedioPlatform对象,
115 //skip是否可以跳过
116 -(void)playVedio:(const char *)filePath delegate:(CCObject *)delegate skip:(bool)skip{
117     vedioDelegate = delegate;//保存代理指针
118     BOOL isOk = YES;
119     @try {
120         CCSize size = CCDirector::sharedDirector()->getWinSize();
121         //设置播放的尺寸
122         [CCVideoPlayer setScrrenSize:CGSizeMake(size.width, size.height)];
123         [CCVideoPlayer setNoSkip:!skip];
124         //将c字符串转化为oc字符串
125         NSString * stringFilePath = [NSString stringWithFormat:@"%s",filePath];
126         //开始播放
127         [CCVideoPlayer playMovieWithFile:stringFilePath];
128     }
129     @catch (NSException *exception) {
130         NSLog(@"%@",exception);
131         isOk = NO;
132     }
133     @finally {
134         if(!isOk){
135             //如果发生异常,回调播放完成
136             VedioPlatform * delegate = (VedioPlatform *)vedioDelegate;
137             delegate->moviePlaybackFinished();
138             delegate = nil;
139         }
140     }
141 }
142
143 //以下是CCVideoPlayerDelegate的实现
144
145 //开始播放
146 - (void) movieStartsPlaying{
147
148 }
149
150 //播放完成
151 - (void) moviePlaybackFinished{
152     //回调代理的播放完成
153     VedioPlatform * delegate = (VedioPlatform *)vedioDelegate;
154     delegate->moviePlaybackFinished();
155     delegate = nil;
156 }

解释:

1)VedioPlatform下边会实现。

2)在didFinishLaunchingWithOption函数里将自己设置为CCVideoPlayer(头文件已经导入该类)的代理,

3)#pragma mark - Play Vedio(是所有播放相关的代码)的代码实现。

9,添加IOSPlayVedio类,注意是c++类,但是是在.mm里实现的,如图:

1)在IOSPlayVedio.h添加如下代码:

1 #include "cocos2d.h"
2 using namespace cocos2d;
3
4 class IOSPlayVedio{
5 public:
6     static void playVedio4iOS(const char * filePath,CCObject * delegate,bool skip);
7 };

只添加了一个供c++调用的static void playVedio4iOS(const char * filePath,CCObject * delegate,bool skip);静态函数。

2)在IOSPlayVedio.mm里实现如下:

1 #include "IOSPlayVedio.h"
2 #include "AppController.h"
3
4 void IOSPlayVedio::playVedio4iOS(const char * filePath,CCObject * delegate,bool skip){
5     AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
6     [app playVedio:filePath delegate:delegate skip:skip];
7 }

调用了AppController的playVedio函数。

10,在Classes里添加VedioPlatform类,注意这回是.cpp文件,见图:

1)在VedioPlatform.h里生命如下函数:

 1 #include "cocos2d.h"
 2 using namespace cocos2d;
 3
 4
 5 class VedioPlatform : CCObject{
 6 private:
 7     int successCallBack;
 8 public:
 9     //创建
10     CREATE_FUNC(VedioPlatform);
11     bool init();
12 public:
13     void setSuccessPlayCallBack(int funcAddress);//步骤1,播放成功回调
14     void play(const char * filePath,bool skip);//步骤2,播放
15 public:
16     void moviePlaybackFinished();
17 };

解释,

1.1)实例变量int successCallBack; 这个是保存播放完成后回调Lua的函数的地址。

1.2)setSuccessPlayCallBack函数顾名思义,开放给Lua的接口,就是给Lua设置播放完成回调函数的地址的接口。

1.3)play(const char * filePath,bool skip);开放给Lua的接口,就是lua调用播放,filePath文件路径,skip是否可以跳过

1.4)void moviePlaybackFinished();是开放给AppController的代理接口,AppController在视频播放完了会回调这个函数。

2) 在VedioPlatform.m里的实现如下:

 1 #include "VedioPlatform.h"
 2 #include "CCLuaEngine.h"
 3
 4 //单例变量保存了VedioPlatform对象
 5 static VedioPlatform * shardObj = NULL;
 6
 7 //依据不同的平台导入不同的头文件
 8 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
 9 //如果是Android得话,导入如下:
10 #include <jni.h>//android的jni
11 #include "platform/android/jni/JniHelper.h"//cocos2d专为jni封装的工具类
12 #include <android/log.h>//android 的日志
13 //这个是java回调c++的c函数,貌似c++类函数不可以,我也没有验证。
14 extern "C"
15 {
16     //finishAction 在Java里生命了这样一个函数。
17     //Java_com_zdl_VedioTest_VedioActivity这是类的完整路径
18     JNIEXPORT void JNICALL Java_com_zdl_VedioTest_VedioActivity_finishAction(JNIEnv *env, jobject thiz, jstring key, jstring message)
19     {
20         //调用了播放完成的函数
21         shardObj->moviePlaybackFinished();
22     }
23 }
24
25 #else
26 //如果是iOS得话,只引用IOSPlayVedio就可以了,还是oc简单。
27 #include "IOSPlayVedio.h"
28 #endif
29
30 #pragma mark - 生命周期
31 bool VedioPlatform::init(){
32     //将Lua回调的函数指针地址初始化为0
33     successCallBack = 0;
34
35     //判空
36     if(shardObj!= NULL){
37         //不为空前release;
38         shardObj->release();
39     }
40     //在赋值,并retain
41     shardObj = this;
42     shardObj->retain();
43
44     return true;
45 }
46
47 #pragma mark - 视频播放
48
49 void VedioPlatform::setSuccessPlayCallBack(int funcAddress){
50     successCallBack = funcAddress;//保存Lua回调的函数指针地址
51 }
52
53 void VedioPlatform::play(const char * filePath,bool skip){
54 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
55     //Android视频播放代码
56     JniMethodInfo minfo;//jni函数结构体
57     // 通过JniHelper来获取Java的静态函数,
58     // minfo->传入的函数结构体信息,调用完成后会给minfo赋值。
59     // "com/zdl/VedioTest/VedioTest"->是你Java静态函数的完整类路径。
60     // "playVedio"->静态函数名称
61     // "(Ljava/lang/String;Z)V"->静态函数的参数和返回值描述,这个大家百度下具体格式,我这儿就不详细的说了,当前这的意思是 viod playVedio(String a,boolean b);这样一个函数。
62     bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/zdl/VedioTest/VedioTest","playVedio","(Ljava/lang/String;Z)V");
63
64     //判断是否有这个函数
65     if (isHave) {
66         //取得Java函数结构体里的执行栈描述
67         JNIEnv* env = minfo.env;
68         CCLOG("zhangdongli*************FilePath:%s\n",filePath);
69         //将Lua里传过来的文件名转化为全路径。
70         char const * newFilePath = CCFileUtils::sharedFileUtils()->fullPathForFilename(filePath).c_str();
71         CCLOG("zhangdongli*************FileFullPath:%s\n",newFilePath);
72         //将c字符串转化为c++描述的java字符串,具体jni的java数据描述,大家百度。
73         jstring jfilePath = env->NewStringUTF(newFilePath);
74         //将是否可以跳过的c bool 转化为jni描述的java的boolean
75         jboolean jskip = skip;
76         //调用java的playVedio函数,将jfilePath和jskip传入。
77         minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID,jfilePath,jskip);
78     }else{
79         CCLOG("zhangdongli**************** not find playVedio(String a,Boolean b) function");
80     }
81 #else
82     //直接调用我们实现的IOSPlayVedio的播放函数,将this传入,作为播放完成的代理。
83     IOSPlayVedio::playVedio4iOS(filePath,this,skip);
84 #endif
85 }
86
87 #pragma mark - 播放回调
88
89 void VedioPlatform::moviePlaybackFinished(){
90     //判断是否指定了lua得回调函数
91     if(successCallBack > 0){
92         //通过cocos2d实现的Lua引擎,回调lua函数
93         CCLuaEngine * engine = (CCLuaEngine *)CCScriptEngineManager::sharedManager()->getScriptEngine();
94         //注意这个函数,版本不同 名称不同。
95         engine->executeEventWithArgs(successCallBack, CCArray::create());
96     }
97 }

解释,

2.1)静态变量 static VedioPlatform * shardObj = NULL;是保存了每次播放的VedioPlatform地址,类似于单体。

2.2)导入#include "IOSPlayVedio.h"头文件,将要调用它的playVedio4iOS函数。

2.3)在init函数里,retain shardObj变量,因为在cocos2d里是手动内存管理的,然后每次赋值之前要release,之所以没有在析构函数里做做最后的release是因为,一直不销毁它,只用程序关闭才销毁,那样系统会自动清理这个变量。

2.4)setSuccessPlayCallBack函数里只是简单的保存了Lua回调函数的地址。

2.5)play函数里首先依据平台宏判断是android还是iOS,具体实现大家看下代码,里边有注释

11.接下来是实现C++与lua的互调了。

Cocos2d-x Lua 播放视频(iOS&android)

时间: 2024-10-06 20:50:40

Cocos2d-x Lua 播放视频(iOS&android)的相关文章

android 播放视频

播放视频的两种方式: 使用VideoView播放视频(方便,推荐) 使用MediaPlayer和SurfaceView播放视频(早期的方式) 第一种方式: 使用VideoView播放视频的步骤如下: 在界面布局文件中定义VideoView组件,或在程序中创建VideoView组建 调用VideoView的如下两个方法加载指定视频 setVideoPath(String paht):加载path文件所代表的视频 setVideoURI(URI uri):加载uri所对应的视频 调用VideoVIe

Android使用TextureView播放视频

1.引言 如果你想显示一段在线视频或者任意的数据流比如视频或者OpenGL 场景,你可以用android中的TextureView做到. 1).TextureView的兄弟SurfaceView 应用程序的视频或者opengl内容往往是显示在一个特别的UI控件中:SurfaceView.SurfaceView的工作方式是创建一个置于应用窗口之后的新窗口.这种 方式的效率非常高,因为SurfaceView窗口刷新的时候不需要重绘应用程序的窗口(android普通窗口的视图绘制机制是一层一层的,任何

android 使用webview访问优酷无法播放视频的问题

在代码中加入 webview.getSettings().setJavaScriptEnabled(true);//支持js //webview.getSettings().setPluginsEnabled(true);//设置webview支持插件,已废弃 webview.settings.setPluginState(PluginState.ON); //设置webview支持插件 同时要在Manifest配置文件的application中加入 android:hardwareAccele

请教:Android正播放视频时的解码输出流如何获取?

============问题描述============ Android播放视频,经过解码器解码 获得数据流 再显示到屏幕上.请问这部分数据(解码器解码后的数据流)通过什么方法可以获取?  请教...  先谢谢啦 ============解决方案1============ 你是想录制视频? ============解决方案2============ 引用 3 楼 yu8fei 的回复: Quote: 引用 2 楼 sagittarius1988 的回复: 你是想录制视频? 不是,跟照相机录像机摄

Android VideoView简单播放视频

给Android VideoView一个文件目录,就可以直接播放智能设备中的视频文件,现在以播放事先用手机拍好并重命名的视频文件test.mp4为例.(1) 需要在布局文件中写一个ViedoView: 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 and

Android三种播放视频的方式

 分类: Android多媒体(12)  Android应用层(93)  版权声明:本文为博主原创文章,未经博主允许不得转载. 在Android中,我们有三种方式来实现视频的播放: 1.使用其自带的播放器.指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型. 2.使用VideoView来播放.在布局文件中使用VideoView结合MediaController来实现对其控制. 3.使用MediaPlayer类和SurfaceView来实现,这种方式很灵活. 1.

Android开发之使用VideoView播放视频

Android提供了 VideoView组件.它的作用与ImageView类似,仅仅是ImageView用于显示图片.而VideoView用于播放视频. 使用VideoView播放视频的过程例如以下: 1)        在界面布局文件里定义VideoView组件,或在程序中创建VideoView组件. 2)        调用VideoView的例如以下两个方法来载入指定视频. setVideoPath(String path):载入 path 文件所代表的视频. setVideoURI(Ur

Android OpenGL 播放视频学习

1, 初步接触Open GL: http://www.cnblogs.com/TerryBlog/archive/2010/07/09/1774475.html 使用GLSurfaceView和Render实现一个简单的三角形和正方形.其中,GLSurfaceView用于显示视图,Render用于3D渲染.这个博客的代码,运行时会报: java.lang.IllegalArgumentException: Must use a native order direct Buffer 是因为顶点Bu

Android实现播放视频

转载:http://www.bdqn.cn/news/201311/12100.shtml 使用VideoView播放视频 VideoView,用于播放一段视频媒体,它继承了SurfaceView,位于"android.widget.VideoView",是一个视频控件. 既然是播放一段视频,那么不可避免的要涉及到一些开始.暂停.停止等操作,VideoView也为开发人员提供了对应的方法,这里简单介绍一些常用的: int getCurrentPosition():获取当前播放的位置.