2014-12-12 2 views
4

나는 Swift에서이 AVFoundation 함수를 호출하는 방법을 알아 내려고하고있다. 저는 선언과 구문을 다루는 데 많은 시간을 할애했고, 지금까지 이걸 가지고 있습니다. 컴파일러는 대부분 행복하지만 마지막 난제가 하나 남아 있습니다.CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer를 어떻게 호출합니까?

public func captureOutput(
    captureOutput: AVCaptureOutput!, 
    didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, 
    fromConnection connection: AVCaptureConnection! 
) { 
    let samplesInBuffer = CMSampleBufferGetNumSamples(sampleBuffer) 
    var audioBufferList: AudioBufferList 

    var buffer: Unmanaged<CMBlockBuffer>? = nil 

    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
     sampleBuffer, 
     nil, 
     &audioBufferList, 
     UInt(sizeof(audioBufferList.dynamicType)), 
     nil, 
     nil, 
     UInt32(kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment), 
     &buffer 
    ) 

    // do stuff 
} 

컴파일러는 3, 4 인수에 대해 불평 :이

변수를 '초기화되기 전에 촬영 한'audioBufferList '변수의

주소 audioBufferList '초기화되기 전에 사용됨

그래서 여기서해야 할 일은 무엇입니까?

저는 this StackOverflow answer으로 일하고 있지만 Objective-C입니다. 나는 이것을 Swift로 번역하려하지만이 문제에 부딪치게됩니다.

아니면 더 나은 방법이 있습니까? 한 번에 한 샘플 씩 버퍼에서 데이터를 읽어야하므로 기본적으로 반복 할 수있는 샘플 배열을 얻으려고합니다.

+0

난 그냥 사실에 관하여이었다. 오늘 아침에 들었어. – nhgrif

답변

4

면책 조항 : 나는 Reading audio samples via AVAssetReader에서 Swift로 코드를 변환하려고 시도했으며 컴파일되었음을 확인했습니다. 나는 실제로 작동하는 경우 을 테스트하지 않았습니다.

// Needs to be initialized somehow, even if we take only the address 
var audioBufferList = AudioBufferList(mNumberBuffers: 1, 
     mBuffers: AudioBuffer(mNumberChannels: 0, mDataByteSize: 0, mData: nil)) 

var buffer: Unmanaged<CMBlockBuffer>? = nil 

CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
    sampleBuffer, 
    nil, 
    &audioBufferList, 
    UInt(sizeof(audioBufferList.dynamicType)), 
    nil, 
    nil, 
    UInt32(kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment), 
    &buffer 
) 

// Ensure that the buffer is released automatically. 
let buf = buffer!.takeRetainedValue() 

// Create UnsafeBufferPointer from the variable length array starting at audioBufferList.mBuffers 
let audioBuffers = UnsafeBufferPointer<AudioBuffer>(start: &audioBufferList.mBuffers, 
    count: Int(audioBufferList.mNumberBuffers)) 

for audioBuffer in audioBuffers { 
    // Create UnsafeBufferPointer<Int16> from the buffer data pointer 
    var samples = UnsafeMutableBufferPointer<Int16>(start: UnsafeMutablePointer(audioBuffer.mData), 
     count: Int(audioBuffer.mDataByteSize)/sizeof(Int16)) 

    for sample in samples { 
     // .... 
    } 
} 
+0

내가 물었던 것과 정확히 일치하는 것으로 받아들이 기 때문에 나는 너의 것을 표시하고있다. 답을 두 번 보더라도'samples'는 1,024 개의 Int16 값의 배열입니까? – nhgrif

+0

@nhgrif : samples는'UnsafeMutableBufferPointer '입니다. '[Int16]'배열로 취급 할 수 있지만, 기존의'audioBuffer.mData'를 배킹 스토어 (C의'(int16_t *)'와 비슷합니다)로 사용합니다. 'samples.count'는 버퍼의 Int16 값의 수이고, 각 sample은 Int16 값입니다. –

+0

여기에 문제가 있습니까? –

1

마틴의 대답은 작품과 내가 질문에 물어 무슨 질문을 게시하고 문제에 더 많은 시간을 보내고 (마틴의 답변을보고 전) 이후, 그러나, 정확히 않습니다, 나는이 함께했다 :

