Почему я не получаю видео при экспорте фильма с помощью AVAssetExportSession?

Звук обрезается, а видео пусто.

Это функция, которая инициирует обрезку

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor blackColor];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(finishedTrimming:)
                                             name:@"videoFinishedTrimming"
                                           object:nil];
    NSURL *furl = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"capture0.mp4"]];

    //[self playVideoWithURL:furl]; //Play original video

    //Play trimmed video
    CMTime startTrim = CMTimeMake(0, 1);
    CMTime endTrim = CMTimeMake(2,1);
    CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTrim, endTrim);

    [ProcessingHelper trimAssetWithURL:furl andRange:exportTimeRange];
}

Это функция, которая экспортирует и обрезает видео.

+(void)trimAssetWithURL:(NSURL *)urlIn andRange:(CMTimeRange)timeRangeIn
{
    AVAsset *videoAsset = [AVAsset assetWithURL:urlIn];

    //Creates the session with the videoasset
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:AVAssetExportPresetHighestQuality];

    //Creates the path to export to  - Saving to temporary directory
    NSString* filename = [NSString stringWithFormat:@"TrimmedCapture%d.mp4", 0];
    NSString* path = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];

    //Checks if there is already a file at the output URL.  session will not overwrite previous data
    if ([[NSFileManager defaultManager] fileExistsAtPath:path])
    {
        NSLog(@"Removing item at path: %@", path);
        [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
    }

    //Set the output url
    exportSession.outputURL = [NSURL fileURLWithPath:path];

    //Set the output file type
    exportSession.outputFileType = AVFileTypeMPEG4; //AVFileTypeAC3; // AVFileTypeMPEGLayer3; // AVFileTypeWAVE; // AVFileTypeQuickTimeMovie;

    exportSession.timeRange = timeRangeIn;

    exportSession.metadata = nil;

    //Exports!
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        switch (exportSession.status) {
            case AVAssetExportSessionStatusCompleted:{
                NSLog(@"Export Complete");
                NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:exportSession.outputURL, @"outputURL", nil];
                [[NSNotificationCenter defaultCenter] postNotificationName:@"videoFinishedTrimming" object:self userInfo:options];
                break;
            }
            case AVAssetExportSessionStatusFailed:
                NSLog(@"Export Error: %@", [exportSession.error description]);
                break;
            case AVAssetExportSessionStatusCancelled:
                NSLog(@"Export Cancelled");
                break;
            default:
                break;
        }
    }];
    exportSession = nil;
}

Это функция, которая инициирует воспроизведение видео.

-(void)finishedTrimming:(NSNotification *)notification
{
    NSDictionary *userInfo = notification.userInfo;
    NSURL *outputURL = [userInfo objectForKey:@"outputURL"];
    [self playVideoWithURL:outputURL];

}

Это функция, которая воспроизводит видео

-(void)playVideoWithURL:(NSURL *)furl
{
    NSData *movieData;
    NSError *dataReadingError = nil;
    movieData = [NSData dataWithContentsOfURL: furl options:NSDataReadingMapped error:&dataReadingError];
    if(movieData != nil)
        NSLog(@"Successfully loaded the data.");
    else
        NSLog(@"Failed to load the data with error = %@", dataReadingError);


    //AVPlayer
    self.avPlayer = [AVPlayer playerWithURL:furl];
    AVPlayerLayer *avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
    avPlayerLayer.frame = self.vPlayBackMovie.bounds;
    avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    avPlayerLayer.needsDisplayOnBoundsChange = YES;

    [self.vPlayBackMovie.layer addSublayer:avPlayerLayer];
    self.vPlayBackMovie.layer.needsDisplayOnBoundsChange = YES;
    [self.avPlayer play];
}

person jgvb    schedule 27.06.2014    source источник
comment
Не могу вспомнить навскидку, но вы подтвердили, что обработчик завершения экспорта происходит в основном потоке?   -  person ChrisH    schedule 28.06.2014
comment
Я не. Где и как я мог это проверить? Должно ли это иметь значение? В обработчике завершения я отправляю уведомление, и в основном потоке я наблюдаю за этим уведомлением. Таким образом, независимо от того, в каком потоке он завершен, всякий раз, когда он завершен, я должен знать об этом в основном потоке, верно?   -  person jgvb    schedule 29.06.2014


Ответы (1)


Спасибо ChrisH, ты был прав! Экспорт происходил в другом потоке, поэтому в обработчике мне нужно получить основную очередь...

Мне нужно было получить основной поток после

case AVAssetExportSessionStatusCompleted:{
    dispatch_async(dispatch_get_main_queue(), ^{
        //post the notification!
    });
    break;
}
person jgvb    schedule 29.06.2014
comment
в случае, если кто-то ищет/заинтересован, вы также можете запустить обратный вызов экспорта, добавив dispatch_main() в конец основного файла (main.swift в моем случае). - person Natalia; 30.06.2016