2015-02-19 2 views
3

Я пытаюсь воспроизвести видео в цикле на AVSampleBufferDisplayLayer. Я могу заставить его играть хотя бы раз без проблем. Но, когда я пытаюсь его зацикливать, он не продолжает играть.Looping Video в AVFoundation AVSampleBufferDisplayLayer

В ответ на AVFoundation to reproduce a video loop нет способа перемотать AVAssetReader, чтобы я его повторно создал. (Я видел ответ на Looping a video with AVFoundation AVPlayer?, но AVPlayer более полнофункциональный. Я читаю файл, но хочу, чтобы AVSampleBufferDisplayLayer по-прежнему.)

Одна из гипотез заключается в том, что мне нужно остановить некоторые заголовки H264, но я не знаю, поможет ли это (и как). Другое дело, что это имеет какое-то отношение к CMTimebase, но я пробовал несколько вещей безрезультатно.

код ниже, основанный на WWDC говорить от Apple на прямой доступ к видео Кодирование:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    NSString *filepath = [[NSBundle mainBundle] pathForResource:@"sample-mp4" ofType:@"mp4"]; 
    NSURL *fileURL = [NSURL fileURLWithPath:filepath]; 
    AVAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil]; 

    UIView *view = self.view; 

    self.videoLayer = [[AVSampleBufferDisplayLayer alloc] init]; 
    self.videoLayer.bounds = view.bounds; 
    self.videoLayer.position = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds)); 
    self.videoLayer.videoGravity = AVLayerVideoGravityResizeAspect; 
    self.videoLayer.backgroundColor = [[UIColor greenColor] CGColor]; 

    CMTimebaseRef controlTimebase; 
    CMTimebaseCreateWithMasterClock(CFAllocatorGetDefault(), CMClockGetHostTimeClock(), &controlTimebase); 

    self.videoLayer.controlTimebase = controlTimebase; 
    CMTimebaseSetTime(self.videoLayer.controlTimebase, CMTimeMake(5, 1)); 
    CMTimebaseSetRate(self.videoLayer.controlTimebase, 1.0); 

    [[view layer] addSublayer:_videoLayer]; 

    dispatch_queue_t assetQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //??? right queue? 


    __block AVAssetReader *assetReaderVideo = [self createAssetReader:asset]; 
    __block AVAssetReaderTrackOutput *outVideo = [assetReaderVideo outputs][0]; 
    if([assetReaderVideo startReading]) 
    { 
     [_videoLayer requestMediaDataWhenReadyOnQueue: assetQueue usingBlock: ^{ 
      while([_videoLayer isReadyForMoreMediaData]) 
      { 
       CMSampleBufferRef sampleVideo; 
       if (([assetReaderVideo status] == AVAssetReaderStatusReading) && (sampleVideo = [outVideo copyNextSampleBuffer])) { 
        [_videoLayer enqueueSampleBuffer:sampleVideo]; 
        CFRelease(sampleVideo); 
        CMTimeShow(CMTimebaseGetTime(_videoLayer.controlTimebase)); 
       } 
       else { 

        [_videoLayer stopRequestingMediaData]; 
        //CMTimebaseSetTime(_videoLayer.controlTimebase, CMTimeMake(5, 1)); 
        //CMTimebaseSetRate(self.videoLayer.controlTimebase, 1.0); 
        //CMTimeShow(CMTimebaseGetTime(_videoLayer.controlTimebase)); 
        assetReaderVideo = [self createAssetReader:asset]; 
        outVideo = [assetReaderVideo outputs][0]; 
        [assetReaderVideo startReading]; 
        //sampleVideo = [outVideo copyNextSampleBuffer]; 

        //[_videoLayer enqueueSampleBuffer:sampleVideo]; 
       } 
      } 
     }]; 
    } 
} 

-(AVAssetReader *)createAssetReader:(AVAsset*)asset { 
    NSError *error=nil; 

    AVAssetReader *assetReaderVideo = [[AVAssetReader alloc] initWithAsset:asset error:&error]; 

    NSArray *videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo]; 
    AVAssetReaderTrackOutput *outVideo = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTracks[0] outputSettings:nil]; //dic]; 
    [outVideo res] 

    [assetReaderVideo addOutput:outVideo]; 
    return assetReaderVideo; 
} 

Спасибо так много.

+0

У меня была такая же проблема сегодня. Я нашел частичное решение, выполнив следующие действия: вызывая [self.videoLayer flushAndRemoveImage] каждый цикл и увеличивая значение itemTime.epoch для каждого цикла. Он работает большую часть времени, но не всегда. – sbwilson

+0

Вызов enqueueSampleBuffer: в главной очереди отправки, похоже, теперь он исправлен для меня. – sbwilson

+0

Вот исходный код для рабочего решения, которое использует аппаратные кодировки и декодирования API, чтобы получить бесшовный цикл без AVAssetReader. https://stackoverflow.com/questions/33285826/looping-avplayer-seamlessly/33335884#33335884 – MoDJ

ответ

0

Попробуйте создать цикл с быстрым, а затем соедините файлы с объективом c быстрыми файлами. у google есть много ответов на мосты и петли, так что просто google с быстрым.

+0

Спасибо nachshon - Я не вижу, что бы я назвал, чтобы он тоже зациклился на Swift. Есть идеи? – danthedev

Смежные вопросы