录制视频,需要解决一些问题
This commit is contained in:
parent
7821f7be4d
commit
22c31d4a7e
@ -23,6 +23,10 @@
|
|||||||
00733EA92BFB462500D53BA8 /* CCSpatialShootController+SessionConfigure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733EA82BFB462500D53BA8 /* CCSpatialShootController+SessionConfigure.swift */; };
|
00733EA92BFB462500D53BA8 /* CCSpatialShootController+SessionConfigure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733EA82BFB462500D53BA8 /* CCSpatialShootController+SessionConfigure.swift */; };
|
||||||
00733EAB2BFB471100D53BA8 /* CCSpatialShootController+CaputreAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733EAA2BFB471100D53BA8 /* CCSpatialShootController+CaputreAction.swift */; };
|
00733EAB2BFB471100D53BA8 /* CCSpatialShootController+CaputreAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733EAA2BFB471100D53BA8 /* CCSpatialShootController+CaputreAction.swift */; };
|
||||||
00733EAD2BFB47AE00D53BA8 /* CCSpatialShootController+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733EAC2BFB47AE00D53BA8 /* CCSpatialShootController+Generate.swift */; };
|
00733EAD2BFB47AE00D53BA8 /* CCSpatialShootController+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733EAC2BFB47AE00D53BA8 /* CCSpatialShootController+Generate.swift */; };
|
||||||
|
00733ECB2BFDD32300D53BA8 /* SpatialVideoDataWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733ECA2BFDD32300D53BA8 /* SpatialVideoDataWriter.swift */; };
|
||||||
|
00733ECD2BFDDDE100D53BA8 /* CCSpatialShootController+GenerateImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733ECC2BFDDDE100D53BA8 /* CCSpatialShootController+GenerateImage.swift */; };
|
||||||
|
00733ECF2BFDDE2300D53BA8 /* CCSpatialShootController+GenerateVideo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733ECE2BFDDE2300D53BA8 /* CCSpatialShootController+GenerateVideo.swift */; };
|
||||||
|
00733EDF2BFF553100D53BA8 /* SVDWStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00733EDE2BFF553100D53BA8 /* SVDWStack.swift */; };
|
||||||
0073BD142BCE80F700721885 /* ZZHCustomPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */; };
|
0073BD142BCE80F700721885 /* ZZHCustomPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */; };
|
||||||
0073BD182BCF7B3400721885 /* ZZHCustomSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */; };
|
0073BD182BCF7B3400721885 /* ZZHCustomSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */; };
|
||||||
0073BD1A2BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */; };
|
0073BD1A2BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */; };
|
||||||
@ -141,6 +145,10 @@
|
|||||||
00733EA82BFB462500D53BA8 /* CCSpatialShootController+SessionConfigure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CCSpatialShootController+SessionConfigure.swift"; sourceTree = "<group>"; };
|
00733EA82BFB462500D53BA8 /* CCSpatialShootController+SessionConfigure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CCSpatialShootController+SessionConfigure.swift"; sourceTree = "<group>"; };
|
||||||
00733EAA2BFB471100D53BA8 /* CCSpatialShootController+CaputreAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CCSpatialShootController+CaputreAction.swift"; sourceTree = "<group>"; };
|
00733EAA2BFB471100D53BA8 /* CCSpatialShootController+CaputreAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CCSpatialShootController+CaputreAction.swift"; sourceTree = "<group>"; };
|
||||||
00733EAC2BFB47AE00D53BA8 /* CCSpatialShootController+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CCSpatialShootController+Generate.swift"; sourceTree = "<group>"; };
|
00733EAC2BFB47AE00D53BA8 /* CCSpatialShootController+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CCSpatialShootController+Generate.swift"; sourceTree = "<group>"; };
|
||||||
|
00733ECA2BFDD32300D53BA8 /* SpatialVideoDataWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpatialVideoDataWriter.swift; sourceTree = "<group>"; };
|
||||||
|
00733ECC2BFDDDE100D53BA8 /* CCSpatialShootController+GenerateImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CCSpatialShootController+GenerateImage.swift"; sourceTree = "<group>"; };
|
||||||
|
00733ECE2BFDDE2300D53BA8 /* CCSpatialShootController+GenerateVideo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CCSpatialShootController+GenerateVideo.swift"; sourceTree = "<group>"; };
|
||||||
|
00733EDE2BFF553100D53BA8 /* SVDWStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SVDWStack.swift; sourceTree = "<group>"; };
|
||||||
0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomPlayer.swift; sourceTree = "<group>"; };
|
0073BD132BCE80F700721885 /* ZZHCustomPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomPlayer.swift; sourceTree = "<group>"; };
|
||||||
0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomSlider.swift; sourceTree = "<group>"; };
|
0073BD172BCF7B3400721885 /* ZZHCustomSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomSlider.swift; sourceTree = "<group>"; };
|
||||||
0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomPlayerForVideoTask.swift; sourceTree = "<group>"; };
|
0073BD192BCFC8E800721885 /* ZZHCustomPlayerForVideoTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZZHCustomPlayerForVideoTask.swift; sourceTree = "<group>"; };
|
||||||
@ -322,6 +330,8 @@
|
|||||||
00733EA82BFB462500D53BA8 /* CCSpatialShootController+SessionConfigure.swift */,
|
00733EA82BFB462500D53BA8 /* CCSpatialShootController+SessionConfigure.swift */,
|
||||||
00733EAA2BFB471100D53BA8 /* CCSpatialShootController+CaputreAction.swift */,
|
00733EAA2BFB471100D53BA8 /* CCSpatialShootController+CaputreAction.swift */,
|
||||||
00733EAC2BFB47AE00D53BA8 /* CCSpatialShootController+Generate.swift */,
|
00733EAC2BFB47AE00D53BA8 /* CCSpatialShootController+Generate.swift */,
|
||||||
|
00733ECE2BFDDE2300D53BA8 /* CCSpatialShootController+GenerateVideo.swift */,
|
||||||
|
00733ECC2BFDDDE100D53BA8 /* CCSpatialShootController+GenerateImage.swift */,
|
||||||
);
|
);
|
||||||
path = CCSpatialShootController;
|
path = CCSpatialShootController;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -414,6 +424,8 @@
|
|||||||
1E1EA28F2B933C8200A5D5D2 /* VideoWriter.swift */,
|
1E1EA28F2B933C8200A5D5D2 /* VideoWriter.swift */,
|
||||||
00D33BF92B9AB21A00604A44 /* ZZHAVExtension.swift */,
|
00D33BF92B9AB21A00604A44 /* ZZHAVExtension.swift */,
|
||||||
1EE5C5F92B8F97BF00EDFC2F /* SpatialVideoWriter.swift */,
|
1EE5C5F92B8F97BF00EDFC2F /* SpatialVideoWriter.swift */,
|
||||||
|
00733ECA2BFDD32300D53BA8 /* SpatialVideoDataWriter.swift */,
|
||||||
|
00733EDE2BFF553100D53BA8 /* SVDWStack.swift */,
|
||||||
005580772B9F1525004B9567 /* ZZHHelper.swift */,
|
005580772B9F1525004B9567 /* ZZHHelper.swift */,
|
||||||
00ED6B332BA04AC200915BDE /* PlayByTransferConvertor.swift */,
|
00ED6B332BA04AC200915BDE /* PlayByTransferConvertor.swift */,
|
||||||
00374AE02BC92B7C00F1F20F /* ZNetUtil.swift */,
|
00374AE02BC92B7C00F1F20F /* ZNetUtil.swift */,
|
||||||
@ -845,6 +857,7 @@
|
|||||||
00B946252B67B7DE00DA668F /* CCSpatialPlayView.swift in Sources */,
|
00B946252B67B7DE00DA668F /* CCSpatialPlayView.swift in Sources */,
|
||||||
0096624A2BB3B45200FCA65F /* ExternalSceneDelegate.swift in Sources */,
|
0096624A2BB3B45200FCA65F /* ExternalSceneDelegate.swift in Sources */,
|
||||||
AFD9F5932B58C34A008716DE /* ImageProcessingShaders.metal in Sources */,
|
AFD9F5932B58C34A008716DE /* ImageProcessingShaders.metal in Sources */,
|
||||||
|
00733ECF2BFDDE2300D53BA8 /* CCSpatialShootController+GenerateVideo.swift in Sources */,
|
||||||
AF2120F02B4EA39D00400B7F /* BaseTableViewGroupedController.swift in Sources */,
|
AF2120F02B4EA39D00400B7F /* BaseTableViewGroupedController.swift in Sources */,
|
||||||
1E1EA2962B936C9600A5D5D2 /* VideoConvertor2.swift in Sources */,
|
1E1EA2962B936C9600A5D5D2 /* VideoConvertor2.swift in Sources */,
|
||||||
AF2120CA2B4E95DA00400B7F /* UITableView+Add.swift in Sources */,
|
AF2120CA2B4E95DA00400B7F /* UITableView+Add.swift in Sources */,
|
||||||
@ -852,6 +865,7 @@
|
|||||||
009DFB0E2BC8CFA2007B56E8 /* FeedbackView.swift in Sources */,
|
009DFB0E2BC8CFA2007B56E8 /* FeedbackView.swift in Sources */,
|
||||||
00BD87862BDE595F0014E8B3 /* CCSpatialPhotoDisplayEx.swift in Sources */,
|
00BD87862BDE595F0014E8B3 /* CCSpatialPhotoDisplayEx.swift in Sources */,
|
||||||
AF2120C42B4E95DA00400B7F /* UIImage+Add.swift in Sources */,
|
AF2120C42B4E95DA00400B7F /* UIImage+Add.swift in Sources */,
|
||||||
|
00733ECD2BFDDDE100D53BA8 /* CCSpatialShootController+GenerateImage.swift in Sources */,
|
||||||
1EFAF0C02B8B7A59002A1773 /* VRPhotoTransformController.swift in Sources */,
|
1EFAF0C02B8B7A59002A1773 /* VRPhotoTransformController.swift in Sources */,
|
||||||
AF2120D82B4E9AC500400B7F /* CCAddImageView.swift in Sources */,
|
AF2120D82B4E9AC500400B7F /* CCAddImageView.swift in Sources */,
|
||||||
00D33BF42B998BF700604A44 /* SpatialImageConvertor.swift in Sources */,
|
00D33BF42B998BF700604A44 /* SpatialImageConvertor.swift in Sources */,
|
||||||
@ -870,6 +884,7 @@
|
|||||||
AF2121092B4EA7E200400B7F /* CCRequestDefine.swift in Sources */,
|
AF2121092B4EA7E200400B7F /* CCRequestDefine.swift in Sources */,
|
||||||
005580782B9F1525004B9567 /* ZZHHelper.swift in Sources */,
|
005580782B9F1525004B9567 /* ZZHHelper.swift in Sources */,
|
||||||
AF2120C32B4E95DA00400B7F /* NSObject+Add.swift in Sources */,
|
AF2120C32B4E95DA00400B7F /* NSObject+Add.swift in Sources */,
|
||||||
|
00733EDF2BFF553100D53BA8 /* SVDWStack.swift in Sources */,
|
||||||
1EE5C5F72B8F973A00EDFC2F /* CCSpatialShootController.swift in Sources */,
|
1EE5C5F72B8F973A00EDFC2F /* CCSpatialShootController.swift in Sources */,
|
||||||
006B61DE2BBCFB45003FCB49 /* CustomSheetCell.swift in Sources */,
|
006B61DE2BBCFB45003FCB49 /* CustomSheetCell.swift in Sources */,
|
||||||
0073BD142BCE80F700721885 /* ZZHCustomPlayer.swift in Sources */,
|
0073BD142BCE80F700721885 /* ZZHCustomPlayer.swift in Sources */,
|
||||||
@ -915,6 +930,7 @@
|
|||||||
1E02C9322B8990C600DD3143 /* CCDeviceOperationListView.swift in Sources */,
|
1E02C9322B8990C600DD3143 /* CCDeviceOperationListView.swift in Sources */,
|
||||||
00BD87972BE10B800014E8B3 /* DisplayLinkProxy.swift in Sources */,
|
00BD87972BE10B800014E8B3 /* DisplayLinkProxy.swift in Sources */,
|
||||||
AF2120DA2B4E9BD400400B7F /* CCAlert.swift in Sources */,
|
AF2120DA2B4E9BD400400B7F /* CCAlert.swift in Sources */,
|
||||||
|
00733ECB2BFDD32300D53BA8 /* SpatialVideoDataWriter.swift in Sources */,
|
||||||
006B61D12BBA5DB4003FCB49 /* MembershipProductView.swift in Sources */,
|
006B61D12BBA5DB4003FCB49 /* MembershipProductView.swift in Sources */,
|
||||||
1EFB8C702B88DA4800C72119 /* CCBottomMenuCell.swift in Sources */,
|
1EFB8C702B88DA4800C72119 /* CCBottomMenuCell.swift in Sources */,
|
||||||
AF2120FA2B4EA5BD00400B7F /* CCHomeController.swift in Sources */,
|
AF2120FA2B4EA5BD00400B7F /* CCHomeController.swift in Sources */,
|
||||||
|
|||||||
Binary file not shown.
@ -505,22 +505,6 @@
|
|||||||
landmarkType = "7">
|
landmarkType = "7">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "E9B8F98E-43F6-47FD-A113-118A931EACBE"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "SwiftProject/Project/Controller/RecordingVideo/CCSpatialShootController/CCSpatialShootController+Generate.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "194"
|
|
||||||
endingLineNumber = "194"
|
|
||||||
landmarkName = "compositeSpatialPhoto()"
|
|
||||||
landmarkType = "7">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
<BreakpointProxy
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
|
|||||||
@ -56,6 +56,30 @@ extension CCSpatialShootController {
|
|||||||
|
|
||||||
//录像
|
//录像
|
||||||
@objc func shutterVideoButtonAction(_ sender: UIButton){
|
@objc func shutterVideoButtonAction(_ sender: UIButton){
|
||||||
|
if !isRecordingVideoData {//开始录制
|
||||||
|
writeVideoQueuen.async {[weak self] in//串行 异步执行
|
||||||
|
if let weakSelf = self {
|
||||||
|
weakSelf.removeExistingFile(at: weakSelf.outputVideoURL)
|
||||||
|
weakSelf.isRecordingVideoData = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {//录制完毕
|
||||||
|
writeVideoQueuen.async {[weak self] in//串行 异步执行
|
||||||
|
if let weakSelf = self {
|
||||||
|
weakSelf.isRecordingVideoData = false
|
||||||
|
weakSelf.svdWriter.writeVideoDataDeInit {result, err in
|
||||||
|
//保存导出视频
|
||||||
|
weakSelf.saveVideoToLibrary(videoURL: weakSelf.outputVideoURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if !self.isRecording {
|
if !self.isRecording {
|
||||||
//录像中
|
//录像中
|
||||||
print("录像中...")
|
print("录像中...")
|
||||||
|
|||||||
@ -57,32 +57,39 @@ extension CCSpatialShootController: AVCaptureAudioDataOutputSampleBufferDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if shootingMode == .CCShootingMode_Video {
|
else if shootingMode == .CCShootingMode_Video {
|
||||||
if output == wideAngleCameraVideoDataOutput {//广角视频
|
if isRecordingVideoData {
|
||||||
// leftEyeVideoURL = outputFileURL
|
|
||||||
}
|
if output == wideAngleCameraVideoDataOutput {//广角视频
|
||||||
else if output == ultraWideCameraVideoDataOutput {//超广角视频
|
writeVideoQueuen.async {[weak self] in//串行 异步执行
|
||||||
// print("ultra Wide video recorded: \(outputFileURL)")
|
self?.svdWriter.exAddLeftSampleBuffer(sampleBuffer)
|
||||||
// rightEyeVideoURL = outputFileURL
|
}
|
||||||
}
|
}
|
||||||
else if output == wuCameraAudioDataOutput {//音频
|
else if output == ultraWideCameraVideoDataOutput {//超广角视频
|
||||||
|
writeVideoQueuen.async {[weak self] in//串行 异步执行
|
||||||
|
self?.svdWriter.exAddRightSampleBuffer(sampleBuffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if output == wuCameraAudioDataOutput {//音频
|
||||||
|
writeVideoQueuen.async {[weak self] in//串行 异步执行
|
||||||
|
self?.svdWriter.exAddAudioSampleBuffer(sampleBuffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if let leftEyeVideoURL,
|
|
||||||
// let rightEyeVideoURL {
|
|
||||||
// createSpVideo()
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//视频掉帧回调
|
//视频掉帧回调
|
||||||
func captureOutput(_ output: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
|
func captureOutput(_ output: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
|
||||||
|
print("录制视频掉帧了...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//通过samplebuffer生成uiimage
|
//通过samplebuffer生成uiimage
|
||||||
func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer,orientation:AVCaptureVideoOrientation ) -> UIImage? {
|
func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer,orientation:AVCaptureVideoOrientation ) -> UIImage? {
|
||||||
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return nil }
|
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return nil }
|
||||||
@ -109,195 +116,44 @@ extension CCSpatialShootController: AVCaptureAudioDataOutputSampleBufferDelegate
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//跟视频相关
|
||||||
|
func removeExistingFile(at outputVideoURL: URL) {
|
||||||
|
if FileManager.default.fileExists(atPath: outputVideoURL.path) {
|
||||||
|
do {
|
||||||
|
try FileManager.default.removeItem(atPath: outputVideoURL.path)
|
||||||
|
print("视频文件删除成功")
|
||||||
|
} catch {
|
||||||
|
print("删除视频文件出错:\(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//MARK: 空间视频合成
|
|
||||||
func createSpVideo(){
|
|
||||||
//
|
|
||||||
// if(rightEyeVideoURL != nil && leftEyeVideoURL != nil){
|
|
||||||
//
|
|
||||||
// Task {
|
|
||||||
// spatialVideoWriter.writeSpatialVideo(leftEyeVideoURL: leftEyeVideoURL!, rightEyeVideoURL: rightEyeVideoURL!, outputVideoURL: outputVideoURL!) {[weak self] success, error in
|
|
||||||
// DispatchQueue.main.async {
|
|
||||||
// SVProgressHUD.dismiss()
|
|
||||||
// print("SVProgressHUD.dismiss..2222.....")
|
|
||||||
// }
|
|
||||||
// if success {
|
|
||||||
// print("空间视频生成成功")
|
|
||||||
// if let ovrul = self?.outputVideoURL{
|
|
||||||
// self?.saveVideoToLibrary(videoURL:ovrul)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// } else if let error = error {
|
|
||||||
// print(".怎么失败了呢.....error\(error)")
|
|
||||||
//
|
|
||||||
// DispatchQueue.main.async {
|
|
||||||
// SVProgressHUD.showInfo(withStatus: "\(NSLocalizedString("空间视频保存失败", comment: "")):\(error.localizedDescription)")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// print("not success......")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
private func saveVideoToLibrary(videoURL: URL) {
|
|
||||||
PHPhotoLibrary.shared().performChanges({
|
|
||||||
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
|
|
||||||
}) {[weak self] success, error in
|
|
||||||
if success {
|
|
||||||
print("保存成功")
|
|
||||||
self?.getAlbumFirstPhoto()
|
|
||||||
} else if let error = error {
|
|
||||||
print("保存失败")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//合成空间图片
|
|
||||||
func compositeSpatialPhoto(){
|
|
||||||
let img1:UIImage = imgs[0] as! UIImage
|
|
||||||
let img2:UIImage = imgs[1] as! UIImage
|
|
||||||
|
|
||||||
let url = URL.documentsDirectory.appending(path:"aaa12.HEIC")
|
|
||||||
let destination = CGImageDestinationCreateWithURL(url as CFURL, UTType.heic.identifier as CFString, 2, nil)!
|
|
||||||
var oo = imageCGImagePropertyOrientation.rawValue
|
|
||||||
// let orientation_cf = CFNumberCreate(nil, CFNumberType.intType, &oo)
|
|
||||||
let properties1 = [
|
|
||||||
kCGImagePropertyGroups: [
|
|
||||||
kCGImagePropertyGroupIndex: 0,
|
|
||||||
kCGImagePropertyGroupType: kCGImagePropertyGroupTypeStereoPair,
|
|
||||||
kCGImagePropertyGroupImageIndexLeft: 0,
|
|
||||||
kCGImagePropertyGroupImageIndexRight: 1,
|
|
||||||
],
|
|
||||||
// kCGImagePropertyTIFFDictionary:[
|
|
||||||
// kCGImagePropertyOrientation:orientation_cf,
|
|
||||||
// ],
|
|
||||||
//
|
|
||||||
// kCGImagePropertyOrientation:orientation_cf as Any,
|
|
||||||
kCGImagePropertyHEIFDictionary: [
|
|
||||||
kIIOMetadata_CameraExtrinsicsKey: [
|
|
||||||
kIIOCameraExtrinsics_CoordinateSystemID: 0,
|
|
||||||
kIIOCameraExtrinsics_Position: [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
kIIOCameraExtrinsics_Rotation: [
|
|
||||||
1, 0, 0,
|
|
||||||
0, 1, 0,
|
|
||||||
0, 0, 1
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
] as [CFString : Any]
|
|
||||||
let properties2 = [
|
|
||||||
kCGImagePropertyGroups: [
|
|
||||||
kCGImagePropertyGroupIndex: 0,
|
|
||||||
kCGImagePropertyGroupType: kCGImagePropertyGroupTypeStereoPair,
|
|
||||||
kCGImagePropertyGroupImageIndexLeft: 0,
|
|
||||||
kCGImagePropertyGroupImageIndexRight: 1,
|
|
||||||
],
|
|
||||||
// kCGImagePropertyTIFFDictionary:[
|
|
||||||
// kCGImagePropertyOrientation:orientation_cf,
|
|
||||||
// ],
|
|
||||||
// kCGImagePropertyOrientation:orientation_cf as Any,
|
|
||||||
|
|
||||||
kCGImagePropertyHEIFDictionary: [
|
|
||||||
kIIOMetadata_CameraExtrinsicsKey: [
|
|
||||||
kIIOCameraExtrinsics_CoordinateSystemID: 0,
|
|
||||||
kIIOCameraExtrinsics_Position: [
|
|
||||||
-0.019238,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
kIIOCameraExtrinsics_Rotation: [
|
|
||||||
1, 0, 0,
|
|
||||||
0, 1, 0,
|
|
||||||
0, 0, 1
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
] as [CFString : Any]
|
|
||||||
|
|
||||||
let leftImg = img1//fixOrientation(img1)
|
|
||||||
let rightImg = img2//fixOrientation(img2)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let p_dic1:CFDictionary = properties1 as CFDictionary
|
|
||||||
CGImageDestinationAddImage(destination, leftImg.cgImage!,p_dic1)
|
|
||||||
let p_dic2:CFDictionary = properties2 as CFDictionary
|
|
||||||
CGImageDestinationAddImage(destination, rightImg.cgImage!, p_dic2)
|
|
||||||
|
|
||||||
let rr = CGImageDestinationFinalize(destination)
|
|
||||||
if rr == false {
|
|
||||||
print("ee..")
|
|
||||||
}
|
|
||||||
savePhoto(url)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//保存照片
|
|
||||||
func savePhoto(_ fileURL: URL) {
|
|
||||||
|
|
||||||
// 创建 PHAssetCreationRequest
|
|
||||||
PHPhotoLibrary.shared().performChanges({
|
|
||||||
let creationRequest = PHAssetCreationRequest.forAsset()
|
|
||||||
creationRequest.addResource(with: .photoProxy, fileURL: fileURL, options: nil)
|
|
||||||
|
|
||||||
}) {[weak self] success, error in
|
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
SVProgressHUD.dismiss()
|
|
||||||
print("SVProgressHUD.dismiss..1111.....")
|
|
||||||
}
|
|
||||||
|
|
||||||
if let error = error {
|
|
||||||
print("Error saving photo to library: \(error.localizedDescription)")
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
SVProgressHUD.showInfo(withStatus: "\(NSLocalizedString("空间图片保存失败", comment: "")): \(error.localizedDescription)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print("Photo saved to library successfully.")
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self?.getAlbumFirstPhoto()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,137 @@
|
|||||||
|
//
|
||||||
|
// CCSpatialShootController+GenerateImage.swift
|
||||||
|
// SwiftProject
|
||||||
|
//
|
||||||
|
// Created by aaa on 2024/5/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import AVFoundation
|
||||||
|
import Photos
|
||||||
|
import AVKit
|
||||||
|
import VideoToolbox
|
||||||
|
import SVProgressHUD
|
||||||
|
import Firebase
|
||||||
|
import CoreMotion
|
||||||
|
|
||||||
|
extension CCSpatialShootController {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//合成空间图片
|
||||||
|
func compositeSpatialPhoto(){
|
||||||
|
let img1:UIImage = imgs[0] as! UIImage
|
||||||
|
let img2:UIImage = imgs[1] as! UIImage
|
||||||
|
|
||||||
|
let url = URL.documentsDirectory.appending(path:"aaa12.HEIC")
|
||||||
|
let destination = CGImageDestinationCreateWithURL(url as CFURL, UTType.heic.identifier as CFString, 2, nil)!
|
||||||
|
var oo = imageCGImagePropertyOrientation.rawValue
|
||||||
|
// let orientation_cf = CFNumberCreate(nil, CFNumberType.intType, &oo)
|
||||||
|
let properties1 = [
|
||||||
|
kCGImagePropertyGroups: [
|
||||||
|
kCGImagePropertyGroupIndex: 0,
|
||||||
|
kCGImagePropertyGroupType: kCGImagePropertyGroupTypeStereoPair,
|
||||||
|
kCGImagePropertyGroupImageIndexLeft: 0,
|
||||||
|
kCGImagePropertyGroupImageIndexRight: 1,
|
||||||
|
],
|
||||||
|
// kCGImagePropertyTIFFDictionary:[
|
||||||
|
// kCGImagePropertyOrientation:orientation_cf,
|
||||||
|
// ],
|
||||||
|
//
|
||||||
|
// kCGImagePropertyOrientation:orientation_cf as Any,
|
||||||
|
kCGImagePropertyHEIFDictionary: [
|
||||||
|
kIIOMetadata_CameraExtrinsicsKey: [
|
||||||
|
kIIOCameraExtrinsics_CoordinateSystemID: 0,
|
||||||
|
kIIOCameraExtrinsics_Position: [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
kIIOCameraExtrinsics_Rotation: [
|
||||||
|
1, 0, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 0, 1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
] as [CFString : Any]
|
||||||
|
let properties2 = [
|
||||||
|
kCGImagePropertyGroups: [
|
||||||
|
kCGImagePropertyGroupIndex: 0,
|
||||||
|
kCGImagePropertyGroupType: kCGImagePropertyGroupTypeStereoPair,
|
||||||
|
kCGImagePropertyGroupImageIndexLeft: 0,
|
||||||
|
kCGImagePropertyGroupImageIndexRight: 1,
|
||||||
|
],
|
||||||
|
// kCGImagePropertyTIFFDictionary:[
|
||||||
|
// kCGImagePropertyOrientation:orientation_cf,
|
||||||
|
// ],
|
||||||
|
// kCGImagePropertyOrientation:orientation_cf as Any,
|
||||||
|
|
||||||
|
kCGImagePropertyHEIFDictionary: [
|
||||||
|
kIIOMetadata_CameraExtrinsicsKey: [
|
||||||
|
kIIOCameraExtrinsics_CoordinateSystemID: 0,
|
||||||
|
kIIOCameraExtrinsics_Position: [
|
||||||
|
-0.019238,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
kIIOCameraExtrinsics_Rotation: [
|
||||||
|
1, 0, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 0, 1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
] as [CFString : Any]
|
||||||
|
|
||||||
|
let leftImg = img1//fixOrientation(img1)
|
||||||
|
let rightImg = img2//fixOrientation(img2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let p_dic1:CFDictionary = properties1 as CFDictionary
|
||||||
|
CGImageDestinationAddImage(destination, leftImg.cgImage!,p_dic1)
|
||||||
|
let p_dic2:CFDictionary = properties2 as CFDictionary
|
||||||
|
CGImageDestinationAddImage(destination, rightImg.cgImage!, p_dic2)
|
||||||
|
|
||||||
|
let rr = CGImageDestinationFinalize(destination)
|
||||||
|
if rr == false {
|
||||||
|
print("ee..")
|
||||||
|
}
|
||||||
|
savePhoto(url)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//保存照片
|
||||||
|
func savePhoto(_ fileURL: URL) {
|
||||||
|
|
||||||
|
// 创建 PHAssetCreationRequest
|
||||||
|
PHPhotoLibrary.shared().performChanges({
|
||||||
|
let creationRequest = PHAssetCreationRequest.forAsset()
|
||||||
|
creationRequest.addResource(with: .photoProxy, fileURL: fileURL, options: nil)
|
||||||
|
|
||||||
|
}) {[weak self] success, error in
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
SVProgressHUD.dismiss()
|
||||||
|
print("SVProgressHUD.dismiss..1111.....")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let error = error {
|
||||||
|
print("Error saving photo to library: \(error.localizedDescription)")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
SVProgressHUD.showInfo(withStatus: "\(NSLocalizedString("空间图片保存失败", comment: "")): \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("Photo saved to library successfully.")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self?.getAlbumFirstPhoto()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// CCSpatialShootController+GenerateVideo.swift
|
||||||
|
// SwiftProject
|
||||||
|
//
|
||||||
|
// Created by aaa on 2024/5/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Photos
|
||||||
|
|
||||||
|
extension CCSpatialShootController {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//MARK: 空间视频合成
|
||||||
|
// func createSpVideo(vd:ZVideoData){
|
||||||
|
// svdWriter.writeVideoData(leftSamplebuffer: vd.leftSampleBuffer!, rightSamplebuffer: vd.rightSampleBuffer!, audioSamplebuffer: vd.audioSampleBuffer!)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func saveVideoToLibrary(videoURL: URL) {
|
||||||
|
PHPhotoLibrary.shared().performChanges({
|
||||||
|
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
|
||||||
|
}) {[weak self] success, error in
|
||||||
|
if success {
|
||||||
|
print("保存成功")
|
||||||
|
self?.getAlbumFirstPhoto()
|
||||||
|
} else if let error = error {
|
||||||
|
print("保存失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,8 +13,25 @@ import VideoToolbox
|
|||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
import Firebase
|
import Firebase
|
||||||
import CoreMotion
|
import CoreMotion
|
||||||
|
|
||||||
|
//class ZVideoData:NSObject {
|
||||||
|
// var leftSampleBuffer:CMSampleBuffer?
|
||||||
|
// var rightSampleBuffer:CMSampleBuffer?
|
||||||
|
// var audioSampleBuffer:CMSampleBuffer?
|
||||||
|
// var isReady:Bool {
|
||||||
|
// get {
|
||||||
|
// return leftSampleBuffer != nil && rightSampleBuffer != nil && audioSampleBuffer != nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override init() {
|
||||||
|
// super.init()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
class CCSpatialShootController: BaseController {
|
class CCSpatialShootController: BaseController {
|
||||||
|
|
||||||
|
let writeVideoQueuen = dispatch_queue_serial_t(label: "ccspatial writeVideoQueuen")//创建一个串行队列
|
||||||
|
|
||||||
let kNowTimeToUserDefaultKey_SpatialShootController:String = "kNowTimeToUserDefaultKey_SpatialShootController"
|
let kNowTimeToUserDefaultKey_SpatialShootController:String = "kNowTimeToUserDefaultKey_SpatialShootController"
|
||||||
var wideAngleCameraDevice:AVCaptureDevice?//测试使用
|
var wideAngleCameraDevice:AVCaptureDevice?//测试使用
|
||||||
@ -22,6 +39,14 @@ class CCSpatialShootController: BaseController {
|
|||||||
var isTakePhoto_ultraCamera = false
|
var isTakePhoto_ultraCamera = false
|
||||||
var isTakePhoto_wideCamera = false
|
var isTakePhoto_wideCamera = false
|
||||||
let takePhotoSemaphore = DispatchSemaphore(value: 1)
|
let takePhotoSemaphore = DispatchSemaphore(value: 1)
|
||||||
|
var isRecordingVideoData = false //是否正在录像
|
||||||
|
// var videoData:ZVideoData = ZVideoData()
|
||||||
|
lazy var svdWriter:SpatialVideoDataWriter = {
|
||||||
|
let writer = SpatialVideoDataWriter()
|
||||||
|
writer.outputVideoURL = outputVideoURL
|
||||||
|
return writer
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
//AVCaptureSession --- 单摄像头
|
//AVCaptureSession --- 单摄像头
|
||||||
var session = AVCaptureMultiCamSession()//多摄像头
|
var session = AVCaptureMultiCamSession()//多摄像头
|
||||||
@ -47,10 +72,10 @@ class CCSpatialShootController: BaseController {
|
|||||||
|
|
||||||
var leftEyeVideoURL:URL?
|
var leftEyeVideoURL:URL?
|
||||||
var rightEyeVideoURL:URL?
|
var rightEyeVideoURL:URL?
|
||||||
var outputVideoURL: URL?
|
let outputVideoURL: URL = URL.documentsDirectory.appendingPathComponent("output.MOV")
|
||||||
let motionManager = CMMotionManager()
|
let motionManager = CMMotionManager()
|
||||||
var imgs:NSMutableArray = NSMutableArray() //存放广角、主摄照片数组
|
var imgs:NSMutableArray = NSMutableArray() //存放广角、主摄照片数组
|
||||||
let spatialVideoWriter = SpatialVideoWriter()
|
// let spatialVideoWriter = SpatialVideoWriter()
|
||||||
//================================
|
//================================
|
||||||
|
|
||||||
//当前相机模式
|
//当前相机模式
|
||||||
@ -244,7 +269,6 @@ class CCSpatialShootController: BaseController {
|
|||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
ZZHHelper.setNowTimeToUserDefaultWithKey(kNowTimeToUserDefaultKey_SpatialShootController)
|
ZZHHelper.setNowTimeToUserDefaultWithKey(kNowTimeToUserDefaultKey_SpatialShootController)
|
||||||
|
|
||||||
outputVideoURL = URL.documentsDirectory.appendingPathComponent("output.MOV")
|
|
||||||
configureSession() // 设置相机参数
|
configureSession() // 设置相机参数
|
||||||
|
|
||||||
setUI()
|
setUI()
|
||||||
|
|||||||
31
SwiftProject/SwiftProject/Project/Util/SVDWStack.swift
Normal file
31
SwiftProject/SwiftProject/Project/Util/SVDWStack.swift
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// SVDWStack.swift
|
||||||
|
// SwiftProject
|
||||||
|
//
|
||||||
|
// Created by aaa on 2024/5/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
struct SVDWStack<Element: Equatable> {
|
||||||
|
private var storage: [Element] = []
|
||||||
|
|
||||||
|
mutating func push(_ element: Element) {
|
||||||
|
storage.append(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func pop() -> Element? {
|
||||||
|
return storage.popLast()
|
||||||
|
}
|
||||||
|
|
||||||
|
func top() -> Element? {
|
||||||
|
return storage.last
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEmpty() -> Bool {
|
||||||
|
return storage.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func clear() {
|
||||||
|
storage.removeAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,184 @@
|
|||||||
|
//
|
||||||
|
// SpatialVideoWriter.swift
|
||||||
|
// tdvideo
|
||||||
|
//
|
||||||
|
// Created by mac on 2024/2/22.
|
||||||
|
//。两个普通视频合成空间视频
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import AVFoundation
|
||||||
|
import VideoToolbox
|
||||||
|
import Photos
|
||||||
|
|
||||||
|
class SpatialVideoDataWriter {
|
||||||
|
|
||||||
|
var assetWriter:AVAssetWriter!
|
||||||
|
var videoSettings: [String: Any]!
|
||||||
|
var input_video:AVAssetWriterInput!
|
||||||
|
let inputSettings_Audio = [
|
||||||
|
AVFormatIDKey: kAudioFormatLinearPCM, // 指定未压缩格式
|
||||||
|
AVSampleRateKey: 44100,
|
||||||
|
AVNumberOfChannelsKey: 2,
|
||||||
|
AVLinearPCMIsBigEndianKey:true,
|
||||||
|
AVLinearPCMIsFloatKey:true,
|
||||||
|
AVLinearPCMBitDepthKey:32,
|
||||||
|
AVLinearPCMIsNonInterleaved:false,
|
||||||
|
] as [String:Any]
|
||||||
|
|
||||||
|
var writerInput_Audio_left:AVAssetWriterInput!
|
||||||
|
var adaptor_inputVideo:AVAssetWriterInputTaggedPixelBufferGroupAdaptor!
|
||||||
|
|
||||||
|
var isReady:Bool {
|
||||||
|
get {
|
||||||
|
return assetWriter != nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var haveStartedSession:Bool = false
|
||||||
|
|
||||||
|
var outputVideoURL:URL!
|
||||||
|
|
||||||
|
var leftSampleBuffer:SVDWStack<CMSampleBuffer> = SVDWStack()
|
||||||
|
var rightSampleBuffer:SVDWStack<CMSampleBuffer> = SVDWStack()
|
||||||
|
var audioSmapleBuffer:SVDWStack<CMSampleBuffer> = SVDWStack()
|
||||||
|
|
||||||
|
|
||||||
|
//MARK: - Function实现
|
||||||
|
func exAddLeftSampleBuffer(_ buffer:CMSampleBuffer) {
|
||||||
|
initWriterWithSmapleBuffer(buffer)
|
||||||
|
leftSampleBuffer.push(buffer)
|
||||||
|
autoWriteData()
|
||||||
|
}
|
||||||
|
|
||||||
|
func exAddRightSampleBuffer(_ buffer:CMSampleBuffer) {
|
||||||
|
initWriterWithSmapleBuffer(buffer)
|
||||||
|
rightSampleBuffer.push(buffer)
|
||||||
|
autoWriteData()
|
||||||
|
}
|
||||||
|
|
||||||
|
func exAddAudioSampleBuffer(_ buffer:CMSampleBuffer) {
|
||||||
|
audioSmapleBuffer.push(buffer)
|
||||||
|
autoWriteData()
|
||||||
|
}
|
||||||
|
|
||||||
|
//开始自动写入
|
||||||
|
func autoWriteData(){
|
||||||
|
if !leftSampleBuffer.isEmpty() && !rightSampleBuffer.isEmpty() && !audioSmapleBuffer.isEmpty() {
|
||||||
|
writeVideoData(leftSamplebuffer: leftSampleBuffer.pop()!, rightSamplebuffer: rightSampleBuffer.pop()!, audioSamplebuffer: audioSmapleBuffer.pop()!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initWriterWithSmapleBuffer(_ buffer:CMSampleBuffer){
|
||||||
|
if !self.isReady {
|
||||||
|
let pixelBuffer = CMSampleBufferGetImageBuffer(buffer)
|
||||||
|
if let pixelBuffer {
|
||||||
|
let videoWidth = CVPixelBufferGetWidth(pixelBuffer)
|
||||||
|
let videoHeight = CVPixelBufferGetHeight(pixelBuffer)
|
||||||
|
writeVideoDataInit(videoWidth: KScreenHeight, videoHeight: KScreenWidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//第一步,写入之前应当先初始化配置信息
|
||||||
|
func writeVideoDataInit(videoWidth:Double,videoHeight:Double) {
|
||||||
|
do {
|
||||||
|
// 创建视频输入
|
||||||
|
assetWriter = try AVAssetWriter(outputURL: outputVideoURL, fileType: .mov)
|
||||||
|
videoSettings = [
|
||||||
|
AVVideoWidthKey: videoWidth,
|
||||||
|
AVVideoHeightKey: videoHeight,
|
||||||
|
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
|
||||||
|
]
|
||||||
|
]
|
||||||
|
input_video = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
|
||||||
|
input_video.expectsMediaDataInRealTime = true
|
||||||
|
adaptor_inputVideo = AVAssetWriterInputTaggedPixelBufferGroupAdaptor(assetWriterInput: input_video)
|
||||||
|
assetWriter.add(input_video)
|
||||||
|
|
||||||
|
// 创建音频输入
|
||||||
|
writerInput_Audio_left = AVAssetWriterInput.init(mediaType: .audio, outputSettings: inputSettings_Audio)
|
||||||
|
writerInput_Audio_left.expectsMediaDataInRealTime = true
|
||||||
|
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)
|
||||||
|
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
print("writeVideoDataInit 初始化遇到问题:\(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//第三部,写入完毕之后应当释放配置信息
|
||||||
|
func writeVideoDataDeInit(completion: @escaping (Bool, Error?) -> Void) {
|
||||||
|
writerInput_Audio_left.markAsFinished()
|
||||||
|
input_video.markAsFinished()
|
||||||
|
assetWriter.finishWriting {
|
||||||
|
print("assetWriter.finishWriting 可以保存")
|
||||||
|
completion(true, nil)
|
||||||
|
}
|
||||||
|
haveStartedSession = false
|
||||||
|
assetWriter = nil
|
||||||
|
input_video = nil
|
||||||
|
adaptor_inputVideo = nil
|
||||||
|
writerInput_Audio_left = nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//第二步,开始写入数据
|
||||||
|
func writeVideoData(leftSamplebuffer:CMSampleBuffer,rightSamplebuffer:CMSampleBuffer,audioSamplebuffer:CMSampleBuffer) {
|
||||||
|
|
||||||
|
//追加视频帧
|
||||||
|
guard let leftCVPixelBuffer = CMSampleBufferGetImageBuffer(leftSamplebuffer) ,
|
||||||
|
let rightCVPixelBuffer = CMSampleBufferGetImageBuffer(rightSamplebuffer) else {
|
||||||
|
print("获取左右眼像素缓冲区失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ( !haveStartedSession ) {
|
||||||
|
assetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(leftSamplebuffer))
|
||||||
|
haveStartedSession = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 CMTaggedBuffer 数组,包含左右眼视图的像素缓冲区
|
||||||
|
|
||||||
|
let left = CMTaggedBuffer(tags: [.stereoView(.leftEye), .videoLayerID(0)], pixelBuffer: leftCVPixelBuffer)
|
||||||
|
let right = CMTaggedBuffer(tags: [.stereoView(.rightEye), .videoLayerID(1)], pixelBuffer: rightCVPixelBuffer)
|
||||||
|
|
||||||
|
while !adaptor_inputVideo.assetWriterInput.isReadyForMoreMediaData {
|
||||||
|
// 等待直到 writerInput 准备好接收下一个视频帧
|
||||||
|
Thread.sleep(forTimeInterval: 0.1) // 暂停一段时间,避免过度占用资源
|
||||||
|
}
|
||||||
|
|
||||||
|
let appendResult = adaptor_inputVideo.appendTaggedBuffers([left, right], withPresentationTime: leftSamplebuffer.presentationTimeStamp)
|
||||||
|
print("appendVideoImage samplebuffer Frame Result :\(appendResult)")
|
||||||
|
|
||||||
|
|
||||||
|
//追加音频帧
|
||||||
|
if writerInput_Audio_left.isReadyForMoreMediaData {
|
||||||
|
if writerInput_Audio_left.append(audioSamplebuffer) == false {
|
||||||
|
print("追加音频失败.....")
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print("audio 追加成功....")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print("audio 追加还未准备好...")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user