Swift: Square video composition

ぐ巨炮叔叔 提交于 2019-12-12 14:37:58

问题


I am following the below code for square video composition

func completeWithVideoAtURL(input: NSURL) {
    let asset = AVAsset(url: input as URL)
    let output = NSURL(fileURLWithPath: NSHomeDirectory() + "/Documents/Video.mp4")

    let session = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetMediumQuality)!
    session.videoComposition = self.squareVideoCompositionForAsset(asset: asset)
    session.outputURL = output as URL
    session.outputFileType = AVFileTypeMPEG4
    session.shouldOptimizeForNetworkUse = true        
    session.exportAsynchronously(completionHandler: { () -> Void in
        DispatchQueue.main.async(execute: { () -> Void in
            // do something with the output
            print("\(output)")
            PHPhotoLibrary.shared().performChanges({
                PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: output as URL)
            }) { saved, error in
                if saved {
                    print("saved to gallery")
                }
            }
        })
    })
}

func squareVideoCompositionForAsset(asset: AVAsset) -> AVVideoComposition {
    let track = asset.tracks(withMediaType: AVMediaTypeVideo)[0]
    let length = max(track.naturalSize.width, track.naturalSize.height)

    var transform = track.preferredTransform

    let size = track.naturalSize
    let scale: CGFloat = (transform.a == -1 && transform.b == 0 && transform.c == 0 && transform.d == -1) ? -1 : 1 // check for inversion

    transform = transform.translatedBy(x: scale * -(size.width - length) / 2, y: scale * -(size.height - length) / 2)

    let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
    transformer.setTransform(transform, at: kCMTimeZero)

    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRange(start: kCMTimeZero, duration: kCMTimePositiveInfinity)
    instruction.layerInstructions = [transformer]

    let composition = AVMutableVideoComposition()
    composition.frameDuration = CMTime(value: 1, timescale: 30)
    composition.renderSize = CGSize(width: length, height: length)
    composition.instructions = [instruction]

    return composition
}

From the squareVideoCompositionForAsset() function I take the max value for length between track.naturalSize.width & track.naturalSize.height cause I don't want to crop any partial part of the video. If I take min value, for portrait video it cropped the upper & lower portion of the video and for landscape video it cropped some left & right portion of the video.

  • For landscape video, output is okay

  • but for portrait video, output is like following image

the video gets left sided. Is it possible to center the video? Any assistance would be great and sorry for long explanation.


回答1:


instead of this line

let scale: CGFloat = (transform.a == -1 && transform.b == 0 && transform.c == 0 && transform.d == -1) ? -1 : 1

I just used this

    var scale = CGFloat()
    if (transform.a == 0 && transform.b == 1 && transform.c == -1 && transform.d == 0) {
        scale = -1
    }
    else if (transform.a == 0 && transform.b == -1 && transform.c == 1 && transform.d == 0) {
        scale = -1
    }
    else if (transform.a == 1 && transform.b == 0 && transform.c == 0 && transform.d == 1) {
        scale = 1
    }
    else if (transform.a == -1 && transform.b == 0 && transform.c == 0 && transform.d == -1) {
        scale = 1
    }

and it worked like a charm




回答2:


Swift 4.2

func suqareCropVideo(videoURL: URL, withSide sideLength: CGFloat, completion: @escaping (_ resultURL: URL?, _ error: Error?) -> ()) {

    let asset = AVAsset(url: videoURL)
    if let assetVideoTrack = asset.tracks(withMediaType: .video).last {

        let originalSize = assetVideoTrack.naturalSize
        var scale: CGFloat
        if originalSize.width < originalSize.height {
            scale = sideLength / originalSize.width
        } else {
            scale = sideLength / originalSize.height
        }

        let scaledSize = CGSize(width: originalSize.width * scale, height: originalSize.height * scale)
        let topLeft = CGPoint(x: sideLength * 0.5 - scaledSize.width * 0.5, y: sideLength  * 0.5 - scaledSize.height * 0.5)

        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: assetVideoTrack)

        var orientationTransform = assetVideoTrack.preferredTransform

        if (orientationTransform.tx == originalSize.width || orientationTransform.tx == originalSize.height) {
            orientationTransform.tx = sideLength
        }

        if (orientationTransform.ty == originalSize.width || orientationTransform.ty == originalSize.height) {
            orientationTransform.ty = sideLength
        }

        let transform = CGAffineTransform(scaleX: scale, y: scale).concatenating(CGAffineTransform(translationX: topLeft.x, y: topLeft.y)).concatenating(orientationTransform)

        layerInstruction.setTransform(transform, at: .zero)


        let instruction = AVMutableVideoCompositionInstruction()
        instruction.layerInstructions = [layerInstruction]
        instruction.timeRange = assetVideoTrack.timeRange

        let videoComposition = AVMutableVideoComposition()
        videoComposition.renderSize = CGSize(width: sideLength, height: sideLength)
        videoComposition.renderScale = 1.0
        videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
        videoComposition.instructions = [instruction]

        if let export = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) {
            export.videoComposition = videoComposition
            export.outputURL = NSURL.fileURL(withPath: "\(NSTemporaryDirectory())\(NSUUID().uuidString).mp4")
            export.outputFileType = AVFileType.mp4
            export.shouldOptimizeForNetworkUse = true
            export.exportAsynchronously {
                DispatchQueue.main.async {
                    if export.status == .completed {
                        completion(export.outputURL, nil)
                    } else {
                        completion(nil, export.error)
                    }
                }
            }
        } else {
            completion(nil, nil)
        }
    }

}


来源:https://stackoverflow.com/questions/43558021/swift-square-video-composition

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!