Swift:合并音频和视频文件。

3

我想将视频和音频文件合并,但我无法做到。视频可以导出,但是音频文件不想被合并。

func mergeAudio(audioURL: NSURL, moviePathUrl: NSURL, savePathUrl: NSURL) {
    var composition = AVMutableComposition()
    let trackVideo:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())
    let trackAudio:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())
    let option = NSDictionary(object: true, forKey: "AVURLAssetPreferPreciseDurationAndTimingKey")
    let sourceAsset = AVURLAsset(URL: moviePathUrl, options: option)
    let audioAsset = AVURLAsset(URL: audioURL, options: option)

    println(sourceAsset)
    println("playable: \(sourceAsset.playable)")
    println("exportable: \(sourceAsset.exportable)")
    println("readable: \(sourceAsset.readable)")

    let tracks = sourceAsset.tracksWithMediaType(AVMediaTypeVideo)
    let audios = audioAsset.tracksWithMediaType(AVMediaTypeAudio)

    if tracks.count > 0 {
        let assetTrack:AVAssetTrack = tracks[0] as AVAssetTrack
        let assetTrackAudio:AVAssetTrack = audios[0] as AVAssetTrack

        let audioDuration:CMTime = assetTrackAudio.timeRange.duration
        let audioSeconds:Float64 = CMTimeGetSeconds(assetTrackAudio.timeRange.duration)
        println(audioSeconds)

        trackVideo.insertTimeRange(CMTimeRangeMake(kCMTimeZero,audioDuration), ofTrack: assetTrack, atTime: kCMTimeZero, error: nil)
        trackAudio.insertTimeRange(CMTimeRangeMake(kCMTimeZero,audioDuration), ofTrack: assetTrackAudio, atTime: kCMTimeZero, error: nil)
    }

    var assetExport: AVAssetExportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough)
    assetExport.outputFileType = AVFileTypeMPEG4
    assetExport.outputURL = savePathUrl
    self.tmpMovieURL = savePathUrl
    assetExport.shouldOptimizeForNetworkUse = true
    assetExport.exportAsynchronouslyWithCompletionHandler({
        self.performSegueWithIdentifier("previewSegue", sender: self)
    })

}

问题出在哪里?我漏掉了什么?

你最终解决了这个问题吗? - swiftyboi
你最终解决了这个问题吗? - user3344977
2个回答

6

我正在寻找将音频和视频文件合并为一个视频的代码,但无处可寻。因此,在阅读苹果文档几个小时后,我编写了这段代码。

注意:这是我测试过的100%有效的代码

步骤1:在您的viewController中导入这些模块。

import UIKit
import AVFoundation
import AVKit
import AssetsLibrary

第二步:在你的代码中添加这个函数。
func mergeFilesWithUrl(videoUrl:NSURL, audioUrl:NSURL)
{
    let mixComposition : AVMutableComposition = AVMutableComposition()
    var mutableCompositionVideoTrack : [AVMutableCompositionTrack] = []
    var mutableCompositionAudioTrack : [AVMutableCompositionTrack] = []
    let totalVideoCompositionInstruction : AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction()
    
    
    //start merge
    
    let aVideoAsset : AVAsset = AVAsset(URL: videoUrl)
    let aAudioAsset : AVAsset = AVAsset(URL: audioUrl)
    
    mutableCompositionVideoTrack.append(mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid))
    mutableCompositionAudioTrack.append( mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid))
    
    let aVideoAssetTrack : AVAssetTrack = aVideoAsset.tracksWithMediaType(AVMediaTypeVideo)[0]
    let aAudioAssetTrack : AVAssetTrack = aAudioAsset.tracksWithMediaType(AVMediaTypeAudio)[0]
    
    
    
    do{
        try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), ofTrack: aVideoAssetTrack, atTime: kCMTimeZero)
        
        //In my case my audio file is longer then video file so i took videoAsset duration
        //instead of audioAsset duration
        
        try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), ofTrack: aAudioAssetTrack, atTime: kCMTimeZero)
        
        //Use this instead above line if your audiofile and video file's playing durations are same
        
        //            try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aAudioAssetTrack.timeRange.duration), ofTrack: aAudioAssetTrack, atTime: kCMTimeZero)
        
    }catch{
        
    }
    
    totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,aVideoAssetTrack.timeRange.duration )
    
    let mutableVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition()
    mutableVideoComposition.frameDuration = CMTimeMake(1, 30)
    
    mutableVideoComposition.renderSize = CGSizeMake(1280,720)
    
    //        playerItem = AVPlayerItem(asset: mixComposition)
    //        player = AVPlayer(playerItem: playerItem!)
    //
    //
    //        AVPlayerVC.player = player
    
    
    
    //find your video on this URl
    let savePathUrl : NSURL = NSURL(fileURLWithPath: NSHomeDirectory() + "/Documents/newVideo.mp4")
    
    let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)!
    assetExport.outputFileType = AVFileTypeMPEG4
    assetExport.outputURL = savePathUrl
    assetExport.shouldOptimizeForNetworkUse = true
    
    assetExport.exportAsynchronouslyWithCompletionHandler { () -> Void in
        switch assetExport.status {
            
        case AVAssetExportSessionStatus.Completed:
            
            //Uncomment this if u want to store your video in asset
            
            //let assetsLib = ALAssetsLibrary()
            //assetsLib.writeVideoAtPathToSavedPhotosAlbum(savePathUrl, completionBlock: nil)
            
            print("success")
        case  AVAssetExportSessionStatus.Failed:
            print("failed \(assetExport.error)")
        case AVAssetExportSessionStatus.Cancelled:
            print("cancelled \(assetExport.error)")
        default:
            print("complete")
        }
    }
    
    
}

步骤3:在您想要的地方调用函数,如下所示。
let videoUrl : NSURL =  NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("SampleVideo", ofType: "mp4")!)
let audioUrl : NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("SampleAudio", ofType: "mp3")!)
        
mergeFilesWithUrl(videoUrl, audioUrl: audioUrl)

希望这能帮到您并节省您的时间。


@DumitruRogojinaru,抱歉兄弟,我对这种格式一无所知。 - Govind Prajapati
@Faruk,我的视频没有画面,只有声音。你知道为什么吗? - Sharad Chauhan
@Faruk,请在此处找到相关内容:https://stackoverflow.com/questions/46129090/merging-video-audio-transparent-blank-video-exported - Sharad Chauhan
我今晚会检查 @sharadchauhan。 - Faruk
@Faruk 我找到了问题。现在问题与导出视频的方向有关。 - Sharad Chauhan
显示剩余5条评论

-1

为了使它起作用,我编写了这段代码。

assetExport.exportAsynchronouslyWithCompletionHandler { () -> Void in
    switch assetExport.status {
    case AVAssetExportSessionStatus.Completed:
        let assetsLib = ALAssetsLibrary()
        assetsLib.writeVideoAtPathToSavedPhotosAlbum(savePathUrl, completionBlock: nil)
    case  AVAssetExportSessionStatus.Failed:
        println("failed \(assetExport.error)")
    case AVAssetExportSessionStatus.Cancelled:
        println("cancelled \(assetExport.error)")
    default:
        println("complete")
    }
}

另外,请注意不能使用相同的文件名覆盖此类文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接