- PVSM.RU - https://www.pvsm.ru -
Здравствуй!
В одном из проектов мне понадобилось решить задачу объединения видео, в частности, пользователь мог поставить видео на паузу, после чего продолжить запись (количество итераций было неизвестно). Поэтому необходимо было найти способ для решения этой задачи доступными средствами. Конечно, в голову пришло два варианта, либо писать всё сразу в один файл, либо записывать в разные, а склеивать уже после сессии. Я решил остановиться на втором, а что из этого вышло, читайте под катом.
Для записи видео я использовал AVCamCaptureManager, основываясь на приложении AVCam, любезно расположенном на всеми нами любимом сайте [1]. Ну а после нажатия кнопки стоп начиналось самое интересное.
Этап 1. Подготовка.
На этом этапе нужно сделать следующее:
AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
NSMutableArray *arrayInstruction = [[NSMutableArray alloc] init];
AVMutableVideoCompositionInstruction *MainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
AVMutableCompositionTrack *audioTrack;
if(self.isSoundOn==YES)
audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
CMTime duration = kCMTimeZero;
Этап 2. Поиск файлов, создание ассетов, генерация инструкций и трансформация видеодорожки при необходимости.
AVAsset *currentAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@%d%@", NSTemporaryDirectory(), @"Movie",i,@".mov"]]];
//VIDEO TRACK
AVMutableCompositionTrack *currentTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[currentTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, currentAsset.duration) ofTrack:[[currentAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:duration error:nil];
Особое внимание здесь стоит уделить тому, куда именно нужно вставлять отрезок, если вы хотите избежать чёрных полос во время проигрывания, или что ещё хуже, накладывания одного видео на другое в процессе воспроизведения. И даже не спрашивайте, почему я акцентирую на этом внимание.
AVMutableVideoCompositionLayerInstruction *currentAssetLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:currentTrack];
При правильном определении положения видео (портретного или лэндскейпного) на выходе вы сможете получить шикарную картинку, в которой горизонтальное или вертикальное видео будет центрироваться в зависимости от того, дорожка в каком режиме у вас идёт первой.
AVAssetTrack *currentAssetTrack = [[currentAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
duration=CMTimeAdd(duration, currentAsset.duration);
Этап 3. Установка параметров MainInstruction и формирование AVMutableVideoComposition
MainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, duration);
MainInstruction.layerInstructions = arrayInstruction;
AVMutableVideoComposition *MainCompositionInst = [AVMutableVideoComposition videoComposition];
MainCompositionInst.instructions = [NSArray arrayWithObject:MainInstruction];
MainCompositionInst.frameDuration = CMTimeMake(1, 30);
MainCompositionInst.renderSize = CGSizeMake(320.0, 480.0);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"mergeVideo-%d.mov",arc4random() % 1000]];
NSURL *url = [NSURL fileURLWithPath:myPathDocs];
Этап 4. Сохранение полученного видео через AVAssetExportSession
Разница между пресетами Highest и Medium очень даже существенна. Поэтому если вы планируете распространять видео в социальных сетях, настоятельно вам рекомендую использовать именно Medium.
NSString *quality = AVAssetExportPresetHighestQuality;
if(self.isHighQuality==NO)
quality = AVAssetExportPresetMediumQuality;
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:quality];
exporter.outputURL=url;
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.videoComposition = MainCompositionInst;
exporter.shouldOptimizeForNetworkUse = YES;
[exporter exportAsynchronouslyWithCompletionHandler:^
{ //здесь можно удалить темповые файлы.
}];
Возможные статусы при экспорте:
switch (exporter.status)
{
case AVAssetExportSessionStatusCompleted:
NSLog(@"Completed exporting!");
break;
case AVAssetExportSessionStatusFailed:
NSLog(@"Failed:%@", exporter.error.description);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Canceled:%@", exporter.error);
break;
case AVAssetExportSessionStatusExporting:
NSLog(@"Exporting!");
break;
case AVAssetExportSessionStatusWaiting:
NSLog(@"Waiting");
break;
default:
break;
}
В статье я постарался акцентировать внимание именно на объединении видео, и думаю, многимам, занимающимся разработкой под iOS, столкнувшимся с такой задачей, этот пост поможет в будущем. В дальнейшем я планирую более подробно рассказать о CMTime, и почему это не просто «время». Кстати, много полезной информации по теме есть на сайте [2]. А сам метод вы можете найти в репозитории [3]
Автор: Viktorianec
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ios-development/29934
Ссылки в тексте:
[1] сайте: http://developer.apple.com/library/ios/#samplecode/AVCam/Introduction/Intro.html
[2] сайте: http://www.raywenderlich.com/13418/how-to-play-record-edit-videos-in-ios
[3] репозитории: https://github.com/Viktorianec/NSMergeVideos
[4] Источник: http://habrahabr.ru/post/173599/
Нажмите здесь для печати.