使用图像(宽高比填充)和视频制作 AVMutableComposition 以适合宽高比

2024-03-04

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

这是我想要实现的目标的一个例子...请注意,我已经有了图像和视频,全部我需要做的是和他们一起制作新视频。它应该是这样的(如图所示):

想要的结果图片在这里—— https://i.stack.imgur.com/aFQPY.png

这是我当前正在尝试的代码,其中包含“背景”的占位符图像(资产中随机的 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
        }
      }
    }
  }

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用图像(宽高比填充)和视频制作 AVMutableComposition 以适合宽高比 的相关文章

  • 检查 UITableViewCell 是否完全可见

    如何检查 UITableViewCell 在屏幕上是否完全可见 不被选项卡或导航栏切断 我可以使用以下代码获取可见单元格 NSArray indexes tableView indexPathsForVisibleRows 但我想排除屏幕中
  • “Firebase Storage”,用于图像 - 但是,获取实际的 URL?

    正在将图像发送到 Firebase Storage 系统 sr a StorageReference ie FIRStorageReference let task sr putData data task observe success
  • Cocoapods 测试链接器错误

    每当我构建测试目标 Xcode 生成的标准目标 时 构建都会失败并出现神秘错误 framework not found Pods AppName AppNameTests 我认为这意味着无法找到为我的测试生成的 pod 目标 我的 podf
  • 快速布尔运算

    这实在令人困惑 有人有什么想法吗 let viewHasMovedToRight false initially I want this to be false then func moveViewToRight sender UIButt
  • TestFlight iOS 应用程序 get-task-allow 问题

    我在 ios 的 testflight 中有一个名为 MapItTrackIt 的应用程序 一切都进展顺利 我刚刚更新到 xcode 5 1 我按照以往的方式构建了该应用程序 相同的配置文件和临时证书 这次 当我尝试上传 IPA 文件时 我
  • 将声音图形化地表示为波

    我创建了一个记录和播放声音的应用程序 我正在寻找一种显示简单波形的方法 记录声音的表示 不需要动画 只需一个简单的图表 如果可以选择波的子集也很好 当然更好 也播放该部分 总而言之 我正在寻找什么 一种以图形方式将录制的声音表示为波的方法
  • 在 iOS 上不显示数字键盘

    根据苹果的文档 http developer apple com library safari documentation AppleApplications Reference SafariHTMLRef Articles InputTy
  • Swift 2 OAuth2 LinkedIn 连接

    我将使用 Swift 2 和 Xcode 7 制作一个本机 iOS 应用程序 用户应该使用 LinkedIn 和 OAuth 2 登录 但我想知道应该如何开始设置 我对 OAuth 2 没有太多经验 有好的教程或示例应用程序吗 我看到了雷
  • 检测用户何时清除通知中心的通知

    我的应用程序需要知道用户是否使用清除按钮从通知中心删除 清除应用程序通知 是否可以检测用户何时从通知中心删除通知或抓取通知中心上的一组通知 你 即App 无法与NotificationCenter交互 NotificationCenter与
  • ios:如何使用 CGPath 模糊图像?

    我创建了一个 CGPath 区域 如绿色圆圈所示 CGPath区域需要清晰 图像的其余部分将应用模糊或半透明效果 我可以使用以下代码在CGPath内剪切图像 UIGraphicsBeginImageContext view frame si
  • 具有自签名证书的 Alamofire / ServerTrustPolicy

    我想使用 Alamofire 通过带有自签名证书的 https 连接与我的服务器进行通信 我的环境在本地主机上运行 我尝试连接 但响应始终如下所示 Success false Response String nil 我用下面的代码完成了它
  • 如何使用 Swift Package Manager 将 SwiftLint 与 iOS 应用程序集成?

    我正在使用 Xcode 11 beta 5 创建一个新的 iOS 应用程序 并且我想使用 Swift Package Manager 而不是 CocoaPods 来管理依赖项 使用 SwiftLint 和 CocoaPods 时的常见模式是
  • 如何让应用更新以吸引人的屏幕形式提供给用户? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我最近在使用 Make My Trip 应用程序 我发现每当我启动应用程序时都会出现一个非常有吸引力的应用程序更新弹出屏幕 它说要更新应用程
  • 领域数据库对象看起来是空的,但实际上不是

    我在用Realm https realm io对于一个小而简单的项目 我正在使用最新版本的框架 昨天从 Github 编译 和当前 AppStore 版本的 Xcode with Swift 2 1 我正在通过 segue 将 Realm
  • Firebase Analytics DebugView 收集的事件数据不完整

    我正在将事件发送到 Firebase Analytics 并发现 DebugView 中缺少部分事件参数 下面是发送到 Firebase 的两个相同事件 我检查了 Xcode 调试控制台中是否存在所有参数 缺失的参数似乎是随机的 有时根本没
  • ios Facebook 添加 FBNativeAdView 作为子视图

    我想使用预建视图FBNativeAdView 不想自定义 FBNative 广告 如link https developers facebook com docs reference ios current class FBNativeAd
  • 启动使用 Simperium 的应用程序时 objectFromJSONString 崩溃

    我得到了一个JSON当我尝试启动使用 Simperium 框架的应用程序时崩溃 NSCFString objectFromJSONString unrecognized selector sent to instance 0x6c561a0
  • 方法调用中的插入符[重复]

    这个问题在这里已经有答案了 我正在阅读本教程 并遇到了这行代码 这让我感到困惑 localSearch startWithCompletionHandler MKLocalSearchResponse response NSError er
  • 了解 React Native 中的默认字体大小

    在过去的几个月里 我一直在开发一个 React Native 应用程序 但有些事情总是让我困惑 而我现在正试图弄清楚它的真相 我正在尝试标准化应用程序中的字体大小 正文 标题等 并且正在努力了解 React Native 究竟从哪里获取默认
  • Xcode 6.4 Swift 单元测试无法编译:“GPUImage.h 未找到”“无法导入桥接标头”

    我的 Xcode 项目构建并运行良好 它有 Swift 和 Objective C 代码 它已安装 GPUImage 我向它添加了单元测试 现在它将不再编译 找不到 GPUImage h 文件 导入桥接标头失败 以下是我发现并尝试过的解决方

随机推荐