首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在AVComposition中创建背景模糊的iOS

在AVComposition中创建背景模糊的iOS
EN

Stack Overflow用户
提问于 2019-10-25 14:41:58
回答 1查看 331关注 0票数 2

我真的不知道该怎么问这个问题,我希望有任何有益的反馈意见来改进这个问题。我试图制作一个函数,它接受一个视频URL作为输入(本地视频),然后这个函数尝试创建一个背景模糊的视频,其中心是原始视频,然后缩小。我的问题是,除了使用直接从iPhone摄像机录制的视频之外,我的代码运行良好。

我试图实现的一个例子如下(摘自我的代码):

这里的输入视频是一个mp4。我已经能够使代码以及我下载的mov文件在线工作。但是,当我使用从iOS摄像机记录的mov文件时,我的结果是:

(我怎么才能发布在问题中占用较少空间的图片?)

现在,我不知道如何问这个问题,是因为在这个过程中有相当多的代码,而且我还没有完全缩小问题的范围,但是我相信它是在下面粘贴的函数中。我还将发布到github存储库的链接,在那里,我的项目的一个基本版本已经发布给任何好奇或愿意帮助的人。我必须承认,我使用的代码最初是由名为StackOverflow的TheTiger用户在以下问题上编写的:AVFoundation -在视频中添加模糊背景。我重新分析了这个问题的各个部分,并允许他们在这里发布这个问题。

我的github回购链接在这里:GITHUB回购我的演示用三个不同的视频设置,一个从网络下载的mp4 (工作),一个从网络下载的mp4(工作),还有一个我在手机上录制的mov (不工作)。

我所设想的引起问题的代码如下:

代码语言:javascript
复制
fileprivate func addAllVideosAtCenterOfBlur(asset: AVURLAsset, blurVideo: AVURLAsset, scale: CGFloat, completion: @escaping BlurredBackgroundManagerCompletion) {

    let mixComposition = AVMutableComposition()

    var instructionLayers : Array<AVMutableVideoCompositionLayerInstruction> = []

    let blurVideoTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)

    if let videoTrack = blurVideo.tracks(withMediaType: AVMediaType.video).first {
        let timeRange = CMTimeRange(start: .zero, duration: blurVideo.duration)
        try? blurVideoTrack?.insertTimeRange(timeRange, of: videoTrack, at: .zero)
    }

    let timeRange = CMTimeRange(start: .zero, duration: asset.duration)

    let track = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)

    if let videoTrack = asset.tracks(withMediaType: AVMediaType.video).first {

        try? track?.insertTimeRange(timeRange, of: videoTrack, at: .zero)
        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track!)

        let properties = scaleAndPositionInAspectFitMode(forTrack: videoTrack, inArea: size, scale: scale)

        let videoOrientation = videoTrack.getVideoOrientation()
        let assetSize = videoTrack.assetSize()

        let preferredTransform = getPreferredTransform(videoOrientation: videoOrientation, assetSize: assetSize, defaultTransform: asset.preferredTransform, properties: properties)

        layerInstruction.setTransform(preferredTransform, at: .zero)

        instructionLayers.append(layerInstruction)
    }

    /// Adding audio
    if let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first {
        let aTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)
        try? aTrack?.insertTimeRange(timeRange, of: audioTrack, at: .zero)
    }


    /// Blur layer instruction
    let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: blurVideoTrack!)
    instructionLayers.append(layerInstruction)

    let mainInstruction = AVMutableVideoCompositionInstruction()
    mainInstruction.timeRange = timeRange
    mainInstruction.layerInstructions = instructionLayers

    let mainCompositionInst = AVMutableVideoComposition()
    mainCompositionInst.instructions = [mainInstruction]
    mainCompositionInst.frameDuration = CMTimeMake(value: 1, timescale: 30)
    mainCompositionInst.renderSize = size

    //let url = URL(fileURLWithPath: "/Users/enacteservices/Desktop/final_video.mov")
    let url = self.videoOutputUrl(filename: "finalBlurred")
    try? FileManager.default.removeItem(at: url)

    performExport(composition: mixComposition, instructions: mainCompositionInst, stage: 2, outputUrl: url) { (error) in
        if let error = error {
            completion(nil, error)
        } else {
            completion(url, nil)
        }
    }
}

getPreferredTransform()函数也非常相关:

代码语言:javascript
复制
fileprivate func getPreferredTransform(videoOrientation: UIImage.Orientation, assetSize: CGSize, defaultTransform: CGAffineTransform, properties: Properties) -> CGAffineTransform {
    switch videoOrientation {
    case .down:
        return handleDownOrientation(assetSize: assetSize, defaultTransform: defaultTransform, properties: properties)
    case .left:
        return handleLeftOrientation(assetSize: assetSize, defaultTransform: defaultTransform, properties: properties)
    case .right:
        return handleRightOrientation(properties: properties)
    case .up:
        return handleUpOrientation(assetSize: assetSize, defaultTransform: defaultTransform, properties: properties)
    default:
        return handleOtherCases(assetSize: assetSize, defaultTransform: defaultTransform, properties: properties)
    }
}

