【问题标题】:Compositing 2 videos with half opacity using AVFoundation without CALayer becomes appending videos?使用不带 CALayer 的 AVFoundation 合成 2 个具有一半不透明度的视频会变成附加视频吗?
【发布时间】:2015-09-21 01:41:48
【问题描述】:

我想要的:在 AVVideoCompositionTrack 的时间 0:00 插入多个不透明的视频层。

我仔细阅读了官方的 AVFoundation 文档以及关于这个主题的许多 WWDC 讨论。但我不明白为什么结果不遵循 API 语句。

我可以在播放过程中使用 2 AVPlayerLayer 实现叠加效果。这也可能意味着我可以在导出过程中使用 AVVideoCompositionCoreAnimationTool 来实现类似的东西。 但我倾向于将 CALayer 留给字幕/图像叠加或动画。

我对任何插入 AVAsset 的尝试:

- (void)addVideo:(AVAsset *)asset_in withOpacity:(float)opacity
{
    // This is demo for composition of opaque videos. So we all insert video at time - 0:00
    [_videoCompositionTrack insertTimeRange:CMTimeRangeMake( kCMTimeZero, asset_in.duration )
                                    ofTrack:[ [asset_in tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0 ]
                                     atTime:kCMTimeZero error:nil ];

    AVMutableVideoCompositionInstruction *mutableVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    AVAssetTrack *assettrack_in = [ [asset_in tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0 ];
    mutableVideoCompositionInstruction.timeRange = CMTimeRangeMake( kCMTimeZero, assettrack_in.timeRange.duration );
    AVMutableVideoCompositionLayerInstruction *videoCompositionLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:_videoCompositionTrack];
    [videoCompositionLayerInstruction setTransform:assettrack_in.preferredTransform atTime:kCMTimeZero];
    [videoCompositionLayerInstruction setOpacity:opacity atTime:kCMTimeZero];
    mutableVideoCompositionInstruction.layerInstructions = @[videoCompositionLayerInstruction];
    [_arrayVideoCompositionInstructions addObject:mutableVideoCompositionInstruction];
}

请注意 insertTimeRange 有 atTime:kCMTimeZero 作为参数。所以我希望它们会放在视频合成的开头。

我尝试导出的内容:

- (IBAction)ExportAndPlay:(id)sender
{
    _mutableVideoComposition.instructions = [_arrayVideoCompositionInstructions copy];

    // Create a static date formatter so we only have to initialize it once.
    static NSDateFormatter *kDateFormatter;
    if (!kDateFormatter) {
        kDateFormatter = [[NSDateFormatter alloc] init];
        kDateFormatter.dateStyle = NSDateFormatterMediumStyle;
        kDateFormatter.timeStyle = NSDateFormatterShortStyle;
    }
    // Create the export session with the composition and set the preset to the highest quality.
    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:_mutableComposition presetName:AVAssetExportPresetHighestQuality];
    // Set the desired output URL for the file created by the export process.
    exporter.outputURL = [[[[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:@YES error:nil] URLByAppendingPathComponent:[kDateFormatter stringFromDate:[NSDate date]]] URLByAppendingPathExtension:CFBridgingRelease(UTTypeCopyPreferredTagWithClass((CFStringRef)AVFileTypeQuickTimeMovie, kUTTagClassFilenameExtension))];
    // Set the output file type to be a QuickTime movie.
    exporter.outputFileType = AVFileTypeQuickTimeMovie;
    exporter.shouldOptimizeForNetworkUse = YES;
    exporter.videoComposition = _mutableVideoComposition;
    _mutableVideoComposition.instructions = [_arrayVideoCompositionInstructions copy];
    // Asynchronously export the composition to a video file and save this file to the camera roll once export completes.
    [exporter exportAsynchronouslyWithCompletionHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            switch ([exporter status]) {
                case AVAssetExportSessionStatusFailed:
                {
                    NSLog(@"Export failed: %@ %@", [[exporter error] localizedDescription],[[exporter error]debugDescription]);
                }
                case AVAssetExportSessionStatusCancelled:
                {
                    NSLog(@"Export canceled");
                    break;
                }
                case AVAssetExportSessionStatusCompleted:
                {
                    NSLog(@"Export complete!");
                    NSLog( @"Export URL = %@", [exporter.outputURL absoluteString] );
                    [self altPlayWithUrl:exporter.outputURL];
                }
                default:
                {
                    NSLog(@"default");
                }
            }

        } );
    }];
}

