【问题标题】:AVAssetExportSession throws error when exporting AVAsset to temporary iOS path将 AVAsset 导出到临时 iOS 路径时 AVAssetExportSession 抛出错误
【发布时间】:2020-06-27 03:09:50
【问题描述】:

我正在尝试修剪用户之前选择的本地 MP3 文件以获得 18 秒的 sn-p。这个 sn-p 应该导出到一个临时文件路径。这是我的代码:

guard songUrl.startAccessingSecurityScopedResource() else {
        print("failed to access path")
        return
    }
    
    // Make sure you release the security-scoped resource when you are done.
    defer { songUrl.stopAccessingSecurityScopedResource() }

    // Use file coordination for reading and writing any of the URL’s content.
    var error: NSError? = nil
    NSFileCoordinator().coordinate(readingItemAt: songUrl, error: &error) { (url) in
        
        
        // Set temporary file path
        let temporaryDirectoryUrl: URL = FileManager.default.temporaryDirectory
        let temporaryDirectoryString: String = temporaryDirectoryUrl.absoluteString
        let temporaryFilename = ProcessInfo().globallyUniqueString + ".m4a"
        let temporaryFilepath = URL(string: (temporaryDirectoryString + temporaryFilename))!

        // shorten audio file
        let originalAsset = AVAsset(url: (url))

        if let exporter = AVAssetExportSession(asset: originalAsset, presetName: AVAssetExportPresetAppleM4A) {
            exporter.outputFileType = AVFileType.m4a
            exporter.outputURL = temporaryFilepath

            let originalDuration = Int64(CMTimeGetSeconds(originalAsset.duration))
            let halftime: Int64 = (originalDuration/2)
            let startTime = CMTimeMake(value: (halftime-9), timescale: 1)
            let stopTime = CMTimeMake(value: (halftime+9), timescale: 1)
            exporter.timeRange = CMTimeRangeFromTimeToTime(start: startTime, end: stopTime)
            print(CMTimeGetSeconds(startTime), CMTimeGetSeconds(stopTime))

            //Export audio snippet
            exporter.exportAsynchronously(completionHandler: {
                
                print("export complete \(exporter.status)")
                    
                switch exporter.status {
                case  AVAssetExportSessionStatus.failed:
                    
                    if let e = exporter.error {
                        print("export failed \(e)")
                    }
                    
                case AVAssetExportSessionStatus.cancelled:
                    print("export cancelled \(String(describing: exporter.error))")
                    
                default:
                    print("export complete")
                    self.shortenedExported(temporaryFilePath: temporaryFilepath)
                }
                })
        }
        else {
                print("cannot create AVAssetExportSession for asset \(originalAsset)")
        }
    }

它打印以下内容:

导出完整的 AVAssetExportSessionStatus

导出失败 Error Domain=AVFoundationErrorDomain Code=-11800 "操作无法完成" UserInfo={NSLocalizedFailureReason=发生未知错误 (-17508), NSLocalizedDescription=操作无法完成, NSUnderlyingError=0x282368b40 {错误域=NSOSStatusErrorDomain 代码=-17508 "(null)"}}

当我使用 Bundle.main.url(forResource: "sample_song", withExtension: "mp3") 而不是协调器的 url 使用我的包资源中的 MP3 文件时,我没有收到错误

提前致谢!

【问题讨论】:

  • 这并不重要,但您需要将print("export complete \(exporter.status)") 更改为print("export complete \(exporter.status.rawValue)"),因为您根本无法从该打印件中获得任何有用的信息。或者干脆删除它,因为在所有情况下你都有一个print
  • 好的,我从来没有使用过coordinate(readingItemAt:,我建议你也不应该使用它,因为它是一个同步阻塞调用,这可能不是你想要的在这里,特别是。因为我没有看到您在后台队列中的任何迹象。
  • 我尝试将coordinate(readingItemAt: 替换为let intent = NSFileAccessIntent.readingIntent(with: songUrl) NSFileCoordinator().coordinate(with: [intent], queue: .main, byAccessor: {file in,然后是处理文件的代码,但现在我似乎无法再访问该文件了,因为它现在返回 -9 和 9开始时间和停止时间
  • 现在显示 export failed Error Domain=AVFoundationErrorDomain Code=-11800 "操作无法完成" UserInfo={NSUnderlyingError=0x282700ab0 {Error Domain=NSOSStatusErrorDomain Code=-16979 "(null )"}, NSLocalizedFailureReason=发生未知错误 (-16979), NSURL=file:///private/var/....mp3, NSLocalizedDescription=操作无法完成} NSURL 显示完整的文件路径mp3

标签: ios swift avassetexportsession


【解决方案1】:

对于任何有同样问题的人:我可以使用 AVMutableComposition() 解决它:

// Access url
    guard songUrl.startAccessingSecurityScopedResource() else {
        print("failed to access path")
        return
    }

    // Make sure you release the security-scoped resource when you are done.
    defer { songUrl.stopAccessingSecurityScopedResource() }

    // Use file coordination for reading and writing any of the URL’s content.
    var error: NSError? = nil
    NSFileCoordinator().coordinate(readingItemAt: songUrl, error: &error) { (url) in

        // Set temporary file's path
        let temporaryDirectoryUrl: URL = FileManager.default.temporaryDirectory
        let temporaryFilename = ProcessInfo().globallyUniqueString
        let temporaryFilepath = temporaryDirectoryUrl.appendingPathComponent("\(temporaryFilename).m4a")

        // Prework
        let originalAsset = AVURLAsset(url: url)
        print(originalAsset)
        let composition = AVMutableComposition()
        let audioTrack: AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)!
        let originalDuration = Int64(CMTimeGetSeconds(originalAsset.duration))
        let startTime, stopTime: CMTime

        // Shorten audio file if longer than 20 seconds
        if originalDuration < 20 {
            startTime = CMTimeMake(value: 0, timescale: 1)
            stopTime = CMTimeMake(value: originalDuration, timescale: 1)
        }
        else {
            let halftime: Int64 = (originalDuration/2)
            startTime = CMTimeMake(value: (halftime-10), timescale: 1)
            stopTime = CMTimeMake(value: (halftime+10), timescale: 1)
        }

        // Export shortened file
        do {
            try audioTrack.insertTimeRange(CMTimeRangeFromTimeToTime(start: startTime, end: stopTime), of: originalAsset.tracks(withMediaType: AVMediaType.audio)[0], at: CMTime.zero)
            let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A)!
            if FileManager.default.fileExists(atPath: temporaryFilepath.absoluteString) {
                try? FileManager.default.removeItem(atPath: temporaryFilepath.absoluteString)
                print("removed existing file")
            }
            assetExport.outputFileType = AVFileType.m4a
            assetExport.outputURL = temporaryFilepath
            assetExport.shouldOptimizeForNetworkUse = true
            assetExport.exportAsynchronously(completionHandler: {
                switch assetExport.status {
                case  AVAssetExportSessionStatus.failed:

                    if let e = assetExport.error {
                        print("export failed \(e)")
                    }
                case AVAssetExportSessionStatus.cancelled:
                    print("export cancelled \(String(describing: assetExport.error))")

                default:
                    print("export completed")
                }
            })
        }
        catch {
            print("error trying to shorten audio file")
        }

【讨论】:

    猜你喜欢
    • 2020-08-03
    • 1970-01-01
    • 2013-03-24
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多