从视频AVFoundation中提取音频

时间:2015-08-07 13:54:46

标签: ios swift avfoundation

func extractAudioFromVideo(videoUrl:NSURL, audioPath:String){
    //2
    var asset = AVURLAsset(URL: videoUrl, options: nil)
    asset.loadValuesAsynchronouslyForKeys(NSArray(object: "tracks") as [AnyObject], completionHandler: { () -> Void in
        var audioTrack = asset.tracksWithMediaType(AVMediaTypeAudio)[0] as! AVAssetTrack

        var audioComposition = AVMutableComposition()

        var audioCompositionTrack:AVMutableCompositionTrack!

        audioCompositionTrack = audioComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())
        audioCompositionTrack.insertTimeRange(audioTrack.timeRange, ofTrack: audioTrack, atTime: CMTimeMake(0, 1), error: nil)

        var exportSession = AVAssetExportSession(asset: audioComposition, presetName: AVAssetExportPresetAppleM4A)
        var toFileUrl = NSURL(fileURLWithPath: audioPath)

        exportSession.outputURL = toFileUrl
        exportSession.outputFileType = "com.apple.m4a-audio"

        exportSession.exportAsynchronouslyWithCompletionHandler({ () -> Void in
            if exportSession.status == AVAssetExportSessionStatus.Completed {
                println("Succes")
            }else{
                println("not working")
            }
        })

    })

}

我正在使用上面的代码从视频中获取音频,但它正在打印"无法正常工作"

我的audioPath是:

var outStr = NSBundle.mainBundle().pathForResource("cheeseburger", ofType: "m4a")

请帮我解决这个问题

由于

2 个答案:

答案 0 :(得分:6)

我重写了 Swift 4.0 的答案,因为有几个API更改了前一个。

import AVFoundation

extension AVAsset {
    // Provide a URL for where you wish to write
    // the audio file if successful
    func writeAudioTrack(to url: URL,
                         success: @escaping () -> (),
                         failure: @escaping (Error) -> ()) {
        do {
            let asset = try audioAsset()
            asset.write(to: url, success: success, failure: failure)
        } catch {
            failure(error)
        }
    }

    private func write(to url: URL,
                       success: @escaping () -> (),
                       failure: @escaping (Error) -> ()) {
        // Create an export session that will output an
        // audio track (M4A file)
        guard let exportSession = AVAssetExportSession(asset: self,
                                                       presetName: AVAssetExportPresetAppleM4A) else {
                                                        // This is just a generic error
                                                        let error = NSError(domain: "domain",
                                                                            code: 0,
                                                                            userInfo: nil)
                                                        failure(error)

                                                        return
        }

        exportSession.outputFileType = .m4a
        exportSession.outputURL = url

        exportSession.exportAsynchronously {
            switch exportSession.status {
            case .completed:
                success()
            case .unknown, .waiting, .exporting, .failed, .cancelled:
                let error = NSError(domain: "domain", code: 0, userInfo: nil)
                failure(error)
            }
        }
    }

    private func audioAsset() throws -> AVAsset {
        // Create a new container to hold the audio track
        let composition = AVMutableComposition()
        // Create an array of audio tracks in the given asset
        // Typically, there is only one
        let audioTracks = tracks(withMediaType: .audio)

        // Iterate through the audio tracks while
        // Adding them to a new AVAsset
        for track in audioTracks {
            let compositionTrack = composition.addMutableTrack(withMediaType: .audio,
                                                               preferredTrackID: kCMPersistentTrackID_Invalid)
            do {
                // Add the current audio track at the beginning of
                // the asset for the duration of the source AVAsset
                try compositionTrack?.insertTimeRange(track.timeRange,
                                                      of: track,
                                                      at: track.timeRange.start)
            } catch {
                throw error
            }
        }

        return composition
    }
}

然后,您调用扩展,并依赖不同的闭包来处理成功和失败。此示例中的错误处理非常原始,因此您需要在实现时进行改进。

asset.writeAudioTrack(to: url, success: {
    print("Success")
}) { (error) in
    print(error.localizedDescription)
}

答案 1 :(得分:1)

来自我的项目( Swift 4.1

import AVFoundation
extension AVAsset {

    func writeAudioTrackToURL(_ url: URL, completion: @escaping (Bool, Error?) -> ()) {
        do {
            let audioAsset = try self.audioAsset()
            audioAsset.writeToURL(url, completion: completion)
        } catch (let error as NSError){
            completion(false, error)
        }
    }

    func writeToURL(_ url: URL, completion: @escaping (Bool, Error?) -> ()) {

        guard let exportSession = AVAssetExportSession(asset: self, presetName: AVAssetExportPresetAppleM4A) else {
            completion(false, nil)
            return
        }

        exportSession.outputFileType = .m4a
        exportSession.outputURL      = url

        exportSession.exportAsynchronously {
            switch exportSession.status {
            case .completed:
                completion(true, nil)
            case .unknown, .waiting, .exporting, .failed, .cancelled:
                completion(false, nil)
            }
        }
    }

    func audioAsset() throws -> AVAsset {

        let composition = AVMutableComposition()
        let audioTracks = tracks(withMediaType: .audio)

        for track in audioTracks {

            let compositionTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)
            try compositionTrack?.insertTimeRange(track.timeRange, of: track, at: track.timeRange.start)
            compositionTrack?.preferredTransform = track.preferredTransform
        }
        return composition
    }
}

像这样使用

    let url = Bundle.main.url(forResource: "video", withExtension: "m4v")!
    let asset = AVURLAsset(url: url, options: nil)

    let pathWhereToSave = "<#path#>"
    asset.writeAudioTrackToURL(URL(fileURLWithPath: pathWhereToSave)) { (success, error) -> () in
        if !success {
            print(error)
        }
    }