修剪视频,同时保持质量

时间:2017-12-29 17:44:52

标签: swift video avasset avcomposition

我正在将现有(存储在图库中)视频修剪成更小的块;但我发现最终的视频质量太差了:

var chunkNumber = 1
let startTime = CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(600.0))
let theDuration = CMTime(seconds: 10.0, preferredTimescale: CMTimeScale(600.0))

// the AVMutableComposition holds the track instances
let mixCompostion = AVMutableComposition()

// video
let videoTrack = mixCompostion.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
do {
    try videoTrack?.insertTimeRange(CMTimeRangeMake(startTime, theDuration),
            of: (asset?.tracks(withMediaType: AVMediaType.video)[0])!, at: kCMTimeZero)
} catch {
    print ("failed to load the video track")
}

// audio
if ((asset?.tracks(withMediaType: AVMediaType.audio).count)! > 0) {
    let audioTrack = mixCompostion.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: 0)
    do {
        try audioTrack?.insertTimeRange(CMTimeRangeMake(startTime, theDuration),
                of: (asset?.tracks(withMediaType: AVMediaType.audio)[0])!, at: kCMTimeZero)
    } catch {
        print ("failed to load the audio track")
    }
}

// layers
let parentLayer = CALayer()
let videoLayer = CALayer()
let layerFrame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
parentLayer.frame = layerFrame
videoLayer.frame = layerFrame
parentLayer.addSublayer(videoLayer)

// master instruction wraps entire set of instructions
let masterInstruction = AVMutableVideoCompositionInstruction()
masterInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, theDuration)
let videoLayerInstruction = videoCompositionInstructionForTrack(track: videoTrack!, asset: asset!)

// add instructions to master, prepare composition
masterInstruction.layerInstructions = [videoLayerInstruction]
let mainComposition = AVMutableVideoComposition()
mainComposition.instructions = [masterInstruction]
mainComposition.frameDuration = CMTimeMake(1, 30)
mainComposition.renderSize = CGSize(width: mainCompositionWidth, height: mainCompositionHeight)
mainComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)

// get path
let date = Date()
let savePath = (documentDirectory as NSString).appendingPathComponent("\(date)-\(chunkNumber).mov")
let url = URL(fileURLWithPath: savePath)
chunkNumber += 1

// create exporter
guard let exporter = AVAssetExportSession(asset: mixCompostion, presetName: AVAssetExportPresetHighestQuality) else { return }
exporter.outputURL = url
exporter.outputFileType = AVFileType.mov
exporter.shouldOptimizeForNetworkUse = true
exporter.videoComposition = mainComposition

// export
exporter.exportAsynchronously(completionHandler: { () -> Void in
    DispatchQueue.global().async {
        self.exportDidFinish(session: exporter)
    }
})

func exportDidFinish(session: AVAssetExportSession) {
    if session.status == AVAssetExportSessionStatus.completed {
        PHPhotoLibrary.shared().performChanges({
            _ = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: session.outputURL!)
        }, completionHandler: { (success, error) in
            let completionString = success ? "Success." : error?.localizedDescription
            print ("Finished updating asset: \(String(describing: completionString))")
        })
    }
    else if session.status == AVAssetExportSessionStatus.failed {
        print ("Export failed -> Reason: \(String(describing: session.error))")
        delegate?.exportFailed()
    }
}

为了保持视频的质量相同,或者至少更接近原始视频,我能做些什么?

1 个答案:

答案 0 :(得分:0)

为了更好地控制视频操作,您可以通过其中一个包装器库使用ffmpeg - 请参阅以下链接:

我没有使用其中一款iOS,但我在Android上做了同样的事情并且运行良好,通常需要注意的是移动设备上的视频处理速度很慢。