AVFoundation 导出方向错误

2024-02-16

我正在尝试将图像和视频结合起来。我将它们组合并导出,但它是横向旋转的。

抱歉批量粘贴代码。我已经看到了有关应用转换的答案compositionVideoTrack.preferredTransform但这没有任何作用。添加到AVMutableVideoCompositionInstruction也什么都不做。

我觉得这个领域是事情开始出错的地方。这儿这儿:

// I feel like this loading here is the problem
        let videoTrack = videoAsset.tracksWithMediaType(AVMediaTypeVideo)[0]

        // because it makes our parentLayer and videoLayer sizes wrong
        let videoSize       = videoTrack.naturalSize

        // this is returning 1920x1080, so it is rotating the video
        print("\(videoSize.width) , \(videoSize.height)")

所以到这里我们的帧大小对于方法的其余部分来说是错误的。现在,当我们尝试创建覆盖图像层时,框架不正确:

    let aLayer = CALayer()
    aLayer.contents = UIImage(named: "OverlayTestImageOverlay")?.CGImage
    aLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height)
    aLayer.opacity = 1

这是我的完整方法。

  func combineImageVid() {

        let path = NSBundle.mainBundle().pathForResource("SampleMovie", ofType:"MOV")
        let fileURL = NSURL(fileURLWithPath: path!)

        let videoAsset = AVURLAsset(URL: fileURL)
        let mixComposition = AVMutableComposition()

        let compositionVideoTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)

        var clipVideoTrack = videoAsset.tracksWithMediaType(AVMediaTypeVideo)

        do {
            try compositionVideoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), ofTrack: clipVideoTrack[0], atTime: kCMTimeZero)
        }
        catch _ {
            print("failed to insertTimeRange")
        }


        compositionVideoTrack.preferredTransform = videoAsset.preferredTransform

        // I feel like this loading here is the problem
        let videoTrack = videoAsset.tracksWithMediaType(AVMediaTypeVideo)[0]

        // because it makes our parentLayer and videoLayer sizes wrong
        let videoSize       = videoTrack.naturalSize

        // this is returning 1920x1080, so it is rotating the video
        print("\(videoSize.width) , \(videoSize.height)")

        let aLayer = CALayer()
        aLayer.contents = UIImage(named: "OverlayTestImageOverlay")?.CGImage
        aLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height)
        aLayer.opacity = 1


        let parentLayer     = CALayer()
        let videoLayer      = CALayer()

        parentLayer.frame   = CGRectMake(0, 0, videoSize.width, videoSize.height)
        videoLayer.frame    = CGRectMake(0, 0, videoSize.width, videoSize.height)

        parentLayer.addSublayer(videoLayer)
        parentLayer.addSublayer(aLayer)


        let videoComp = AVMutableVideoComposition()
        videoComp.renderSize = videoSize
        videoComp.frameDuration = CMTimeMake(1, 30)
        videoComp.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, inLayer: parentLayer)

        let instruction = AVMutableVideoCompositionInstruction()

        instruction.timeRange = CMTimeRangeMake(kCMTimeZero, mixComposition.duration)

        let mixVideoTrack = mixComposition.tracksWithMediaType(AVMediaTypeVideo)[0]
        mixVideoTrack.preferredTransform = CGAffineTransformMakeRotation(CGFloat(M_PI * 90.0 / 180))

        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: mixVideoTrack)
        instruction.layerInstructions = [layerInstruction]
        videoComp.instructions = [instruction]


        //  create new file to receive data
        let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
        let docsDir: AnyObject = dirPaths[0]
        let movieFilePath = docsDir.stringByAppendingPathComponent("result.mov")
        let movieDestinationUrl = NSURL(fileURLWithPath: movieFilePath)

        do {
            try NSFileManager.defaultManager().removeItemAtPath(movieFilePath)
        }
        catch _ {}


        // use AVAssetExportSession to export video
        let assetExport = AVAssetExportSession(asset: mixComposition, presetName:AVAssetExportPresetHighestQuality)
        assetExport?.videoComposition = videoComp
        assetExport!.outputFileType = AVFileTypeQuickTimeMovie
        assetExport!.outputURL = movieDestinationUrl
        assetExport!.exportAsynchronouslyWithCompletionHandler({
            switch assetExport!.status{
            case  AVAssetExportSessionStatus.Failed:
                print("failed \(assetExport!.error)")
            case AVAssetExportSessionStatus.Cancelled:
                print("cancelled \(assetExport!.error)")
            default:
                print("Movie complete")


                // play video
                NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                    print(movieDestinationUrl)
                })
            }
        })
    }