结果:如果我选择 2 个视频剪辑,它会导出一个视频,并在第一个视频之后附加第二个视频。

这与我从 :AVMutableCompositionTrack 读到的内容不同

有人可以为这只无助的羔羊提供一些启示吗?

编辑:是否缺少任何细节,以至于没有人可以帮我一把?如果是这样,请留下评论,以便我可以弥补。

【问题讨论】:

    标签: ios objective-c avfoundation


    【解决方案1】:

    好的,很抱歉因为API对AVMutableCompositionTrack的一些误解而问这个问题。

    如果您想像我一样将 2 个视频混合为 2 个叠加层。您将需要 2 个 AVMutableCompositionTrack 实例,它们都从同一个 AVMutableComposition 实例化,如下所示:

        // 0. Setup AVMutableCompositionTracks <=  FOR EACH AVAssets !!!
    AVMutableCompositionTrack *mutableCompositionVideoTrack1 = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    AVMutableCompositionTrack *mutableCompositionVideoTrack2 = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    

    然后将你想要的两个 AVAsset 插入到他们自己的 AVMutableCompositionTrack 中:

        AVAssetTrack *videoAssetTrack1 = [ [ [_arrayVideoAssets firstObject] tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0 ];
    AVAssetTrack *videoAssetTrack2 = [ [ [_arrayVideoAssets lastObject] tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0 ];
        [ mutableCompositionVideoTrack1 insertTimeRange:CMTimeRangeMake( kCMTimeZero, videoAssetTrack1.timeRange.duration ) ofTrack:videoAssetTrack1 atTime:kCMTimeZero error:nil ];
        [ mutableCompositionVideoTrack2 insertTimeRange:CMTimeRangeMake( kCMTimeZero, videoAssetTrack2.timeRange.duration ) ofTrack:videoAssetTrack2 atTime:kCMTimeZero error:nil ];
    

    然后用每个 AVMutableCompositionTracks 的 2 层指令设置 AVMutableVideoComposition:

    AVMutableVideoCompositionInstruction *compInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    compInstruction.timeRange = CMTimeRangeMake( kCMTimeZero, videoAssetTrack1.timeRange.duration );
    AVMutableVideoCompositionLayerInstruction *layerInstruction1 = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableCompositionVideoTrack1];
    [layerInstruction1 setOpacity:0.5f atTime:kCMTimeZero];
    
    AVMutableVideoCompositionLayerInstruction *layerInstruction2 = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableCompositionVideoTrack2];
    [layerInstruction2 setOpacity:0.8f atTime:kCMTimeZero];
    CGAffineTransform transformScale = CGAffineTransformMakeScale( 0.5f, 0.5f );
    CGAffineTransform transformTransition = CGAffineTransformMakeTranslation( videoComposition.renderSize.width / 2,  videoComposition.renderSize.height / 2 );
    [ layerInstruction2 setTransform:CGAffineTransformConcat(transformScale, transformTransition) atTime:kCMTimeZero ];
    compInstruction.layerInstructions = @[ layerInstruction1, layerInstruction2 ];
    videoComposition.instructions = @[ compInstruction ];
    

    最后,在导出过程中应该没问题。 很抱歉打扰,如果有人看过。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-08
      • 2016-01-21
      • 2011-04-09
      • 1970-01-01
      • 2017-04-15
      • 1970-01-01
      • 2017-01-05
      • 1970-01-01
      相关资源
      最近更新 更多