public func captureOutput(
    captureOutput: AVCaptureOutput!, 
    didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, 
    fromConnection connection: AVCaptureConnection! 
) { 
    let samplesInBuffer = CMSampleBufferGetNumSamples(sampleBuffer) 
    self.currentZ = Double(samplesInBuffer) 

    let buffer: CMBlockBufferRef = CMSampleBufferGetDataBuffer(sampleBuffer) 

    var lengthAtOffset: size_t = 0 
    var totalLength: size_t = 0 
    var data: UnsafeMutablePointer<Int8> = nil 

    if(CMBlockBufferGetDataPointer(buffer, 0, &lengthAtOffset, &totalLength, &data) != noErr) { 
     println("some sort of error happened") 
    } else { 
     for i in stride(from: 0, to: totalLength, by: 2) { 
      // do stuff 
     } 
    } 
} 

이것은 약간 다른 접근법이며 개선의 여지가 여전히 남아 있습니다.하지만 여기서 핵심은 적어도 iPad Mini (및 다른 장치)에서이 메서드를 호출 할 때마다 1,024 개의 샘플을 얻습니다 . 그러나 그 샘플은 2,048 Int8 값의 배열로옵니다. 다른 하나는 Int16이 2,048 개의 반 샘플을 1,024 개의 전체 샘플로 변환하기 위해 결합되어야하는 왼쪽/오른쪽 바이트입니다.

0

나를 위해 작동합니다. 그것을 시도 :

let musicUrl: NSURL = mediaItemCollection.items[0].valueForProperty(MPMediaItemPropertyAssetURL) as! NSURL 
let asset: AVURLAsset = AVURLAsset(URL: musicUrl, options: nil) 
let assetOutput = AVAssetReaderTrackOutput(track: asset.tracks[0] as! AVAssetTrack, outputSettings: nil) 

var error : NSError? 

let assetReader: AVAssetReader = AVAssetReader(asset: asset, error: &error) 

if error != nil { 
    print("Error asset Reader: \(error?.localizedDescription)") 
} 

assetReader.addOutput(assetOutput) 
assetReader.startReading() 

let sampleBuffer: CMSampleBufferRef = assetOutput.copyNextSampleBuffer() 

var audioBufferList = AudioBufferList(mNumberBuffers: 1, mBuffers: AudioBuffer(mNumberChannels: 0, mDataByteSize: 0, mData: nil)) 
var blockBuffer: Unmanaged<CMBlockBuffer>? = nil 


CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
    sampleBuffer, 
    nil, 
    &audioBufferList, 
    sizeof(audioBufferList.dynamicType), // instead of UInt(sizeof(audioBufferList.dynamicType)) 
    nil, 
    nil, 
    UInt32(kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment), 
    &blockBuffer 
) 
2

Swift3 솔루션 :

func loopAmplitudes(audioFileUrl: URL) { 

    let asset = AVAsset(url: audioFileUrl) 

    let reader = try! AVAssetReader(asset: asset) 

    let track = asset.tracks(withMediaType: AVMediaTypeAudio)[0] 

    let settings = [ 
     AVFormatIDKey : kAudioFormatLinearPCM 
    ] 

    let readerOutput = AVAssetReaderTrackOutput(track: track, outputSettings: settings) 
    reader.add(readerOutput) 
    reader.startReading() 

    while let buffer = readerOutput.copyNextSampleBuffer() { 

     var audioBufferList = AudioBufferList(mNumberBuffers: 1, mBuffers: AudioBuffer(mNumberChannels: 0, mDataByteSize: 0, mData: nil)) 
     var blockBuffer: CMBlockBuffer? 

     CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
      buffer, 
      nil, 
      &audioBufferList, 
      MemoryLayout<AudioBufferList>.size, 
      nil, 
      nil, 
      kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, 
      &blockBuffer 
     ); 

     let buffers = UnsafeBufferPointer<AudioBuffer>(start: &audioBufferList.mBuffers, count: Int(audioBufferList.mNumberBuffers)) 

     for buffer in buffers { 

      let samplesCount = Int(buffer.mDataByteSize)/MemoryLayout<Int16>.size 
      let samplesPointer = audioBufferList.mBuffers.mData!.bindMemory(to: Int16.self, capacity: samplesCount) 
      let samples = UnsafeMutableBufferPointer<Int16>(start: samplesPointer, count: samplesCount) 

      for sample in samples { 

       //do something with you sample (which is Int16 amplitude value) 

      } 
     } 
    } 
} 
관련 문제