Last active
September 5, 2016 03:08
-
-
Save oozoofrog/ca30fa5c96a71ae174fb44ffe7938ab4 to your computer and use it in GitHub Desktop.
FFmpeg->AVFrame(Audio)->AVAudioEngine再生のやり方。+ Accelerateフレームワークの能力も借ります。 ref: http://qiita.com/funcodes/items/87dc9981e74ba2b79b2b
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let audioContext: UnsafeMutablePointer<AVCodecContext> | |
// プレイするサウンドの基本設定 | |
let audioFormat: AVAudioFormat( | |
commonFormat: .pcmFormatFloat32, | |
sampleRate: Double(audioContext.pointee.sample_rate), | |
channels: 2, // サウンドシステムのoutputチャンネルを超えたらクラッシューが発生されます。 | |
interleaved: false) | |
let audioEngine = AVAudioEngine() | |
let audioPlayer = AVAudioPlayerNode() | |
// オディオエンジンにプレイヤーを付けます。 | |
engine.attach(audioPlayer) | |
// オディオエンジンの基本出力ノードにプレイヤーを連結します。 | |
engine.connect(audioPlayer, to: engine.mainMixerNode, format: audioFormat) | |
engine.prepare() | |
try! engine.start() | |
audioPlayer.play() | |
... | |
// ディコードされたAVFrameをAVAudioPCMBufferに格納します。 | |
let frame: AVFrame | |
// frameCapacityはframeに配置されているfloatデータの個数を計算し渡します。 | |
let pcmBuffer = AVAudioPCMBuffer( | |
pcmFormat: audioFormat, | |
frameCapacity: AVAudioFrameCount(frame.linesize.0 / MemoryLayout<Float>.size)) | |
// frameLengthは実際のaudioのfloatデータの個数を渡します。 | |
// バーファーの長さとsamplesの個数は同じ場合も違う場合もあります。 | |
pcmBuffer.frameLength = frame.nb_samples // AVAudioFileを利用する場合は自動に設定されるところですが、その以外は直接やります。 | |
// ファファーに設定したformatでかくチャンネルのデータのメモリが配置されます。 | |
// 普通はステレオで2個になります。 | |
let channels = buffer.floatChannelData! | |
let leftOutputChannel: UnsafeMutablePointer<UnsafeMutablePointer<Float>> = channels[0] | |
let rightOutputChannel: UnsafeMutablePointer<UnsafeMutablePointer<Float>> = channels[1] | |
// frameのデータタイプは常にUInt8なのでFloatに変えます。 | |
let leftAudioBuffer: UnsafeMutablePointer<Float> = frame.data.0!.withMemoryRebound(to: Float.self, capacity: Int(pcmBuffer.frameLength)){$0} | |
let rightAudioBuffer: UnsafeMutablePointer<Float> = frame.data.1!.withMemoryRebound(to: Float.self, capacity: Int(pcmBuffer.frameLength)){$0} | |
// leftAudioBufferの内容をAccelerateの関数を利用し複写します。 | |
cblas_scopy(Int32(pcmBuffer.frameLength), leftAudioBuffer, 1, channels[0], 1) | |
cblas_scopy(Int32(pcmBuffer.frameLength), rightAudioBuffer, 1, channels[1], 1) | |
// オディオのデータが2チャンネル以上を持つ場合、ここでは5.1chのオディオだと仮定します。 | |
// 出力のチャンネルは二つなので余るデータはAccelerateの関数を使って既存のデータに加えます。 | |
let lbuf1 = frame.data.2!.withMemoryRebound(to: Float.self, capacity: Int(buffer.frameLength)){$0} | |
let rbuf1 = frame.data.3!.withMemoryRebound(to: Float.self, capacity: Int(buffer.frameLength)){$0} | |
let lbuf2 = frame.data.4!.withMemoryRebound(to: Float.self, capacity: Int(buffer.frameLength)){$0} | |
let rbuf2 = frame.data.5!.withMemoryRebound(to: Float.self, capacity: Int(buffer.frameLength)){$0} | |
vDSP_vadd(channels[0], 1, lbuf1, 1, channels[0], 1, vDSP_Length(buffer.frameLength)) | |
vDSP_vadd(channels[1], 1, rbuf1, 1, channels[1], 1, vDSP_Length(buffer.frameLength)) | |
vDSP_vadd(channels[0], 1, lbuf2, 1, channels[0], 1, vDSP_Length(buffer.frameLength)) | |
vDSP_vadd(channels[1], 1, rbuf2, 1, channels[1], 1, vDSP_Length(buffer.frameLength)) | |
//最後に作ったオディオのbufferをAVAudioPlayerNodeに入れます。 | |
audioPlayer.scheduleBuffer(pcmBuffer, completionHandler: nil) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment