Наложение звука на видео и сохранение результата в camera roll iPhone/iPad
В этой статье будет рассмотрен способ наложения звукового файла на видео. Данная реализация основана на использовании фреймворка AV Foundation, который входит в стандартный состав iOS (начиная с версии 2.2). Полученный результат нужно сделать доступным для просмотра с телефона, для этого мы сохраним его в camera roll на iPhone или iPad.
Подразумевается, что файлы лежат в определенном месте на устройстве (предполагается, что во временной папке нашей программы). Возможные ситуации возникновения ошибок не обрабатываются, но они заносятся в объект класса NSError. Таким образом, данный код представляет из себя набор сниппетов для использования в своем коде.
Реализация
Создадим функцию, в которая будет вызываться для смешивания звука с видео и записи результата в camera roll. В качестве аргументов она принимает пути к файлам с видео и аудио данными в строковом формате NSString.
- (void) mixAudioVideo: (NSString *) strAudioFile: (NSString *) strVideoFile { NSError *err = nil; }
Создадим дополнительно строковую переменную, в которой будет храниться путь к файлу с нашим результатом. Он будет располагаться как и другие файлы во временной папке нашего приложения под именем mix.m4v.
NSString* strMixFile = [[NSTemporaryDirectory() stringByAppendingPathComponent:@"mix.m4v"] retain];
Теперь исходные файлы нам нужно представить в виде хранилища, которые затем будем смешивать.
AVURLAsset* mixAudioAsset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:strAudioFile] options:nil]; AVURLAsset* mixVideoAsset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:strVideoFile] options:nil];
Создаем пустую композицию, в которой будем использовать наши хранилища.
AVMutableComposition* mixComposition = [AVMutableComposition composition];
Полученная композиция должна состоять из одного или более треков, которые мы ниже и создаем, указывая шкалу времени, на которой они будут располагаться, тип трека и т.д..
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, mixAudioAsset.duration) ofTrack:[[mixAudioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:&err]; AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, mixVideoAsset.duration) ofTrack:[[mixVideoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:&err];
Создаем сессию для экспорта.
AVAssetExportSession* assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetPassthrough];
Задаем для нее такие параметры, как тип файла, путь к нему и оптимизировать ли для использования в сети.
assetExport.outputFileType = @"com.apple.quicktime-movie"; assetExport.outputURL = [NSURL fileURLWithPath:movieWrite]; assetExport.shouldOptimizeForNetworkUse = YES;
И, наконец, запускаем нашу сессию смешивания в асинхронном режиме. Также в отмеченном месте можно вставить любой код, который будет выполняться при смешивании очередного семпла.
[_assetExport exportAsynchronouslyWithCompletionHandler: ^(void) { //Здесь промежуточный код для обработки семплов } ];
Осталось только сохранить полученный результат в camera roll. Реализуется это следующей строчкой:
UISaveVideoAtPathToSavedPhotosAlbum (path, self, @selector(video:didFinishSavingWithError: contextInfo:), nil);
В последней строке мы указали вызов функции, которая будет запускаться при возникновении ошибки во время сохранения в camera roll. Поэтому, нужно создать эту функцию, в которой будут обрабатываться ошибки. Для примера ниже представлена пустая функция:
- (void) video: (NSString *) videoPath didFinishSavingWithError: (NSError *) err contextInfo: (void *) contextInfo { //Здесь код для обработки ошибки }