Cocos2dx播放mp4文件(IOS和Android)
来源:互联网 发布:深入理解大数据微盘 编辑:程序博客网 时间:2024/04/29 08:09
http://blog.csdn.net/tyxkzzf/article/details/39081045
(头注:Cocos2d-x3.2引擎已经集成了MP4播放功能了,本篇文章写于2.x版本)
游戏需要播放mp4文件展示游戏背景,在网上搜了好久,IOS平台比较容易实现,Android就不敢恭维了;
播放mp4需要分平台实现,悲催的是IOS和Android的原生开发都没有做过,所以只能从网上找资料;
目前实现的功能播放,跳过和播放完成之后回到游戏,IOS和Android一样都已经实现;
1、IOS实现:
首先,参考文章:点击打开链接,我是完全按照这篇文章的介绍做的,里面有源代码地址,相信各位了看了之后就回明白,至少也有方向了;
- 类说明:
- LHVideoPlayerImplCpp.h/mm
- LHVideoPlayerImpl.h/m
- LHVideoPlayer.h/m
- LHVideoOverlayView.h/m
我就功能点而言,介绍其中的两个类。第一个是LHVideoPlayerImplCpp.h/mm文件,这个是负责给2dx调用的。该类有两个静态方法:- class LHVideoPlayerImplCpp {
- public:
-
-
-
-
-
- static void playMP4WithName(const char* name, cocos2d::Rect frameRect);
-
-
-
-
- static void setSkipTitle(const char* title);
- };
第二个是LHVideoPlayer.h/m,这个是负责播放MP4。a、这个方法是播放MP4。注释很清楚。- - (void)playMP4WithName: (NSString *)name VideoFrame:(CGRect)rect
- {
- UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
-
-
- NSString *url = [[NSBundle mainBundle]pathForResource:name ofType:@"mp4"];
-
- _player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:url]];
- [keyWindow.rootViewController.view addSubview: [_player view]];
-
-
- [_player setControlStyle: MPMovieControlStyleNone];
- [[_player view] setFrame: rect];
-
-
- [[NSNotificationCenter defaultCenter]
- addObserver:self selector:@selector(movieFinishedCallback:)
- name:MPMoviePlayerPlaybackDidFinishNotification object:_player];
-
-
- [_player play];
-
-
- _videoOverlayView = [ [LHVideoOverlayView alloc] initWithFrame: rect];
- [keyWindow.rootViewController.view addSubview: _videoOverlayView];
- }
b、这个方法是播放结束之后,移除播放view。- - (void)removePlayer:(MPMoviePlayerController*)player
- {
- [[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:player];
-
- [player.view removeFromSuperview];
- [_player release];
- _player = nil;
-
- [_videoOverlayView removeFromSuperview];
- [_videoOverlayView release];
- _videoOverlayView = nil;
- }
3、播放完成,通知外界。playerPlayFinished 这个方法是空的,没有通知外界。我看了下,感觉没什么需要,所以没加。(原作者没加,不过考虑到我播放的mp4是挂在一个layer里面实现的,所以还是希望在播放结束的时候该layer能知道;所以,我另外添加了一个函数):
- bool LHVideoPlayerImplCpp::getFinshState() {
- return [LHVideoPlayerImpl getFinshState];
- }
至于里面调用的函数就不写了,用于获取视频已经播放结束,然后在layer的visit里面处理:- void ShowMovieStart::visit() {
- GUILayer::visit();
- bool isfinish = false;
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
-
- #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
- isfinish = LHVideoPlayerImplCpp::getFinshState();
- #endif
- if (isfinish) {
- CCLog("视频播放结束了");
-
- }
- }
注意看ios实现的部分,当视频结束时,做相关处理;使用方法:
a、导入头文件
- #include “LHVideoPlayerImplCpp.h”
b、开始调用接口,假设你要播放的是“loading.mp4”- Size visibleSize = Director::getInstance()->getVisibleSize();
- LHVideoPlayerImplCpp::playMP4WithName(“loading”, Rect(0, 0, visibleSize.width, visibleSize.height));
- LHVideoPlayerImplCpp::setSkipTitle(“Skip”);
c、影片结束之后,会自动移除视图;git地址:点击打开链接
IOS实现相对于Android来说比较容易,而且上诉源代码还提供了跳过功能,非常不错;
2、Android部分,这个比较复杂,一开始我根本不知道从何下手,只能从网上找,但是相关资料也不是很多,而且大多数不容易解决问题,有些可能是写给Android老手看的,像我Android开发只见皮毛者完全云里雾里,不过,看得资料多了,代码还是可以理解的,虽然有时候一知半解,但还是一步步实现了;之前只用过C++和脚本,lua Js什么的,java代码也没写过,不过语言从来不是问题,主要的是原理。
a、首先,如何把mp4播放出来;
视频播放Veiw实现VideoView.java文件:
- package org.cocos2dx.common;
-
- import java.io.FileDescriptor;
- import java.io.IOException;
-
- import android.app.Activity;
- import android.content.res.AssetFileDescriptor;
- import android.media.MediaPlayer;
- import android.net.Uri;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.view.View;
-
- public class VideoView extends SurfaceView implements
- SurfaceHolder.Callback,
- View.OnTouchListener,
- MediaPlayer.OnPreparedListener,
- MediaPlayer.OnErrorListener,
- MediaPlayer.OnInfoListener,
- MediaPlayer.OnCompletionListener {
- private static final String TAG = "VideoView";
-
- private MediaPlayer mPlayer = null;
- private Activity gameActivity;
- private Uri resUri;
- private AssetFileDescriptor fd;
- private boolean surfaceCreated;
- private OnFinishListener onFinishListener;
-
- public VideoView(Activity context) {
- super(context);
- this.gameActivity = context;
- final SurfaceHolder holder = getHolder();
- holder.addCallback(this);
- holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- setOnTouchListener(this);
- if (mPlayer != null) {
- mPlayer.reset();
- mPlayer.release();
- mPlayer = null;
- }
- mPlayer = new MediaPlayer();
-
- mPlayer = new MediaPlayer();
- mPlayer.setScreenOnWhilePlaying(true);
- mPlayer.setOnPreparedListener(this);
- mPlayer.setOnCompletionListener(this);
- mPlayer.setOnErrorListener(this);
- mPlayer.setOnInfoListener(this);
-
-
-
- }
-
- public VideoView setOnFinishListener(OnFinishListener onFinishListener) {
- this.onFinishListener = onFinishListener;
- return this;
- }
-
- public void setVideo(Uri resUri) {
- this.resUri = resUri;
- try {
- mPlayer.setDataSource(gameActivity, resUri);
- } catch (Exception e) {
- }
- }
-
- public void setVideo(AssetFileDescriptor fd) {
- this.fd = fd;
-
- try {
- mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-
- }
-
- @Override
- public void surfaceCreated(final SurfaceHolder holder) {
- Log.i(TAG, "surfaceCreated");
-
- surfaceCreated = true;
-
- mPlayer.setDisplay(holder);
- try {
- mPlayer.prepare();
- } catch (Exception e1) {
-
- }
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.i(TAG, "surfaceDestroyed");
- surfaceCreated = false;
-
- if(mPlayer != null){
- mPlayer.stop();
- mPlayer.reset();
- }
- }
-
- @Override
- public void onPrepared(MediaPlayer player) {
- Log.i(TAG, "onPrepared");
-
- int wWidth = getWidth();
- int wHeight = getHeight();
-
-
- int vWidth = mPlayer.getVideoWidth();
- int vHeight = mPlayer.getVideoHeight();
-
-
- float wRatio = (float) vWidth / (float) wWidth;
- float hRatio = (float) vHeight / (float) wHeight;
- float ratio = Math.max(wRatio, hRatio);
- vWidth = (int) Math.ceil((float) vWidth / ratio);
- vHeight = (int) Math.ceil((float) vHeight / ratio);
-
-
- getHolder().setFixedSize(vWidth, vHeight);
- mPlayer.seekTo(posttion);
- mPlayer.start();
- }
-
- private void dispose() {
- mPlayer.release();
- mPlayer = null;
- resUri = null;
- if (fd != null) {
- try {
- fd.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- fd = null;
- }
- }
-
- @Override
- public void onCompletion(MediaPlayer mp) {
- Log.i(TAG, "onCompletion");
-
- dispose();
-
- if(onFinishListener != null)
- onFinishListener.onVideoFinish();
- }
-
- @Override
- public boolean onInfo(MediaPlayer mp, int what, int extra) {
- return true;
- }
-
- @Override
- public boolean onError(MediaPlayer mp, int what, int extra) {
- return true;
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
-
-
- }
-
- return true;
- }
-
- public void stop() {
- mPlayer.stop();
- dispose();
- if(onFinishListener != null) {
- onFinishListener.onVideoFinish();
- }
- }
-
- int posttion;
- public void pause() {
- posttion = mPlayer.getCurrentPosition();
- mPlayer.pause();
- }
-
-
-
-
- public void resume() {
- if(surfaceCreated){
- mPlayer.start();
- }else {
- try {
- if(resUri != null)
- mPlayer.setDataSource(gameActivity, resUri);
- else if (fd != null) {
- mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
- }
- } catch (Exception e) {
- }
- }
- }
-
- public interface OnFinishListener {
- public void onVideoFinish();
- }
- }
主要用到MediaPlayer来实现,至于MediaPlayer怎么用,我刚开始也不大懂,从网上找资料,很多,有兴趣google之,这里实现了一个视频播放的主要功能,另外有停止(跳过)的功能;下面是PlayeVideo文件:
其中XXXX是继承之Cocos2dxActivity的实例,用SetActivity方法,将之传进来,播放PlayVideo,传一个视频文件名,这里需要用到JNI,C++调用java函数,网上也是一大堆的资料,知之为知之,不知百度之,再不知谷歌之,然后就可以实现实现游戏的播放了,注意在VideoView中实现了,播放完成之后会将试图从viewgourp中移除;到这一步还比较简单,由于之前没有做过Android原生开发,所以连怎么添加一个button都不知道(跳过按钮),不过了解了一下之后,还是实现了,虽然代码不知道写得合不合理;
-
- Context mContext = ShenMoJie.getContext();
-
- LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- layout = inflater.inflate(R.layout.video, null);
-
- viewgroup.addView(layout);
-
- skipbtn = (Button)layout.findViewById(R.id.skipbutton);
- skipbtn.setOnClickListener(listener);
-
- int width = instance.getWindowManager().getDefaultDisplay().getWidth();
- int height = instance.getWindowManager().getDefaultDisplay().getHeight();
- System.out.println("width: "+width+"height: "+height);
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)skipbtn.getLayoutParams();
-
- params.setMargins(width*5/6, 10, 0, 0);
- skipbtn.setLayoutParams(params);
详情请看PlayVideo文件,下面是vidio.xml- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent">
- <Button android:text="@string/video_skip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/skipbutton" />
- </LinearLayout>
就这样,Android版也实现了播放跳过功能; 0 0