123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- #import <UIKit/UIKit.h>
- #import <AVFoundation/AVFoundation.h>
- #import <AVKit/AVKit.h>
- #import <UIKit/UIGestureRecognizerSubclass.h>
- #include "UnityAppController.h"
- #include "UI/UnityView.h"
- #include "UI/UnityViewControllerBase.h"
- #include "UI/OrientationSupport.h"
- #include "UI/UnityAppController+ViewHandling.h"
- #include "Unity/ObjCRuntime.h"
- #include "Unity/VideoPlayer.h"
- #include "PluginBase/UnityViewControllerListener.h"
- @interface UICancelGestureRecognizer : UITapGestureRecognizer
- @end
- @interface AVKitVideoPlayback : NSObject<VideoPlayerDelegate, UIViewControllerTransitioningDelegate, UIGestureRecognizerDelegate>
- {
- AVPlayerViewController* videoViewController;
- VideoPlayer* videoPlayer;
- UIColor* bgColor;
- const NSString* videoGravity;
- BOOL showControls;
- BOOL cancelOnTouch;
- }
- - (void)onPlayerReady;
- - (void)onPlayerDidFinishPlayingVideo;
- - (id)initAndPlay:(NSURL*)url bgColor:(UIColor*)color showControls:(BOOL)controls videoGravity:(const NSString*)scaling cancelOnTouch:(BOOL)cot;
- - (void)actuallyStartTheMovie:(NSURL*)url;
- - (void)finish;
- @end
- static AVKitVideoPlayback* _AVKitVideoPlayback = nil;
- @implementation AVKitVideoPlayback
- #if PLATFORM_IOS
- static void AVPlayerViewController_SetAllowsPictureInPicturePlayback_OldIOSImpl(id self_, SEL _cmd, BOOL allow) {}
- static NSUInteger supportedInterfaceOrientations_DefaultImpl(id self_, SEL _cmd)
- {
- return GetAppController().rootViewController.supportedInterfaceOrientations;
- }
- static bool prefersStatusBarHidden_DefaultImpl(id self_, SEL _cmd)
- {
- if (_AVKitVideoPlayback) // video is still playing
- return _AVKitVideoPlayback->videoViewController.showsPlaybackControls ? NO : YES;
- else // video has beed stopped
- return GetAppController().rootViewController.prefersStatusBarHidden;
- }
- #endif
- + (void)initialize
- {
- if (self == [AVKitVideoPlayback class])
- {
- #if PLATFORM_IOS
- class_replaceMethod([AVPlayerViewController class], @selector(supportedInterfaceOrientations), (IMP)&supportedInterfaceOrientations_DefaultImpl, UIViewController_supportedInterfaceOrientations_Enc);
- class_replaceMethod([AVPlayerViewController class], @selector(prefersStatusBarHidden), (IMP)&prefersStatusBarHidden_DefaultImpl, UIViewController_prefersStatusBarHidden_Enc);
- #endif
- }
- }
- - (id)initAndPlay:(NSURL*)url bgColor:(UIColor*)color showControls:(BOOL)controls videoGravity:(const NSString*)scaling cancelOnTouch:(BOOL)cot
- {
- if ((self = [super init]))
- {
- UnityPause(1);
- showControls = controls;
- videoGravity = scaling;
- bgColor = color;
- cancelOnTouch = cot;
- [self performSelector: @selector(actuallyStartTheMovie:) withObject: url afterDelay: 0];
- }
- return self;
- }
- - (void)dealloc
- {
- [self finish];
- }
- - (void)actuallyStartTheMovie:(NSURL*)url
- {
- @autoreleasepool
- {
- videoViewController = [[AVPlayerViewController alloc] init];
- videoViewController.showsPlaybackControls = showControls;
- videoViewController.view.backgroundColor = bgColor;
- videoViewController.videoGravity = (NSString*)videoGravity;
- videoViewController.transitioningDelegate = self;
- #if PLATFORM_IOS
- videoViewController.allowsPictureInPicturePlayback = NO;
- #endif
- #if PLATFORM_TVOS
- // In tvOS clicking Menu button while video is playing will exit the app. So when
- // app disables exiting to menu behavior, we need to catch the click and ignore it.
- if (!UnityGetAppleTVRemoteAllowExitToMenu())
- {
- UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(handleTap:)];
- tapRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
- [videoViewController.view addGestureRecognizer: tapRecognizer];
- }
- #endif
- if (cancelOnTouch)
- {
- UICancelGestureRecognizer *cancelTouch = [[UICancelGestureRecognizer alloc] initWithTarget: self action: @selector(handleTap:)];
- cancelTouch.delegate = self;
- [videoViewController.view addGestureRecognizer: cancelTouch];
- }
- videoPlayer = [[VideoPlayer alloc] init];
- videoPlayer.delegate = self;
- [videoPlayer loadVideo: url];
- }
- }
- - (void)handleTap:(UITapGestureRecognizer*)sender
- {
- if (cancelOnTouch && (sender.state == UIGestureRecognizerStateEnded))
- [self finish];
- }
- - (void)onPlayerReady
- {
- videoViewController.player = videoPlayer.player;
- CGSize screenSize = GetAppController().rootView.bounds.size;
- BOOL ret = [VideoPlayer CheckScalingModeAspectFill: videoPlayer.videoSize screenSize: screenSize];
- if (ret == YES && [videoViewController.videoGravity isEqualToString: AVLayerVideoGravityResizeAspect] == YES)
- {
- videoViewController.videoGravity = AVLayerVideoGravityResizeAspectFill;
- }
- [videoPlayer playVideoPlayer];
- #if PLATFORM_TVOS
- GetAppController().window.rootViewController = videoViewController;
- #else
- UIViewController *viewController = [GetAppController() topMostController];
- if ([viewController isEqual: videoViewController] == NO && [videoViewController isBeingPresented] == NO)
- [viewController presentViewController: videoViewController animated: NO completion: nil];
- #endif
- }
- - (void)onPlayerDidFinishPlayingVideo
- {
- [self finish];
- }
- - (void)onPlayerTryResume
- {
- if (![videoPlayer isPlaying])
- [videoPlayer resume];
- }
- - (void)onPlayerError:(NSError*)error
- {
- [self finish];
- }
- - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
- {
- if ([dismissed isEqual: videoViewController] == YES)
- {
- [self finish];
- }
- return nil;
- }
- - (void)finish
- {
- @synchronized(self)
- {
- #if PLATFORM_TVOS
- GetAppController().window.rootViewController = GetAppController().rootViewController;
- #else
- UIViewController *viewController = [GetAppController() topMostController];
- if ([viewController isEqual: videoViewController] == YES && [viewController isBeingDismissed] == NO)
- [viewController dismissViewControllerAnimated: NO completion: nil];
- #endif
- [videoPlayer unloadPlayer];
- videoPlayer = nil;
- videoViewController = nil;
- _AVKitVideoPlayback = nil;
- #if PLATFORM_TVOS
- UnityCancelTouches();
- #endif
- if (UnityIsPaused())
- UnityPause(0);
- }
- }
- @end
- @implementation UICancelGestureRecognizer
- //instead of having lots of UITapGestureRecognizers with different finger numbers
- - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- {
- [self setState: UIGestureRecognizerStateRecognized];
- }
- @end
- extern "C" void UnityPlayFullScreenVideo(const char* path, const float* color, unsigned controls, unsigned scaling)
- {
- const BOOL cancelOnTouch[] = { NO, NO, YES, NO };
- UIColor* bgColor = [UIColor colorWithRed: color[0] green: color[1] blue: color[2] alpha: color[3]];
- const bool isURL = ::strstr(path, "://") != 0;
- NSURL* url = nil;
- if (isURL)
- {
- url = [NSURL URLWithString: [NSString stringWithUTF8String: path]];
- }
- else
- {
- NSString* relPath = path[0] == '/' ? [NSString stringWithUTF8String: path] : [NSString stringWithFormat: @"Data/Raw/%s", path];
- NSString* fullPath = [[NSString stringWithUTF8String: UnityDataBundleDir()] stringByAppendingPathComponent: relPath];
- url = [NSURL fileURLWithPath: fullPath];
- }
- const BOOL showControls[] = { YES, YES, NO, NO };
- const NSString* videoGravity[] =
- {
- AVLayerVideoGravityResizeAspectFill, // ???
- AVLayerVideoGravityResizeAspect,
- AVLayerVideoGravityResizeAspectFill,
- AVLayerVideoGravityResize,
- };
- if (_AVKitVideoPlayback)
- [_AVKitVideoPlayback finish];
- _AVKitVideoPlayback = [[AVKitVideoPlayback alloc] initAndPlay: url bgColor: bgColor
- showControls: showControls[controls] videoGravity: videoGravity[scaling] cancelOnTouch: cancelOnTouch[controls]];
- }
- extern "C" void UnityStopFullScreenVideoIfPlaying()
- {
- if (_AVKitVideoPlayback)
- [_AVKitVideoPlayback finish];
- }
- extern "C" int UnityIsFullScreenPlaying()
- {
- return _AVKitVideoPlayback ? 1 : 0;
- }
- extern "C" void TryResumeFullScreenVideo()
- {
- if (_AVKitVideoPlayback)
- [_AVKitVideoPlayback onPlayerTryResume];
- }
|