ios - AVAssetExportSession 只工作前 6 次

标签 ios swift avassetexportsession avmutablecomposition cmtime

更新的代码示例、控制台输出和信息

我正在尝试获取视频合成的总持续时间,将其除以 10,四舍五入,然后循环遍历并以这些间隔拼接视频合成。

它有效,但在“currentDuration”变为 60+ 后,它会抛出“在此服务器上找不到请求的 URL”。

基本上,如果它确定它需要制作 9 个剪辑,它会在前 6 个剪辑中成功,而在其他 3 个剪辑中失败。而且我的 numLoop 没有按预期工作,似乎 while 循环在尝试 9 个剪辑中的任何一个之前完成.

希望对导出所有 9 个剪辑有一些帮助/见解。

I've noticed if the video is less than 60 seconds long, it has 100% success rate. Any video I choose over 60 seconds will fails on the 7th clip.

这是我的方法:

func splitVideo(videoComposition: AVMutableVideoComposition) {


let fileManager = NSFileManager.defaultManager()
let documentsPath : String = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0]

//grab total duration/number of splits
let exporter: AVAssetExportSession = AVAssetExportSession(asset: asset!, presetName:AVAssetExportPresetHighestQuality)!
let totalDuration = Float64(CMTimeGetSeconds(exporter.asset.duration))
let totalDurationPieces = (totalDuration/10)
var numberOfSplits=Int(ceil(Double(totalDurationPieces)))

//prepare for loop
var loopNum : Int = 0
var currentDuration : Float64 = 0
var sessionNumber = (arc4random()%1000)

let opQueue = NSOperationQueue()
    opQueue.maxConcurrentOperationCount = 1

    while loopNum < numberOfSplits {

        //new exporter
        var destinationPath: String = documentsPath + "/splitVideo-"+String(sessionNumber)
        destinationPath+="-"+String(Int(loopNum))+".mp4"

        let new_exporter = AVAssetExportSession(asset: asset!, presetName:AVAssetExportPresetHighestQuality)!

        new_exporter.outputURL = NSURL(fileURLWithPath: destinationPath as String)
        new_exporter.videoComposition = videoComposition
        new_exporter.outputFileType = AVFileTypeMPEG4
        new_exporter.shouldOptimizeForNetworkUse = false

        new_exporter.timeRange = CMTimeRangeMake(
            CMTimeMakeWithSeconds(currentDuration, framesPerSecond!),CMTimeMakeWithSeconds(Float64(10),framesPerSecond!))

        // Set up the exporter, then:
        opQueue.addOperationWithBlock { () -> Void in
            new_exporter.exportAsynchronouslyWithCompletionHandler({
                dispatch_async(dispatch_get_main_queue(),{
                    print("Exporting... \(loopNum)")
                    self.exportDidFinish(new_exporter, loopNum: loopNum)
                })
            }) // end completion handler
        } // end block



        //prepare for next loop
        loopNum = loopNum+1
        currentDuration = currentDuration+10

    if(loopNum>=numberOfSplits){
        self.allExportsDone(Int(numberOfSplits))
        }
} // end while


}

这是 exportDidFinish 方法:

func exportDidFinish(session: AVAssetExportSession, loopNum: Int) {
let outputURL: NSURL = session.outputURL!
let library: ALAssetsLibrary = ALAssetsLibrary()
if(library.videoAtPathIsCompatibleWithSavedPhotosAlbum(outputURL)) {
    library.writeVideoAtPathToSavedPhotosAlbum(outputURL, completionBlock: {(url, error) in
//done
print("Success on \(Int(loopNum))")
})
}
}

这是控制台输出:

Exporting... 9
2016-08-20 13:39:27.980 TrimVideo[4776:1576022] Video /var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-6.mp4 cannot be saved to the saved photos album: Error Domain=NSURLErrorDomain Code=-1100 "The requested URL was not found on this server." UserInfo={NSUnderlyingError=0x1457f43f0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}, NSErrorFailingURLStringKey=file:///var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-6.mp4, NSErrorFailingURLKey=file:///var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-6.mp4, NSURL=file:///var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-6.mp4, NSLocalizedDescription=The requested URL was not found on this server.}
Exporting... 9
2016-08-20 13:39:27.984 TrimVideo[4776:1576022] Video /var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-7.mp4 cannot be saved to the saved photos album: Error Domain=NSURLErrorDomain Code=-1100 "The requested URL was not found on this server." UserInfo={NSUnderlyingError=0x1457f88c0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}, NSErrorFailingURLStringKey=file:///var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-7.mp4, NSErrorFailingURLKey=file:///var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-7.mp4, NSURL=file:///var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-7.mp4, NSLocalizedDescription=The requested URL was not found on this server.}
Exporting... 9
2016-08-20 13:39:27.988 TrimVideo[4776:1576022] Video /var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-8.mp4 cannot be saved to the saved photos album: Error Domain=NSURLErrorDomain Code=-1100 "The requested URL was not found on this server." UserInfo={NSUnderlyingError=0x14687cb30 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}, NSErrorFailingURLStringKey=file:///var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-8.mp4, NSErrorFailingURLKey=file:///var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-8.mp4, NSURL=file:///var/mobile/Containers/Data/Application/BE125EB7-AFC4-48B5-95C3-941B420BB71F/Documents/splitVideo-972-8.mp4, NSLocalizedDescription=The requested URL was not found on this server.}
Exporting... 9
Success on 9
Exporting... 9
Success on 9
Exporting... 9
Success on 9
Exporting... 9
Success on 9
Exporting... 9

最佳答案

好的,一些新闻。

  1. 自 iOS 8 以来,ALAssetsLibrary 已被弃用,Apple 将所有人转移到照片框架来执行此操作。好消息是 AVAssetExportSession 没有被弃用。虽然您可以继续使用已弃用的 API,但重写 exportDidFinish 函数以使用新 API 可能是个好主意。

  2. splitVideo 函数中的 while 循环抛出了十个并发导出操作。老实说,这是一个猜测,但我怀疑一旦你到达剪辑 6,就会出现一些资源争用。

因此需要重新设计以使其更加友好。最好的办法是使用 NSOperationQueue 并将 maxConcurrentOperationsCount 设置为 1(即串行队列)。

类似于:

let opQueue = NSOperationQueue()
opQueue.maxConcurrentOperationsCount = 1

for loopNum in 0..<numberOfSplits {

   // Set up the exporter, then:

    opQueue.addOperationWithBlock { () -> Void in
        new_exporter.exportAsynchronouslyWithCompletionHandler({
            dispatch_async(dispatch_get_main_queue(),{
                print("Exporting... \(loopNum)")
                self.exportDidFinish(new_exporter, loopNum: loopNum)
            })
        } // end completion handler
    } // end block

} // end while

这样做的目的是确保导出操作一次运行一个,而不是一次尝试一次。如果成功,您可以尝试提高 maxConcurrentOperationsCount 以进行一些多线程处理。

关于ios - AVAssetExportSession 只工作前 6 次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39057099/

相关文章:

IOS webview 回调 url 更改

iphone - 如何选择名称为 Object 的 UIImageView

ios - Firebase 通知无法在后台运行

swift - 继续在后台运行倒计时器

objective-c - AVAssetExportSession - 仅 mov 音频文件导出失败?

ios - AudioFile 修剪不起作用

iphone - 如何在 iPhone 图片库中获取图像的嵌入式 GPS 和地理定位数据

iphone - iOS 6 中 View Controller 的错误旋转

ios - 在 ViewControllers Swift 3 之间传递 Double

ios - 在 Instagram 中打开 AVMutableComposition 时出现白色视频