Commit ffc3b9ab authored by Felix Paul Kühne's avatar Felix Paul Kühne

playback: split any non-UI logic from the view controller to a designated global instance

parent 371d0a05
......@@ -31,6 +31,7 @@
#import "VLCAlertView.h"
#import <BoxSDK/BoxSDK.h>
#import "VLCNotificationRelay.h"
#import "VLCPlaybackController.h"
#define HAVE_FABRIC 0
......@@ -541,20 +542,23 @@
{
if (!_movieViewController)
_movieViewController = [[VLCMovieViewController alloc] initWithNibName:nil bundle:nil];
else
[_movieViewController unanimatedPlaybackStop];
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
if ([mediaObject isKindOfClass:[MLFile class]])
_movieViewController.fileFromMediaLibrary = (MLFile *)mediaObject;
vpc.fileFromMediaLibrary = (MLFile *)mediaObject;
else if ([mediaObject isKindOfClass:[MLAlbumTrack class]])
_movieViewController.fileFromMediaLibrary = [(MLAlbumTrack*)mediaObject files].anyObject;
vpc.fileFromMediaLibrary = [(MLAlbumTrack*)mediaObject files].anyObject;
else if ([mediaObject isKindOfClass:[MLShowEpisode class]])
_movieViewController.fileFromMediaLibrary = [(MLShowEpisode*)mediaObject files].anyObject;
[(MLFile *)_movieViewController.fileFromMediaLibrary setUnread:@(NO)];
vpc.fileFromMediaLibrary = [(MLShowEpisode*)mediaObject files].anyObject;
[(MLFile *)vpc.fileFromMediaLibrary setUnread:@(NO)];
vpc.delegate = _movieViewController;
UINavigationController *navCon = [[VLCPlaybackNavigationController alloc] initWithRootViewController:_movieViewController];
navCon.modalPresentationStyle = UIModalPresentationFullScreen;
[self.window.rootViewController presentViewController:navCon animated:YES completion:nil];
[vpc startPlayback];
}
- (void)openMovieFromURL:(NSURL *)url
......@@ -564,13 +568,18 @@
if (!_movieViewController)
_movieViewController = [[VLCMovieViewController alloc] initWithNibName:nil bundle:nil];
_movieViewController.url = url;
_movieViewController.successCallback = successCallback;
_movieViewController.errorCallback = errorCallback;
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
vpc.url = url;
vpc.successCallback = successCallback;
vpc.errorCallback = errorCallback;
vpc.delegate = _movieViewController;
UINavigationController *navCon = [[VLCPlaybackNavigationController alloc] initWithRootViewController:_movieViewController];
navCon.modalPresentationStyle = UIModalPresentationFullScreen;
[self.window.rootViewController presentViewController:navCon animated:YES completion:nil];
[vpc startPlayback];
}
- (void)openMovieFromURL:(NSURL *)url
......@@ -583,13 +592,18 @@
if (!_movieViewController)
_movieViewController = [[VLCMovieViewController alloc] initWithNibName:nil bundle:nil];
_movieViewController.mediaList = list;
_movieViewController.itemInMediaListToBePlayedFirst = index;
_movieViewController.pathToExternalSubtitlesFile = nil;
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
vpc.mediaList = list;
vpc.itemInMediaListToBePlayedFirst = index;
vpc.pathToExternalSubtitlesFile = nil;
vpc.delegate = _movieViewController;
UINavigationController *navCon = [[VLCPlaybackNavigationController alloc] initWithRootViewController:_movieViewController];
navCon.modalPresentationStyle = UIModalPresentationFullScreen;
[self.window.rootViewController presentViewController:navCon animated:YES completion:nil];
[vpc startPlayback];
}
- (void)openMovieWithExternalSubtitleFromURL:(NSURL *)url externalSubURL:(NSString *)SubtitlePath
......@@ -597,12 +611,17 @@
if (!_movieViewController)
_movieViewController = [[VLCMovieViewController alloc] initWithNibName:nil bundle:nil];
_movieViewController.url = url;
_movieViewController.pathToExternalSubtitlesFile = SubtitlePath;
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
vpc.url = url;
vpc.pathToExternalSubtitlesFile = SubtitlePath;
vpc.delegate = _movieViewController;
UINavigationController *navCon = [[VLCPlaybackNavigationController alloc] initWithRootViewController:_movieViewController];
navCon.modalPresentationStyle = UIModalPresentationFullScreen;
[self.window.rootViewController presentViewController:navCon animated:YES completion:nil];
[vpc startPlayback];
}
#pragma mark - watch struff
......@@ -658,14 +677,14 @@
- (NSDictionary *)nowPlayingResponseDict {
NSMutableDictionary *response = [NSMutableDictionary new];
NSMutableDictionary *nowPlayingInfo = [[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo mutableCopy];
NSNumber *playbackTime = [_movieViewController mediaPlayer].time.numberValue;
NSNumber *playbackTime = [VLCPlaybackController sharedInstance].mediaPlayer.time.numberValue;
if (playbackTime) {
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = @(playbackTime.floatValue/1000);
}
if (nowPlayingInfo) {
response[@"nowPlayingInfo"] = nowPlayingInfo;
}
MLFile *currentFile = _movieViewController.currentlyPlayingMediaFile;
MLFile *currentFile = [VLCPlaybackController sharedInstance].currentlyPlayingMediaFile;
NSString *URIString = currentFile.objectID.URIRepresentation.absoluteString;
if (URIString) {
response[@"URIRepresentation"] = URIString;
......
......@@ -25,10 +25,18 @@
@end
@protocol VLCEqualizerViewUIDelegate <NSObject>
@optional
- (void)equalizerViewReceivedUserInput;
@end
@interface VLCEqualizerView : VLCFrostedGlasView <UITableViewDataSource,UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@property (weak) id <VLCEqualizerViewDelegate>delegate;
@property (weak) id <VLCEqualizerViewUIDelegate>UIdelegate;
- (void)reloadData;
......
......@@ -268,12 +268,16 @@
{
if (self.delegate)
[self.delegate setAmplification:[sender value] forBand:(unsigned)[sender tag]];
if ([self.UIdelegate respondsToSelector:@selector(equalizerViewReceivedUserInput)])
[self.UIdelegate equalizerViewReceivedUserInput];
}
- (IBAction)preampSliderChangedValue:(VLCSlider *)sender
{
if (self.delegate)
[self.delegate setPreAmplification:sender.value];
if ([self.UIdelegate respondsToSelector:@selector(equalizerViewReceivedUserInput)])
[self.UIdelegate equalizerViewReceivedUserInput];
}
- (void)reloadData
......
......@@ -13,13 +13,14 @@
#import <MediaPlayer/MediaPlayer.h>
#import "VLCFrostedGlasView.h"
#import "VLCPlaybackController.h"
@class OBSlider;
@class VLCStatusLabel;
@class VLCHorizontalSwipeGestureRecognizer;
@class VLCVerticalSwipeGestureRecognizer;
@interface VLCMovieViewController : UIViewController <VLCMediaPlayerDelegate, UIActionSheetDelegate>
@interface VLCMovieViewController : UIViewController <UIActionSheetDelegate, VLCPlaybackControllerDelegate>
@property (nonatomic, strong) IBOutlet UIView *movieView;
@property (nonatomic, strong) IBOutlet UIBarButtonItem *backButton;
......@@ -84,20 +85,7 @@
@property (nonatomic, strong) IBOutlet UILabel *trackNameLabel;
@property (nonatomic, strong) IBOutlet UIImageView *artworkImageView;
@property (nonatomic, strong) MLFile *fileFromMediaLibrary;
@property (nonatomic, strong) NSURL *url;
@property (nonatomic, strong) NSURL *successCallback;
@property (nonatomic, strong) NSURL *errorCallback;
@property (nonatomic, strong) NSString *pathToExternalSubtitlesFile;
@property (nonatomic, retain) VLCMediaList *mediaList;
@property (nonatomic, strong) VLCMediaPlayer *mediaPlayer;
@property (nonatomic, readwrite) int itemInMediaListToBePlayedFirst;
/* returns nil if currenlty plaing item is not a MLFile, e.g. a url */
@property (nonatomic, strong, readonly) MLFile *currentlyPlayingMediaFile;
- (IBAction)closePlayback:(id)sender;
- (void)unanimatedPlaybackStop;
- (IBAction)positionSliderAction:(id)sender;
- (IBAction)positionSliderTouchDown:(id)sender;
......
This diff is collapsed.
/*****************************************************************************
* VLCPlaybackController.h
* VLC for iOS
*****************************************************************************
* Copyright (c) 2013-2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Felix Paul Kühne <fkuehne # videolan.org>
* Tobias Conradi <videolan # tobias-conradi.de>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "VLCEqualizerView.h"
@class VLCPlaybackController;
@protocol VLCPlaybackControllerDelegate <NSObject>
- (void)playbackPositionUpdated:(VLCPlaybackController *)controller;
- (void)playbackRateUpdated:(float)rate forPlaybackController:(VLCPlaybackController *)controller;
- (void)mediaPlayerStateChanged:(VLCMediaPlayerState)currentState
isPlaying:(BOOL)isPlaying
currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
currentMediaHasChapters:(BOOL)currentMediaHasChapters
forPlaybackController:(VLCPlaybackController *)controller;
- (void)prepareForMediaPlayback:(VLCPlaybackController *)controller;
- (void)presentingViewControllerShouldBeClosed:(VLCPlaybackController *)controller;
- (void)presentingViewControllerShouldBeClosedAfterADelay:(VLCPlaybackController *)controller;
- (void)showStatusMessage:(NSString *)statusMessage forPlaybackController:(VLCPlaybackController *)controller;
- (void)audioOnlyPlaybackWasDetected:(BOOL)audioOnly forPlaybackController:(VLCPlaybackController *)controller;
- (void)displayMetadataForPlaybackController:(VLCPlaybackController *)controller
title:(NSString *)title
artwork:(UIImage *)artwork
artist:(NSString *)artist
album:(NSString *)album
audioOnly:(BOOL)audioOnly;
@end
@interface VLCPlaybackController : NSObject <VLCEqualizerViewDelegate>
@property (nonatomic, readonly) VLCMediaListPlayer *listPlayer;
@property (nonatomic, readonly) VLCMediaPlayer *mediaPlayer;
@property (nonatomic, strong) UIView *videoOutputView;
@property (nonatomic, strong) MLFile *fileFromMediaLibrary;
@property (nonatomic, strong) NSURL *url;
@property (nonatomic, strong) NSURL *successCallback;
@property (nonatomic, strong) NSURL *errorCallback;
@property (nonatomic, strong) NSString *pathToExternalSubtitlesFile;
@property (nonatomic, retain) VLCMediaList *mediaList;
@property (nonatomic, readwrite) int itemInMediaListToBePlayedFirst;
/* returns nil if currenlty plaing item is not a MLFile, e.g. a url */
@property (nonatomic, strong, readonly) MLFile *currentlyPlayingMediaFile;
@property (nonatomic, weak) id<VLCPlaybackControllerDelegate> delegate;
@property (nonatomic, readonly) VLCMediaPlayerState mediaPlayerState;
@property (nonatomic, readonly) NSInteger mediaDuration;
@property (nonatomic, readonly) BOOL isPlaying;
@property (nonatomic, readwrite) VLCRepeatMode repeatMode;
@property (nonatomic, readwrite) float playbackRate;
@property (nonatomic, readonly) BOOL currentMediaHasChapters;
@property (nonatomic, readonly) BOOL currentMediaHasTrackToChooseFrom;
+ (VLCPlaybackController *)sharedInstance;
- (void)startPlayback;
- (void)stopPlayback;
- (void)playPause;
- (void)forward;
- (void)backward;
- (void)switchAspectRatio;
- (void)recoverDisplayedMetadata;
@end
/*****************************************************************************
* VLCPlaybackController.m
* VLC for iOS
*****************************************************************************
* Copyright (c) 2013-2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Felix Paul Kühne <fkuehne # videolan.org>
* Carola Nitz <caro # videolan.org>
* Gleb Pinigin <gpinigin # gmail.com>
* Pierre Sagaspe <pierre.sagaspe # me.com>
* Tobias Conradi <videolan # tobias-conradi.de>
* Sylver Bruneau <sylver.bruneau # gmail dot com>
* Winston Weinert <winston # ml1 dot net>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "VLCPlaybackController.h"
#import <CommonCrypto/CommonDigest.h>
#import "UIDevice+VLC.h"
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import "VLCThumbnailsCache.h"
#import <WatchKit/WatchKit.h>
@interface VLCPlaybackController () <AVAudioSessionDelegate, VLCMediaPlayerDelegate, VLCMediaDelegate>
{
BOOL _playerIsSetup;
BOOL _playbackFailed;
BOOL _shouldResumePlaying;
NSArray *_aspectRatios;
NSUInteger _currentAspectRatioMask;
float _currentPlaybackRate;
UIView *_videoOutputViewWrapper;
UIView *_actualVideoOutputView;
/* cached stuff for the VC */
NSString *_title;
UIImage *_artworkImage;
NSString *_artist;
NSString *_albumName;
BOOL _mediaIsAudioOnly;
}
@end
@implementation VLCPlaybackController
#pragma mark instance management
+ (VLCPlaybackController *)sharedInstance
{
static VLCPlaybackController *sharedInstance = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
sharedInstance = [self new];
});
return sharedInstance;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - playback management
- (BOOL)_blobCheck
{
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *directoryPath = searchPaths[0];
if (![[NSFileManager defaultManager] fileExistsAtPath:[directoryPath stringByAppendingPathComponent:@"blob.bin"]])
return NO;
NSData *data = [NSData dataWithContentsOfFile:[directoryPath stringByAppendingPathComponent:@"blob.bin"]];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, (unsigned int)data.length, digest);
NSMutableString *hash = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for (unsigned int u = 0; u < CC_SHA1_DIGEST_LENGTH; u++)
[hash appendFormat:@"%02x", digest[u]];
if ([hash isEqualToString:kBlobHash])
return YES;
else
return NO;
}
- (BOOL)_isMediaSuitableForDevice
{
if (!self.fileFromMediaLibrary)
return YES;
NSUInteger totalNumberOfPixels = [[[self.fileFromMediaLibrary videoTrack] valueForKey:@"width"] doubleValue] * [[[self.fileFromMediaLibrary videoTrack] valueForKey:@"height"] doubleValue];
NSInteger speedCategory = [[UIDevice currentDevice] speedCategory];
if (speedCategory == 1) {
// iPhone 3GS, iPhone 4, first gen. iPad, 3rd and 4th generation iPod touch
return (totalNumberOfPixels < 600000); // between 480p and 720p
} else if (speedCategory == 2) {
// iPhone 4S, iPad 2 and 3, iPod 4 and 5
return (totalNumberOfPixels < 922000); // 720p
} else if (speedCategory == 3) {
// iPhone 5, iPad 4
return (totalNumberOfPixels < 2074000); // 1080p
} else if (speedCategory == 4) {
// iPhone 6, 2014 iPads
return (totalNumberOfPixels < 8850000); // 4K
}
return YES;
}
- (void)startPlayback
{
if (_playerIsSetup)
return;
[[AVAudioSession sharedInstance] setDelegate:self];
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self selector:@selector(audioSessionRouteChange:)
name:AVAudioSessionRouteChangeNotification object:nil];
[defaultCenter addObserver:self selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification object:nil];
[defaultCenter addObserver:self selector:@selector(applicationDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification object:nil];
[defaultCenter addObserver:self selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification object:nil];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
_aspectRatios = @[@"DEFAULT", @"FILL_TO_SCREEN", @"4:3", @"16:9", @"16:10", @"2.21:1"];
if (!self.fileFromMediaLibrary && !self.url && !self.mediaList) {
[self stopPlayback];
return;
}
if (self.pathToExternalSubtitlesFile)
_listPlayer = [[VLCMediaListPlayer alloc] initWithOptions:@[[NSString stringWithFormat:@"--%@=%@", kVLCSettingSubtitlesFilePath, self.pathToExternalSubtitlesFile]]];
else
_listPlayer = [[VLCMediaListPlayer alloc] init];
/* video decoding permanently fails if we don't provide a UIView to draw into on init
* hence we provide one which is not attached to any view controller for off-screen drawing
* and disable video decoding once playback started */
_actualVideoOutputView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
_actualVideoOutputView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_actualVideoOutputView.autoresizesSubviews = YES;
_mediaPlayer = _listPlayer.mediaPlayer;
[_mediaPlayer setDelegate:self];
[_mediaPlayer setDrawable:_actualVideoOutputView];
if ([[defaults objectForKey:kVLCSettingPlaybackSpeedDefaultValue] floatValue] != 0)
[_mediaPlayer setRate: [[defaults objectForKey:kVLCSettingPlaybackSpeedDefaultValue] floatValue]];
if ([[defaults objectForKey:kVLCSettingDeinterlace] intValue] != 0)
[_mediaPlayer setDeinterlaceFilter:@"blend"];
else
[_mediaPlayer setDeinterlaceFilter:nil];
if (self.pathToExternalSubtitlesFile)
[_mediaPlayer openVideoSubTitlesFromFile:self.pathToExternalSubtitlesFile];
VLCMedia *media;
if (self.fileFromMediaLibrary) {
MLFile *item = self.fileFromMediaLibrary;
media = [VLCMedia mediaWithURL:[NSURL URLWithString:item.url]];
media.delegate = self;
} else if (self.mediaList) {
media = [self.mediaList mediaAtIndex:self.itemInMediaListToBePlayedFirst];
media.delegate = self;
} else {
media = [VLCMedia mediaWithURL:self.url];
media.delegate = self;
[media parse];
}
NSMutableDictionary *mediaDictionary = [[NSMutableDictionary alloc] init];
[mediaDictionary setObject:[defaults objectForKey:kVLCSettingNetworkCaching] forKey:kVLCSettingNetworkCaching];
[mediaDictionary setObject:[[defaults objectForKey:kVLCSettingStretchAudio] boolValue] ? kVLCSettingStretchAudioOnValue : kVLCSettingStretchAudioOffValue forKey:kVLCSettingStretchAudio];
[mediaDictionary setObject:[defaults objectForKey:kVLCSettingTextEncoding] forKey:kVLCSettingTextEncoding];
[mediaDictionary setObject:[defaults objectForKey:kVLCSettingSkipLoopFilter] forKey:kVLCSettingSkipLoopFilter];
#if 0
[NSTimeZone resetSystemTimeZone];
NSString *tzName = [[NSTimeZone systemTimeZone] name];
NSArray *tzNames = @[@"America/Adak", @"America/Anchorage", @"America/Boise", @"America/Chicago", @"America/Denver", @"America/Detroit", @"America/Indiana/Indianapolis", @"America/Indiana/Knox", @"America/Indiana/Marengo", @"America/Indiana/Petersburg", @"America/Indiana/Tell_City", @"America/Indiana/Vevay", @"America/Indiana/Vincennes", @"America/Indiana/Winamac", @"America/Juneau", @"America/Kentucky/Louisville", @"America/Kentucky/Monticello", @"America/Los_Angeles", @"America/Menominee", @"America/Metlakatla", @"America/New_York", @"America/Nome", @"America/North_Dakota/Beulah", @"America/North_Dakota/Center", @"America/North_Dakota/New_Salem", @"America/Phoenix", @"America/Puerto_Rico", @"America/Shiprock", @"America/Sitka", @"America/St_Thomas", @"America/Thule", @"America/Yakutat", @"Pacific/Guam", @"Pacific/Honolulu", @"Pacific/Johnston", @"Pacific/Kwajalein", @"Pacific/Midway", @"Pacific/Pago_Pago", @"Pacific/Saipan", @"Pacific/Wake"];
if ([tzNames containsObject:tzName] || [[tzName stringByDeletingLastPathComponent] isEqualToString:@"US"]) {
NSArray *tracksInfo = media.tracksInformation;
for (NSUInteger x = 0; x < tracksInfo.count; x++) {
if ([[tracksInfo[x] objectForKey:VLCMediaTracksInformationType] isEqualToString:VLCMediaTracksInformationTypeAudio])
{
NSInteger fourcc = [[tracksInfo[x] objectForKey:VLCMediaTracksInformationCodec] integerValue];
switch (fourcc) {
case 540161377:
case 1647457633:
case 858612577:
case 862151027:
case 862151013:
case 1684566644:
case 2126701:
{
if (![self _blobCheck]) {
[mediaDictionary setObject:[NSNull null] forKey:@"no-audio"];
APLog(@"audio playback disabled because an unsupported codec was found");
}
break;
}
default:
break;
}
}
}
}
#endif
if (self.mediaList) {
VLCMediaList *list = self.mediaList;
NSUInteger count = list.count;
for (NSUInteger x = 0; x < count; x++)
[[list mediaAtIndex:x] addOptions:mediaDictionary];
[_listPlayer setMediaList:self.mediaList];
} else {
[media addOptions:mediaDictionary];
[_listPlayer setRootMedia:media];
}
[_listPlayer setRepeatMode:VLCDoNotRepeat];
if (![self _isMediaSuitableForDevice]) {
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"DEVICE_TOOSLOW_TITLE", nil) message:[NSString stringWithFormat:NSLocalizedString(@"DEVICE_TOOSLOW", nil), [[UIDevice currentDevice] model], self.fileFromMediaLibrary.title] delegate:self cancelButtonTitle:NSLocalizedString(@"BUTTON_CANCEL", nil) otherButtonTitles:NSLocalizedString(@"BUTTON_OPEN", nil), nil];
[alert show];
} else
[self _playNewMedia];
}
- (void)_playNewMedia
{
NSNumber *playbackPositionInTime = @(0);
CGFloat lastPosition = .0;
NSInteger duration = 0;
MLFile *matchedFile;
// Set last selected equalizer profile
unsigned int profile = (unsigned int)[[[NSUserDefaults standardUserDefaults] objectForKey:kVLCSettingEqualizerProfile] integerValue];
[_mediaPlayer resetEqualizerFromProfile:profile];
[_mediaPlayer setPreAmplification:[_mediaPlayer preAmplification]];
if (self.fileFromMediaLibrary)
matchedFile = self.fileFromMediaLibrary;
else if (self.mediaList) {
/* TODO: move this code to MLKit */
NSString *path = [[[self.mediaList mediaAtIndex:self.itemInMediaListToBePlayedFirst] url] absoluteString];
NSString *componentString = @"";
NSArray *pathComponents = [path componentsSeparatedByString:@"/"];
NSUInteger componentCount = pathComponents.count;
if ([pathComponents[componentCount - 2] isEqualToString:@"Documents"])
componentString = [path lastPathComponent];
else {
NSUInteger firstElement = [pathComponents indexOfObject:@"Documents"] + 1;
for (NSUInteger x = 0; x < componentCount - firstElement; x++) {
if (x == 0)
componentString = [componentString stringByAppendingFormat:@"%@", pathComponents[firstElement + x]];
else
componentString = [componentString stringByAppendingFormat:@"/%@", pathComponents[firstElement + x]];
}
}
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSManagedObjectContext *moc = [[MLMediaLibrary sharedMediaLibrary] managedObjectContext];
if (moc) {
NSEntityDescription *entity = [NSEntityDescription entityForName:@"File" inManagedObjectContext:moc];
[request setEntity:entity];
[request setPredicate:[NSPredicate predicateWithFormat:@"url CONTAINS %@", componentString]];
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
[request setSortDescriptors:@[descriptor]];
NSArray *matches = [moc executeFetchRequest:request error:nil];
if (matches.count > 0)
matchedFile = matches[0];
}
}
if (matchedFile.lastPosition)
lastPosition = matchedFile.lastPosition.floatValue;
duration = matchedFile.duration.intValue;
if (lastPosition < .95) {
if (duration != 0)
playbackPositionInTime = @(lastPosition * (duration / 1000.));
}
if (playbackPositionInTime.intValue > 0 && (duration * lastPosition - duration) < -60000) {
[_mediaPlayer.media addOptions:@{@"start-time": playbackPositionInTime}];
APLog(@"set starttime to %i", playbackPositionInTime.intValue);
}
[_mediaPlayer addObserver:self forKeyPath:@"time" options:0 context:nil];
[_mediaPlayer addObserver:self forKeyPath:@"remainingTime" options:0 context:nil];
if (self.mediaList)
[_listPlayer playItemAtIndex:self.itemInMediaListToBePlayedFirst];
else
[_listPlayer playMedia:_listPlayer.rootMedia];
if (matchedFile) {
if (matchedFile.lastAudioTrack.intValue > 0)
_mediaPlayer.currentAudioTrackIndex = matchedFile.lastAudioTrack.intValue;
if (matchedFile.lastSubtitleTrack.intValue > 0)
_mediaPlayer.currentVideoSubTitleIndex = matchedFile.lastSubtitleTrack.intValue;
}
if ([self.delegate respondsToSelector:@selector(prepareForMediaPlayback:)])
[self.delegate prepareForMediaPlayback:self];
_currentAspectRatioMask = 0;
_mediaPlayer.videoAspectRatio = NULL;
/* some demuxers don't respect :start-time, so re-try here */
if (lastPosition < .95 && _mediaPlayer.position < lastPosition && (duration * lastPosition - duration) < -60000)
_mediaPlayer.position = lastPosition;
[self subscribeRemoteCommands];
_playerIsSetup = YES;
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
[self _playNewMedia];
else {
[self stopPlayback];
}
}
- (void)stopPlayback
{
if (_mediaPlayer) {
@try {
[_mediaPlayer removeObserver:self forKeyPath:@"time"];
[_mediaPlayer removeObserver:self forKeyPath:@"remainingTime"];
}
@catch (NSException *exception) {
APLog(@"we weren't an observer yet");
}
if (_mediaPlayer.media) {
[_mediaPlayer pause];
[self _savePlaybackState];
[_mediaPlayer stop];
}
if (_mediaPlayer)
_mediaPlayer = nil;
if (_listPlayer)
_listPlayer = nil;
}
if (_fileFromMediaLibrary)
_fileFromMediaLibrary = nil;
if (_mediaList)
_mediaList = nil;
if (_url)
_url = nil;
if (_pathToExternalSubtitlesFile) {
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:_pathToExternalSubtitlesFile])
[fileManager removeItemAtPath:_pathToExternalSubtitlesFile error:nil];
_pathToExternalSubtitlesFile = nil;
}
_playerIsSetup = NO;
if (self.errorCallback && _playbackFailed)
[[UIApplication sharedApplication] openURL:self.errorCallback];
else if (self.successCallback)
[[UIApplication sharedApplication] openURL:self.successCallback];
if ([self.delegate respondsToSelector:@selector(presentingViewControllerShouldBeClosed:)])
[self.delegate presentingViewControllerShouldBeClosed:self];
}
- (void)_savePlaybackState
{
if (self.fileFromMediaLibrary) {
@try {
MLFile *item = self.fileFromMediaLibrary;
item.lastPosition = @([_mediaPlayer position]);
item.lastAudioTrack = @(_mediaPlayer.currentAudioTrackIndex);
item.lastSubtitleTrack = @(_mediaPlayer.currentVideoSubTitleIndex);
}
@catch (NSException *exception) {
APLog(@"failed to save current media state - file removed?");
}
} else {
NSArray *files = [MLFile fileForURL:[[_mediaPlayer.media url] absoluteString]];
if (files.count > 0) {
MLFile *fileFromList = files[0];
fileFromList.lastPosition = @([_mediaPlayer position]);
fileFromList.lastAudioTrack = @(_mediaPlayer.currentAudioTrackIndex);
fileFromList.lastSubtitleTrack = @(_mediaPlayer.currentVideoSubTitleIndex);
}
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([self.delegate respondsToSelector:@selector(playbackPositionUpdated:)])
[self.delegate playbackPositionUpdated:self];
}
- (NSInteger)mediaDuration
{
return _listPlayer.mediaPlayer.media.length.intValue;;
}
- (BOOL)isPlaying
{
return _mediaPlayer.isPlaying;
}
- (VLCRepeatMode)repeatMode
{
return _listPlayer.repeatMode;
}
- (void)setRepeatMode:(VLCRepeatMode)repeatMode
{
_listPlayer.repeatMode = repeatMode;