Как объединить несколько видео и аудио с помощью AVAsset

Привет, я пытаюсь объединить видео вместе с помощью AVMutableComposition . Проблема у меня заключается в том, что метод AVAsset trackWithMediaTypes возвращает пустой массив, и приложение аварийно завершает работу.

Может кто-то указать, что я делаю не так. Спасибо

Вот что у меня так далеко:

-(void) mergeVideosAndAudio:(AVAsset *)audioAsset{

    //Load Video Assets

    NSError *error;
    NSArray *dirFiles;
    if ((dirFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self documentsDirectory] error:&error]) == nil) {
        // handle the error
    };
    // find all the temp files
    NSArray *movFiles = [dirFiles filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self BEGINSWITH 'temp'"]];
    NSLog(@"The are %i temp files",movFiles.count);
    NSArray *filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:[self documentsDirectory]  error:nil];

        //Create the composition
    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];

    // 1 - Video track
    AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];
    CMTime videoTrackDuration;

    for (int j = 0; j < filePathsArray.count; j++) {
        NSURL *url = [NSURL fileURLWithPath:filePathsArray[j]];
        AVURLAsset *currentAsset = [[AVURLAsset alloc]initWithURL:url options:nil];
        videoTrackDuration = CMTimeAdd(videoTrackDuration, currentAsset.duration);
        CMTime time;
        if (j == 0) {
            time = kCMTimeZero;

        }else{
            NSURL *previousAssetURL = [NSURL fileURLWithPath:filePathsArray[j-1]];
            AVURLAsset *previousAsset = [[AVURLAsset alloc]initWithURL:previousAssetURL options:nil];
            time = previousAsset.duration;
        }

        [firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, currentAsset.duration) ofTrack:[[currentAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:time error:nil];
    }

    // 2 - Audio track
    if (audioAsset!=nil){
        AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                            preferredTrackID:kCMPersistentTrackID_Invalid];
        [AudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoTrackDuration)
                            ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
    }

    //3 - Get Path for merge
    NSString *myPathDocs =  [[self documentsDirectory] stringByAppendingPathComponent:
                             [NSString stringWithFormat:@"mergeVideo-%d.mov",arc4random() % 1000]];
    self.fileURL = [NSURL URLWithString: myPathDocs];

    // 5 - Create exporter
    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
                                                                      presetName:AVAssetExportPresetHighestQuality];
    exporter.outputURL=self.fileURL;
    exporter.outputFileType = AVFileTypeQuickTimeMovie;
    exporter.shouldOptimizeForNetworkUse = YES;
    [exporter exportAsynchronouslyWithCompletionHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [self exportDidFinish:exporter];
        });
    }];

}
-(void)exportDidFinish:(AVAssetExportSession*)session {
    if (session.status == AVAssetExportSessionStatusCompleted) {
        self.fileURL = session.outputURL;
        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
        if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:self.fileURL]) {
            [library writeVideoAtPathToSavedPhotosAlbum:self.fileURL completionBlock:^(NSURL *assetURL, NSError *error){
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (error) {
                        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Video Saving Failed"
                                                                       delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
                        [alert show];
                    } else {
                        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Video Saved" message:@"Saved To Photo Album"
                                                                       delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                        [alert show];
                    }
                });
            }];
        }
    }
    [self removeTempFilesFromDocuments];
}

Вот скриншот ошибки:

4 ответа

Пожалуйста, проверьте продолжительность ваших файлов, которая не должна быть нулевой.

Первая проверка видео присутствует на определенном пути и работает правильно.

В моем случае видео присутствует в пути, но не может работать. В основном это происходит потому, что видео не пишется по этому пути. Надеюсь, поможет.

Ну, ошибка тут же "индекс 0 за пределами для пустого массива". Это означает, что у вас есть пустой массив видео активов. Таким образом, что-то не так с получением ваших видеоактивов через NSFileManager, Иди проверь массив filePathsArray, что-то не так с этим.

Не уверен, что это решит вашу проблему. Но я сталкивался с этой проблемой раньше, когда пытался загрузить AVAsset с URL-адреса, но получал актив без треков. Для меня это исправило добавление "isDirectory:NO" при создании NSURL:

NSURL *url = [NSURL fileURLWithPath:filePathsArray[j] isDirectory:NO];
Другие вопросы по тегам