fileprivate func handleDownOrientation(assetSize: CGSize, defaultTransform: CGAffineTransform, properties: Properties) -> CGAffineTransform {
    let rotateTransform = CGAffineTransform(rotationAngle: -CGFloat(Double.pi/2.0))

    // Scale
    let scaleTransform = CGAffineTransform(scaleX: properties.scale.width, y: properties.scale.height)

    // Translate
    var ytranslation: CGFloat = assetSize.height
    var xtranslation: CGFloat = 0
    if properties.position.y == 0 {
        xtranslation = -(assetSize.width - ((size.width/size.height) * assetSize.height))/2.0
    }
    else {
        ytranslation = assetSize.height - (assetSize.height - ((size.height/size.width) * assetSize.width))/2.0
    }
    let translationTransform = CGAffineTransform(translationX: xtranslation, y: ytranslation)

    // Final transformation - Concatination
    let finalTransform = defaultTransform.concatenating(rotateTransform).concatenating(translationTransform).concatenating(scaleTransform)
    return finalTransform
}

fileprivate func handleLeftOrientation(assetSize: CGSize, defaultTransform: CGAffineTransform, properties: Properties) -> CGAffineTransform {

    let rotateTransform = CGAffineTransform(rotationAngle: -CGFloat(Double.pi))

    // Scale
    let scaleTransform = CGAffineTransform(scaleX: properties.scale.width, y: properties.scale.height)

    // Translate
    var ytranslation: CGFloat = assetSize.height
    var xtranslation: CGFloat = assetSize.width
    if properties.position.y == 0 {
        xtranslation = assetSize.width - (assetSize.width - ((size.width/size.height) * assetSize.height))/2.0
    } else {
        ytranslation = assetSize.height - (assetSize.height - ((size.height/size.width) * assetSize.width))/2.0
    }
    let translationTransform = CGAffineTransform(translationX: xtranslation, y: ytranslation)

    // Final transformation - Concatination
    let finalTransform = defaultTransform.concatenating(rotateTransform).concatenating(translationTransform).concatenating(scaleTransform)

    return finalTransform
}

fileprivate func handleRightOrientation(properties: Properties) -> CGAffineTransform  {
    let scaleTransform = CGAffineTransform(scaleX: properties.scale.width, y: properties.scale.height)

    // Translate
    let translationTransform = CGAffineTransform(translationX: properties.position.x, y: properties.position.y)

    let finalTransform  = scaleTransform.concatenating(translationTransform)
    return finalTransform
}

fileprivate func handleUpOrientation(assetSize: CGSize, defaultTransform: CGAffineTransform, properties: Properties) -> CGAffineTransform {

    return handleOtherCases(assetSize: assetSize, defaultTransform: defaultTransform, properties: properties)
}

fileprivate func handleOtherCases(assetSize: CGSize, defaultTransform: CGAffineTransform, properties: Properties) -> CGAffineTransform {
    let rotateTransform = CGAffineTransform(rotationAngle: CGFloat(Double.pi/2.0))

    let scaleTransform = CGAffineTransform(scaleX: properties.scale.width, y: properties.scale.height)

    var ytranslation: CGFloat = 0
    var xtranslation: CGFloat = assetSize.width
    if properties.position.y == 0 {
        xtranslation = assetSize.width - (assetSize.width - ((size.width/size.height) * assetSize.height))/2.0
    }
    else {
        ytranslation = -(assetSize.height - ((size.height/size.width) * assetSize.width))/2.0
    }
    let translationTransform = CGAffineTransform(translationX: xtranslation, y: ytranslation)

    let finalTransform = defaultTransform.concatenating(rotateTransform).concatenating(translationTransform).concatenating(scaleTransform)
    return finalTransform
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-31 11:46:37

问题在于您的handleOtherCases函数,您在其中创建并返回要应用于框架的CGAffineTransform。所采用的尺度变换和旋转变换都很好。但是你计算出来的翻译变换是不正确的。一定要尝试下面的代码片段,它将产生所需的结果,如所附图像所示。

代码语言:javascript
复制
    fileprivate func handleOtherCases(assetSize: CGSize, defaultTransform: CGAffineTransform, properties: Properties) -> CGAffineTransform {
        let rotateTransform = CGAffineTransform(rotationAngle: CGFloat(Double.pi/2.0))

        let scaleTransform = CGAffineTransform(scaleX: properties.scale.width, y: properties.scale.height)

        let ytranslation: CGFloat = ( self.size.height - ( assetSize.height * properties.scale.height ) ) / 2
        let xtranslation: CGFloat = ( assetSize.width * properties.scale.width ) + ( self.size.width - ( assetSize.width * properties.scale.width ) ) / 2
        let translationTransform = CGAffineTransform(translationX: xtranslation, y: ytranslation)

        let finalTransform = defaultTransform.concatenating(scaleTransform).concatenating(rotateTransform).concatenating(translationTransform)
        return finalTransform
    }

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58560700

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档