Swift 2:AVAssetReader和NSInputStream音频图

7
我正在尝试将Bob McCune的《学习AVFoundation》一书中的示例进行转换,但在使用AVAssetReader和NSInputStream时遇到了一些问题。图形应该是一个纯正弦波,但值似乎在X轴上反射。我尝试了我能想到的所有字节交换迭代,但都没有成功。Playground发布在github上:https://github.com/justinlevi/AVAssetReader
//: Playground - noun: a place where people can play

import UIKit
import AVFoundation
import XCPlayground

func plotArrayInPlayground<T>(arrayToPlot:Array<T>, title:String) {
  for currentValue in arrayToPlot {
    XCPCaptureValue(title, value: currentValue)
  }
}

class SSSampleDataFilter {
  var sampleData:NSData?

  init(data:NSData) {
    sampleData = data
  }

  func filteredSamplesForSize(size:CGSize) -> [Int]{
    var filterSamples = [UInt16]()

    if let sampleData = sampleData {
      let sampleCount = sampleData.length
      let binSize = CGFloat(sampleCount) / size.width

      let stream = NSInputStream(data: sampleData)
      stream.open()

      var readBuffer = Array<UInt8>(count: 16 * 1024, repeatedValue: 0)
      var totalBytesRead = 0

      let size = sizeof(UInt16)
      while (totalBytesRead < sampleData.length) {
        let numberOfBytesRead = stream.read(&readBuffer, maxLength: size)
        let u16: UInt16 = UnsafePointer<UInt16>(readBuffer).memory

        var sampleBin = [UInt16]()
        for _ in 0..<Int(binSize) {
          sampleBin.append(u16)
        }

        filterSamples.append(sampleBin.maxElement()!)
        totalBytesRead += numberOfBytesRead
      }

      //plotArrayInPlayground(filterSamples, title: "Samples")
    }

    return [0]

  }
}

let sineURL = NSBundle.mainBundle().URLForResource("440.0-sine", withExtension: "aif")!
let asset = AVAsset(URL: sineURL)
var assetReader:AVAssetReader

do{
  assetReader = try AVAssetReader(asset: asset)
}catch{
  fatalError("Unable to read Asset: \(error) : \(__FUNCTION__).")
}

let track = asset.tracksWithMediaType(AVMediaTypeAudio).first
let outputSettings: [String:Int] =
  [ AVFormatIDKey: Int(kAudioFormatLinearPCM),
    AVLinearPCMIsBigEndianKey: 0,
    AVLinearPCMIsFloatKey: 0,
    AVLinearPCMBitDepthKey: 16,
    AVLinearPCMIsNonInterleaved: 0]

let trackOutput = AVAssetReaderTrackOutput(track: track!, outputSettings: outputSettings)

assetReader.addOutput(trackOutput)
assetReader.startReading()

var sampleData = NSMutableData()

while assetReader.status == AVAssetReaderStatus.Reading {
  if let sampleBufferRef = trackOutput.copyNextSampleBuffer() {
    if let blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef) {
      let bufferLength = CMBlockBufferGetDataLength(blockBufferRef)
      var data = NSMutableData(length: bufferLength)
      CMBlockBufferCopyDataBytes(blockBufferRef, 0, bufferLength, data!.mutableBytes)
      var samples = UnsafeMutablePointer<Int16>(data!.mutableBytes)
      sampleData.appendBytes(samples, length: bufferLength)
      CMSampleBufferInvalidate(sampleBufferRef)
    }
  }
}

let view = UIView(frame: CGRectMake(0, 0, 375.0, 667.0))
//view.backgroundColor = UIColor.lightGrayColor()

if assetReader.status == AVAssetReaderStatus.Completed {
  print("complete")

  let filter = SSSampleDataFilter(data: sampleData)
  let filteredSamples = filter.filteredSamplesForSize(view.bounds.size)
}

//XCPShowView("Bezier Path", view: view)
XCPSetExecutionShouldContinueIndefinitely(true)

这是图表应该呈现的样子(来自Audacity):音频文件的正弦波图 这是在playground中图表的样子: 输入图像描述
1个回答

2

很不幸,您的游乐场在Xcode7b5中对我无法呈现任何内容。然而,您正在要求AVAssetReaderTrackOutput提供给您带符号的16位整数,但是您的代码将它们视为无符号的UInt16(您的Audacity文件使用浮点数)。

在您的游乐场中将所有UInt16实例更改为Int16似乎打印出看起来合理的正弦数据。


1
很奇怪,它在你的Xcode7b5中没有渲染。你是否从Github获取了包含AIFF音频文件的版本?确实,一旦我将所有UInt16的实例更改为'Int16`,一切似乎都正常工作了。 - Justin Levi Winter
昨天我盯着那个问题看了好几个小时。谢谢。 - Justin Levi Winter
跟进问题,你知道为什么aif,caf,m4a都可以正常工作,但同一音频的mp3版本不行吗?我需要回到文档中去看看是否能够理解其中的原因,但我认为AVassetReader也应该能处理mp3压缩。 - Justin Levi Winter
mp3会发生什么? - Rhythmic Fistman
在游乐场里很难说,但错误是“执行被中断,原因:EXC_BAD_INSTRUCTION(code=EXC_i386_INVOP,subcode=0x0)”。不过,在我将其发布到我的 Github 帐户的 iOS 项目中似乎工作正常,所以看起来不值得去解决它 :) 再次感谢。 - Justin Levi Winter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接