From 9d228353438a39381009af1d7bee456ced012da6 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 8 Aug 2018 13:56:11 -0700 Subject: [PATCH 1/8] Rework logic for extension detection --- ios/VideoCaching/RCTVideoCache.m | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ios/VideoCaching/RCTVideoCache.m b/ios/VideoCaching/RCTVideoCache.m index 4f23a1132a..d4d922c2cd 100644 --- a/ios/VideoCaching/RCTVideoCache.m +++ b/ios/VideoCaching/RCTVideoCache.m @@ -105,7 +105,7 @@ - (NSString *)generateCacheKeyForUri:(NSString *)uri { NSString * pathExtension = [uriWithoutQueryParams pathExtension]; NSArray * supportedExtensions = @[@"m4v", @"mp4", @"mov"]; - if ([supportedExtensions containsObject:pathExtension] == NO) { + if ([pathExtension isEqualToString:@""]) { NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"Missing file extension.", nil), NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"Missing file extension.", nil), @@ -114,11 +114,12 @@ - (NSString *)generateCacheKeyForUri:(NSString *)uri { NSError *error = [NSError errorWithDomain:@"RCTVideoCache" code:RCTVideoCacheStatusMissingFileExtension userInfo:userInfo]; @throw error; - } else if ([pathExtension isEqualToString:@"m3u8"]) { + } else if (![supportedExtensions containsObject:pathExtension]) { + // Notably, we don't currently support m3u8 (HLS playlists) NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: NSLocalizedString(@"Missing file extension.", nil), - NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"Missing file extension.", nil), - NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Missing file extension.", nil) + NSLocalizedDescriptionKey: NSLocalizedString(@"Unsupported file extension.", nil), + NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"Unsupported file extension.", nil), + NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Unsupported file extension.", nil) }; NSError *error = [NSError errorWithDomain:@"RCTVideoCache" code:RCTVideoCacheStatusUnsupportedFileExtension userInfo:userInfo]; From 8084b160d5c48bd0874ee2d16b0318c8d6721a9e Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 8 Aug 2018 15:34:07 -0700 Subject: [PATCH 2/8] Code style cleanups --- ios/VideoCaching/RCTVideoCache.m | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/ios/VideoCaching/RCTVideoCache.m b/ios/VideoCaching/RCTVideoCache.m index d4d922c2cd..1a2b83a53b 100644 --- a/ios/VideoCaching/RCTVideoCache.m +++ b/ios/VideoCaching/RCTVideoCache.m @@ -7,8 +7,7 @@ @implementation RCTVideoCache @synthesize cacheIdentifier; @synthesize temporaryCachePath; -+ (RCTVideoCache *) sharedInstance -{ ++ (RCTVideoCache *)sharedInstance { static RCTVideoCache *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -41,9 +40,8 @@ - (id)init { return self; } -- (void) createTemporaryPath -{ - NSError * error = nil; +- (void) createTemporaryPath { + NSError *error = nil; BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:self.temporaryCachePath withIntermediateDirectories:YES attributes:nil @@ -77,19 +75,19 @@ - (void)storeItem:(NSData *)data forUri:(NSString *)uri withCallback:(void(^)(BO } - (AVURLAsset *)getItemFromTemporaryStorage:(NSString *)key { - NSString * temporaryFilePath =[self.temporaryCachePath stringByAppendingPathComponent:key]; + NSString * temporaryFilePath = [self.temporaryCachePath stringByAppendingPathComponent:key]; BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:temporaryFilePath]; if (!fileExists) { return nil; } - NSURL * assetUrl = [[NSURL alloc] initFileURLWithPath:temporaryFilePath]; + NSURL *assetUrl = [[NSURL alloc] initFileURLWithPath:temporaryFilePath]; AVURLAsset *asset = [AVURLAsset URLAssetWithURL:assetUrl options:nil]; return asset; } - (BOOL)saveDataToTemporaryStorage:(NSData *)data key:(NSString *)key { - NSString * temporaryFilePath = [self.temporaryCachePath stringByAppendingPathComponent:key]; + NSString *temporaryFilePath = [self.temporaryCachePath stringByAppendingPathComponent:key]; [data writeToFile:temporaryFilePath atomically:YES]; return YES; } @@ -159,7 +157,7 @@ - (void)getItemForUri:(NSString *)uri withCallback:(void(^)(RCTVideoCacheStatus, } } -- (NSString *) generateHashForUrl:(NSString *)string { +- (NSString *)generateHashForUrl:(NSString *)string { const char *cStr = [string UTF8String]; unsigned char result[CC_MD5_DIGEST_LENGTH]; CC_MD5( cStr, (CC_LONG)strlen(cStr), result ); From 86d655c3d1c8a81f6b841d7379ba624903440b32 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 8 Aug 2018 15:37:18 -0700 Subject: [PATCH 3/8] Refactor to move caching code into a single block --- ios/Video/RCTVideo.h | 3 +- ios/Video/RCTVideo.m | 132 +++++++++++++++++++++++++------------------ 2 files changed, 80 insertions(+), 55 deletions(-) diff --git a/ios/Video/RCTVideo.h b/ios/Video/RCTVideo.h index 0028c3f70b..b2296c5d84 100644 --- a/ios/Video/RCTVideo.h +++ b/ios/Video/RCTVideo.h @@ -7,7 +7,8 @@ #if __has_include() #import -#import "DVURLAsset.h" +#import +#import #endif @class RCTEventDispatcher; diff --git a/ios/Video/RCTVideo.m b/ios/Video/RCTVideo.m index 7c98707b6b..68c04e8369 100644 --- a/ios/Video/RCTVideo.m +++ b/ios/Video/RCTVideo.m @@ -15,6 +15,12 @@ static int const RCTVideoUnset = -1; +#ifdef DEBUG + #define DebugLog(...) NSLog(__VA_ARGS__) +#else + #define DebugLog(...) (void)0 +#endif + @implementation RCTVideo { AVPlayer *_player; @@ -25,6 +31,7 @@ @implementation RCTVideo BOOL _playerLayerObserverSet; AVPlayerViewController *_playerViewController; NSURL *_videoURL; + AVURLAsset *_testAsset; /* Required to publish events */ RCTEventDispatcher *_eventDispatcher; @@ -312,7 +319,7 @@ - (void)setSrc:(NSDictionary *)source [self removePlayerTimeObserver]; [self removePlayerItemObservers]; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) 0), dispatch_get_main_queue(), ^{ // perform on next run loop, otherwise other passed react-props may not be set [self playerItemForSource:source withCallback:^(AVPlayerItem * playerItem) { @@ -337,7 +344,7 @@ - (void)setSrc:(NSDictionary *)source [self addPlayerTimeObserver]; //Perform on next run loop, otherwise onVideoLoadStart is nil - if(self.onVideoLoadStart) { + if (self.onVideoLoadStart) { id uri = [source objectForKey:@"uri"]; id type = [source objectForKey:@"type"]; self.onVideoLoadStart(@{@"src": @{ @@ -362,7 +369,7 @@ - (NSURL*) urlFilePath:(NSString*) filepath { NSString* relativeFilePath = [filepath lastPathComponent]; // the file may be multiple levels below the documents directory NSArray* fileComponents = [filepath componentsSeparatedByString:@"Documents/"]; - if (fileComponents.count>1) { + if (fileComponents.count > 1) { relativeFilePath = [fileComponents objectAtIndex:1]; } @@ -373,12 +380,13 @@ - (NSURL*) urlFilePath:(NSString*) filepath { return nil; } -- (void)playerItemPrepareText:(AVAsset *)asset assetOptions:(NSMutableDictionary * __nullable)assetOptions withCallback:(void(^)(AVPlayerItem *))handler +- (void)playerItemPrepareText:(AVAsset *)asset assetOptions:(NSDictionary * __nullable)assetOptions withCallback:(void(^)(AVPlayerItem *))handler { if (!_textTracks) { handler([AVPlayerItem playerItemWithAsset:asset]); return; } + // sideload text tracks AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; @@ -430,53 +438,29 @@ - (void)playerItemForSource:(NSDictionary *)source withCallback:(void(^)(AVPlaye NSString *uri = [source objectForKey:@"uri"]; NSString *type = [source objectForKey:@"type"]; - NSURL *url = (isNetwork || isAsset) ? - [NSURL URLWithString:uri] : - [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]]; + NSURL *url = isNetwork || isAsset + ? [NSURL URLWithString:uri] + : [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]]; NSMutableDictionary *assetOptions = [[NSMutableDictionary alloc] init]; if (isNetwork) { -#if __has_include() - [_videoCache getItemForUri:uri withCallback:^(RCTVideoCacheStatus videoCacheStatus, AVAsset * _Nullable cachedAsset) { - switch (videoCacheStatus) { - case RCTVideoCacheStatusMissingFileExtension: { -#ifdef DEBUG - NSLog(@"Could not generate cache key for uri '%@'. It is currently not supported to cache urls that do not include a file extension. The video file will not be cached. Checkout https://github.com/react-native-community/react-native-video/blob/master/docs/caching.md.", uri); -#endif - AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; - [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; - return; - } - case RCTVideoCacheStatusUnsupportedFileExtension: { -#ifdef DEBUG - NSLog(@"Could not generate cache key for uri '%@'. The file extension of that uri is currently not supported. The video file will not be cached. Checkout https://github.com/react-native-community/react-native-video/blob/master/docs/caching.md.", uri); -#endif - AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; - [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; - return; - } - default: - if (cachedAsset) { - [self playerItemPrepareText:cachedAsset assetOptions:assetOptions withCallback:handler]; - return; - } - } -#endif + /* Per #1091, this is not a public API. + * We need to either get approval from Apple to use this or use a different approach. + NSDictionary *headers = [source objectForKey:@"requestHeaders"]; + if ([headers count] > 0) { + [assetOptions setObject:headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"]; + } + */ NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; [assetOptions setObject:cookies forKey:AVURLAssetHTTPCookiesKey]; #if __has_include() - DVURLAsset *asset = [[DVURLAsset alloc] initWithURL:url options:assetOptions networkTimeout: 10000]; - asset.loaderDelegate = self; + [self playerItemForSourceUsingCache:uri assetOptions:assetOptions withCallback:handler]; #else AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; -#endif [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; -#if __has_include() - }]; #endif return; - } - else if (isAsset) { + } else if (isAsset) { AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil]; [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; return; @@ -486,6 +470,60 @@ - (void)playerItemForSource:(NSDictionary *)source withCallback:(void(^)(AVPlaye [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; } +#if __has_include() + +- (void)playerItemForSourceUsingCache:(NSString *)uri assetOptions:(NSDictionary *)options withCallback:(void(^)(AVPlayerItem *))handler { + NSURL *url = [NSURL URLWithString:uri]; + [_videoCache getItemForUri:uri withCallback:^(RCTVideoCacheStatus videoCacheStatus, AVAsset * _Nullable cachedAsset) { + switch (videoCacheStatus) { + case RCTVideoCacheStatusMissingFileExtension: { + DebugLog(@"Could not generate cache key for uri '%@'. It is currently not supported to cache urls that do not include a file extension. The video file will not be cached. Checkout https://github.com/react-native-community/react-native-video/blob/master/docs/caching.md", uri); + AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:options]; + [self playerItemPrepareText:asset assetOptions:options withCallback:handler]; + return; + } + case RCTVideoCacheStatusUnsupportedFileExtension: { + DebugLog(@"Could not generate cache key for uri '%@'. The file extension of that uri is currently not supported. The video file will not be cached. Checkout https://github.com/react-native-community/react-native-video/blob/master/docs/caching.md", uri); + AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:options]; + [self playerItemPrepareText:asset assetOptions:options withCallback:handler]; + return; + } + default: + if (cachedAsset) { + DebugLog(@"Playing back uri '%@' from cache", uri); + [self playerItemPrepareText:cachedAsset assetOptions:options withCallback:handler]; + return; + } + } + + /* + DVURLAsset *asset = [[DVURLAsset alloc] initWithURL:url options:options networkTimeout:10000]; + asset.loaderDelegate = self; + */ + + DVAssetLoaderDelegate *resourceLoaderDelegate = [[DVAssetLoaderDelegate alloc] initWithURL:url]; + resourceLoaderDelegate.delegate = self; + NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO]; + components.scheme = [DVAssetLoaderDelegate scheme]; + AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[components URL] options:options]; + [asset.resourceLoader setDelegate:resourceLoaderDelegate queue:dispatch_get_main_queue()]; + + [self playerItemPrepareText:asset assetOptions:options withCallback:handler]; + }]; +} + +#pragma mark - DVAssetLoaderDelegate + +- (void)dvAssetLoaderDelegate:(DVAssetLoaderDelegate *)loaderDelegate + didLoadData:(NSData *)data + forURL:(NSURL *)url { + [_videoCache storeItem:data forUri:[url absoluteString] withCallback:^(BOOL success) { + DebugLog(@"Cache data stored successfully 🎉"); + }]; +} + +#endif + - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == _playerItem) { @@ -1153,20 +1191,6 @@ - (void)removePlayerLayer _playerLayer = nil; } -#if __has_include() -#pragma mark - DVAssetLoaderDelegate -- (void)dvAssetLoaderDelegate:(DVAssetLoaderDelegate *)loaderDelegate - didLoadData:(NSData *)data - forURL:(NSURL *)url { - [_videoCache storeItem:data forUri:[url absoluteString] withCallback:^(BOOL success) { -#ifdef DEBUG - NSLog(@"data stored succesfully 🎉"); -#endif - }]; -} - -#endif - #pragma mark - RCTVideoPlayerViewControllerDelegate - (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController From a26dc264b289164f6d1f28c2f08147a3d44ba6b2 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 27 Aug 2018 17:55:33 -0700 Subject: [PATCH 4/8] Bypass cache when sideloaded text tracks are specified Fixes a crash when using the cache & sideloaded text tracks together due to the tracks on the asset not being available. Re-visit when someone with more expertise on the cache can look at it. --- ios/Video/RCTVideo.m | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/ios/Video/RCTVideo.m b/ios/Video/RCTVideo.m index 68c04e8369..91bf269e84 100644 --- a/ios/Video/RCTVideo.m +++ b/ios/Video/RCTVideo.m @@ -382,11 +382,6 @@ - (NSURL*) urlFilePath:(NSString*) filepath { - (void)playerItemPrepareText:(AVAsset *)asset assetOptions:(NSDictionary * __nullable)assetOptions withCallback:(void(^)(AVPlayerItem *))handler { - if (!_textTracks) { - handler([AVPlayerItem playerItemWithAsset:asset]); - return; - } - // sideload text tracks AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; @@ -454,7 +449,16 @@ - (void)playerItemForSource:(NSDictionary *)source withCallback:(void(^)(AVPlaye NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; [assetOptions setObject:cookies forKey:AVURLAssetHTTPCookiesKey]; #if __has_include() - [self playerItemForSourceUsingCache:uri assetOptions:assetOptions withCallback:handler]; + if (_textTracks) { + /* The DVURLAsset created by cache doesn't have a tracksWithMediaType property, so trying + * to bring in the text track code will crash. I suspect this is because the asset hasn't fully loaded. + * Until this is fixed, we need to bypass caching when text tracks are specified. + */ + AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; + [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; + } else { + [self playerItemForSourceUsingCache:uri assetOptions:assetOptions withCallback:handler]; + } #else AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; @@ -496,19 +500,19 @@ - (void)playerItemForSourceUsingCache:(NSString *)uri assetOptions:(NSDictionary } } - /* - DVURLAsset *asset = [[DVURLAsset alloc] initWithURL:url options:options networkTimeout:10000]; - asset.loaderDelegate = self; - */ + DVURLAsset *asset = [[DVURLAsset alloc] initWithURL:url options:options networkTimeout:10000]; + asset.loaderDelegate = self; + /* More granular code to DVAssetLoaderDelegate *resourceLoaderDelegate = [[DVAssetLoaderDelegate alloc] initWithURL:url]; resourceLoaderDelegate.delegate = self; NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO]; components.scheme = [DVAssetLoaderDelegate scheme]; AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[components URL] options:options]; [asset.resourceLoader setDelegate:resourceLoaderDelegate queue:dispatch_get_main_queue()]; + */ - [self playerItemPrepareText:asset assetOptions:options withCallback:handler]; + handler([AVPlayerItem playerItemWithAsset:asset]); }]; } From b6ee8f7fed86d54dc6ee1f648de685e84985eb62 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 27 Aug 2018 18:05:41 -0700 Subject: [PATCH 5/8] Simplify text track + cache bypass code --- ios/Video/RCTVideo.m | 53 ++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/ios/Video/RCTVideo.m b/ios/Video/RCTVideo.m index 91bf269e84..f872e7398b 100644 --- a/ios/Video/RCTVideo.m +++ b/ios/Video/RCTVideo.m @@ -382,6 +382,11 @@ - (NSURL*) urlFilePath:(NSString*) filepath { - (void)playerItemPrepareText:(AVAsset *)asset assetOptions:(NSDictionary * __nullable)assetOptions withCallback:(void(^)(AVPlayerItem *))handler { + if (!_textTracks) { + handler([AVPlayerItem playerItemWithAsset:asset]); + return; + } + // sideload text tracks AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; @@ -439,30 +444,29 @@ - (void)playerItemForSource:(NSDictionary *)source withCallback:(void(^)(AVPlaye NSMutableDictionary *assetOptions = [[NSMutableDictionary alloc] init]; if (isNetwork) { - /* Per #1091, this is not a public API. - * We need to either get approval from Apple to use this or use a different approach. - NSDictionary *headers = [source objectForKey:@"requestHeaders"]; - if ([headers count] > 0) { - [assetOptions setObject:headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"]; - } - */ - NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; - [assetOptions setObject:cookies forKey:AVURLAssetHTTPCookiesKey]; + /* Per #1091, this is not a public API. + * We need to either get approval from Apple to use this or use a different approach. + NSDictionary *headers = [source objectForKey:@"requestHeaders"]; + if ([headers count] > 0) { + [assetOptions setObject:headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"]; + } + */ + NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; + [assetOptions setObject:cookies forKey:AVURLAssetHTTPCookiesKey]; + #if __has_include() - if (_textTracks) { - /* The DVURLAsset created by cache doesn't have a tracksWithMediaType property, so trying - * to bring in the text track code will crash. I suspect this is because the asset hasn't fully loaded. - * Until this is fixed, we need to bypass caching when text tracks are specified. - */ - AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; - [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; - } else { - [self playerItemForSourceUsingCache:uri assetOptions:assetOptions withCallback:handler]; - } -#else - AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; - [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; + if (!_textTracks) { + /* The DVURLAsset created by cache doesn't have a tracksWithMediaType property, so trying + * to bring in the text track code will crash. I suspect this is because the asset hasn't fully loaded. + * Until this is fixed, we need to bypass caching when text tracks are specified. + */ + [self playerItemForSourceUsingCache:uri assetOptions:assetOptions withCallback:handler]; + return; + } #endif + + AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; + [self playerItemPrepareText:asset assetOptions:assetOptions withCallback:handler]; return; } else if (isAsset) { AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil]; @@ -495,7 +499,8 @@ - (void)playerItemForSourceUsingCache:(NSString *)uri assetOptions:(NSDictionary default: if (cachedAsset) { DebugLog(@"Playing back uri '%@' from cache", uri); - [self playerItemPrepareText:cachedAsset assetOptions:options withCallback:handler]; + // See note in playerItemForSource about not being able to support text tracks & caching + handler([AVPlayerItem playerItemWithAsset:asset]); return; } } @@ -503,7 +508,7 @@ - (void)playerItemForSourceUsingCache:(NSString *)uri assetOptions:(NSDictionary DVURLAsset *asset = [[DVURLAsset alloc] initWithURL:url options:options networkTimeout:10000]; asset.loaderDelegate = self; - /* More granular code to + /* More granular code to have control over the DVURLAsset DVAssetLoaderDelegate *resourceLoaderDelegate = [[DVAssetLoaderDelegate alloc] initWithURL:url]; resourceLoaderDelegate.delegate = self; NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO]; From 67a388911d3a1bd87478d49922848f2af768405a Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 27 Aug 2018 18:16:59 -0700 Subject: [PATCH 6/8] Add debug message when disabling caching due to text tracks --- ios/Video/RCTVideo.m | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/Video/RCTVideo.m b/ios/Video/RCTVideo.m index f872e7398b..3dfcfc9f00 100644 --- a/ios/Video/RCTVideo.m +++ b/ios/Video/RCTVideo.m @@ -460,6 +460,7 @@ - (void)playerItemForSource:(NSDictionary *)source withCallback:(void(^)(AVPlaye * to bring in the text track code will crash. I suspect this is because the asset hasn't fully loaded. * Until this is fixed, we need to bypass caching when text tracks are specified. */ + DebugLog(@"Caching is not supported for uri '%@' because text tracks are not compatible with the cache. Checkout https://github.com/react-native-community/react-native-video/blob/master/docs/caching.md", uri); [self playerItemForSourceUsingCache:uri assetOptions:assetOptions withCallback:handler]; return; } From 152978d11151d374e3f894229a95cb8303c3cc89 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 27 Aug 2018 18:17:15 -0700 Subject: [PATCH 7/8] Provide info about caching not working with text tracks --- docs/caching.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/caching.md b/docs/caching.md index 143218e1ed..c2b8df97ab 100644 --- a/docs/caching.md +++ b/docs/caching.md @@ -9,11 +9,13 @@ The cache is backed by [SPTPersistentCache](https://github.com/spotify/SPTPersis # How Does It Work The caching is based on the url of the asset. -SPTPersistentCache is a LRU ([last recently used](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU))) cache. +SPTPersistentCache is a LRU ([Least Recently Used](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU))) cache. # Restrictions -Currenly the uri of the resource that should be cached needs to have the appropriate file extension (one of `mp4`, `m4v` or `mov`). In order to be cached. In future versions (once dependencies allow access to the `content-type` header) this will no longer be necessary. You will also receive warnings in the xcode logs by using the `debug` mode. So if you are not 100% sure if your video is cached, check your xcode logs! +Currently, caching is only supported for URLs that end in a `.mp4`, `.m4v`, or `.mov` extension. In future versions, URLs that end in a query string (e.g. test.mp4?resolution=480p) will be support once dependencies allow access to the `Content-Type` header. At this time, HLS playlists (.m3u8) and videos that sideload text tracks are not supported and will bypass the cache. + +You will also receive warnings in the Xcode logs by using the `debug` mode. So if you are not 100% sure if your video is cached, check your Xcode logs! By default files expire after 30 days and the maxmimum cache size is 100mb. From b6512e4316daa6f9b34657625a20233c40fbf9a7 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 27 Aug 2018 18:19:15 -0700 Subject: [PATCH 8/8] Remove old test var --- ios/Video/RCTVideo.m | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/Video/RCTVideo.m b/ios/Video/RCTVideo.m index 3dfcfc9f00..9fe30b6357 100644 --- a/ios/Video/RCTVideo.m +++ b/ios/Video/RCTVideo.m @@ -31,7 +31,6 @@ @implementation RCTVideo BOOL _playerLayerObserverSet; AVPlayerViewController *_playerViewController; NSURL *_videoURL; - AVURLAsset *_testAsset; /* Required to publish events */ RCTEventDispatcher *_eventDispatcher;