[英]Merging Videos but AVAssetExportSession never completes
Trying to merge some videos together and export them as a single file, everything seems to be correct from looking at tutorials/examples however my AVAssetExportSession never seems to be complete, and my video file is never exported, any help as to a blindingly obvious error I'm missing would be very appreciated. 尝试将一些视频合并在一起并将它们导出为单个文件,从看教程/示例来看,一切似乎都是正确的,但是我的AVAssetExportSession似乎从来都不完整,并且我的视频文件也从未导出过,这对于显而易见的错误是有帮助的我很想念我。
Below is the function where i merge the videos 以下是我合并视频的功能
note 'videos' in the loop is a member variable var videos = [AVAsset]()
which gets populated (and it does i checked) before merge is called. 请注意,循环中的“视频”是成员变量
var videos = [AVAsset]()
,在调用合并之前填充了该变量(并且我进行了检查)。
private func merge()
{
// Create AVMutableComposition to contain all AVMutableComposition tracks
var mix_composition = AVMutableComposition()
var total_time_seconds = 0.0
var tracks = [AVCompositionTrack]()
// Loop over videos and create tracks, keep incrementing total duration
for video in videos
{
// Create the composition track for this video
let track = mix_composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
// Add video duration to total time
total_time_seconds = total_time_seconds + video.duration.seconds
// Add track to array of tracks
tracks.append(track)
// Add time range to track
do
{
try track.insertTimeRange(CMTimeRangeMake(kCMTimeZero, video.duration), ofTrack: video.tracksWithMediaType(AVMediaTypeVideo)[0], atTime: video.duration)
}
catch _
{
}
}
// Set total time
let preferred_time_scale: Int32 = 600;
let total_time = CMTimeMakeWithSeconds(total_time_seconds, preferred_time_scale)
// Create main instrcution for video composition
let main_instruction = AVMutableVideoCompositionInstruction()
main_instruction.timeRange = CMTimeRangeMake(kCMTimeZero, total_time)
// Create array to hold instructions
var layer_instructions = [AVVideoCompositionLayerInstruction]()
// Ensure we have the same number of tracks as videos
if videos.count == tracks.count
{
// Loop number of videos and tracks
for var index = 0; index < videos.count; ++index
{
// Create compositioninstruction for each track
let instruction = videoCompositionInstructionForTrack(tracks[index], asset: videos[index])
if(index == 0)
{
instruction.setOpacity(0.0, atTime: videos[index].duration)
}
// Add instruction to instructions array
layer_instructions.append(instruction)
}
}
// Set tack instructions to main instruction
main_instruction.layerInstructions = layer_instructions
let main_composition = AVMutableVideoComposition()
main_composition.instructions = [main_instruction]
main_composition.frameDuration = CMTimeMake(1, 30)
main_composition.renderSize = CGSize(width: UIScreen.mainScreen().bounds.width, height: UIScreen.mainScreen().bounds.height)
// Get path for Final video in the current project directory
let documents_url = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let final_url = documents_url.URLByAppendingPathComponent("TEST.mp4")
// Create AV Export Session
let exporter = AVAssetExportSession(asset: mix_composition, presetName: AVAssetExportPresetHighestQuality)
exporter!.outputURL = final_url
exporter!.outputFileType = AVFileTypeMPEG4
exporter!.shouldOptimizeForNetworkUse = true
exporter!.videoComposition = main_composition
// Perform the Export
exporter!.exportAsynchronouslyWithCompletionHandler() {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.exportDidFinish(exporter!)
})
}
}
Below shows the exportDidFinished function which is called when exportAsynchronouslyWithCompletionHandler
is called. 下面显示了exportDidFinished函数,该函数在调用
exportAsynchronouslyWithCompletionHandler
调用。 I get inside this function but nothing ever happens because the session status is never completed. 我进入了此函数,但由于会话状态从未完成,因此什么也没发生。
func exportDidFinish(session: AVAssetExportSession)
{
if session.status == AVAssetExportSessionStatus.Completed
{
let outputURL = session.outputURL
let library = ALAssetsLibrary()
if library.videoAtPathIsCompatibleWithSavedPhotosAlbum(outputURL)
{
library.writeVideoAtPathToSavedPhotosAlbum(outputURL,
completionBlock: { (assetURL:NSURL!, error:NSError!) -> Void in
if error != nil
{
let alert = UIAlertView(title: "Error", message: "Video Not Saved", delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
else
{
let alert = UIAlertView(title: "Success", message: "Video Saved", delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
})
}
}
}
printed the session status showed that it was 4 which is failed, so i printed session.error and got this, but I'm unsure on what it means, any help would be great 打印会话状态显示为4,这是失败的,所以我打印了session.error并得到了它,但是我不确定这意味着什么,任何帮助都将是非常有用的
Optional(Error Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped" UserInfo={NSLocalizedDescription=Operation Stopped, NSLocalizedFailureReason=The video could not be composed.})
If exportDidFinish
is called but nothing happens, your session's status is not AVAssetExportSessionStatus.Completed
. 如果调用
exportDidFinish
,但没有任何反应,则会话的状态不是AVAssetExportSessionStatus.Completed
。 It may be AVAssetExportSessionStatus.Failed
, or some other value. 它可能是
AVAssetExportSessionStatus.Failed
或其他一些值。 Check those values and if it did fail check the session.error property for more info. 检查这些值,如果确实失败,请检查session.error属性以获取更多信息。
EDIT : If you want one video to play after another, create only one AVMutableCompositionTrack
. 编辑 :如果要一个视频播放另一个,只创建一个
AVMutableCompositionTrack
。 See below for relevant changes: 请参阅以下相关更改:
...
var mix_composition = AVMutableComposition()
// Create the composition track for the videos
let track = mix_composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
//keep track of total time
var totalTime = kCMTimeZero
for video in videos
{
// Add time range to track
do
{
let videoTrack = video.tracksWithMediaType(AVMediaTypeVideo)[0]
let videoDuration = videoTrack.duration
let timeRange = CMTimeRangeMake(kCMTimeZero,videoDuration)
try track.insertTimeRange(timeRange, ofTrack: videoTrack, atTime: totalTime)
totalTime = CMTimeAdd(totalTime,videoDuration)
}
catch _
{
}
}
// Create main instruction for video composition
let main_instruction = AVMutableVideoCompositionInstruction()
main_instruction.timeRange = CMTimeRangeMake(kCMTimeZero, totalTime)
// Create array to hold instructions
var layer_instructions = [AVVideoCompositionLayerInstruction]()
// Create layer instruction
let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
// Add it to the array
layer_instructions.append(layerInstruction)
...
You'll also want to adjust your renderSize to something appropriate. 您还需要将renderSize调整为适当的值。 The size of your videos may not be the size of your screen.
视频的大小可能不等于屏幕的大小。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.