Media Manager: refactoring (download video/image with a unique API)

This commit is contained in:
giomfo
2015-01-12 11:00:53 +01:00
parent 7c7d023efa
commit ae8f610c76
10 changed files with 132 additions and 217 deletions
+3 -2
View File
@@ -16,6 +16,7 @@
#import "MediaManager.h"
#import "MatrixHandler.h"
#import "ConsoleTools.h"
NSString *const kMediaDownloadProgressNotification = @"kMediaDownloadProgressNotification";
NSString *const kMediaUploadProgressNotification = @"kMediaUploadProgressNotification";
@@ -144,7 +145,7 @@ NSString *const kMediaLoaderProgressDownloadRateKey = @"kMediaLoaderProgressDown
NSString* progressString = [NSString stringWithFormat:@"%@ / %@", [NSByteCountFormatter stringFromByteCount:downloadData.length countStyle:NSByteCountFormatterCountStyleFile], [NSByteCountFormatter stringFromByteCount:expectedSize countStyle:NSByteCountFormatterCountStyleFile]];
[dict setValue:progressString forKey:kMediaLoaderProgressStringKey];
[dict setValue:[MediaManager formatSecondsInterval:dataRemainingTime] forKey:kMediaLoaderProgressRemaingTimeKey];
[dict setValue:[ConsoleTools formatSecondsInterval:dataRemainingTime] forKey:kMediaLoaderProgressRemaingTimeKey];
NSString* downloadRateStr = [NSString stringWithFormat:@"%@/s", [NSByteCountFormatter stringFromByteCount:meanRate * 1024 countStyle:NSByteCountFormatterCountStyleFile]];
[dict setValue:downloadRateStr forKey:kMediaLoaderProgressDownloadRateKey];
@@ -180,7 +181,7 @@ NSString *const kMediaLoaderProgressDownloadRateKey = @"kMediaLoaderProgressDown
if (downloadData.length) {
// Cache the downloaded data
NSString *cacheFilePath = [MediaManager cacheMediaData:downloadData forURL:mediaURL mimeType:mimeType];
NSString *cacheFilePath = [MediaManager cacheMediaData:downloadData forURL:mediaURL andType:mimeType];
// Call registered block
if (onMediaReady) {
onMediaReady(cacheFilePath);
+9 -20
View File
@@ -28,28 +28,17 @@ extern NSString *const kMediaDownloadDidFailNotification;
+ (id)sharedInstance;
+ (NSString*)formatSecondsInterval:(CGFloat)secondsInterval;
+ (UIImage *)resize:(UIImage *)image toFitInSize:(CGSize)size;
// Launch data download from the provided URL. Return a mediaLoader reference in order to let the user cancel this action.
+ (MediaLoader*)downloadMedia:(NSString*)mediaURL mimeType:(NSString *)mimeType;
// Check whether a download is already running for this media url. Return loader if any
+ (MediaLoader*)existingDownloaderForURL:(NSString*)url;
// Load a picture from the local cache (Do not start any remote requests)
+ (UIImage*)loadCachePicture:(NSString*)pictureURL;
// Launch picture downloading. Return a mediaLoader reference in order to let the user cancel this action.
+ (MediaLoader*)downloadPicture:(NSString*)pictureURL;
// Prepare a media from the local cache or download it if it is not available yet.
// In this second case a mediaLoader reference is returned in order to let the user cancel this action.
+ (MediaLoader*)prepareMedia:(NSString *)mediaURL
mimeType:(NSString *)mimeType
success:(blockMediaLoader_onMediaReady)success
failure:(blockMediaLoader_onError)failure;
// Check whether a media loader is already running for this media url. Return loader if any
+ (MediaLoader*)mediaLoaderForURL:(NSString*)url;
+ (NSString *)cacheMediaData:(NSData *)mediaData forURL:(NSString *)mediaURL mimeType:(NSString *)mimeType;
+ (UIImage*)loadCachePictureForURL:(NSString*)pictureURL;
// Store in cache the provided data for the media URL, return the path of the resulting file
+ (NSString*)cacheMediaData:(NSData *)mediaData forURL:(NSString *)mediaURL andType:(NSString *)mimeType;
// Return the cache path deduced from media URL and type
+ (NSString*)cachePathForMediaURL:(NSString*)mediaURL andType:(NSString *)mimeType;
+ (NSUInteger)cacheSize;
+ (void)clearCache;
+57 -159
View File
@@ -29,155 +29,69 @@ static MediaManager *sharedMediaManager = nil;
@implementation MediaManager
// Table of mediaLoaders in progress
static NSMutableDictionary* pendingMediaLoadersByURL = nil;
static NSMutableDictionary* downloadTableByURL = nil;
+ (id)sharedInstance {
@synchronized(self) {
if(sharedMediaManager == nil)
if(sharedMediaManager == nil) {
sharedMediaManager = [[self alloc] init];
// Create download table here
downloadTableByURL = [[NSMutableDictionary alloc] init];
}
}
return sharedMediaManager;
}
+ (NSString*)formatSecondsInterval:(CGFloat)secondsInterval {
NSMutableString* formattedString = [[NSMutableString alloc] init];
if (secondsInterval < 1) {
[formattedString appendString:@"< 1s"];
} else if (secondsInterval < 60)
{
[formattedString appendFormat:@"%ds", (int)secondsInterval];
}
else if (secondsInterval < 3600)
{
[formattedString appendFormat:@"%dm %2ds", (int)(secondsInterval/60), ((int)secondsInterval) % 60];
}
else if (secondsInterval >= 3600)
{
[formattedString appendFormat:@"%dh %dm %ds", (int)(secondsInterval / 3600),
((int)(secondsInterval) % 3600) / 60,
(int)(secondsInterval) % 60];
}
[formattedString appendString:@" left"];
return formattedString;
}
#pragma mark - Media Download
+ (UIImage *)resize:(UIImage *)image toFitInSize:(CGSize)size {
UIImage *resizedImage = image;
// Check whether resize is required
if (size.width && size.height) {
CGFloat width = image.size.width;
CGFloat height = image.size.height;
if (width > size.width) {
height = (height * size.width) / width;
height = floorf(height / 2) * 2;
width = size.width;
}
if (height > size.height) {
width = (width * size.height) / height;
width = floorf(width / 2) * 2;
height = size.height;
}
if (width != image.size.width || height != image.size.height) {
// Create the thumbnail
CGSize imageSize = CGSizeMake(width, height);
UIGraphicsBeginImageContext(imageSize);
// // set to the top quality
// CGContextRef context = UIGraphicsGetCurrentContext();
// CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGRect thumbnailRect = CGRectMake(0, 0, 0, 0);
thumbnailRect.origin = CGPointMake(0.0,0.0);
thumbnailRect.size.width = imageSize.width;
thumbnailRect.size.height = imageSize.height;
[image drawInRect:thumbnailRect];
resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
return resizedImage;
}
+ (id)downloadPicture:(NSString*)pictureURL {
if ([pictureURL hasPrefix:kMediaManagerPrefixForDummyURL] == NO) {
// Create a media loader to download picture
+ (MediaLoader*)downloadMedia:(NSString*)mediaURL mimeType:(NSString *)mimeType {
if ([mediaURL hasPrefix:kMediaManagerPrefixForDummyURL] == NO) {
// Create a media loader to download data
MediaLoader *mediaLoader = [[MediaLoader alloc] init];
[self setMediaLoader:mediaLoader forURL:pictureURL];
[mediaLoader downloadMedia:pictureURL mimeType:@"image/jpeg" success:^(NSString *cacheFilePath) {
[self removeMediaLoaderWithUrl:pictureURL];
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFinishNotification object:pictureURL userInfo:nil];
// Report this loader
[downloadTableByURL setValue:mediaLoader forKey:mediaURL];
// Launch download
[mediaLoader downloadMedia:mediaURL mimeType:mimeType success:^(NSString *cacheFilePath) {
[downloadTableByURL removeObjectForKey:mediaURL];
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFinishNotification object:mediaURL userInfo:nil];
} failure:^(NSError *error) {
[self removeMediaLoaderWithUrl:pictureURL];
NSLog(@"Failed to download image (%@): %@", pictureURL, error);
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFailNotification object:pictureURL userInfo:nil];
[downloadTableByURL removeObjectForKey:mediaURL];
NSLog(@"Failed to download image (%@): %@", mediaURL, error);
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFailNotification object:mediaURL userInfo:nil];
}];
return mediaLoader;
}
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFailNotification object:pictureURL userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFailNotification object:mediaURL userInfo:nil];
return nil;
}
+ (id)prepareMedia:(NSString *)mediaURL
mimeType:(NSString *)mimeType
success:(blockMediaLoader_onMediaReady)success
failure:(blockMediaLoader_onError)failure {
id ret = nil;
// Check cache
NSString* filename = [MediaManager getCacheFileNameFor:mediaURL mimeType:mimeType];
if ([[NSFileManager defaultManager] fileExistsAtPath:filename]) {
if (success) {
// Reply synchronously
success (filename);
}
}
else if ([mediaURL hasPrefix:kMediaManagerPrefixForDummyURL] == NO) {
// Create a media loader to download media content
MediaLoader *mediaLoader = [[MediaLoader alloc] init];
[mediaLoader downloadMedia:mediaURL mimeType:mimeType success:success failure:failure];
ret = mediaLoader;
} else {
NSLog(@"Load tmp media from cache failed: %@", mediaURL);
if (failure){
failure(nil);
}
}
return ret;
}
// try to find out a media loader from a media URL
+ (id)mediaLoaderForURL:(NSString*)url {
if (pendingMediaLoadersByURL && url) {
return [pendingMediaLoadersByURL valueForKey:url];
+ (id)existingDownloaderForURL:(NSString*)url {
if (downloadTableByURL && url) {
return [downloadTableByURL valueForKey:url];
}
return nil;
}
+ (void)setMediaLoader:(MediaLoader*)mediaLoader forURL:(NSString*)url {
if (!pendingMediaLoadersByURL) {
pendingMediaLoadersByURL = [[NSMutableDictionary alloc] init];
#pragma mark - Cache Handling
+ (UIImage*)loadCachePictureForURL:(NSString*)pictureURL {
UIImage* res = nil;
NSString* filename = [MediaManager cachePathForMediaURL:pictureURL andType:@"image/jpeg"];
if ([[NSFileManager defaultManager] fileExistsAtPath:filename]) {
NSData* imageContent = [NSData dataWithContentsOfFile:filename options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:nil];
if (imageContent) {
res = [[UIImage alloc] initWithData:imageContent];
}
}
// sanity check
if (mediaLoader && url) {
[pendingMediaLoadersByURL setValue:mediaLoader forKey:url];
}
return res;
}
+ (void)removeMediaLoaderWithUrl:(NSString*)url {
if (url) {
[pendingMediaLoadersByURL removeObjectForKey:url];
}
}
+ (NSString*)cacheMediaData:(NSData*)mediaData forURL:(NSString *)mediaURL mimeType:(NSString *)mimeType {
NSString* filename = [MediaManager getCacheFileNameFor:mediaURL mimeType:mimeType];
+ (NSString*)cacheMediaData:(NSData*)mediaData forURL:(NSString *)mediaURL andType:(NSString *)mimeType {
NSString* filename = [MediaManager cachePathForMediaURL:mediaURL andType:mimeType];
if ([mediaData writeToFile:filename atomically:YES]) {
return filename;
@@ -186,6 +100,26 @@ static NSMutableDictionary* pendingMediaLoadersByURL = nil;
}
}
+ (NSString*)cachePathForMediaURL:(NSString*)mediaURL andType:(NSString *)mimeType {
NSString *fileName;
if ([mimeType isEqualToString:@"image/jpeg"]) {
fileName = [NSString stringWithFormat:@"ima%lu.jpg", (unsigned long)mediaURL.hash];
} else if ([mimeType isEqualToString:@"video/mp4"]) {
fileName = [NSString stringWithFormat:@"video%lu.mp4", (unsigned long)mediaURL.hash];
} else if ([mimeType isEqualToString:@"video/quicktime"]) {
fileName = [NSString stringWithFormat:@"video%lu.mov", (unsigned long)mediaURL.hash];
} else {
NSString *extension = @"";
NSArray *components = [mediaURL componentsSeparatedByString:@"."];
if (components && components.count > 1) {
extension = [components lastObject];
}
fileName = [NSString stringWithFormat:@"%lu.%@", (unsigned long)mediaURL.hash, extension];
}
return [[MediaManager getCachePath] stringByAppendingPathComponent:fileName];
}
+ (void)clearCache {
NSError *error = nil;
@@ -246,22 +180,6 @@ static NSMutableDictionary* pendingMediaLoadersByURL = nil;
return (NSUInteger)[MediaManager folderSize:mediaCachePath];
}
#pragma mark - Cache handling
+ (UIImage*)loadCachePicture:(NSString*)pictureURL {
UIImage* res = nil;
NSString* filename = [MediaManager getCacheFileNameFor:pictureURL mimeType:@"image/jpeg"];
if ([[NSFileManager defaultManager] fileExistsAtPath:filename]) {
NSData* imageContent = [NSData dataWithContentsOfFile:filename options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:nil];
if (imageContent) {
res = [[UIImage alloc] initWithData:imageContent];
}
}
return res;
}
+ (NSString*)getCachePath {
NSString *cachePath = nil;
@@ -280,24 +198,4 @@ static NSMutableDictionary* pendingMediaLoadersByURL = nil;
return cachePath;
}
+ (NSString*)getCacheFileNameFor:(NSString*)mediaURL mimeType:(NSString *)mimeType {
NSString *fileName;
if ([mimeType isEqualToString:@"image/jpeg"]) {
fileName = [NSString stringWithFormat:@"ima%lu.jpg", (unsigned long)mediaURL.hash];
} else if ([mimeType isEqualToString:@"video/mp4"]) {
fileName = [NSString stringWithFormat:@"video%lu.mp4", (unsigned long)mediaURL.hash];
} else if ([mimeType isEqualToString:@"video/quicktime"]) {
fileName = [NSString stringWithFormat:@"video%lu.mov", (unsigned long)mediaURL.hash];
} else {
NSString *extension = @"";
NSArray *components = [mediaURL componentsSeparatedByString:@"."];
if (components && components.count > 1) {
extension = [components lastObject];
}
fileName = [NSString stringWithFormat:@"%lu.%@", (unsigned long)mediaURL.hash, extension];
}
return [[MediaManager getCachePath] stringByAppendingPathComponent:fileName];
}
@end
+2 -1
View File
@@ -16,6 +16,7 @@
#import "UploadManager.h"
#import "MediaManager.h"
#import "ConsoleTools.h"
NSString *const kUploadManagerUploadStartTimeKey = @"kUploadManagerUploadStartTimeKey";
NSString *const kUploadManagerStatsStartTimeKey = @"kUploadManagerUploadStartTimeKey";
@@ -85,7 +86,7 @@ static NSMutableDictionary* statsByURL = nil;
NSString* progressString = [NSString stringWithFormat:@"%@ / %@", [NSByteCountFormatter stringFromByteCount:totalBytesWritten countStyle:NSByteCountFormatterCountStyleFile], [NSByteCountFormatter stringFromByteCount:totalBytesExpectedToWrite countStyle:NSByteCountFormatterCountStyleFile]];
[dict setValue:progressString forKey:kMediaLoaderProgressStringKey];
[dict setValue:[MediaManager formatSecondsInterval:dataRemainingTime] forKey:kMediaLoaderProgressRemaingTimeKey];
[dict setValue:[ConsoleTools formatSecondsInterval:dataRemainingTime] forKey:kMediaLoaderProgressRemaingTimeKey];
NSString* downloadRateStr = [NSString stringWithFormat:@"%@/s", [NSByteCountFormatter stringFromByteCount:dataRate * 1024 countStyle:NSByteCountFormatterCountStyleFile]];
[dict setValue:downloadRateStr forKey:kMediaLoaderProgressDownloadRateKey];