如何在 OS X 上调整、裁剪和导出 Swift 中的 AVAsset?

How to resize, crop and export AVAsset in Swift on OS X?

我正在尝试调整和裁剪 AVAsset 并将其导出到 OS X 上 Swift 中的电影文件。

我正在使用 AVAssetExportSession 导出 AVAsset,如果未将 videoComposition 设置为 AVAssetExportSession,它可以正常工作。以下代码可以毫无问题地导出资产,但由于 videoComposition 行被注释掉,它不会调整大小和裁剪。

self.asset = AVAsset( URL: validURL )!

if let exportSession = AVAssetExportSession( asset: self.asset,
                                        presetName: AVAssetExportPresetAppleProRes422LPCM ) {
        exportSession.outputURL = exportURL
        exportSession.outputFileType = AVFileTypeQuickTimeMovie
//      exportSession.videoComposition = self.videoComposition   // *** problematic line
        exportSession.timeRange = CMTimeRangeMake( kCMTimeZero, self.asset.duration )

        exportSession.exportAsynchronouslyWithCompletionHandler( { () -> Void in

            print( "[export completed]" )       
        })
}

但是,如果我将videoComposition设置为AVAssetExportSession,通过移除评论来调整大小和裁剪资产,导出的文件只有调整大小和裁剪视频的第一帧,第二帧和后面的帧都是黑帧,而音频导出没有问题。

我设置的videoComposition如下。 (为了简化代码,本例固定渲染大小和仿射变换)

var videoComposition: AVVideoComposition {
    //---------------
    //  composition
    //---------------
    let composition = AVMutableVideoComposition()
    composition.renderSize = NSMakeSize( 720, 480 )  // fixed size in this example
    composition.frameDuration = self.asset.duration

    //---------------
    //  instruction
    //---------------
    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRangeMake( kCMTimeZero, self.asset.duration )

    //-------------------------
    //  transform instruction
    //-------------------------
    let videoTracks = self.asset.tracksWithMediaType( AVMediaTypeVideo )
    let assetTrack = videoTracks[0]
    let layerInstruction = AVMutableVideoCompositionLayerInstruction( assetTrack: assetTrack )

    let transform = CGAffineTransformMake( 1.5,  // fixed transform in this example
        0.0,
        0.0,
        2.0,
        -100.0,
        -100.0 )

    layerInstruction.setTransformRampFromStartTransform( transform,
                                         toEndTransform: transform,
                                              timeRange: CMTimeRangeMake( kCMTimeZero, self.asset.duration ) )

    instruction.layerInstructions = [ layerInstruction ]
    composition.instructions = [ instruction ]

    return composition
}

如何避免第二帧和后面的帧变黑并成功导出所有调整大小和裁剪的帧?

你合成的frameDuration属性是每帧的时间间隔——也就是你视频每秒的帧数。您当前已将此设置为整个资产轨道的长度,因此一帧持续整个轨道长度。

例如,以下代码会将您的合成设置为每秒 30 帧的帧速率:

composition.frameDuration = CMTimeMake(1, 30)

理想情况下,您将使用视频轨道的帧速率(AVAssetTrack 有 nominalFrameRate 属性),如下所示:

composition.frameDuration = CMTimeMake(1, assetTrack.nominalFrameRate)