Извлечь аудио из видео файла

Как я могу извлечь аудио из видео файла, не используя FFmpeg?

Я хочу использовать AVMutableComposition а также AVURLAsset для решения it.eg преобразования из.mov в.m4a файл.

2 ответа

Решение

Следующий код Swift 3 показывает, как извлечь аудио из файла фильма (.mov) и преобразовать его в аудио файл (.m4a) с помощью AVURLAsset, AVMutableComposition а также AVAssetExportSession:

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: AVMediaTypeAudio).first else { return }
            let audioCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)
            try audioCompositionTrack.insertTimeRange(audioAssetTrack.timeRange, of: audioAssetTrack, at: kCMTimeZero)
        } catch {
            print(error)
        }

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

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

        // Export file
        exportSession.exportAsynchronously {
            guard case exportSession.status = AVAssetExportSessionStatus.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)
            }
        }
    }

}

Во всех мультимедийных форматах аудио кодируется отдельно от видео, а их кадры чередуются в файле. Таким образом, удаление видео из мультимедийного файла не требует никаких действий с кодировщиками и декодерами: вы можете написать синтаксический анализатор формата файла, который будет отбрасывать видео дорожку, без использования мультимедийных API на телефоне.

Чтобы сделать это без использования сторонней библиотеки, вам нужно написать парсер с нуля, который может быть простым или сложным в зависимости от формата файла, который вы хотите использовать. Например, FLV очень прост, поэтому вырезать трек из него очень просто (просто пройдите по потоку, определите начало кадра и удалите "0x09" = видеокадры). MP4 немного сложнее, его заголовок (MOOV) имеет иерархическую структуру, в которой у вас есть заголовки для каждой дорожки (атомы TRAK). Вам нужно отбросить видео TRAK, а затем скопировать чередующийся битовый атом (MDAT), пропуская все кластеры видеоданных при копировании.

Помимо ffmpeg вы можете использовать сторонние библиотеки. На ум приходит GPAC MP4BOX (лицензия LGPL). Если LGPL является проблемой, есть много коммерческих SDK, которые вы можете использовать.

Другие вопросы по тегам