首页 > 解决方案 > 使 AVMutableComposition 与图像(方面填充)和视频在方面适合

问题描述

我正在尝试使用始终大小为 CGSize(375, 667) 的图像制作新视频,但视频的大小将不同,并且 contentMode 为 .`aspectFit'。问题是我无法弄清楚如何使整个视频合成具有正确的大小(即图像大小),而是视频的自然大小和一堆奇怪的结果。(编辑说明:视频应该在视图中居中,就像普通 aspectFit 对 UIImageView 所做的那样......)

这是我要实现的目标的示例...请注意,我已经有了图像和视频,我需要做的就是用它们制作新视频。这就是它的样子(在图片中):

此处所需的结果图像-

这是我目前正在尝试的代码,带有“背景”的占位符图像(资产中的随机 375、667 图像..):我想我可能在评论“重要的东西”周围做的事情不正确......但是我目前无法弄清楚:/

  func makeVideo(fromVideoAt videoURL: URL, forName name: String, onComplete: @escaping (URL?) -> Void) {
    let asset = AVURLAsset(url: videoURL)
    let composition = AVMutableComposition()
    
    guard
      let compositionTrack = composition.addMutableTrack(
        withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid),
      let assetTrack = asset.tracks(withMediaType: .video).first
      else {
        print("Something is wrong with the asset.")
        onComplete(nil)
        return
    }
    
    do {
      let timeRange = CMTimeRange(start: .zero, duration: asset.duration)
      try compositionTrack.insertTimeRange(timeRange, of: assetTrack, at: .zero)
      
      if let audioAssetTrack = asset.tracks(withMediaType: .audio).first,
        let compositionAudioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) {
        try compositionAudioTrack.insertTimeRange(timeRange, of: audioAssetTrack, at: .zero)
      }
    } catch {
      print(error)
      onComplete(nil)
      return
    }
    
    compositionTrack.preferredTransform = assetTrack.preferredTransform
    let videoInfo = orientation(from: assetTrack.preferredTransform)
    
    
    
    //Important stuff potentially? general below:
    
    let videoSize: CGSize
    if videoInfo.isPortrait {
      videoSize = CGSize(width: 720, height: 1280)
    } else {
      videoSize = CGSize(width: 720, height: 1280) //720.0, 1280 tiktok default..?
    }
    
    
    
    //the Background image:
    let backgroundLayer = CALayer()
    backgroundLayer.frame = CGRect(origin: .zero, size: videoSize) //videosize
    
    backgroundLayer.contents = UIImage(named: "background")?.cgImage
    backgroundLayer.contentsGravity = .resizeAspectFill
    backgroundLayer.backgroundColor = UIColor.red.cgColor

    //Video layer:
    let videoLayer = CALayer()
//    videoLayer.frame = CGRect(origin: .zero, size: CGSize(width: composition.naturalSize.width, height: composition.naturalSize.height)) //videosize
    videoLayer.backgroundColor = UIColor.yellow.cgColor
        
    print(composition.naturalSize, "<-- composition.naturalSize")
    videoLayer.frame = CGRect(origin: .zero, size: CGSize(width: videoSize.width, height: composition.naturalSize.height))//CGRect(x: 0, y: 0, width: videoSize.width, height: composition.naturalSize.height)

    
    //OutPutlayer putting the together?
    let outputLayer = CALayer()
    outputLayer.frame = CGRect(origin: .zero, size: CGSize(width: 720, height: 1280)) //videosize
    outputLayer.backgroundColor = UIColor.white.cgColor
    outputLayer.addSublayer(backgroundLayer)
    outputLayer.addSublayer(videoLayer)
//    outputLayer.addSublayer(overlayLayer)
    
    let videoComposition = AVMutableVideoComposition()
    videoComposition.renderSize = videoSize
    videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
    videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: outputLayer)
    
    
    //Setting Up Instructions
    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRange(start: .zero, duration: composition.duration)
    videoComposition.instructions = [instruction]
    let layerInstruction = compositionLayerInstruction(for: compositionTrack, assetTrack: assetTrack)
    instruction.layerInstructions = [layerInstruction]
    
    
    
    //EXPORTING
    guard let export = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else {
        print("Cannot create export session.")
        onComplete(nil)
        return
    }
    
    let videoName = UUID().uuidString
    let exportURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(videoName).appendingPathExtension("mp4")
    
    export.videoComposition = videoComposition
    export.outputFileType = .mov
    export.outputURL = exportURL
    
    export.exportAsynchronously {
      DispatchQueue.main.async {
        switch export.status {
        case .completed:
          onComplete(exportURL)
        default:
          print("Something went wrong during export.")
          print(export.error ?? "unknown error")
          onComplete(nil)
          break
        }
      }
    }
  }

标签: iosswiftavfoundationavmutablecomposition

解决方案


尝试使用此代码https://github.com/vabe1337/VBVideoEditor。它可以渲染像 TikTok、Instagram 这样的视频。


推荐阅读