mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-11-24 06:47:34 +00:00
初始化
This commit is contained in:
296
cocos2d-x/cocos/ui/videoplayer/VideoPlayer-android.cpp
Normal file
296
cocos2d-x/cocos/ui/videoplayer/VideoPlayer-android.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "VideoPlayer.h"
|
||||
#include "base/CCLog.h"
|
||||
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
#include <unordered_map>
|
||||
#include <stdlib.h>
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
#include "platform/CCApplication.h"
|
||||
#include "platform/android/jni/JniHelper.h"
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "renderer/gfx/Texture2D.h"
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
|
||||
static const std::string videoHelperClassName = "org/cocos2dx/lib/Cocos2dxVideoHelper";
|
||||
|
||||
USING_NS_CC;
|
||||
|
||||
static void executeVideoCallback(int index,int event);
|
||||
|
||||
#define QUIT_FULLSCREEN 1000
|
||||
|
||||
extern "C" {
|
||||
void Java_org_cocos2dx_lib_Cocos2dxVideoHelper_nativeExecuteVideoCallback(JNIEnv * env, jobject obj, jint index,jint event) {
|
||||
executeVideoCallback(index,event);
|
||||
}
|
||||
}
|
||||
|
||||
int createVideoWidgetJNI()
|
||||
{
|
||||
JniMethodInfo t;
|
||||
int ret = -1;
|
||||
if (JniHelper::getStaticMethodInfo(t, videoHelperClassName.c_str(), "createVideoWidget", "()I")) {
|
||||
ret = t.env->CallStaticIntMethod(t.classID, t.methodID);
|
||||
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
|
||||
static std::unordered_map<int, VideoPlayer*> s_allVideoPlayers;
|
||||
static jobject s_jobj = nullptr;
|
||||
|
||||
VideoPlayer::VideoPlayer()
|
||||
: _videoPlayerIndex(-1)
|
||||
, _fullScreenEnabled(false)
|
||||
, _fullScreenDirty(false)
|
||||
, _keepAspectRatioEnabled(false)
|
||||
, _videoPixels(nullptr)
|
||||
, _texDataSize(0)
|
||||
, _maxDataLen(0)
|
||||
{
|
||||
_videoPlayerIndex = createVideoWidgetJNI();
|
||||
s_allVideoPlayers[_videoPlayerIndex] = this;
|
||||
|
||||
#if CC_VIDEOPLAYER_DEBUG_DRAW
|
||||
_debugDrawNode = DrawNode::create();
|
||||
addChild(_debugDrawNode);
|
||||
#endif
|
||||
|
||||
if(s_jobj == nullptr) {
|
||||
s_jobj = JniHelper::getEnv()->NewGlobalRef(JniHelper::newObject(videoHelperClassName.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
VideoPlayer::~VideoPlayer()
|
||||
{
|
||||
s_allVideoPlayers.erase(_videoPlayerIndex);
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "removeVideoWidget", _videoPlayerIndex);
|
||||
|
||||
if (_videoPixels != nullptr) free(_videoPixels);
|
||||
}
|
||||
|
||||
void VideoPlayer::setURL(const std::string& videoUrl)
|
||||
{
|
||||
if (videoUrl.find("://") == std::string::npos)
|
||||
{
|
||||
_videoURL = FileUtils::getInstance()->fullPathForFilename(videoUrl);
|
||||
_videoSource = VideoPlayer::Source::FILENAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
_videoURL = videoUrl;
|
||||
_videoSource = VideoPlayer::Source::URL;
|
||||
}
|
||||
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setVideoUrl", _videoPlayerIndex,
|
||||
(int)_videoSource,_videoURL);
|
||||
}
|
||||
|
||||
void VideoPlayer::VideoPlayer::setFrame(float x, float y, float width, float height)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setVideoRect", _videoPlayerIndex,
|
||||
(int)x, (int)y, (int)width, (int)height);
|
||||
}
|
||||
|
||||
void VideoPlayer::setFullScreenEnabled(bool enabled)
|
||||
{
|
||||
if (_fullScreenEnabled != enabled)
|
||||
{
|
||||
_fullScreenEnabled = enabled;
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setFullScreenEnabled", _videoPlayerIndex, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setKeepAspectRatioEnabled(bool enable)
|
||||
{
|
||||
if (_keepAspectRatioEnabled != enable)
|
||||
{
|
||||
_keepAspectRatioEnabled = enable;
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setVideoKeepRatioEnabled", _videoPlayerIndex, enable);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::play()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "startVideo", _videoPlayerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::pause()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "pauseVideo", _videoPlayerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::stop()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "stopVideo", _videoPlayerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::seekTo(float sec)
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "seekVideoTo", _videoPlayerIndex, int(sec * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setVisible(bool visible)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setVideoVisible", _videoPlayerIndex, visible);
|
||||
}
|
||||
|
||||
void VideoPlayer::addEventListener(const std::string& name, const VideoPlayer::ccVideoPlayerCallback& callback)
|
||||
{
|
||||
_eventCallback[name] = callback;
|
||||
}
|
||||
|
||||
void VideoPlayer::onPlayEvent(int event)
|
||||
{
|
||||
if (event == QUIT_FULLSCREEN)
|
||||
{
|
||||
_fullScreenEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
VideoPlayer::EventType videoEvent = (VideoPlayer::EventType)event;
|
||||
|
||||
|
||||
switch (videoEvent) {
|
||||
case EventType::PLAYING:
|
||||
_eventCallback["play"]();
|
||||
break;
|
||||
case EventType::PAUSED:
|
||||
_eventCallback["pause"]();
|
||||
break;
|
||||
case EventType::STOPPED:
|
||||
_eventCallback["stoped"]();
|
||||
break;
|
||||
case EventType::COMPLETED:
|
||||
_eventCallback["ended"]();
|
||||
break;
|
||||
case EventType::META_LOADED:
|
||||
_eventCallback["loadedmetadata"]();
|
||||
break;
|
||||
case EventType::CLICKED:
|
||||
_eventCallback["click"]();
|
||||
break;
|
||||
case EventType::READY_TO_PLAY:
|
||||
_eventCallback["suspend"]();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void executeVideoCallback(int index,int event)
|
||||
{
|
||||
auto it = s_allVideoPlayers.find(index);
|
||||
if (it != s_allVideoPlayers.end())
|
||||
{
|
||||
s_allVideoPlayers[index]->onPlayEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
float VideoPlayer::currentTime() const
|
||||
{
|
||||
return JniHelper::callStaticFloatMethod(videoHelperClassName, "getCurrentTime", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
float VideoPlayer::duration() const
|
||||
{
|
||||
return JniHelper::callStaticFloatMethod(videoHelperClassName, "getDuration", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
void VideoPlayer::getFrame() {
|
||||
jbyteArray arr = JniHelper::callObjectByteArrayMethod(s_jobj, videoHelperClassName, "getFrame", _videoPlayerIndex);
|
||||
if (arr == nullptr) return;
|
||||
jsize len = JniHelper::getEnv()->GetArrayLength(arr);
|
||||
if (len == 0) return;
|
||||
_texDataSize = len;
|
||||
if (len > _maxDataLen) {
|
||||
_maxDataLen = len;
|
||||
|
||||
if(_videoPixels != nullptr) free(_videoPixels);
|
||||
_videoPixels = (unsigned char*)malloc(len * sizeof(unsigned char));
|
||||
}
|
||||
|
||||
JniHelper::getEnv()->GetByteArrayRegion(arr, 0, len, reinterpret_cast<jbyte*>(_videoPixels));
|
||||
JniHelper::getEnv()->DeleteLocalRef(arr);
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameChannel() const {
|
||||
return (int)JniHelper::callObjectFloatMethod(s_jobj, videoHelperClassName, "getFrameChannel", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameWidth() const {
|
||||
return (int)JniHelper::callObjectFloatMethod(s_jobj, videoHelperClassName, "getFrameWidth", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameHeight() const {
|
||||
return (int)JniHelper::callObjectFloatMethod(s_jobj, videoHelperClassName, "getFrameHeight", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
int VideoPlayer::getVideoTexDataSize() const {
|
||||
return _texDataSize;
|
||||
}
|
||||
|
||||
void VideoPlayer::pushFrameDataToTexture2D(cocos2d::renderer::Texture* tex) const {
|
||||
if(tex == nullptr) log("Can't find texture!");
|
||||
else {
|
||||
if(_videoPixels != nullptr && getFrameWidth() > 0 && getFrameHeight() > 0) {
|
||||
renderer::Texture::SubImageOption opt(0, 0, getFrameWidth(), getFrameHeight(), 0, false,
|
||||
false);
|
||||
opt.imageData = _videoPixels;
|
||||
((cocos2d::renderer::Texture2D*)tex)->updateSubImage(opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setShowRawFrame(bool show) const {
|
||||
JniHelper::callObjectVoidMethod(s_jobj, videoHelperClassName, "setShowRawFrame", _videoPlayerIndex, show);
|
||||
}
|
||||
|
||||
void VideoPlayer::update() {
|
||||
//test
|
||||
}
|
||||
|
||||
#endif
|
||||
631
cocos2d-x/cocos/ui/videoplayer/VideoPlayer-ios.mm
Normal file
631
cocos2d-x/cocos/ui/videoplayer/VideoPlayer-ios.mm
Normal file
@@ -0,0 +1,631 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "VideoPlayer.h"
|
||||
|
||||
USING_NS_CC;
|
||||
|
||||
// No Available on tvOS
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS && !defined(CC_TARGET_OS_TVOS)
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
#import <AVKit/AVPlayerViewController.h>
|
||||
#import <CoreMedia/CMTime.h>
|
||||
#import <CoreVideo/CVPixelBuffer.h>
|
||||
|
||||
#include "platform/CCApplication.h"
|
||||
#include "platform/ios/CCEAGLView-ios.h"
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "renderer/gfx/Texture2D.h"
|
||||
|
||||
@interface UIVideoViewWrapperIos : NSObject
|
||||
|
||||
typedef NS_ENUM(NSInteger, PlayerbackState) {
|
||||
PlayerbackStateUnknown = 0,
|
||||
PlayerbackStatePaused,
|
||||
PlayerbackStopped,
|
||||
PlayerbackStatePlaying,
|
||||
PlayerbackStateCompleted
|
||||
};
|
||||
|
||||
@property (assign, nonatomic) AVPlayerViewController * playerController;
|
||||
|
||||
- (void) setFrame:(int) left :(int) top :(int) width :(int) height;
|
||||
- (void) setURL:(int) videoSource :(std::string&) videoUrl;
|
||||
- (void) play;
|
||||
- (void) pause;
|
||||
- (void) resume;
|
||||
- (void) stop;
|
||||
- (BOOL) isPlaying;
|
||||
- (void) seekTo:(float) sec;
|
||||
- (float) currentTime;
|
||||
- (float) duration;
|
||||
- (void) setVisible:(BOOL) visible;
|
||||
- (void) setKeepRatioEnabled:(BOOL) enabled;
|
||||
- (void) setFullScreenEnabled:(BOOL) enabled;
|
||||
- (void) showPlaybackControls:(BOOL) value;
|
||||
- (BOOL) isFullScreenEnabled;
|
||||
- (void) cleanup;
|
||||
-(id) init:(void*) videoPlayer;
|
||||
|
||||
- (unsigned char*) getFrame;
|
||||
- (bool) copyFinished;
|
||||
- (int) getFrameWidth;
|
||||
- (int) getFrameHeight;
|
||||
- (int) getFrameDataSize;
|
||||
- (int) getBitCount;
|
||||
- (void) setShowRaw:(BOOL) show;
|
||||
- (void) clearBuffers;
|
||||
|
||||
-(void) videoFinished:(NSNotification*) notification;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIVideoViewWrapperIos
|
||||
{
|
||||
int _left;
|
||||
int _top;
|
||||
int _width;
|
||||
int _height;
|
||||
bool _keepRatioEnabled;
|
||||
bool _fullscreen;
|
||||
CGRect _restoreRect;
|
||||
PlayerbackState _state;
|
||||
VideoPlayer* _videoPlayer;
|
||||
|
||||
int _frameWidth;
|
||||
int _frameHeight;
|
||||
int _frameDataSize;
|
||||
int _frameBitCount;
|
||||
unsigned char* _videoPixels;
|
||||
bool _finishCopy;
|
||||
}
|
||||
|
||||
-(id)init:(void*)videoPlayer
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_keepRatioEnabled = FALSE;
|
||||
_left = _top = _width = _height = 0;
|
||||
|
||||
[self initPlayerController];
|
||||
_videoPlayer = (VideoPlayer*)videoPlayer;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)initPlayerController
|
||||
{
|
||||
self.playerController = [AVPlayerViewController new];
|
||||
[self setFrame:_left :_top :_width :_height];
|
||||
[self showPlaybackControls:TRUE];
|
||||
[self setKeepRatioEnabled:_keepRatioEnabled];
|
||||
_state = PlayerbackStateUnknown;
|
||||
|
||||
_frameWidth = 0;
|
||||
_frameHeight = 0;
|
||||
_frameDataSize = 0;
|
||||
_frameBitCount = 1;
|
||||
_videoPixels = nullptr;
|
||||
_finishCopy = false;
|
||||
|
||||
[self setShowRaw:YES];
|
||||
}
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
if(_videoPixels != nullptr) free(_videoPixels);
|
||||
|
||||
_videoPlayer = nullptr;
|
||||
[self cleanup];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(void) setFrame:(int)left :(int)top :(int)width :(int)height
|
||||
{
|
||||
if (_left == left && _width == width && _top == top && _height == height)
|
||||
return;
|
||||
|
||||
_left = left;
|
||||
_width = width;
|
||||
_top = top;
|
||||
_height = height;
|
||||
[self.playerController.view setFrame:CGRectMake(left, top, width, height)];
|
||||
}
|
||||
|
||||
-(unsigned char*) getFrame
|
||||
{
|
||||
UInt32 type = kCVPixelFormatType_32BGRA;
|
||||
AVPlayerItem* item = self.playerController.player.currentItem;
|
||||
if(item.outputs.count == 0) {
|
||||
NSDictionary* settings = @{ (id)kCVPixelBufferPixelFormatTypeKey : @(type) };
|
||||
AVPlayerItemVideoOutput* output = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:settings];
|
||||
[item addOutput:output];
|
||||
}
|
||||
AVPlayerItemOutput* output = item.outputs[0];
|
||||
|
||||
CMTime time = self.playerController.player.currentTime;
|
||||
CVPixelBufferRef pixelBuffer = [output copyPixelBufferForItemTime:time itemTimeForDisplay:nil];
|
||||
|
||||
_frameBitCount = 4;
|
||||
_frameHeight = (int)CVPixelBufferGetHeight(pixelBuffer);
|
||||
_frameWidth = (int)CVPixelBufferGetBytesPerRow(pixelBuffer) / _frameBitCount;
|
||||
_frameDataSize = (int)CVPixelBufferGetDataSize(pixelBuffer);
|
||||
|
||||
if(_videoPixels == nullptr && _frameWidth > 0 && _frameHeight > 0) {
|
||||
_videoPixels = (unsigned char*)calloc(_frameDataSize, 1);
|
||||
}
|
||||
|
||||
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
|
||||
void* pixels = CVPixelBufferGetBaseAddress(pixelBuffer);
|
||||
if(_videoPixels != nullptr && pixels != nullptr) {
|
||||
memcpy(_videoPixels, pixels, _frameDataSize);
|
||||
_finishCopy = true;
|
||||
}
|
||||
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
|
||||
|
||||
return _videoPixels;
|
||||
}
|
||||
|
||||
-(bool) copyFinished
|
||||
{
|
||||
return _finishCopy;
|
||||
}
|
||||
|
||||
-(int) getFrameWidth
|
||||
{
|
||||
return _frameWidth;
|
||||
}
|
||||
|
||||
-(int) getFrameHeight
|
||||
{
|
||||
return _frameHeight;
|
||||
}
|
||||
|
||||
-(int) getFrameDataSize
|
||||
{
|
||||
return _frameDataSize;
|
||||
}
|
||||
|
||||
-(int) getBitCount
|
||||
{
|
||||
return _frameBitCount;
|
||||
}
|
||||
|
||||
-(void) setShowRaw:(BOOL) show
|
||||
{
|
||||
if(show == YES) {
|
||||
self.playerController.view.alpha = 1;
|
||||
} else {
|
||||
self.playerController.view.alpha = 0;
|
||||
}
|
||||
}
|
||||
|
||||
-(void) setFullScreenEnabled:(BOOL) enabled
|
||||
{
|
||||
// AVPlayerViewController doesn't provide API to enable fullscreen. But you can toggle
|
||||
// fullsreen by the playback controllers.
|
||||
}
|
||||
|
||||
-(BOOL) isFullScreenEnabled
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
-(BOOL) isPlaying
|
||||
{
|
||||
return (self.playerController.player && self.playerController.player.rate != 0);
|
||||
}
|
||||
|
||||
-(void) setURL:(int)videoSource :(std::string &)videoUrl
|
||||
{
|
||||
[self clearBuffers];
|
||||
[self cleanup];
|
||||
[self initPlayerController];
|
||||
|
||||
if (videoSource == 1)
|
||||
self.playerController.player = [[[AVPlayer alloc] initWithURL:[NSURL URLWithString:@(videoUrl.c_str())]] autorelease];
|
||||
else
|
||||
self.playerController.player = [[[AVPlayer alloc] initWithURL:[NSURL fileURLWithPath:@(videoUrl.c_str())]] autorelease];
|
||||
|
||||
[self registerPlayerEventListener];
|
||||
}
|
||||
|
||||
-(void) seekTo:(float)sec
|
||||
{
|
||||
if (self.playerController.player)
|
||||
[self.playerController.player seekToTime:CMTimeMake(sec * 600, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
|
||||
|
||||
}
|
||||
|
||||
-(float) currentTime
|
||||
{
|
||||
if (self.playerController.player)
|
||||
return CMTimeGetSeconds([self.playerController.player currentTime]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
-(float) duration
|
||||
{
|
||||
if (self.playerController.player)
|
||||
return CMTimeGetSeconds(self.playerController.player.currentItem.asset.duration);
|
||||
|
||||
return -1;;
|
||||
}
|
||||
|
||||
-(void) setVisible:(BOOL)visible
|
||||
{
|
||||
[self.playerController.view setHidden:!visible];
|
||||
if (!visible)
|
||||
[self pause];
|
||||
}
|
||||
|
||||
-(void) setKeepRatioEnabled:(BOOL)enabled
|
||||
{
|
||||
_keepRatioEnabled = enabled;
|
||||
if (_keepRatioEnabled)
|
||||
self.playerController.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||
else
|
||||
self.playerController.videoGravity = AVLayerVideoGravityResize;
|
||||
}
|
||||
|
||||
-(void) play
|
||||
{
|
||||
if (self.playerController.player && ![self isPlaying] ) {
|
||||
[self.playerController.player play];
|
||||
_state = PlayerbackStatePlaying;
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
-(void) pause
|
||||
{
|
||||
if ( [self isPlaying] ) {
|
||||
[self.playerController.player pause];
|
||||
_state = PlayerbackStatePaused;
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::PAUSED);
|
||||
}
|
||||
}
|
||||
|
||||
-(void) resume
|
||||
{
|
||||
if (self.playerController.player && _state == PlayerbackStatePaused)
|
||||
[self play];
|
||||
}
|
||||
|
||||
-(void) stop
|
||||
{
|
||||
// AVPlayer doesn't have `stop` method, so just pause it, and seek time to 0.
|
||||
if (self.playerController.player && _state != PlayerbackStopped) {
|
||||
[self seekTo:0];
|
||||
[self.playerController.player pause];
|
||||
_state = PlayerbackStopped;
|
||||
|
||||
// stop() will be invoked in dealloc, which is invoked by _videoPlayer's destructor,
|
||||
// so do't send the message when _videoPlayer is being deleted.
|
||||
if (_videoPlayer)
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
// Private functions
|
||||
-(void) clearBuffers
|
||||
{
|
||||
if(_videoPixels != nullptr) {
|
||||
free(_videoPixels);
|
||||
_videoPixels = nullptr;
|
||||
}
|
||||
|
||||
AVPlayerItem* item = self.playerController.player.currentItem;
|
||||
if(item.outputs.count > 0) {
|
||||
AVPlayerItemOutput* output = item.outputs[0];
|
||||
[item removeOutput:output];
|
||||
[output dealloc];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) cleanup
|
||||
{
|
||||
[self stop];
|
||||
[self removePlayerEventListener];
|
||||
[self.playerController.view removeFromSuperview];
|
||||
[self.playerController release];
|
||||
}
|
||||
|
||||
-(void) removePlayerEventListener {
|
||||
if (self.playerController.player)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:AVPlayerItemDidPlayToEndTimeNotification
|
||||
object:self.playerController.player.currentItem];
|
||||
|
||||
[self.playerController.player removeObserver:self forKeyPath:@"status"];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) registerPlayerEventListener
|
||||
{
|
||||
if (self.playerController.player)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(videoFinished:)
|
||||
name:AVPlayerItemDidPlayToEndTimeNotification
|
||||
object:self.playerController.player.currentItem];
|
||||
|
||||
[self.playerController.player addObserver:self forKeyPath:@"status" options:0 context:nil];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) showPlaybackControls:(BOOL)value
|
||||
{
|
||||
self.playerController.showsPlaybackControls = value;
|
||||
}
|
||||
|
||||
-(void) videoFinished:(NSNotification *)notification
|
||||
{
|
||||
if(_videoPlayer != nullptr) {
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::COMPLETED);
|
||||
_state = PlayerbackStateCompleted;
|
||||
|
||||
// Seek to 0 to make it playable again.
|
||||
[self seekTo:0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
|
||||
change:(NSDictionary *)change context:(void *)context {
|
||||
|
||||
auto player = self.playerController.player;
|
||||
if (object == player && [keyPath isEqualToString:@"status"]) {
|
||||
if (player.status == AVPlayerStatusReadyToPlay) {
|
||||
[self addPlayerControllerSubView];
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::META_LOADED);
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::READY_TO_PLAY);
|
||||
} else if (player.status == AVPlayerStatusFailed) {
|
||||
// something went wrong. player.error should contain some information
|
||||
NSLog(@"Failed to load video");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)addPlayerControllerSubView {
|
||||
auto eaglview = (CCEAGLView*)cocos2d::Application::getInstance()->getView();
|
||||
[eaglview addSubview:self.playerController.view];
|
||||
}
|
||||
|
||||
@end
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
|
||||
VideoPlayer::VideoPlayer()
|
||||
: _videoPlayerIndex(-1)
|
||||
, _fullScreenEnabled(false)
|
||||
, _fullScreenDirty(false)
|
||||
, _keepAspectRatioEnabled(false)
|
||||
{
|
||||
_videoView = [[UIVideoViewWrapperIos alloc] init:this];
|
||||
|
||||
#if CC_VIDEOPLAYER_DEBUG_DRAW
|
||||
_debugDrawNode = DrawNode::create();
|
||||
addChild(_debugDrawNode);
|
||||
#endif
|
||||
|
||||
_videoPixels = nullptr;
|
||||
_texDataSize = 0;
|
||||
_maxDataLen = 0;
|
||||
}
|
||||
|
||||
VideoPlayer::~VideoPlayer()
|
||||
{
|
||||
if(_videoView)
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) dealloc];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setURL(const std::string& videoUrl)
|
||||
{
|
||||
if (videoUrl.find("://") == std::string::npos)
|
||||
{
|
||||
_videoURL = FileUtils::getInstance()->fullPathForFilename(videoUrl);
|
||||
_videoSource = VideoPlayer::Source::FILENAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
_videoURL = videoUrl;
|
||||
_videoSource = VideoPlayer::Source::URL;
|
||||
}
|
||||
|
||||
[((UIVideoViewWrapperIos*)_videoView) setURL:(int)_videoSource :_videoURL];
|
||||
}
|
||||
|
||||
void VideoPlayer::setFullScreenEnabled(bool enabled)
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) setFullScreenEnabled:enabled];
|
||||
}
|
||||
|
||||
void VideoPlayer::setKeepAspectRatioEnabled(bool enable)
|
||||
{
|
||||
if (_keepAspectRatioEnabled != enable)
|
||||
{
|
||||
_keepAspectRatioEnabled = enable;
|
||||
[((UIVideoViewWrapperIos*)_videoView) setKeepRatioEnabled:enable];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::play()
|
||||
{
|
||||
if (! _videoURL.empty() && _isVisible)
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) play];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::pause()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) pause];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::stop()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) stop];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::seekTo(float sec)
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) seekTo:sec];
|
||||
}
|
||||
}
|
||||
|
||||
float VideoPlayer::currentTime()const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) currentTime];
|
||||
}
|
||||
|
||||
float VideoPlayer::duration()const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) duration];
|
||||
}
|
||||
|
||||
void VideoPlayer::setVisible(bool visible)
|
||||
{
|
||||
_isVisible = visible;
|
||||
|
||||
if (!visible)
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) setVisible:NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) setVisible:YES];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::addEventListener(const std::string& name, const VideoPlayer::ccVideoPlayerCallback& callback)
|
||||
{
|
||||
_eventCallback[name] = callback;
|
||||
}
|
||||
|
||||
void VideoPlayer::onPlayEvent(int event)
|
||||
{
|
||||
switch ((EventType)event) {
|
||||
case EventType::PLAYING:
|
||||
_eventCallback["play"]();
|
||||
break;
|
||||
case EventType::PAUSED:
|
||||
_eventCallback["pause"]();
|
||||
break;
|
||||
case EventType::STOPPED:
|
||||
_eventCallback["stoped"]();
|
||||
break;
|
||||
case EventType::COMPLETED:
|
||||
_eventCallback["ended"]();
|
||||
break;
|
||||
case EventType::META_LOADED:
|
||||
_eventCallback["loadedmetadata"]();
|
||||
break;
|
||||
case EventType::CLICKED:
|
||||
_eventCallback["click"]();
|
||||
break;
|
||||
case EventType::READY_TO_PLAY:
|
||||
_eventCallback["suspend"]();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setFrame(float x, float y, float width, float height)
|
||||
{
|
||||
auto eaglview = (CCEAGLView*)cocos2d::Application::getInstance()->getView();
|
||||
auto scaleFactor = [eaglview contentScaleFactor];
|
||||
[((UIVideoViewWrapperIos*)_videoView) setFrame:x/scaleFactor
|
||||
:y/scaleFactor
|
||||
:width/scaleFactor
|
||||
:height/scaleFactor];
|
||||
}
|
||||
|
||||
void VideoPlayer::getFrame()
|
||||
{
|
||||
_videoPixels = [((UIVideoViewWrapperIos*)_videoView) getFrame];
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameChannel() const
|
||||
{
|
||||
int res = VideoPlayer::PX_BGRA;
|
||||
return res;
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameWidth() const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) getFrameWidth];
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameHeight() const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) getFrameHeight];
|
||||
}
|
||||
|
||||
int VideoPlayer::getVideoTexDataSize() const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) getFrameDataSize];
|
||||
}
|
||||
|
||||
void VideoPlayer::update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VideoPlayer::pushFrameDataToTexture2D(cocos2d::renderer::Texture* tex) const
|
||||
{
|
||||
if(tex == nullptr) {
|
||||
printf("Can't find texture!\n");
|
||||
} else {
|
||||
bool finshCopy = [((UIVideoViewWrapperIos*)_videoView) copyFinished];
|
||||
if(_videoPixels != nullptr && getFrameWidth() > 0 && getFrameHeight() > 0 && finshCopy) {
|
||||
renderer::Texture::SubImageOption opt(0, 0, getFrameWidth(), getFrameHeight(), 0, false, false);
|
||||
opt.imageData = _videoPixels;
|
||||
((cocos2d::renderer::Texture2D*)tex)->updateSubImage(opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setShowRawFrame(bool show) const
|
||||
{
|
||||
if(show)
|
||||
[((UIVideoViewWrapperIos*)_videoView) setShowRaw: YES];
|
||||
else
|
||||
[((UIVideoViewWrapperIos*)_videoView) setShowRaw: NO];
|
||||
}
|
||||
|
||||
#endif
|
||||
211
cocos2d-x/cocos/ui/videoplayer/VideoPlayer.h
Normal file
211
cocos2d-x/cocos/ui/videoplayer/VideoPlayer.h
Normal file
@@ -0,0 +1,211 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/ccMacros.h"
|
||||
#include "base/CCData.h"
|
||||
#include "base/CCRef.h"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "renderer/gfx/Texture2D.h"
|
||||
|
||||
#ifndef OBJC_CLASS
|
||||
#ifdef __OBJC__
|
||||
#define OBJC_CLASS(name) @class name
|
||||
#else
|
||||
#define OBJC_CLASS(name) class name
|
||||
#endif
|
||||
#endif // OBJC_CLASS
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
/**
|
||||
* @class VideoPlayer
|
||||
* @brief Displays a video file.
|
||||
*
|
||||
* @note VideoPlayer displays a video file base on system widget.
|
||||
* It's mean VideoPlayer displays a video file above all graphical elements of cocos2d-x.
|
||||
* @js NA
|
||||
*/
|
||||
class VideoPlayer : public Ref
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Videoplayer play event type.
|
||||
*/
|
||||
enum class EventType
|
||||
{
|
||||
PLAYING = 0,
|
||||
PAUSED,
|
||||
STOPPED,
|
||||
COMPLETED,
|
||||
META_LOADED,
|
||||
CLICKED,
|
||||
READY_TO_PLAY
|
||||
};
|
||||
|
||||
VideoPlayer();
|
||||
|
||||
/**
|
||||
* A callback which will be called after specific VideoPlayer event happens.
|
||||
*/
|
||||
typedef std::function<void()> ccVideoPlayerCallback;
|
||||
|
||||
|
||||
/**
|
||||
* Sets a URL as a video source for VideoPlayer.
|
||||
*/
|
||||
virtual void setURL(const std::string &_videoURL);
|
||||
|
||||
/**
|
||||
* Starts playback.
|
||||
*/
|
||||
virtual void play();
|
||||
|
||||
/**
|
||||
* Pauses playback.
|
||||
*/
|
||||
virtual void pause();
|
||||
|
||||
/**
|
||||
* Stops playback.
|
||||
*/
|
||||
virtual void stop();
|
||||
|
||||
/**
|
||||
* Seeks to specified time position.
|
||||
*
|
||||
* @param sec The offset in seconds from the start to seek to.
|
||||
*/
|
||||
virtual void seekTo(float sec);
|
||||
|
||||
/**
|
||||
* Get the current play time, measure in seconds.
|
||||
*/
|
||||
float currentTime() const;
|
||||
|
||||
float duration() const;
|
||||
|
||||
/**
|
||||
* Get frame rgba pixel as bytes
|
||||
*/
|
||||
void getFrame();
|
||||
|
||||
int getFrameChannel() const;
|
||||
|
||||
int getFrameWidth() const;
|
||||
|
||||
int getFrameHeight() const;
|
||||
|
||||
int getVideoTexDataSize() const;
|
||||
|
||||
void update();
|
||||
|
||||
void pushFrameDataToTexture2D(cocos2d::renderer::Texture* tex) const;
|
||||
|
||||
void setShowRawFrame(bool show) const;
|
||||
|
||||
/**
|
||||
* Causes the video player to keep aspect ratio or no when displaying the video.
|
||||
*
|
||||
* @param enable Specify true to keep aspect ratio or false to scale the video until
|
||||
* both dimensions fit the visible bounds of the view exactly.
|
||||
*/
|
||||
virtual void setKeepAspectRatioEnabled(bool enable);
|
||||
|
||||
/**
|
||||
* Indicates whether the video player keep aspect ratio when displaying the video.
|
||||
*/
|
||||
virtual bool isKeepAspectRatioEnabled() const { return _keepAspectRatioEnabled; }
|
||||
|
||||
/**
|
||||
* Causes the video player to enter or exit full-screen mode.
|
||||
*
|
||||
* @param fullscreen Specify true to enter full-screen mode or false to exit full-screen mode.
|
||||
*/
|
||||
virtual void setFullScreenEnabled(bool fullscreen);
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when the video state is updated.
|
||||
*
|
||||
* @param callback The callback that will be run.
|
||||
*/
|
||||
virtual void addEventListener(const std::string& name, const VideoPlayer::ccVideoPlayerCallback& callback);
|
||||
|
||||
/**
|
||||
* @brief A function which will be called when video is playing.
|
||||
*
|
||||
* @param event @see VideoPlayer::EventType.
|
||||
*/
|
||||
virtual void onPlayEvent(int event);
|
||||
|
||||
/**
|
||||
* Toggle visibility of VideoPlayer.
|
||||
*/
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
/**
|
||||
* Set the rect of VideoPlayer.
|
||||
*/
|
||||
virtual void setFrame(float x, float y, float width, float height);
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~VideoPlayer();
|
||||
|
||||
protected:
|
||||
|
||||
enum class Source
|
||||
{
|
||||
FILENAME = 0,
|
||||
URL
|
||||
};
|
||||
|
||||
bool _isVisible;
|
||||
bool _fullScreenDirty;
|
||||
bool _fullScreenEnabled;
|
||||
bool _keepAspectRatioEnabled;
|
||||
|
||||
std::string _videoURL;
|
||||
Source _videoSource;
|
||||
|
||||
int _videoPlayerIndex;
|
||||
std::map<std::string, ccVideoPlayerCallback> _eventCallback;
|
||||
|
||||
void *_videoView;
|
||||
|
||||
int _texDataSize;
|
||||
|
||||
private:
|
||||
unsigned char* _videoPixels;
|
||||
int _maxDataLen;
|
||||
|
||||
static const int PX_RGBA = 3;
|
||||
static const int PX_RGB565 = 6;
|
||||
static const int PX_BGRA = 7;
|
||||
};
|
||||
|
||||
NS_CC_END
|
||||
Reference in New Issue
Block a user