2012-05-19 5 views
6

Próbuję zmienić układ kompozycji wideo (to znaczy przekształcić jej fragmenty klatek) podczas odtwarzania. Wydaje się, że czasami to działa, a skład wideo płynnie zmienia się w nowy zestaw przekształceń, ale innym razem po prostu zawiesza się i pozostaje z obecnymi przekształceniami. W instancji AVPlayer nie ma zmian w kodzie statusu i nie ma żadnych błędów ani w odtwarzaczu, ani w odtwarzaczu.Zmiana właściwości wideoComposition AVM (AVMutableVideoComposition) podczas odtwarzania

Czy ktoś wcześniej tego doświadczył? Sugerowane są wszelkie sugestie dotyczące tego, dlaczego tak się dzieje lub jak go obejść.

Jakiś kod pokazano poniżej. Ważnym bitem jest "playerItem.videoComposition = videoComposition", który jest tutaj wyzwalany po dotknięciu wideo (do celów testowych).

Innym rozwiązaniem tego problemu byłoby wyświetlanie filmów na osobnych warstwach, ale konieczne jest, aby filmy były zsynchronizowane, więc kompozycja wydaje się być jedyną drogą do osiągnięcia tego.

@implementation VideoView 
{ 
    CGSize _videoSize; 
    CMTimeRange _videoFullRange; 

    AVMutableCompositionTrack * _compositionTrackVideoA; 
    AVMutableCompositionTrack * _compositionTrackVideoB; 
} 

+ (Class)layerClass 
{ 
    return [AVPlayerLayer class]; 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) 
    { 
     NSString * videoAPath = [[NSBundle mainBundle] pathForResource:@"cam09v2" ofType:@"mp4"]; 
     NSString * videoBPath = [[NSBundle mainBundle] pathForResource:@"cam10v2_b" ofType:@"mp4"]; 
     AVURLAsset * videoAAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:videoAPath] options:nil]; 
     AVURLAsset * videoBAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:videoBPath] options:nil]; 

     AVAssetTrack * videoATrack = [[videoAAsset tracksWithMediaType:AVMediaTypeVideo] lastObject]; 
     AVAssetTrack * videoBTrack = [[videoBAsset tracksWithMediaType:AVMediaTypeVideo] lastObject]; 
     AVAssetTrack * audioTrack = [[videoAAsset tracksWithMediaType:AVMediaTypeAudio] lastObject]; 

     _videoSize = [videoATrack naturalSize]; 
     CMTime videoDuration = videoAAsset.duration; 
     _videoFullRange = CMTimeRangeMake(kCMTimeZero, videoDuration); 

     AVMutableComposition *composition = [AVMutableComposition composition]; 
     AVMutableCompositionTrack * compositionTrackVideoA = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
     AVMutableCompositionTrack * compositionTrackVideoB = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
     AVMutableCompositionTrack * compositionTrackAudio = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 

     compositionTrackVideoA.preferredTransform = videoATrack.preferredTransform; 

     NSError * error = nil; 
     if (! [compositionTrackVideoA insertTimeRange:_videoFullRange ofTrack:videoATrack atTime:kCMTimeZero error:&error]) 
      NSLog(@"%@", error); 

     if (! [compositionTrackVideoB insertTimeRange:_videoFullRange ofTrack:videoBTrack atTime:kCMTimeZero error:&error]) 
      NSLog(@"%@", error); 

     if (! [compositionTrackAudio insertTimeRange:_videoFullRange ofTrack:audioTrack atTime:kCMTimeZero error:&error]) 
      NSLog(@"%@", error); 

     _compositionTrackVideoA = [compositionTrackVideoA copy]; 
     _compositionTrackVideoB = [compositionTrackVideoB copy]; 

     AVPlayerItem * playerItem = [AVPlayerItem playerItemWithAsset:composition]; 

     AVPlayer * player = [AVPlayer playerWithPlayerItem:playerItem]; 

     [(AVPlayerLayer *)self.layer setPlayer:player]; 

     [player play]; 

     [player addObserver:self forKeyPath:@"status" options:0 context:0]; 

     [self updateCompositionForPlayerItem:playerItem]; 

     UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)]; 
     [self addGestureRecognizer:tapGesture]; 
    } 
    return self; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if ([keyPath isEqualToString:@"status"]) 
     NSLog(@"STATUS %d", ((AVPlayer *)object).status); 
} 

- (void)updateCompositionForPlayerItem:(AVPlayerItem *)playerItem 
{ 

    AVMutableVideoComposition * videoComposition = [AVMutableVideoComposition videoComposition]; 

    AVMutableVideoCompositionInstruction *videoInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
    videoInstruction.enablePostProcessing = NO; 
    videoInstruction.timeRange = _videoFullRange; 

    AVMutableVideoCompositionLayerInstruction * layerInstructionA = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:_compositionTrackVideoA]; 
    CGAffineTransform transformA = CGAffineTransformMakeScale(0.5, 0.5); 
    [layerInstructionA setTransform:transformA atTime:kCMTimeZero]; 
    AVMutableVideoCompositionLayerInstruction * layerInstructionB = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:_compositionTrackVideoB]; 
    CGAffineTransform transformB = CGAffineTransformMakeScale(0.5, 0.5); 
    static int i = 0; 
    transformB = CGAffineTransformTranslate(transformB, (i++ % 2 == 0) ? _videoSize.width : 0, _videoSize.height); 
    [layerInstructionB setTransform:transformB atTime:kCMTimeZero]; 

    videoInstruction.layerInstructions = [NSArray arrayWithObjects:layerInstructionA, layerInstructionB, nil]; 

    videoComposition.instructions = [NSArray arrayWithObject:videoInstruction]; 

    videoComposition.frameDuration = CMTimeMake(1, 30); // 30 fps 
    videoComposition.renderSize = _videoSize; 

    playerItem.videoComposition = videoComposition; 

} 

- (void)didTap:(UITapGestureRecognizer *)tapGesture 
{ 
    [self updateCompositionForPlayerItem:((AVPlayerLayer *)self.layer).player.currentItem]; 
} 

@end 

Odpowiedz

1

Można zaoszczędzić czas, w którym chcesz ją zmienić i zastąpić element gracz z nowym składzie wideo i ponownie uruchomić odtwarzacz z nowej pozycji gracza od momentu, w którym przestaliśmy grać.