ios - 播放使用 AVCaptureAudioDataOutput 录制的音频
问题描述
我正在尝试录制视频和音频并通过网络发送它们,以便它们可以在其他客户端上实时播放。我已成功录制和播放视频,但仍然无法播放音频(请参阅下面代码底部的 AVAudioPlayer)。我做错了什么或缺少什么?(还有几个其他 StackOverflow 问题似乎解决了同样的问题,但即使那里的评论表明有些人能够使它工作,但没有一个显示出明确的工作答案。)提前谢谢你任何输入。
let captureSession = AVCaptureSession()
private func startVideoFeed() {
let sessionPreset = AVCaptureSession.Preset.low
if captureSession.canSetSessionPreset(sessionPreset) {
captureSession.sessionPreset = sessionPreset
}
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { success in
self.startVideoFeed()
}
case .authorized:
captureSession.beginConfiguration()
let captureVideoDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)!
let captureVideoInput = try! AVCaptureDeviceInput(device: captureVideoDevice)
if captureSession.canAddInput(captureVideoInput) {
captureSession.addInput(captureVideoInput)
}
let captureVideoOutput = AVCaptureVideoDataOutput()
captureVideoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
if captureSession.canAddOutput(captureVideoOutput) {
captureSession.addOutput(captureVideoOutput)
}
captureSession.commitConfiguration()
captureSession.startRunning()
default:
break
}
}
private func startAudioFeed() {
switch AVCaptureDevice.authorizationStatus(for: .audio) {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .audio) { success in
self.startAudioFeed()
}
case .authorized:
captureSession.beginConfiguration()
let captureAudioDevice = AVCaptureDevice.default(for: .audio)!
let captureAudioInput = try! AVCaptureDeviceInput(device: captureAudioDevice)
if captureSession.canAddInput(captureAudioInput) {
captureSession.addInput(captureAudioInput)
}
let captureAudioOutput = AVCaptureAudioDataOutput()
captureAudioOutput.audioSettings = [AVFormatIDKey: kAudioFormatLinearPCM, AVNumberOfChannelsKey: NSNumber(value: 1), AVSampleRateKey: NSNumber(value: 44100)]
captureAudioOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
if captureSession.canAddOutput(captureAudioOutput) {
captureSession.addOutput(captureAudioOutput)
}
captureSession.commitConfiguration()
default:
break
}
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
if let imageBuffer = sampleBuffer.imageBuffer {
let ciImage = CIImage(cvPixelBuffer: imageBuffer)
let cgImage = CIContext().createCGImage(ciImage, from: ciImage.extent)!
let data = CFDataCreateMutable(nil, 0)!
let imageDestination = CGImageDestinationCreateWithData(data, kUTTypeJPEG, 1, nil)!
CGImageDestinationAddImage(imageDestination, cgImage, [kCGImageDestinationLossyCompressionQuality: NSNumber(value: 0)] as CFDictionary)
CGImageDestinationFinalize(imageDestination)
play(data: data as Data)
} else if let dataBuffer = sampleBuffer.dataBuffer {
let data = try! dataBuffer.dataBytes()
play(data: data)
}
}
private func play(data: Data) {
if let image = CGImage(jpegDataProviderSource: CGDataProvider(data: data as CFData)!, decode: nil, shouldInterpolate: false, intent: .defaultIntent) {
// image is a valid image
} else if let audioPlayer = try? AVAudioPlayer(data: data) {
audioPlayer.play()
// audioPlayer is always nil with error: Error Domain=NSOSStatusErrorDomain Code=1954115647 "(null)"
}
}
解决方案
https://developer.apple.com/documentation/coremedia/1489629-cmsamplebuffergetdatabuffer
调用者不拥有返回的 dataBuffer,如果调用者需要维护对它的引用,则必须显式保留它。
您将需要对数据执行CFRetain和 CFRelease。
由于您正在初始化它的数据,播放器为零。将 sampleBuffer 转换为 Data。
推荐阅读
- javascript - 适合任何宽度/高度容器的正方形网格
- javascript - 如何将不同的 url 映射到同一页面 (HTML) Javascript?
- python - Plotly Dash:为什么我的图形无法通过多个下拉选择显示?
- r - 数值公差的矢量化匹配
- error-handling - AS400-MOVEA 未编译以将十进制数据结构移动到十进制数组
- java - 动态创建作业的春季批处理测试
- google-colaboratory - 在 Google Colab 中安装 NVIDIA docker
- python - 在数据框中的新列中连接日期
- sql-server - 查询性能存储过程与单个语句
- python - 避免对未使用 CNN 训练的输入进行预测