处理 AVPlayer 的音频输出

Processing audio output from AVPlayer

很简单的问题:

最好的方法是什么(即 framework/class)?

最好的方法是将音频与视频分开,并使用 AVAudioEngine 对音频应用音频处理,同时同步两个播放器。

import UIKit
import AVKit
import AVFoundation

extension CGRect {
    init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
        self.init(x:x, y:y, width:w, height:h)}
}
func delay(_ delay:Double, closure:@escaping ()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}

class ViewController: UIViewController {

    var audioPlayer : AVAudioPlayer!
    var engine = AVAudioEngine()
    var f = AVAudioFile()
    var player = AVAudioPlayerNode()
    var effect = AVAudioUnitEQ(numberOfBands: 4)
    var timestamp = Date().timeIntervalSince1970
    var didInitialLayout = false
    var videoplayer = AVPlayer()
    var videostate = 0
    var freq = [150, 250, 3000, 6000]

    override var prefersStatusBarHidden : Bool {
        return true
    }

    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .pad {
            return .all
        }
        return .landscape
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        try? AVAudioSession.sharedInstance().setCategory(.playback, mode:.default)
        try? AVAudioSession.sharedInstance().setActive(true)
    }


    @IBAction func launchVideoPlayer(_ sender: Any) {
        self.videoplayer.pause()
        let urlvideo = Bundle.main.url(forResource:"videofile",     withExtension:"mp4")!
        self.videoplayer = AVPlayer(url:urlvideo)
        let av = AVPlayerViewController()
        av.showsPlaybackControls = false
        av.player = videoplayer
        av.view.frame = CGRect(140,20,1100,800)
        self.addChild(av)
        self.view.addSubview(av.view)
        av.didMove(toParent:self)
        self.videostate = 1
    }

    @IBAction func audioprocess(_ sender: Any) {
        self.engine.stop()
        self.engine = AVAudioEngine()
        self.player = AVAudioPlayerNode()
        let url = Bundle.main.url(forResource:"yoursong", withExtension: "m4a")!
        self.f = try! AVAudioFile(forReading: url)
        self.engine.attach(player)
        self.effect = AVAudioUnitEQ(numberOfBands: 4)
        let bands = effect.bands
        for i in 0...(bands.count - 1) {
            bands[i].frequency = Float(self.freq[i])
        }
        bands[0].gain = 10.0
        bands[0].filterType = .parametric
        bands[0].bandwidth = 1
        bands[1].gain = 10.0
        bands[1].filterType = .parametric
        bands[1].bandwidth = 0.5
        bands[2].gain = 0.0
        bands[2].filterType = .parametric
        bands[2].bandwidth = 1
        bands[3].gain = 0.0
        bands[3].filterType = .parametric
        bands[3].bandwidth = 1
        self.engine.attach(effect)
        self.engine.connect(player, to: effect, format: f.processingFormat)
        let mixer = self.engine.mainMixerNode
        self.engine.connect(effect, to: mixer, format: f.processingFormat)
        player.scheduleFile(f, at: nil) {
            print("stopping")
            delay(0.1) {
                if self.engine.isRunning {
                    print("engine was running, really stopping")
                    self.engine.stop()
                }
            }
        }
        self.engine.prepare()
        try! self.engine.start()
        player.play()
    
        if self.videostate == 1 {
            self.videoplayer.play()
        } else {
            return }
    }

    @IBAction func stopsound(_ sender: Any) {
        self.player.stop()
        self.videoplayer.pause()
    }
    
    @IBAction func changeEQ(_ sender: Any) {
        let bands = self.effect.bands
        for i in 0...(bands.count - 1) {
            bands[i].frequency = Float(self.freq[i])
        }
        bands[0].bypass = false
        bands[1].bypass = false
        bands[2].bypass = false
        bands[3].bypass = false
        bands[0].gain = -60.0
        bands[0].filterType = .parametric
        bands[0].bandwidth = 1
        bands[1].gain = -40.0
        bands[1].filterType = .parametric
        bands[1].bandwidth = 0.5
        bands[2].gain = -20.0
        bands[2].filterType = .parametric
        bands[2].bandwidth = 1
        bands[3].gain = 0.0
        bands[3].filterType = .parametric
        bands[3].bandwidth = 1
        self.engine.attach(effect)
    }
}