This is what I'm getting exported: enter image description here


我尝试添加这两种方法来旋转视频:

class func videoCompositionInstructionForTrack(track: AVCompositionTrack, asset: AVAsset) -> AVMutableVideoCompositionLayerInstruction {

    let instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)

    let assetTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0]

    let transform = assetTrack.preferredTransform
    let assetInfo = orientationFromTransform(transform)
    var scaleToFitRatio = UIScreen.mainScreen().bounds.width / assetTrack.naturalSize.width

    if assetInfo.isPortrait {

        scaleToFitRatio = UIScreen.mainScreen().bounds.width / assetTrack.naturalSize.height
        let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio)
        instruction.setTransform(CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor),
            atTime: kCMTimeZero)
    } else {

        let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio)
        var concat = CGAffineTransformConcat(CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor), CGAffineTransformMakeTranslation(0, UIScreen.mainScreen().bounds.width / 2))
        if assetInfo.orientation == .Down {
            let fixUpsideDown = CGAffineTransformMakeRotation(CGFloat(M_PI))
            let windowBounds = UIScreen.mainScreen().bounds
            let yFix = assetTrack.naturalSize.height + windowBounds.height
            let centerFix = CGAffineTransformMakeTranslation(assetTrack.naturalSize.width, yFix)
            concat = CGAffineTransformConcat(CGAffineTransformConcat(fixUpsideDown, centerFix), scaleFactor)
        }
        instruction.setTransform(concat, atTime: kCMTimeZero)
    }

    return instruction
}

class func orientationFromTransform(transform: CGAffineTransform) -> (orientation: UIImageOrientation, isPortrait: Bool) {
    var assetOrientation = UIImageOrientation.Up
    var isPortrait = false
    if transform.a == 0 && transform.b == 1.0 && transform.c == -1.0 && transform.d == 0 {
        assetOrientation = .Right
        isPortrait = true
    } else if transform.a == 0 && transform.b == -1.0 && transform.c == 1.0 && transform.d == 0 {
        assetOrientation = .Left
        isPortrait = true
    } else if transform.a == 1.0 && transform.b == 0 && transform.c == 0 && transform.d == 1.0 {
        assetOrientation = .Up
    } else if transform.a == -1.0 && transform.b == 0 && transform.c == 0 && transform.d == -1.0 {
        assetOrientation = .Down
    }
    return (assetOrientation, isPortrait)
}

更新了我的combineImageVid()方法将其添加到

let instruction = AVMutableVideoCompositionInstruction()

instruction.timeRange = CMTimeRangeMake(kCMTimeZero, mixComposition.duration)

let mixVideoTrack = mixComposition.tracksWithMediaType(AVMediaTypeVideo)[0]

//let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: mixVideoTrack)
//layerInstruction.setTransform(videoAsset.preferredTransform, atTime: kCMTimeZero)

let layerInstruction = videoCompositionInstructionForTrack(compositionVideoTrack, asset: videoAsset)

这给了我这个输出:

所以我越来越接近了,但我觉得因为轨道最初加载的方式是错误的,所以我需要解决那里的问题。另外,我不知道为什么现在会有一个巨大的黑匣子。我想这可能是因为我的图像层占据了此处加载的视频资源的边界:

aLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height)

