From f5848365f7de9cff12f0fc70fedb57b8e464b54b Mon Sep 17 00:00:00 2001 From: Christine Corbett Date: Wed, 28 Jan 2015 17:50:41 -1000 Subject: [PATCH] Deliberate handling of MIME types for video, audio, and images. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • rejects unhandled media with unsupported attachment message • for supported media, handling of MIME type/file extension conversion in a single place • groundwork for future handling of additional types via e.g. conversion --- Signal.xcodeproj/project.pbxproj | 6 + Signal/src/AppDelegate.m | 3 +- .../Attachements/TSAttachmentStream.m | 25 +- .../Messages/TSMessagesManager+attachments.m | 4 +- Signal/src/util/MIMETypeUtil.h | 38 +++ Signal/src/util/MIMETypeUtil.m | 218 ++++++++++++++++++ Signal/src/util/UIUtil.h | 1 + .../view controllers/MessagesViewController.m | 58 +---- .../view controllers/TSAttachmentAdapter.h | 3 +- .../view controllers/TSAttachmentAdapter.m | 10 + .../TSVideoAttachmentAdapter.m | 13 +- 11 files changed, 292 insertions(+), 87 deletions(-) create mode 100644 Signal/src/util/MIMETypeUtil.h create mode 100644 Signal/src/util/MIMETypeUtil.m diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 2400df02c..f47822bd0 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -281,6 +281,7 @@ A5578C721A646E5300704A25 /* VersionMigrationsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A5578C711A646E5300704A25 /* VersionMigrationsTests.m */; }; A56977911A351BC400173BF2 /* ScanIdentityBarcodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A569778E1A351BC400173BF2 /* ScanIdentityBarcodeViewController.m */; }; A56977921A351BC400173BF2 /* PresentIdentityQRCodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A569778F1A351BC400173BF2 /* PresentIdentityQRCodeViewController.m */; }; + A59E6D721A79E5D100D98E2E /* MIMETypeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = A59E6D711A79E5D100D98E2E /* MIMETypeUtil.m */; }; A5D0699B1A50E9CB004CB540 /* ShowGroupMembersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A5D069991A50E9CB004CB540 /* ShowGroupMembersViewController.m */; }; A5E9D4BB1A65FAD800E4481C /* TSVideoAttachmentAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = A5E9D4B91A65FAD800E4481C /* TSVideoAttachmentAdapter.m */; }; AA0C8E498E2046B0B81EEE6E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313AE91B4954215858A5662 /* libPods.a */; }; @@ -889,6 +890,8 @@ A569778E1A351BC400173BF2 /* ScanIdentityBarcodeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScanIdentityBarcodeViewController.m; sourceTree = ""; }; A569778F1A351BC400173BF2 /* PresentIdentityQRCodeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PresentIdentityQRCodeViewController.m; sourceTree = ""; }; A56977901A351BC400173BF2 /* PresentIdentityQRCodeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PresentIdentityQRCodeViewController.h; sourceTree = ""; }; + A59E6D701A79E5D100D98E2E /* MIMETypeUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIMETypeUtil.h; sourceTree = ""; }; + A59E6D711A79E5D100D98E2E /* MIMETypeUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIMETypeUtil.m; sourceTree = ""; }; A5D069991A50E9CB004CB540 /* ShowGroupMembersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ShowGroupMembersViewController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; A5D0699A1A50E9CB004CB540 /* ShowGroupMembersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShowGroupMembersViewController.h; sourceTree = ""; }; A5E9D4B91A65FAD800E4481C /* TSVideoAttachmentAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSVideoAttachmentAdapter.m; sourceTree = ""; }; @@ -1806,6 +1809,8 @@ 76EB04C818170B33006006FC /* util */ = { isa = PBXGroup; children = ( + A59E6D701A79E5D100D98E2E /* MIMETypeUtil.h */, + A59E6D711A79E5D100D98E2E /* MIMETypeUtil.m */, FCFA64B11A24F29E0007FB87 /* UI Categories */, 76EB04C918170B33006006FC /* ArrayUtil.h */, 76EB04CA18170B33006006FC /* ArrayUtil.m */, @@ -3277,6 +3282,7 @@ E197B60F18BBEC1A00F073E5 /* EncodedAudioFrame.m in Sources */, B6B0966C1A1D25ED008BFAA6 /* TSCall.m in Sources */, 76EB061818170B33006006FC /* AnonymousValueLogger.m in Sources */, + A59E6D721A79E5D100D98E2E /* MIMETypeUtil.m in Sources */, 76EB05E618170B33006006FC /* CallController.m in Sources */, FC31962A1A067D8F0094C78E /* MessageComposeTableViewController.m in Sources */, E16E5BEE18AAC40200B7C403 /* EC25KeyAgreementParticipant.m in Sources */, diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 8656a5650..5c8f8bda1 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -20,6 +20,7 @@ #import "VersionMigrations.h" #import "UIColor+OWS.h" #import "CodeVerificationViewController.h" +#import "MIMETypeUtil.h" #import @@ -65,7 +66,6 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue"; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - BOOL loggingIsEnabled; [self setupAppearance]; #ifdef DEBUG @@ -129,6 +129,7 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue"; [self refreshContacts]; [TSPreKeyManager refreshPreKeys]; } + [MIMETypeUtil initialize]; return YES; } diff --git a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m index 257dfc819..c99399252 100644 --- a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m +++ b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m @@ -7,9 +7,8 @@ // #import "TSAttachmentStream.h" -#import "UIImage+contentTypes.h" #import - +#import "MIMETypeUtil.h" NSString * const TSAttachementFileRelationshipEdge = @"TSAttachementFileEdge"; @implementation TSAttachmentStream @@ -53,17 +52,7 @@ NSString * const TSAttachementFileRelationshipEdge = @"TSAttachementFileEdge"; } - (NSString*)filePath { - if ([self isVideo] || [self isAudio]) { - NSString *path = [[[[self class] attachmentsFolder] stringByAppendingFormat:@"/%@", self.uniqueId] stringByAppendingPathExtension:[self mediaExtension]]; - NSURL *pathURL = [NSURL URLWithString:path]; - NSString *mp3String = [NSString stringWithFormat:@"%@.mp3", [[pathURL URLByDeletingPathExtension] absoluteString]]; - if ([[NSFileManager defaultManager] fileExistsAtPath:mp3String]) { - return mp3String; - } else return path; - } - else { - return [[[self class] attachmentsFolder] stringByAppendingFormat:@"/%@", self.uniqueId]; - } + return [MIMETypeUtil filePathForAttachment:self.uniqueId ofMIMEType:self.contentType inFolder:[[self class] attachmentsFolder]]; } -(NSURL*) mediaURL { @@ -71,19 +60,17 @@ NSString * const TSAttachementFileRelationshipEdge = @"TSAttachementFileEdge"; } - (BOOL)isImage { - return [self.contentType containsString:@"image/"]; + return [MIMETypeUtil isImage:self.contentType]; } --(NSString*)mediaExtension { - return [[self.contentType stringByReplacingOccurrencesOfString:@"video/" withString:@""] stringByReplacingOccurrencesOfString:@"audio/" withString:@""]; -} + - (BOOL)isVideo { - return [self.contentType containsString:@"video/"]; + return [MIMETypeUtil isVideo:self.contentType]; } -(BOOL)isAudio { - return [self.contentType containsString:@"audio/"]; + return [MIMETypeUtil isAudio:self.contentType]; } - (UIImage*)image { diff --git a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m index 178bbed7e..1ca827afa 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m +++ b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m @@ -21,6 +21,7 @@ #import "TSMessagesManager+attachments.h" #import "TSMessagesManager+sendMessages.h" #import "TSNetworkManager.h" +#import "MIMETypeUtil.h" @interface TSMessagesManager () @@ -48,9 +49,8 @@ dispatch_queue_t attachmentsQueue() { for (PushMessageContentAttachmentPointer *pointer in attachmentsToRetrieve) { TSAttachmentPointer *attachmentPointer = (content.group != nil && (content.group.type == PushMessageContentGroupContextTypeUpdate)) ? [[TSAttachmentPointer alloc] initWithIdentifier:pointer.id key:pointer.key contentType:pointer.contentType relay:message.relay avatarOfGroupId:content.group.id] : [[TSAttachmentPointer alloc] initWithIdentifier:pointer.id key:pointer.key contentType:pointer.contentType relay:message.relay]; - if ([attachmentPointer.contentType hasPrefix:@"image/"]||[attachmentPointer.contentType hasPrefix:@"video/"] || [attachmentPointer.contentType hasPrefix:@"audio/"]) { + if ([MIMETypeUtil isSupportedMIMEType:attachmentPointer.contentType]) { [attachmentPointer saveWithTransaction:transaction]; - [retrievedAttachments addObject:attachmentPointer.uniqueId]; shouldProcessMessage = YES; } diff --git a/Signal/src/util/MIMETypeUtil.h b/Signal/src/util/MIMETypeUtil.h new file mode 100644 index 000000000..c89cf8338 --- /dev/null +++ b/Signal/src/util/MIMETypeUtil.h @@ -0,0 +1,38 @@ +#import + +@interface MIMETypeUtil : NSObject + ++(void) initialize; + ++(BOOL)isSupportedMIMEType:(NSString*)contentType; ++(BOOL)isSupportedVideoMIMEType:(NSString*)contentType; ++(BOOL)isSupportedAudioMIMEType:(NSString*)contentType; ++(BOOL)isSupportedImageMIMEType:(NSString*)contentType; + ++(BOOL)isSupportedVideoFile:(NSString*)filePath; ++(BOOL)isSupportedAudioFile:(NSString*)filePath; ++(BOOL)isSupportedImageFile:(NSString*)filePath; + ++(NSString*)getSupportedExtensionFromVideoMIMEType:(NSString*)supportedMIMEType; ++(NSString*)getSupportedExtensionFromAudioMIMEType:(NSString*)supportedMIMEType; ++(NSString*)getSupportedExtensionFromImageMIMEType:(NSString*)supportedMIMEType; + ++(NSString*)getSupportedMIMETypeFromVideoFile:(NSString*)supportedVideoFile; ++(NSString*)getSupportedMIMETypeFromAudioFile:(NSString*)supportedAudioFile; ++(NSString*)getSupportedMIMETypeFromImageFile:(NSString*)supportedImageFile; + ++(NSString*)getSupportedImageMIMETypeFromImage:(UIImage*)image; ++(BOOL)getIsSupportedTypeFromImage:(UIImage*)image; + ++(BOOL)isImage:(NSString*)contentType; ++(BOOL)isVideo:(NSString*)contentType; ++(BOOL)isAudio:(NSString*)contentType; + ++(NSString*)filePathForAttachment:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder; ++(NSString*)filePathForImage:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder; ++(NSString*)filePathForVideo:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder; ++(NSString*)filePathForAudio:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder; + ++(NSURL*)simLinkCorrectExtensionOfFile:(NSURL*)mediaURL ofMIMEType:(NSString*)contentType; + +@end diff --git a/Signal/src/util/MIMETypeUtil.m b/Signal/src/util/MIMETypeUtil.m new file mode 100644 index 000000000..596915da4 --- /dev/null +++ b/Signal/src/util/MIMETypeUtil.m @@ -0,0 +1,218 @@ +#import "MIMETypeUtil.h" +#import "UIImage+contentTypes.h" + +@implementation MIMETypeUtil + +static NSDictionary *supportedVideoMIMETypesToExtensionTypes; +static NSDictionary *supportedAudioMIMETypesToExtensionTypes; +static NSDictionary *supportedImageMIMETypesToExtensionTypes; +static NSDictionary *supportedVideoExtensionTypesToMIMETypes; +static NSDictionary *supportedAudioExtensionTypesToMIMETypes; +static NSDictionary *supportedImageExtensionTypesToMIMETypes; + +#pragma mark uses file extensions or MIME types only ++(void) initialize { + // Initialize must be called before this class is used. Could later be in e.g. a .plist + supportedVideoMIMETypesToExtensionTypes =@{@"video/3gpp":@"3gp", + @"video/3gpp2":@"3g2", + @"video/mp4":@"mp4", + @"video/quicktime":@"mov", + @"video/x-m4v":@"m4v" + }; + + supportedAudioMIMETypesToExtensionTypes = @{@"audio/x-m4p":@"m4p", + @"audio/x-m4b":@"m4b", + @"audio/x-m4a":@"m4a", + @"audio/wav":@"wav", + @"audio/x-wav":@"wav", + @"audio/x-mpeg":@"mp3", + @"audio/mpeg":@"mp3", + @"audio/mp4":@"mp4", + @"audio/mp3":@"mp3", + @"audio/mpeg3":@"mp3", + @"audio/x-mp3":@"mp3", + @"audio/x-mpeg3":@"mp3", + @"audio/amr":@"amr", + @"audio/aiff":@"aiff", + @"audio/x-aiff":@"aiff", + @"audio/3gpp2":@"3g2", + @"audio/3gpp":@"3gp" + }; + + + supportedImageMIMETypesToExtensionTypes = @{@"image/jpeg":@"jpeg", + @"image/pjpeg":@"jpeg", + @"image/png":@"png", + @"image/gif":@"gif", + @"image/tiff":@"tif", + @"image/x-tiff":@"tif", + @"image/bmp":@"bmp", + @"image/x-windows-bmp":@"bmp" + }; + + + supportedVideoExtensionTypesToMIMETypes = @{@"3gp":@"video/3gpp", + @"3gpp":@"video/3gpp", + @"3gp2":@"video/3gpp2", + @"3gpp2":@"video/3gpp2", + @"mp4":@"video/mp4", + @"mov":@"video/quicktime", + @"mqv":@"video/quicktime", + @"m4v":@"video/x-m4v" + }; + + supportedAudioExtensionTypesToMIMETypes = @{@"3gp":@"audio/3gpp", + @"3gpp":@"@audio/3gpp", + @"3g2":@"audio/3gpp2", + @"3gp2":@"audio/3gpp2", + @"aiff":@"audio/aiff", + @"aif":@"audio/aiff", + @"aifc":@"audio/aiff", + @"cdda":@"audio/aiff", + @"amr":@"audio/amr", + @"mp3":@"audio/mp3", + @"swa":@"audio/mp3", + @"mp4":@"audio/mp4", + @"mpeg":@"audio/mpeg", + @"mpg":@"audio/mpeg", + @"wav":@"audio/wav", + @"bwf":@"audio/wav", + @"m4a":@"audio/x-m4a", + @"m4b":@"audio/x-m4b", + @"m4p":@"audio/x-m4p" + }; + + supportedImageExtensionTypesToMIMETypes = @{@"png":@"image/png", + @"x-png":@"image/png", + @"jfif":@"image/jpeg", + @"jfif":@"image/pjpeg", + @"jfif-tbnl":@"image/jpeg", + @"jpe":@"image/jpeg", + @"jpe":@"image/pjpeg", + @"jpeg":@"image/jpeg", + @"jpg":@"image/jpeg", + @"gif":@"image/gif", + @".tif":@"image/tiff", + @".tiff":@"image/tiff" + }; +} + ++(BOOL) isSupportedVideoMIMEType:(NSString*)contentType { + return [supportedVideoMIMETypesToExtensionTypes objectForKey:contentType]!=nil; +} + ++(BOOL) isSupportedAudioMIMEType:(NSString*)contentType { + return [supportedAudioMIMETypesToExtensionTypes objectForKey:contentType]!=nil; +} + ++(BOOL) isSupportedImageMIMEType:(NSString*)contentType { + return [supportedImageMIMETypesToExtensionTypes objectForKey:contentType]!=nil; +} + ++(BOOL) isSupportedMIMEType:(NSString*)contentType { + return [self isSupportedImageMIMEType:contentType] || [self isSupportedAudioMIMEType:contentType] || [self isSupportedVideoMIMEType:contentType]; +} + ++(BOOL) isSupportedVideoFile:(NSString*) filePath { + return [supportedVideoExtensionTypesToMIMETypes objectForKey:[filePath pathExtension]]!=nil; +} + ++(BOOL) isSupportedAudioFile:(NSString*) filePath { + return [supportedAudioExtensionTypesToMIMETypes objectForKey:[filePath pathExtension]]!=nil; +} + ++(BOOL) isSupportedImageFile:(NSString*) filePath { + return [supportedImageExtensionTypesToMIMETypes objectForKey:[filePath pathExtension]]!=nil; +} + ++(NSString*) getSupportedExtensionFromVideoMIMEType:(NSString*)supportedMIMEType { + return [supportedVideoMIMETypesToExtensionTypes objectForKey:supportedMIMEType]; +} + ++(NSString*) getSupportedExtensionFromAudioMIMEType:(NSString*)supportedMIMEType { + return [supportedAudioMIMETypesToExtensionTypes objectForKey:supportedMIMEType]; +} + ++(NSString*) getSupportedExtensionFromImageMIMEType:(NSString*)supportedMIMEType { + return [supportedImageMIMETypesToExtensionTypes objectForKey:supportedMIMEType]; +} + ++(NSString*) getSupportedMIMETypeFromVideoFile:(NSString*)supportedVideoFile { + return [supportedVideoExtensionTypesToMIMETypes objectForKey:[supportedVideoFile pathExtension]]; +} + ++(NSString*) getSupportedMIMETypeFromAudioFile:(NSString*)supportedAudioFile { + return [supportedAudioExtensionTypesToMIMETypes objectForKey:[supportedAudioFile pathExtension]]; +} + ++(NSString*) getSupportedMIMETypeFromImageFile:(NSString*)supportedImageFile { + return [supportedImageExtensionTypesToMIMETypes objectForKey:[supportedImageFile pathExtension]]; +} + +#pragma mark uses bytes ++(NSString*) getSupportedImageMIMETypeFromImage:(UIImage*)image { + return [image contentType]; +} + ++(BOOL) getIsSupportedTypeFromImage:(UIImage*)image { + return [image isSupportedImageType]; +} + +#pragma mark full attachment utilities ++ (BOOL)isImage:(NSString*)contentType { + return [MIMETypeUtil isSupportedImageMIMEType:contentType]; +} + ++ (BOOL)isVideo:(NSString*)contentType { + return [MIMETypeUtil isSupportedVideoMIMEType:contentType]; +} + ++(BOOL)isAudio:(NSString*)contentType { + return [MIMETypeUtil isSupportedAudioMIMEType:contentType]; +} + ++ (NSString*)filePathForAttachment:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder { + if ([self isVideo:contentType]){ + return [MIMETypeUtil filePathForVideo:uniqueId ofMIMEType:contentType inFolder:folder]; + } + + else if([self isAudio:contentType]) { + return [MIMETypeUtil filePathForAudio:uniqueId ofMIMEType:contentType inFolder:folder]; + } + else { + return [MIMETypeUtil filePathForImage:uniqueId ofMIMEType:contentType inFolder:folder]; + } +} + ++(NSURL*) simLinkCorrectExtensionOfFile:(NSURL*)mediaURL ofMIMEType:(NSString*)contentType { + if([self isAudio:contentType]) { + // Audio files in current framework require changing to have extension for player + return [self changeFile:mediaURL toHaveExtension:[supportedAudioMIMETypesToExtensionTypes objectForKey:contentType]]; + } + return mediaURL; +} + ++(NSURL*) changeFile:(NSURL*)originalFile toHaveExtension:(NSString*)extension { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString* newPath = [originalFile.URLByDeletingPathExtension.absoluteString stringByAppendingPathExtension:extension]; + if (![fileManager fileExistsAtPath:newPath]) { + NSError *error = nil; + [fileManager createSymbolicLinkAtPath:newPath withDestinationPath:[originalFile path] error: &error]; + return [NSURL URLWithString:newPath]; + } + return originalFile; +} + ++ (NSString*)filePathForImage:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder{ + return [folder stringByAppendingFormat:@"/%@",uniqueId]; +} + ++ (NSString*)filePathForVideo:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder{ + return [[folder stringByAppendingFormat:@"/%@",uniqueId] stringByAppendingPathExtension:[self getSupportedExtensionFromVideoMIMEType:contentType]]; +} + ++ (NSString*)filePathForAudio:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder{ + return [[folder stringByAppendingFormat:@"/%@",uniqueId] stringByAppendingPathExtension:[self getSupportedExtensionFromAudioMIMEType:contentType]]; +} + +@end diff --git a/Signal/src/util/UIUtil.h b/Signal/src/util/UIUtil.h index 97d608655..178de3f3a 100644 --- a/Signal/src/util/UIUtil.h +++ b/Signal/src/util/UIUtil.h @@ -4,6 +4,7 @@ #import "UIFont+OWS.h" #import "UIImage+normalizeImage.h" #import "UIImage+contentTypes.h" +#import "MIMETypeUtil.h" /** * diff --git a/Signal/src/view controllers/MessagesViewController.m b/Signal/src/view controllers/MessagesViewController.m index 67a9e9a60..4fe561309 100644 --- a/Signal/src/view controllers/MessagesViewController.m +++ b/Signal/src/view controllers/MessagesViewController.m @@ -840,16 +840,7 @@ typedef enum : NSUInteger { } } --(NSURL*) changeFile:(NSURL*)originalFile toHaveExtension:(NSString*)extension { - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSString* newPath = [[originalFile path] stringByAppendingPathExtension:extension]; - if (![fileManager fileExistsAtPath:newPath]) { - NSError *error = nil; - [fileManager createSymbolicLinkAtPath:newPath withDestinationPath:[originalFile path] error: &error]; - return [NSURL URLWithString:newPath]; - } - return originalFile; -} + -(void)moviePlayBackDidFinish:(id)sender { DDLogDebug(@"playback finished"); } @@ -1093,7 +1084,7 @@ typedef enum : NSUInteger { } -(void)sendQualityAdjustedAttachment:(NSURL*)movieURL { - + // TODO: should support anything that is in the videos directory AVAsset *video = [AVAsset assetWithURL:movieURL]; AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetMediumQuality]; exportSession.shouldOptimizeForNetworkUse = YES; @@ -1115,55 +1106,12 @@ typedef enum : NSUInteger { [exportSession exportAsynchronouslyWithCompletionHandler:^{ }]; + //SHOULD PROBABLY REMOVE THIS while(exportSession.progress!=1){ } [self sendMessageAttachment:[NSData dataWithContentsOfURL:compressedVideoUrl] ofType:@"video/mp4"]; -#if 0 - return [NSData dataWithContentsOfURL:movieURL]; -#endif -#if 0 - NSString *serializationQueueDescription = [NSString stringWithFormat:@"%@ serialization queue", self]; - - // Create the main serialization queue. - self.mainSerializationQueue = dispatch_queue_create([serializationQueueDescription UTF8String], NULL); - NSString *rwAudioSerializationQueueDescription = [NSString stringWithFormat:@"%@ rw audio serialization queue", self]; - - // Create the serialization queue to use for reading and writing the audio data. - self.rwAudioSerializationQueue = dispatch_queue_create([rwAudioSerializationQueueDescription UTF8String], NULL); - NSString *rwVideoSerializationQueueDescription = [NSString stringWithFormat:@"%@ rw video serialization queue", self]; - - // Create the serialization queue to use for reading and writing the video data. - self.rwVideoSerializationQueue = dispatch_queue_create([rwVideoSerializationQueueDescription UTF8String], NULL); - - - - int videoWidth = 1920; - int videoHeight = 1920; - int desiredKeyframeInterval = 2; - int desiredBitrate = 3000; - NSError *error = nil; - AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL: - [NSURL fileURLWithPath:@"hello"] - fileType:AVFileTypeQuickTimeMovie - error:&error]; - NSParameterAssert(videoWriter); - - - NSDictionary* settings = @{AVVideoCodecKey:AVVideoCodecH264, - AVVideoCompressionPropertiesKey:@{AVVideoAverageBitRateKey:[NSNumber numberWithInt:desiredBitrate],AVVideoProfileLevelKey:AVVideoProfileLevelH264Main31}, - AVVideoWidthKey: [NSNumber numberWithInt:videoWidth], - AVVideoHeightKey:[NSNumber numberWithInt:videoHeight]}; - - - AVAssetWriterInput* writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings]; - NSParameterAssert(writerInput); - NSParameterAssert([videoWriter canAddInput:writerInput]); - [videoWriter addInput:writerInput]; -#endif - - } -(NSData*)qualityAdjustedAttachmentForImage:(UIImage*)image diff --git a/Signal/src/view controllers/TSAttachmentAdapter.h b/Signal/src/view controllers/TSAttachmentAdapter.h index 1e8c0a889..b4a7d6d32 100644 --- a/Signal/src/view controllers/TSAttachmentAdapter.h +++ b/Signal/src/view controllers/TSAttachmentAdapter.h @@ -15,7 +15,8 @@ - (instancetype)initWithAttachment:(TSAttachmentStream*)attachment; - (BOOL)isImage; - +- (BOOL)isAudio; +- (BOOL)isVideo; @property NSString *attachmentId; @end diff --git a/Signal/src/view controllers/TSAttachmentAdapter.m b/Signal/src/view controllers/TSAttachmentAdapter.m index 600150803..defa84a93 100644 --- a/Signal/src/view controllers/TSAttachmentAdapter.m +++ b/Signal/src/view controllers/TSAttachmentAdapter.m @@ -75,6 +75,16 @@ return YES; } + +-(BOOL) isAudio { + return NO; +} + + +-(BOOL) isVideo { + return NO; +} + #pragma mark - Utility -(CGSize)getBubbleSizeForImage:(UIImage*)image diff --git a/Signal/src/view controllers/TSVideoAttachmentAdapter.m b/Signal/src/view controllers/TSVideoAttachmentAdapter.m index 0c37844f3..b4edf80ed 100644 --- a/Signal/src/view controllers/TSVideoAttachmentAdapter.m +++ b/Signal/src/view controllers/TSVideoAttachmentAdapter.m @@ -16,7 +16,7 @@ #import "TSNetworkManager.h" #import "UIColor+OWS.h" #import "SCWaveformView.h" - +#import "MIMETypeUtil.h" #define AUDIO_BAR_HEIGHT 36 @interface TSVideoAttachmentAdapter () @@ -58,12 +58,12 @@ } -(BOOL) isAudio { - return [_contentType containsString:@"audio/"]; + return [MIMETypeUtil isSupportedAudioMIMEType:_contentType]; } -(BOOL) isVideo { - return [_contentType containsString:@"video/"]; + return [MIMETypeUtil isSupportedVideoMIMEType:_contentType]; } -(NSString*)formatDuration:(NSTimeInterval)duration { @@ -141,14 +141,9 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(attachmentUploadProgress:) name:@"attachmentUploadProgress" object:nil]; } } else if ([self isAudio]) { - //aac files like from android don't play, gotta convert - - NSString *convertedFile = [NSString stringWithFormat:@"%@.mp3", _attachment.mediaURL.URLByDeletingPathExtension.absoluteString]; NSError * err = NULL; - NSFileManager *fm = [NSFileManager defaultManager]; - [fm moveItemAtURL:_attachment.mediaURL toURL:[NSURL URLWithString:convertedFile] error:&err]; + NSURL* url = [MIMETypeUtil simLinkCorrectExtensionOfFile:_attachment.mediaURL ofMIMEType:_attachment.contentType]; - NSURL *url = [NSURL URLWithString:convertedFile]; AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil]; _waveform = [[SCWaveformView alloc] init]; _waveform.frame = CGRectMake(42.0, 0.0, size.width-84, size.height);