AVAssetExportSession在设备上不起作用,但在模拟器上起作用(AVFoundationErrorDomain代码= -11800,未知错误代码-12780) [英] AVAssetExportSession not working on devices, but working on simulator (AVFoundationErrorDomain Code = -11800, Unknown Error code -12780)

查看:94
本文介绍了AVAssetExportSession在设备上不起作用,但在模拟器上起作用(AVFoundationErrorDomain代码= -11800,未知错误代码-12780)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:为了使对解决此问题感兴趣的任何人都更轻松,我向

To make things easier to anyone interested in checking out this problem, I added a demo project to this github repository.

问题

我看到了几个具有相同错误的问题,但是那里没有找到解决方案对我有帮助.想通了,我会试试运气的.

I've seen several questions that had the same error, but none of the solutions found there helped me. Figured I'd try my luck.

我正尝试按原样导出视频,主要是为了了解AVFoundation和AVAssetExportSession.我的导出在模拟器上可以正常运行,但在我尝试过的任何iOS设备上均无法运行(即,每个运行iOS 12的iPhone X和iPhone XR).我主要遵循在此链接上找到的Ray Wenderleich教程来执行视频导出: https://www.raywenderlich.com/2734-avfoundation-tutorial-adding-overlays-and-animations-to-videos

I'm trying to export a video as is, mainly to learn about AVFoundation and AVAssetExportSession. My export works perfectly fine on the simulator, but does not work on any iOS device I've tried (namely an iPhone X and an iPhone XR running iOS 12 each). I Mainly followed a Ray Wenderleich tutorial found on this link to perform the Video Exporting: https://www.raywenderlich.com/2734-avfoundation-tutorial-adding-overlays-and-animations-to-videos

将感谢您对该主题的任何帮助.我的代码如下:

Would appreciate any help on the topic. My code is as follows:

检索我添加到应用程序捆绑包中名为Demo.mp4的视频的URL:

Retrieving the URL of a video I've added to the App Bundle called Demo.mp4:

@objc func export() {
    let urlString = Bundle.main.path(forResource: "Demo", ofType: ".mp4")!
    let url = URL(fileURLWithPath: urlString)
    ExportManager.shared.exportWithAVFoundation(url:url) { (outputUrl, errorString) in
        if let outputUrl = outputUrl {
            self.playVideo(url: outputUrl)
        } else if let errorString = errorString {
            print("ERROR: \(errorString)")
        }
    }
}

我在ExportManager中的导出功能如下(很抱歉,很长一段时间)

My Exporting function in ExportManager is as follows (Sorry quite long)

