从视频文件中提取音频

8

怎么在不使用FFmpeg的情况下提取视频文件中的音频?

我想使用AVMutableCompositionAVURLAsset来解决这个问题,例如将.mov文件转换为.m4a文件。


1
据我所知,iOS上的AVFoundation对于解码或打开“.flv”文件一无所知,因此这个问题根本就行不通。这就是为什么你需要使用一些第三方库,比如ffmpeg或其他类似的库,来打开.flv文件并将其转换为你可以正确使用的格式。 - Michael Dautermann
我会编辑这个例子,因为我没有考虑到这一点...但是我的要求仍然是一样的.. :( - Tripti Kumar
2个回答

15
以下是Swift 5 / iOS 12.3代码示例,演示如何使用AVURLAsset、AVMutableComposition和AVAssetExportSession从电影文件(.mov)中提取音频并将其转换为音频文件(.m4a):
import UIKit
import AVFoundation

class ViewController: UIViewController {

    @IBAction func extractAudioAndExport(_ sender: UIButton) {
        // Create a composition
        let composition = AVMutableComposition()
        do {
            let sourceUrl = Bundle.main.url(forResource: "Movie", withExtension: "mov")!
            let asset = AVURLAsset(url: sourceUrl)
            guard let audioAssetTrack = asset.tracks(withMediaType: AVMediaType.audio).first else { return }
            guard let audioCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid) else { return }
            try audioCompositionTrack.insertTimeRange(audioAssetTrack.timeRange, of: audioAssetTrack, at: CMTime.zero)
        } catch {
            print(error)
        }

        // Get url for output
        let outputUrl = URL(fileURLWithPath: NSTemporaryDirectory() + "out.m4a")
        if FileManager.default.fileExists(atPath: outputUrl.path) {
            try? FileManager.default.removeItem(atPath: outputUrl.path)
        }

        // Create an export session
        let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough)!
        exportSession.outputFileType = AVFileType.m4a
        exportSession.outputURL = outputUrl

        // Export file
        exportSession.exportAsynchronously {
            guard case exportSession.status = AVAssetExportSession.Status.completed else { return }

            DispatchQueue.main.async {
                // Present a UIActivityViewController to share audio file
                guard let outputURL = exportSession.outputURL else { return }
                let activityViewController = UIActivityViewController(activityItems: [outputURL], applicationActivities: [])
                self.present(activityViewController, animated: true, completion: nil)
            }
        }
    }

}

4
在所有多媒体格式中,音频都是单独编码的,与视频分开编排在文件中。因此,要从多媒体文件中删除视频不需要对编码器和解码器进行任何操作:你可以编写一个文件格式解析器来清除视频轨道,而不使用手机上的多媒体API。
要做到这一点而不使用第三方库,你需要从头开始编写解析器,这可能会根据所需使用的文件格式而简单或困难。例如,FLV非常简单,因此剥离轨道非常容易(只需浏览流,检测帧开始并删除“0x09”=视频帧)。MP4稍微复杂一些,它的头文件(MOOV)具有分层结构,在其中你需要为每个轨道(TRAK原子)设置标题。你需要删除视频TRAK,然后复制交错比特流原子(MDAT),同时跳过所有视频数据群集。
除了ffmpeg之外,还有第三方库可供使用。其中之一是GPAC MP4BOX(LGPL许可证)。如果LGPL成为问题,还有很多商业SDK可供使用。

谢谢你的回答,我给你点赞了。但如果你能帮我解决编程部分的问题,那将是非常有帮助的 :) - Tripti Kumar
抱歉... MOV(类似于MP4)是一种复杂的文件格式,编写这样的解析器至少需要一两天的编码时间,所以我无法帮助您。我猜您最初尝试使用AVMutableComposition来完成是更好的方法(它应该可以做到相同的效果)- 基本上,M4A文件几乎与MOV相似,只是没有音频轨道,因此将MOV作为AVMutableComposition打开并执行removeTrack可能会有用。 - onon15
@onon15 - (+1) 我有一个包含1个音频TRAK和1个视频TRAK(aac,h264)的文件,如何区分'mdat'原子中的样本?谢谢! - Avishay Cohen
这并不像你想象的那么容易,但一旦掌握了方法就不难。你不能从MDAT本身获取它。每个轨道所属数据块的偏移量存储在TRAK>MDIA>MINF>STBL内部的STCO表(或CO64)中。每个块的长度是另一个需要根据STBL中的信息计算的值。请参阅此参考资料 - onon15

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