Skip to content

Instantly share code, notes, and snippets.

@oozoofrog
Last active September 5, 2016 03:08
Show Gist options
  • Save oozoofrog/ca30fa5c96a71ae174fb44ffe7938ab4 to your computer and use it in GitHub Desktop.
Save oozoofrog/ca30fa5c96a71ae174fb44ffe7938ab4 to your computer and use it in GitHub Desktop.
FFmpeg->AVFrame(Audio)->AVAudioEngine再生のやり方。+ Accelerateフレームワークの能力も借ります。 ref: http://qiita.com/funcodes/items/87dc9981e74ba2b79b2b
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