2012-05-19 8 views
6

Estoy intentando cambiar el diseño de la composición de un video (es decir, las transformaciones de sus cuadros componentes) durante la reproducción. Parece que a veces esto funciona, y la composición del video cambia sin problemas al nuevo conjunto de transformaciones, pero otras simplemente se congela y se queda con las transformaciones actuales. No hay cambio de código de estado en la instancia de AVPlayer, y no hay errores ni en el jugador ni en el elemento jugador.Modificación de la propiedad videoComposition de AVPlayerItem (AVMutableVideoComposition) durante la reproducción

¿Alguien ha experimentado esto antes? Cualquier sugerencia sobre por qué esto está sucediendo, o cómo evitarlo, sería apreciada.

A continuación, se muestra un código. El bit más importante es 'playerItem.videoComposition = videoComposition', que aquí se activa al tocar el video (para fines de prueba).

Otra solución a este problema sería mostrar los videos en capas separadas, pero es imperativo que los videos estén sincronizados, por lo que una composición parece ser la única forma de lograr esto.

@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 

Respuesta

1

Puede ahorrar el tiempo en el que desea cambiar y sustituir el artículo del jugador con una nueva composición de vídeo e iniciar el reproductor de nuevo con el nuevo artículo del jugador desde el momento en el que haya detenido la reproducción.

Cuestiones relacionadas