From dc2fb63193d7cbcd7379494a4bc612e0b43e02e3 Mon Sep 17 00:00:00 2001 From: bluesea <307723040@qq.com> Date: Thu, 14 Mar 2024 10:07:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90app=E5=86=85=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E6=8B=8D=E6=91=84=E5=AE=8C=E6=AF=95=E5=90=8E=E7=9A=84?= =?UTF-8?q?=E5=A3=B0=E9=9F=B3=E5=90=88=E6=88=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Project/Util/SpatialVideoWriter.swift | 112 +++++++++++++++--- 1 file changed, 95 insertions(+), 17 deletions(-) diff --git a/SwiftProject/SwiftProject/Project/Util/SpatialVideoWriter.swift b/SwiftProject/SwiftProject/Project/Util/SpatialVideoWriter.swift index 23cab76..60424ff 100644 --- a/SwiftProject/SwiftProject/Project/Util/SpatialVideoWriter.swift +++ b/SwiftProject/SwiftProject/Project/Util/SpatialVideoWriter.swift @@ -30,9 +30,14 @@ class SpatialVideoWriter { let leftEyeAsset = AVURLAsset(url: leftEyeVideoURL) let rightEyeAsset = AVURLAsset(url: rightEyeVideoURL) - let assetWriter = try AVAssetWriter(outputURL: outputVideoURL, fileType: .mov) + let leftVideoTrack = leftEyeAsset.tracks(withMediaType: .video).first! + let rightVideoTrack = rightEyeAsset.tracks(withMediaType: .video).first! + let letAudioTrack = leftEyeAsset.tracks(withMediaType: .audio).first! + + // 创建视频输入 + let assetWriter = try AVAssetWriter(outputURL: outputVideoURL, fileType: .mov) let videoSettings: [String: Any] = [ AVVideoWidthKey: leftVideoTrack.naturalSize.width, AVVideoHeightKey: leftVideoTrack.naturalSize.height, @@ -43,13 +48,40 @@ class SpatialVideoWriter { kVTCompressionPropertyKey_HorizontalDisparityAdjustment: 200, // asset-specific ] ] - let input = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings) - assetWriter.add(input) + let input_video = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings) + input_video.expectsMediaDataInRealTime = true + let adaptor_inputVideo = AVAssetWriterInputTaggedPixelBufferGroupAdaptor(assetWriterInput: input_video) + assetWriter.add(input_video) - let adaptor = AVAssetWriterInputTaggedPixelBufferGroupAdaptor(assetWriterInput: input) + + // 创建音频输入 + let inputSettings_Audio = [ + AVFormatIDKey: kAudioFormatLinearPCM, // 指定未压缩格式 + AVSampleRateKey: 44100, + AVNumberOfChannelsKey: 2, + AVLinearPCMIsBigEndianKey:true, + AVLinearPCMIsFloatKey:true, + AVLinearPCMBitDepthKey:32, + AVLinearPCMIsNonInterleaved:false, + ] as [String:Any] + + + let writerInput_Audio_left = AVAssetWriterInput.init(mediaType: .audio, outputSettings: inputSettings_Audio) + + writerInput_Audio_left.expectsMediaDataInRealTime = false + if assetWriter.canAdd(writerInput_Audio_left) { + assetWriter.add(writerInput_Audio_left) + print("assetWriter 添加writerInput_Audio_left成功...") + } + else { + print("assetWriter 添加writerInput_Audio_left失败...") + } + assetWriter.startWriting() assetWriter.startSession(atSourceTime: .zero) + + //创建视频读取 let leftEyeReader = try AVAssetReader(asset: leftEyeAsset) let rightEyeReader = try AVAssetReader(asset: rightEyeAsset) @@ -60,13 +92,38 @@ class SpatialVideoWriter { ] let leftEyeOutput = AVAssetReaderTrackOutput(track: leftVideoTrack, outputSettings: readerOutputSettings) - let rightEyeOutput = AVAssetReaderTrackOutput(track: rightEyeAsset.tracks(withMediaType: .video).first!, outputSettings: readerOutputSettings) + let rightEyeOutput = AVAssetReaderTrackOutput(track:rightVideoTrack , outputSettings: readerOutputSettings) leftEyeReader.add(leftEyeOutput) rightEyeReader.add(rightEyeOutput) + //加载音频轨道读取 从左眼视频读取 + let outputSettings_Audio = [ + AVFormatIDKey: kAudioFormatLinearPCM, // 指定未压缩格式 + AVSampleRateKey: 44100, + AVNumberOfChannelsKey: 2, + ] +// + + + let output_audio_left = AVAssetReaderTrackOutput( + track: letAudioTrack, + outputSettings:outputSettings_Audio + ) + + if leftEyeReader.canAdd(output_audio_left){ + leftEyeReader.add(output_audio_left) + print("output_audio_left添加音频read output成功。。。。") + } + else{ + print("output_audio_left添加音频read output失败。。。。") + } + + leftEyeReader.startReading() rightEyeReader.startReading() + + while let leftBuffer = leftEyeOutput.copyNextSampleBuffer(), let rightBuffer = rightEyeOutput.copyNextSampleBuffer() { @@ -87,16 +144,20 @@ class SpatialVideoWriter { let left = CMTaggedBuffer(tags: [.stereoView(.leftEye), .videoLayerID(0)], pixelBuffer: leftCVPixelBuffer) let right = CMTaggedBuffer(tags: [.stereoView(.rightEye), .videoLayerID(1)], pixelBuffer: rightCVPixelBuffer) - while !adaptor.assetWriterInput.isReadyForMoreMediaData { + while !adaptor_inputVideo.assetWriterInput.isReadyForMoreMediaData { // 等待直到 writerInput 准备好接收下一个视频帧 Thread.sleep(forTimeInterval: 0.1) // 暂停一段时间,避免过度占用资源 } - adaptor.appendTaggedBuffers([left, right], withPresentationTime: leftBuffer.presentationTimeStamp) + adaptor_inputVideo.appendTaggedBuffers([left, right], withPresentationTime: leftBuffer.presentationTimeStamp) } + + self.addAudio(assetTrackOutput: output_audio_left, audio_input: writerInput_Audio_left) + // 完成写入 print("完成写入") - input.markAsFinished() + writerInput_Audio_left.markAsFinished() + input_video.markAsFinished() outputVideoURL.stopAccessingSecurityScopedResource() assetWriter.finishWriting { [self] in print("可以保存") @@ -110,15 +171,32 @@ class SpatialVideoWriter { } } - private func saveVideoToLibrary(videoURL: URL, completion: @escaping (Bool, Error?) -> Void) { - PHPhotoLibrary.shared().performChanges({ - PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL) - }) { success, error in - if success { - print("保存成功") - } else if let error = error { - print("保存失败") + + //追加音频 + func addAudio(assetTrackOutput:AVAssetReaderTrackOutput,audio_input:AVAssetWriterInput) { + while let sample = assetTrackOutput.copyNextSampleBuffer() { + print("audio read buffer....") + let formatDesc:CMFormatDescription = CMSampleBufferGetFormatDescription(sample)! + let mediaType:CMMediaType = CMFormatDescriptionGetMediaType(formatDesc); + if mediaType == kCMMediaType_Audio { + if audio_input.isReadyForMoreMediaData { + if audio_input.append(sample) == false { +// print("追加音频失败....:\(String(describing: self.writer.error?.localizedDescription))") + print("追加音频失败.....") + } + else{ + print("audio 追加成功....") + } + } + else { + print("audio 追加还未准备好...") + + } + } + else { + print("不是audio类型...") + } } - } + print("audio func 执行完毕。。。。...") } }