func exportWithAVFoundation(url: URL, completion: @escaping (_ outputUrl: URL?, _ errorString: String?) -> ()) {
    let asset = AVAsset(url: url)
    print("URL IS \(url)")
    guard let avAssetTrack = asset.tracks(withMediaType: .video).first else {
        completion(nil, "Couldn't Create Asset Track")
        return
    }

    let mutableComposition = AVMutableComposition()
    guard let videoTrack = mutableComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) else { return }
    try? videoTrack.insertTimeRange(CMTimeRange(start: .zero, duration: asset.duration), of: avAssetTrack, at: .zero)
    videoTrack.preferredTransform = avAssetTrack.preferredTransform

    if let audioAssetTrack = asset.tracks(withMediaType: .audio).first {
        let audioTrack = mutableComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)
        try? audioTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: asset.duration), of: audioAssetTrack, at: .zero)
    }

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

    let videoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)

    // Fix video orientation
    var videoAssetOrientation = UIImage.Orientation.up
    var isVideoAssetPortrait = false
    let videoTransform = avAssetTrack.preferredTransform

    switch (videoTransform.a, videoTransform.b, videoTransform.c, videoTransform.c) {
    case (0, 1.0, -1.0, 0):
        videoAssetOrientation = .right
        isVideoAssetPortrait = true
    case(0, -1.0, 1.0, 0):
        videoAssetOrientation = .left
        isVideoAssetPortrait = true
    case(1.0, 0, 0, 1.0):
        videoAssetOrientation = .up
    case(-1.0, 0, 0, -1.0):
        videoAssetOrientation = .down
    default:
        break
    }

    var naturalSize = avAssetTrack.naturalSize
    switch (videoAssetOrientation, isVideoAssetPortrait) {
    case (.right, true):
        naturalSize = CGSize(width: avAssetTrack.naturalSize.height, height: avAssetTrack.naturalSize.width)
    case (.left, true):
        naturalSize = CGSize(width: avAssetTrack.naturalSize.height, height: avAssetTrack.naturalSize.width)
    case (.leftMirrored, true):
        naturalSize = CGSize(width: avAssetTrack.naturalSize.height, height: avAssetTrack.naturalSize.width)
    case (.rightMirrored, true):
        naturalSize = CGSize(width: avAssetTrack.naturalSize.height, height: avAssetTrack.naturalSize.width)
    default:
        break
    }

    videoLayerInstruction.setTransform(avAssetTrack.preferredTransform, at: .zero)
    videoLayerInstruction.setOpacity(0, at: asset.duration)

    mainInstruction.layerInstructions = [videoLayerInstruction]

    let mainCompositionInstruction = AVMutableVideoComposition()

    mainCompositionInstruction.renderSize = naturalSize
    mainCompositionInstruction.instructions = [mainInstruction]
    mainCompositionInstruction.frameDuration = CMTimeMake(value: 1, timescale: 30);

    let documentsDirectoryURL = createPath()

    guard let exporter = AVAssetExportSession(asset: mutableComposition, presetName: AVAssetExportPresetHighestQuality) else {
        print("Couldnt create AVAssetExportSession")

        completion(nil, "Couldn't Create AVAssetExportSession")
        return
    }

    exporter.outputURL = documentsDirectoryURL
    exporter.outputFileType = .mov
    exporter.shouldOptimizeForNetworkUse = true
    exporter.videoComposition = mainCompositionInstruction

    exporter.exportAsynchronously {
        if let error = exporter.error {
            print(error)
            completion(nil, error.localizedDescription)
            return
        }

        completion(exporter.outputURL, nil)
        print("Finished Exporting")
    }
}

我尝试做的一些事情是将AudioTrack添加到合成中(我以前没有包括过).并没有帮助它在实际设备上运行,但是至少我导出的视频现在有音频.

Some things I've tried to do have been to add an AudioTrack to the composition (which I didn't include previously). Hasn't helped it work on an actual device, but at least my exported video has audio now.

我还尝试将预设质量"更改为通过",而不是最高质量",正如我从其他主题中读到的那样,这可能有所帮助,但无济于事.

I also tried to change the Preset Quality to Passthrough as opposed to Highest Quality, as I read from other threads that this could help, but to no avail.

编辑:

添加了createPath函数:

Added createPath function:

func createPath() -> URL {
    let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
    let documentDirectory = paths.first!
    let myPathDocs = documentDirectory.appending("FinalVideo.mov")
    let url = URL(fileURLWithPath: myPathDocs)

    if FileManager.default.fileExists(atPath: myPathDocs) {
        try? FileManager.default.removeItem(atPath: myPathDocs)
    }

    return url
}

注意:createPath()只是在目录中创建一个有效路径来保存导出的视频.如果在导出之前该路径上存在文件,则会将其删除.

Note: createPath() just creates a valid path in the directory to save the exported video in. If a file exists at that path prior to exporting, it gets deleted.

推荐答案

问题是您将字符串附加到另一个字符串,导致该文件的路径错误,例如 file:///var/移动/容器/数据/应用/<stripped>/DocumentsFinalVideo.mov

The problem is that you're appending string to another string resulting in wrong path to the file like file:///var/mobile/Containers/Data/Application/<stripped>/DocumentsFinalVideo.mov

您应该改用 appendingPathComponent():

func createPath() -> URL {
    let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
    let documentDirectory = URL(fileURLWithPath: paths.first!)
    let url = documentDirectory.appendingPathComponent("FinalVideo.mov")

    if FileManager.default.fileExists(atPath: url.path) {
        try? FileManager.default.removeItem(at: url)
    }

    return url
}

这篇关于AVAssetExportSession在设备上不起作用,但在模拟器上起作用(AVFoundationErrorDomain代码= -11800,未知错误代码-12780)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