AVCaptureSession
을 사용하여 비디오 및 오디오 입력을 사용하고 AVAssetWriter
과 함께 H.264 비디오를 인코딩합니다.AVAssetWriter를 사용하여 오디오 및 비디오 캡처가 손상된 비디오
오디오를 쓰지 않으면 비디오가 예상대로 인코딩됩니다. 그러나 오디오를 쓰면 비디오가 손상됩니다. I는 CMSampleBuffer
은 AVAssetWriter
공급되는 오디오를 검사하면
가이 정보를 보여준다
invalid = NO
dataReady = YES
makeDataReadyCallback = 0x0
makeDataReadyRefcon = 0x0
formatDescription = <CMAudioFormatDescription 0x17410ba30 [0x1b3a70bb8]> {
mediaType:'soun'
mediaSubType:'lpcm'
mediaSpecific: {
ASBD: {
mSampleRate: 44100.000000
mFormatID: 'lpcm'
mFormatFlags: 0xc
mBytesPerPacket: 2
mFramesPerPacket: 1
mBytesPerFrame: 2
mChannelsPerFrame: 1
mBitsPerChannel: 16 }
cookie: {(null)}
ACL: {(null)}
FormatList Array: {(null)}
}
extensions: {(null)}
는 LPCM 오디오를 공급하기 때문에, I를 음이 설정과 AVAssetWriterInput
구성한을 (I 모두를 시도 및 두 개의 채널) :
var channelLayout = AudioChannelLayout()
memset(&channelLayout, 0, MemoryLayout<AudioChannelLayout>.size);
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono
let audioOutputSettings:[String: Any] = [AVFormatIDKey as String:UInt(kAudioFormatLinearPCM),
AVNumberOfChannelsKey as String:1,
AVSampleRateKey as String:44100.0,
AVLinearPCMIsBigEndianKey as String:false,
AVLinearPCMIsFloatKey as String:false,
AVLinearPCMBitDepthKey as String:16,
AVLinearPCMIsNonInterleaved as String:false,
AVChannelLayoutKey: NSData(bytes:&channelLayout, length:MemoryLayout<AudioChannelLayout>.size)]
self.assetWriterAudioInput = AVAssetWriterInput(mediaType: AVMediaTypeAudio, outputSettings: audioOutputSettings)
self.assetWriter.add(self.assetWriterAudioInput)
위의 lpcm 설정을 사용할 때 응용 프로그램에서 비디오를 열 수 없습니다. kAudioFormatMPEG4AAC
과 kAudioFormatAppleLossless
을 사용해 보았는데 여전히 비디오가 손상되었지만 QuickTime Player 8 (QuickTime Player 7 아님)을 사용하여 비디오를 볼 수는 있지만 비디오 재생 시간에 대해서는 혼란스럽고 사운드는 재생되지 않습니다. 기록
내가 부르고 완료 :
func endRecording(_ completionHandler: @escaping() ->()) {
isRecording = false
assetWriterVideoInput.markAsFinished()
assetWriterAudioInput.markAsFinished()
assetWriter.finishWriting(completionHandler: completionHandler)
}
이것은 AVCaptureSession
가 구성되는 방식입니다 :
func setupCapture() {
captureSession = AVCaptureSession()
if (captureSession == nil) {
fatalError("ERROR: Couldnt create a capture session")
}
captureSession?.beginConfiguration()
captureSession?.sessionPreset = AVCaptureSessionPreset1280x720
let frontDevices = AVCaptureDevice.devices().filter{ ($0 as AnyObject).hasMediaType(AVMediaTypeVideo) && ($0 as AnyObject).position == AVCaptureDevicePosition.front }
if let captureDevice = frontDevices.first as? AVCaptureDevice {
do {
let videoDeviceInput: AVCaptureDeviceInput
do {
videoDeviceInput = try AVCaptureDeviceInput(device: captureDevice)
}
catch {
fatalError("Could not create AVCaptureDeviceInput instance with error: \(error).")
}
guard (captureSession?.canAddInput(videoDeviceInput))! else {
fatalError()
}
captureSession?.addInput(videoDeviceInput)
}
}
do {
let audioDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
let audioDeviceInput: AVCaptureDeviceInput
do {
audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice)
}
catch {
fatalError("Could not create AVCaptureDeviceInput instance with error: \(error).")
}
guard (captureSession?.canAddInput(audioDeviceInput))! else {
fatalError()
}
captureSession?.addInput(audioDeviceInput)
}
do {
let dataOutput = AVCaptureVideoDataOutput()
dataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String : kCVPixelFormatType_32BGRA]
dataOutput.alwaysDiscardsLateVideoFrames = true
let queue = DispatchQueue(label: "com.3DTOPO.videosamplequeue")
dataOutput.setSampleBufferDelegate(self, queue: queue)
guard (captureSession?.canAddOutput(dataOutput))! else {
fatalError()
}
captureSession?.addOutput(dataOutput)
videoConnection = dataOutput.connection(withMediaType: AVMediaTypeVideo)
}
do {
let audioDataOutput = AVCaptureAudioDataOutput()
let queue = DispatchQueue(label: "com.3DTOPO.audiosamplequeue")
audioDataOutput.setSampleBufferDelegate(self, queue: queue)
guard (captureSession?.canAddOutput(audioDataOutput))! else {
fatalError()
}
captureSession?.addOutput(audioDataOutput)
audioConnection = audioDataOutput.connection(withMediaType: AVMediaTypeAudio)
}
captureSession?.commitConfiguration()
// this will trigger capture on its own queue
captureSession?.startRunning()
}
AVCaptureVideoDataOutput
위임 방법 : 호출
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
// func captureOutput(captureOutput: AVCaptureOutput, sampleBuffer: CMSampleBuffer, connection:AVCaptureConnection) {
var error: CVReturn
if (connection == audioConnection) {
delegate?.audioSampleUpdated(sampleBuffer: sampleBuffer)
return
}
// ... Write video buffer ...//
}
:
위의 assetWriterAudioInput.append()
호출을 사용하지 않으면 비디오가 손상되지 않지만 물론 인코딩 된 오디오가 없습니다. 비디오 및 오디오 인코딩을 모두 작동 시키려면 어떻게합니까?