Swift 2 : AVAssetReader 和 NSInputStream 音频图
Swift 2 : AVAssetReader and NSInputStream Audio Graph
我正在尝试转换 Bob McCune 的 Learning AVFoundation 一书中的示例,但在使用 AVAssetReader 和 NSInputStream 时遇到了一些问题。该图应该是一个纯正弦波,但这些值似乎以某种方式反映在 X 轴上。
我已经尝试了我能想到的每一次字节交换迭代,但都没有用。
游乐场发布到 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 中的图形
不幸的是,你的游乐场在 Xcode7b5 中没有为我呈现任何东西,但是你要求 AVAssetReaderTrackOutput
给你签名的 16 位整数,但你的代码将它们视为未签名的 UInt16
s(并且您的 Audacity 文件使用浮点数)。
在你的 playground 中将 UInt16
的所有实例更改为 Int16
似乎打印出看起来合理的正弦数据。
我正在尝试转换 Bob McCune 的 Learning AVFoundation 一书中的示例,但在使用 AVAssetReader 和 NSInputStream 时遇到了一些问题。该图应该是一个纯正弦波,但这些值似乎以某种方式反映在 X 轴上。
我已经尝试了我能想到的每一次字节交换迭代,但都没有用。
游乐场发布到 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 中的图形
不幸的是,你的游乐场在 Xcode7b5 中没有为我呈现任何东西,但是你要求 AVAssetReaderTrackOutput
给你签名的 16 位整数,但你的代码将它们视为未签名的 UInt16
s(并且您的 Audacity 文件使用浮点数)。
在你的 playground 中将 UInt16
的所有实例更改为 Int16
似乎打印出看起来合理的正弦数据。