然而,将其更改为较小的宽度/高度并没有什么区别。然后我考虑添加一个裁剪记录来消除黑色方块,但这也不起作用:(


遵循 Allens 不使用这两种方法的建议:

class func videoCompositionInstructionForTrack(track: AVCompositionTrack, asset: AVAsset) -> AVMutableVideoCompositionLayerInstruction

class func orientationFromTransform(transform: CGAffineTransform) -> (orientation: UIImageOrientation, isPortrait: Bool) 

但将我原来的方法更新为如下所示:

videoLayer.frame    = CGRectMake(0, 0, videoSize.height, videoSize.width) //notice the switched width and height
...
videoComp.renderSize = CGSizeMake(videoSize.height,videoSize.width) //this make the final video in portrait
...
layerInstruction.setTransform(videoTrack.preferredTransform, atTime: kCMTimeZero) //important piece of information let composition know you want to rotate the original video in output

我们已经非常接近了,但是现在的问题似乎是编辑renderSize。如果我将其更改为横向尺寸以外的任何尺寸,我会得到以下结果:


以下是 Apple 的入职培训文档:

https://developer.apple.com/library/ios/qa/qa1744/_index.html https://developer.apple.com/library/ios/qa/qa1744/_index.html

如果您的原始视频是在 iOS 纵向模式下拍摄的,它的自然尺寸仍然是横向的,但它在 mov 文件中带有旋转元数据。为了旋转视频,您需要对第一段代码进行以下更改:

videoLayer.frame    = CGRectMake(0, 0, videoSize.height, videoSize.width) //notice the switched width and height
...
videoComp.renderSize = CGSizeMake(videoSize.height,videoSize.width) //this make the final video in portrait
...
layerInstruction.setTransform(videoTrack.preferredTransform, atTime: kCMTimeZero) //important piece of information let composition know you want to rotate the original video in output

是的,你们真的很接近!

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

AVFoundation 导出方向错误 的相关文章

  • SwiftUI:发送电子邮件

    在正常情况下UIViewController在 Swift 中 我使用此代码发送邮件 let mailComposeViewController configuredMailComposeViewController mailCompose
  • 将 UIToolBar 添加到所有键盘(swift)

    我正在尝试以尽可能少的重复次数将自定义 UIToolBar 添加到我的所有键盘中 我目前的做法要求我将代码添加到所有 viewDidLoads 中 并将每个文本字段的委托分配给我正在使用的 viewController 我尝试创建自己的 U
  • 如何为 iPhone 6+、6 和 5 指定不同尺寸?

    我想让 iPhone 6 6 和 5 上的视图看起来几乎相同 在附图中 我的意思是 例如 取消 按钮在 iPhone 5 中距离屏幕左边缘应为 30 像素 在 6 中为 35 像素 在 6 中为 45 像素 其他元素也类似 如何为每种类型设
  • BigQuery 未显示链接的 Firebase Analytics 事件日志的任何数据集

    我将我的帐户链接到 Big Query 但 Firebase Analytics 事件不会自动加载到 BigQuery 中 显示 未找到数据集 警告 我的工作进度附在下面 请查收 I have getting firebase Analyt
  • 在 iOS 7 中 viewForHeaderInSection 部分是从 1 开始而不是从 0 开始

    我正在处理UITableView在我的项目中 这个项目是在 Xcode 4 5 中创建的 现在我正在使用 Xcode 5 所以我的问题是何时在 iOS 6 中运行我的项目 viewForHeaderInSection方法部分从 0 开始没问
  • 如何删除 UITableView 中的缩进?

    首先 我对此很陌生 我很可能忘记了一些非常简单的事情 问题 我正在制作一个应用程序 在 a 中显示来自 imgur com 的随机图像tableView 由于某种原因 所有单元格都会缩进少量 如下图所示 我摆弄了许多设置storyboard
  • CATextLayer 上 iOS 6 中不需要的垂直填充

    背景 我在 iOS 5 中开始了我的项目 并构建了一个带有图层的漂亮按钮 我在按钮上添加了一个 textLayer 并使用以下代码将其居中 float textLayerVerticlePadding self bounds size he
  • 关闭捕获上下文 Swift

    当我尝试更改闭包中的变量时出现此错误 A C function pointer cannot be formed from a closure that captures context 是否有解决方法或者仍然可以更改闭包内的变量 My C
  • NSPredicate IN 从数组元素查询

    对于一个古怪的标题表示歉意 我有一个 Int 数组 我想定义一个 NSPredicate 来过滤掉 connectionType 等于数组中包含的值的项目 所以基本上是这样的 fetchRequest predicate NSPredica
  • 根据内容自动更改单元格高度 - Swift

    在 Swift 中使用 UITableView 有人可以帮我根据标签 图片和描述自动更改单元格的高度吗 所有信息都正确传递 我只需要帮助格式化它 我尝试使用调整它cell frame size height 但这没有效果 我可以更改故事板中
  • 如何使用 IOS 12 在 UITableViewCell 中正确添加 UICollectionView

    由于某些原因 在使用 Xcode 10 beta 时 我无法正确显示 tableview 单元格内集合中的某些项目 在过去的四天里我尝试了我所知道的一切 我做了一个小项目样本来看看我的问题是什么 如果有人想在本地运行完整代码 请参见此处 h
  • 从现有坐标地图套件中查找最近的位置

    我正在为拥有多家商店的客户开发 iPhone 应用程序 目标 C 我有数组中所有商店 20 的坐标 纬度 长 目前我正在考虑循环遍历商店坐标数组并获取从用户当前位置到商店位置的距离 然后将它们添加到数组中并按最小距离进行排序 这是正确的方法
  • UICollectionView setLayout:animated: 不保留 zIndex

    我注意到打电话时setLayout animated in a UICollectionView要在两个布局之间切换 当前可见的单元格不遵循zIndex它的布局属性已设置在layoutAttributesForItemAtIndexPath
  • 在 SwiftUI 中使用可观察对象切换视图

    我正在练习尝试使用 SwiftUI 中的可观察对象切换视图 但我的代码无法正常工作 我知道我可以用 State 来做到这一点 但我想用可观察的对象来实现这一点 当我单击内容视图中的图像时 图像不会改变 有人能帮我吗 内容视图 swift i
  • 使用输入类型 = 文件捕获照片时移动 safari 崩溃

    我正在使用输入类型文件在 iOS 中启动相机 我正在使用以下代码行
  • iOS:Facebook 登录访问令牌错误:由于模拟器错误,回退到从 NSUserDefaults 加载访问令牌

    根据说明进行配置后 我不断收到此错误 并且无法在我的应用程序上成功使用 Facebook 登录 我在 XCode 8 1 上运行它并使用 iOS 10 1 模拟器 我按照 Facebook iOS SDK 指南中的步骤操作 并将 Faceb
  • ios8 键盘高度有所不同

    我使用下面的代码来获取键盘高度 该高度在带有 ios8 的 iPhone 5s 设备中与带有 ios7 的 IPhone4s 设备中有所不同 因此 当我在带有 ios8 的 iPhone5s 中点击它时 我的文本字段移动得非常高 而相同的代
  • Mac 上的 Delphi - 可能吗? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我负责一个 Delphi Win32 项目管理应用程序 我刚刚完成了向 Delphi 2009 的迁移
  • UIViewController 内的 UIsearchController 使用自动布局

    有没有人成功实施过UIViewController其中包含两个UISearchController searchBar and a UItableView使用自动布局来布局所有内容 我正在尝试实现类似的目标1密码 https itunes
  • 致命错误:在 Swift 中解包可选值时意外发现 nil

    所以我试图获取 Swift 中输入字段的文本 这就是我得到的 class ViewController UIViewController IBOutlet var passwordField UITextField IBOutlet var

随机推荐

  • jQuery - 通过文本描述设置选择控件的选定值

    我有一个选择控件 在 JavaScript 变量中我有一个文本字符串 使用 jQuery 我想将选择控件的选定元素设置为具有我拥有的文本描述的项目 而不是我没有的值 我知道按值设置它非常简单 例如 my select val myVal 但
  • 获取那些有子子 ul 的 li

    如何获得那些li有孩子的ul 我想将 CSS 设置为那些li 我无法设置班级 因为li是动态打印的 当我如下设置 CSS 时 它设置了所有父级li来加 ul width 200px position relative ul li posit
  • 贝塞尔曲线和画布

    如何在画布上绘制贝塞尔曲线 我只有起点和终点 我想从起点到终点画一条线 我怎样才能做到这一点 您可以使用Path quadTo or Path cubicTo 为了那个原因 示例可以在 SDK 示例 FingerPaint 中找到 在你的情
  • backbone.js 解析 1 个元素(Id)

    对于骨干模型上的 id 来说 它只是id并且全部小写 如果我在服务器上的Id被调用怎么办UserId 在主干的解析方法中 我该如何更改UserId to id并对所有其他属性使用相同的名称 For eg window User Backbo
  • JTable 的页脚

    JTable 不支持显示包含每列聚合数据的页脚 受到建议解决方案的启发Oracle Suns 错误数据库 https bugs java com bugdatabase view bug bug id 4242646看起来很有希望 我从用滚
  • Python + 正则表达式:如何在Python中提取两个下划线之间的值?

    我正在尝试提取两个下划线之间的值 为此我写了这段代码 patient ids for file in files print file patient id re findall file patient ids append patien
  • componentWillReceiveProps 与 getDerivedStateFromProps

    componentWillReceiveProps 和 getDerivedStateFromProps 到底是什么对我来说是个微妙的问题 因为 我在使用 getDerivedStateFromProps 时遇到了一个问题 Componen
  • python 请求和 cx_freeze

    我试图冻结一个依赖于请求的 python 应用程序 但出现以下错误 Traceback most recent call last File c Python33 lib site packages requests packages ur
  • 找不到 SPSite 名称空间

    我无法找到名称空间SPSite 到目前为止我已经导入了这些 using System using System Collections Generic using System Linq using System Text using Sy
  • Solr 创建核心时出错:在架构中找不到 fieldType [x]

    我正在尝试让 Solr 核心与我自己的一起运行schema xml 但是Solr 版本5 2 1 一直抱怨丢失fieldType甚至不在我的元素中fields定义 org apache solr common SolrException f
  • 我的股票市场计划可以使用什么数据源? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想为 Linux 和 Windows 制作一个免费的开源 C 应用程序 它将创建实时股票市场图表 即
  • 使用 Windbg 调试 .NET OutOfMemoryException

    我需要帮助调试 net dll 中的 OutOfMemoryException 该 dll 将 rtf 文本转换为原始文本或 html 这是转换代码 http matthewmanela com blog converting rtf to
  • 永久删除机器范围的包源

    我最近从我的计算机上卸载了 Service Fabric 及其 SDK 然而 它留下了一个机器范围的包源 微软 Azure Service Fabric SDKC Program Files Microsoft SDKs Service F
  • 递归地用innerHTML替换shadowRoot[重复]

    这个问题在这里已经有答案了 我想获得提取了shadowRoot 元素的纯HTML 网站上有很多 ShadowRoot 元素 并且嵌套很深 我用那段代码来实现它 但它只提取了部分元素 const getShadowDomHtml shadow
  • 如何在 AngularJS 中丢弃预检响应

    当向我的服务发送 http post 请求时 我首先发送一个 Option 请求 根据 Cors 的要求 然而我已经意识到我的OPTIONS 飞行前 请求返回否response data在其回应中 但我的POST请求是 这带来了一个问题 因
  • 如何更改 Chart.JS 中标签的字体(系列)?

    我想将 Chart JS 水平条形图中的字体更改为更时尚的字体 我尝试过以下方法 但都不起作用 var optionsBar fontFamily Candara Calibri Courier serif bodyFontFamily C
  • 如何在 C# 中为用户获取 AD LDS 条目的有效权限?

    我有第 3 方应用程序使用 AD LDS 来存储其分层数据 并且我需要在 ASP NET MVC 中为此系统提供 Web UI 它在目录条目上使用 DACL 来控制用户对各个条目的访问权限 我发现了一些解释如何阅读的好文章ActiveDir
  • Xcode 总是显示“FBSDKShareKit/FBSDKShareKit”.h 文件未找到

    无论我做什么 我可能做错了 当我尝试构建 Unity IOS 应用程序进行测试时 Xcode 总是显示 FBSDKShareKit FBSDKShareKit h 文件未找到 我已在 Xcode 项目中添加了 iOS 快速入门中指示的 Fa
  • 如何在没有登录按钮的情况下初始化 Google 登录?

    下面的代码作为一个简单的测试页面 使用谷歌登录 https developers google com identity sign in web
  • AVFoundation 导出方向错误

    我正在尝试将图像和视频结合起来 我将它们组合并导出 但它是横向旋转的 抱歉批量粘贴代码 我已经看到了有关应用转换的答案compositionVideoTrack preferredTransform但这没有任何作用 添加到AVMutable