VPCamera3/tdvideo/tdvideo/SpatialVideoWriter.swift
2024-03-05 11:44:34 +08:00

125 lines
5.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// SpatialVideoWriter.swift
// tdvideo
//
// Created by mac on 2024/2/22.
//
import UIKit
import AVFoundation
import VideoToolbox
import Photos
class SpatialVideoWriter {
private func removeExistingFile(at outputVideoURL: URL) throws {
do {
try FileManager.default.removeItem(atPath: outputVideoURL.path)
print("视频文件删除成功")
} catch {
print("删除视频文件出错:\(error)")
}
}
func writeSpatialVideo(leftEyeVideoURL: URL, rightEyeVideoURL: URL, outputVideoURL: URL, completion: @escaping (Bool, Error?) -> Void) {
do {
try removeExistingFile(at: outputVideoURL)
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 videoSettings: [String: Any] = [
AVVideoWidthKey: leftVideoTrack.naturalSize.width,
AVVideoHeightKey: leftVideoTrack.naturalSize.height,
AVVideoCodecKey: AVVideoCodecType.hevc,
AVVideoCompressionPropertiesKey: [
kVTCompressionPropertyKey_MVHEVCVideoLayerIDs: [0, 1] as CFArray,
kCMFormatDescriptionExtension_HorizontalFieldOfView: 90_000, // asset-specific, in thousandths of a degree
kVTCompressionPropertyKey_HorizontalDisparityAdjustment: 200, // asset-specific
]
]
let input = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
assetWriter.add(input)
let adaptor = AVAssetWriterInputTaggedPixelBufferGroupAdaptor(assetWriterInput: input)
assetWriter.startWriting()
assetWriter.startSession(atSourceTime: .zero)
let leftEyeReader = try AVAssetReader(asset: leftEyeAsset)
let rightEyeReader = try AVAssetReader(asset: rightEyeAsset)
let readerOutputSettings: [String:Any] = [
kCVPixelBufferPixelFormatTypeKey as String: NSNumber(value: kCVPixelFormatType_32BGRA),
kCVPixelBufferWidthKey as String: leftVideoTrack.naturalSize.width,
kCVPixelBufferHeightKey as String: leftVideoTrack.naturalSize.height
]
let leftEyeOutput = AVAssetReaderTrackOutput(track: leftVideoTrack, outputSettings: readerOutputSettings)
let rightEyeOutput = AVAssetReaderTrackOutput(track: rightEyeAsset.tracks(withMediaType: .video).first!, outputSettings: readerOutputSettings)
leftEyeReader.add(leftEyeOutput)
rightEyeReader.add(rightEyeOutput)
leftEyeReader.startReading()
rightEyeReader.startReading()
while let leftBuffer = leftEyeOutput.copyNextSampleBuffer(),
let rightBuffer = rightEyeOutput.copyNextSampleBuffer() {
let time = Date().timeIntervalSince1970
print("获取了一帧" + String(time))
//
guard let leftFrameBuffer = CMSampleBufferGetImageBuffer(leftBuffer),
let rightFrameBuffer = CMSampleBufferGetImageBuffer(rightBuffer) else {
print("获取左右眼像素缓冲区失败")
return
}
// CMTaggedBuffer
let leftCVPixelBuffer = leftFrameBuffer as CVPixelBuffer
let rightCVPixelBuffer = rightFrameBuffer as CVPixelBuffer
let left = CMTaggedBuffer(tags: [.stereoView(.leftEye), .videoLayerID(0)], pixelBuffer: leftCVPixelBuffer)
let right = CMTaggedBuffer(tags: [.stereoView(.rightEye), .videoLayerID(1)], pixelBuffer: rightCVPixelBuffer)
while !adaptor.assetWriterInput.isReadyForMoreMediaData {
// writerInput
Thread.sleep(forTimeInterval: 0.1) //
}
adaptor.appendTaggedBuffers([left, right], withPresentationTime: leftBuffer.presentationTimeStamp)
}
//
print("完成写入")
input.markAsFinished()
outputVideoURL.stopAccessingSecurityScopedResource()
assetWriter.finishWriting { [self] in
print("可以保存")
completion(true, nil)
self.saveVideoToLibrary(videoURL: outputVideoURL, completion: completion)
}
} catch {
print("生成失败")
completion(false, error)
}
}
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("保存失败")
}
}
}
}