VPCamera/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController.swift
bluesea 06ab0e319d 空间视频转换页面:
1,增加平行眼选项;
2,修正切换红蓝立体、交叉眼选项之后无法再次转码的问题,主要是使用了转码后的非空间视频进行转码失败导致,需要使用原空间视频转码才正确;
2024-03-06 16:54:01 +08:00

549 lines
21 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.

//
// CCSpatialVideoDisplayController.swift
// SwiftProject
//
// Created by Zhang, Joyce on 2024/3/2.
//
import UIKit
import AVFoundation
enum SpatialType : Int {
/*
2D
*/
case monocular2D
case parallelEyes
case redBlueSolid
case crossedEyes
}
class CCSpatialVideoDisplayController: BaseController {
var link = false//
var isPlaying = false//
var selectedIndex:SpatialType = .monocular2D//
let convertor2 = VideoConvertor2()
var videoOriginalAsset:AVAsset?
var videoTempAsset:AVAsset?
//
var sourceVideoURL:URL?
var outputVideoURL:URL?
var imgData:Data?
//
var type = 0
var player:AVPlayer = AVPlayer()
lazy var mTopImgView:UIImageView = {
//393*236
let view = UIImageView(frame: CGRect(x: 0, y: 0, width: SCREEN_Width, height: SCREEN_Height * 236/393))
view.image = UIImage.init(named: "BG_Top")
return view
}()
lazy var transformButton: UIButton = {
//76*56
let transformButton = UIButton.init(type: UIButton.ButtonType.custom)
transformButton.tag = 201
transformButton.isSelected = false
transformButton.backgroundColor = UIColor(hexString: "#5326D6")
transformButton.addTarget(self, action: #selector(navgationButtonClick2(sender:)), for: UIControl.Event.touchUpInside)
let img2:UIImage = UIImage.init(named: "transform_button" as String)!
transformButton.setImage(img2, for: UIControl.State.normal)
transformButton.frame = CGRect(x: 0, y: 0, width: 56, height: 36)
transformButton.layer.cornerRadius = 18
transformButton.layer.masksToBounds = true
transformButton.centerY = StatuBar_Height + NavBar_Height * 0.5
transformButton.right = SCREEN_Width - 24
return transformButton
}()
lazy var mTopCenterTypeButton: UIButton = {
//173*36
let button = UIButton()
button.backgroundColor = UIColor.hexStringToColor(hexString: "#1F1E20")
button.tag = 202
button.isSelected = false
button.addTarget(self, action: #selector(navgationButtonClick2(sender:)), for: UIControl.Event.touchUpInside)
button.frame = CGRect(x: 2, y: 10, width: SCREEN_Width * 0.4, height: 36)
button.centerY = StatuBar_Height + NavBar_Height * 0.5
button.centerX = SCREEN_Width * 0.5
button.clipsToBounds = true
button.layer.cornerRadius = 18
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.white.cgColor
button.setTitle("单眼2D", for: UIControl.State.normal)
button.setImage(UIImage.init(named: "type_button_arrow_down"), for: .normal)
button.updateBtnEdgeInsets(style: .Right, space: 10)
button.setTitleColor(UIColor.white, for: UIControl.State.normal)
button.titleLabel?.font = KFont_Medium(14)
return button
}()
lazy var playerLay:AVPlayerLayer = {
let view = AVPlayerLayer()
view.backgroundColor = UIColor.black.cgColor
view.frame = CGRect.init(x: 0, y: 250, width: self.view.frame.size.width, height: 240)
return view
}()
var typeData:[(icon:String,title:String,isHiden:Bool)] = [(icon:"type_check",title:"单眼2D",isHiden:false),
(icon:"type_check",title:"平行眼",isHiden:false),
(icon:"type_check",title:"红蓝立体",isHiden:false),
(icon:"type_check",title:"交叉眼",isHiden:false)]
lazy var menuView: CCSpatialDisplayTypeView = {
//icon
// let popData = [(icon:"type_check",title:"2D",isHiden:false),
// (icon:"type_check",title:"",isHiden:false),
// (icon:"type_check",title:"",isHiden:false),
// (icon:"type_check",title:"",isHiden:false)]
//
let parameters:[CCSpatialDisplayTypeConfigure] = [
.PopMenuTextColor(UIColor.white),
.popMenuItemHeight(40),
.PopMenuTextFont(KFont_Medium(12)),
.PopMenuBackgroudColor(UIColor(hexString: "#1F1E20"))
]
//init (testarrow)
let pointOnScreen = navtionImgView!.convert(CGPointMake(navtionImgView!.centerX, navtionImgView!.bottom), to: KWindow)
let popMenu = CCSpatialDisplayTypeView(menuWidth: SCREEN_Width * 0.4, arrow: pointOnScreen, datas: typeData,configures: parameters)
return popMenu
}()
lazy var progressView: UIProgressView = {
var view = UIProgressView (progressViewStyle:.default)
view.frame = CGRect(x: 24, y: SCREEN_Height - KStatusBarHeight - 20, width: SCREEN_Width-48, height: 36)
view.progress = 0.0 //50%
return view
}()
lazy var tipsButton: UIButton = {
//76*56
let button = UIButton.init(type: UIButton.ButtonType.custom)
button.tag = 203
button.backgroundColor = .clear
button.addTarget(self, action: #selector(navgationButtonClick2(sender:)), for: UIControl.Event.touchUpInside)
let img2:UIImage = UIImage.init(named: "tips_button" as String)!
button.setImage(img2, for: UIControl.State.normal)
button.frame = CGRect(x: 0, y: 0, width: 130, height: 30)
button.titleLabel?.font = KFont_Regular(14)
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.updateBtnEdgeInsets(style: .Left, space: 8)
// button.layer.cornerRadius = 18
// button.layer.masksToBounds = true
button.centerY = progressView.top - 70
button.centerX = self.view.centerX
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(hexString: "#060507")
// Do any additional setup after loading the view.
// let path = Bundle.main.path(forResource: "img3", ofType: "HEIC")
// photoOriginalURL = URL.init(filePath: path!)
outputVideoURL = URL.documentsDirectory.appending(path:"output11114.jpg")
//
self.setLeftOneBtnImg(imgStr: "spatial_back_button")
// self.setLeftBtnImg(imgStr1: "", imgStr2: "spatial_back_button")
self.setNavgationBarColorImg(color: .clear)
self.setNavgationBarLine(color: .clear)
self.view.addSubview(mTopImgView)
self.view.bringSubviewToFront(self.navtionBar!)
// navtionBar?.addSubview(backButton)
navtionBar?.addSubview(transformButton)
navtionBar?.addSubview(mTopCenterTypeButton)
self.view.addSubview(progressView)
self.view.layer.addSublayer(playerLay)
self.view.addSubview(tipsButton)
if sourceVideoURL != nil {
outputVideoURL = URL.documentsDirectory.appending(path:"output1111.mp4")
videoOriginalAsset = AVAsset(url: sourceVideoURL!)
videoTempAsset = videoOriginalAsset
play()
}else{
print("这不是一张空间图片")
}
// AirPlay
NotificationCenter.default.addObserver(self, selector: #selector(airPlayStatusDidChange(_:)), name: AVAudioSession.routeChangeNotification, object: nil)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// AirPlay
checkAirPlayStatus()
}
//MARK: -
@objc private func airPlayStatusDidChange(_ notification: Notification) {
checkAirPlayStatus()
}
private func checkAirPlayStatus() {
print("设备连接变化")
let currentRoute = AVAudioSession.sharedInstance().currentRoute
let isAirPlayActive = currentRoute.outputs.contains { output in
return output.portType == AVAudioSession.Port.HDMI ||
output.portType == AVAudioSession.Port.airPlay
}
setttinisScreenMirroring(isScreenMirroring: isAirPlayActive)
}
func setttinisScreenMirroring(isScreenMirroring:Bool){
//
if(isScreenMirroring){
print("已连接")
link = true
isPlaying = true
playerLay.player!.usesExternalPlaybackWhileExternalScreenIsActive = true
playerLay.player!.allowsExternalPlayback = true
//
// mTopCenterTypeButton.setTitle("", for: UIControl.State.normal)
mTopCenterTypeButton.setImage(UIImage.init(named: "linked_button"), for: .normal)
mTopCenterTypeButton.setTitleColor(UIColor(hexString: "#D0C0FF"), for: .normal)
mTopCenterTypeButton.layer.borderColor = UIColor(hexString: "#D0C0FF").cgColor
mTopCenterTypeButton.backgroundColor = UIColor(hexString: "#5326D6")
mTopCenterTypeButton.updateBtnEdgeInsets(style: .Left, space: 5)
playerLay.player!.play()
//
if isPlaying {
// ---
menuView.showFooterView(isShow: true, showText: "结束串流")
mTopCenterTypeButton.setTitle("外部串流中", for: UIControl.State.normal)
}else{
// ---
menuView.showFooterView(isShow: true, showText: "开始串流")
mTopCenterTypeButton.setTitle("已连接外部设备", for: UIControl.State.normal)
}
}else{
//
print("未连接")
link = false
isPlaying = false
// AirPlay
playerLay.player!.usesExternalPlaybackWhileExternalScreenIsActive = false
playerLay.player!.allowsExternalPlayback = false
if self.selectedIndex == .monocular2D {
mTopCenterTypeButton.setTitle("单眼2D", for: UIControl.State.normal)
}else if self.selectedIndex == .redBlueSolid {
mTopCenterTypeButton.setTitle("红蓝立体", for: UIControl.State.normal)
}else if self.selectedIndex == .crossedEyes {
mTopCenterTypeButton.setTitle("交叉眼", for: UIControl.State.normal)
}
else if self.selectedIndex == .parallelEyes {
mTopCenterTypeButton.setTitle("平行眼", for: UIControl.State.normal)
}
mTopCenterTypeButton.setImage(UIImage.init(named: "type_button_arrow_down"), for: .normal)
mTopCenterTypeButton.setTitleColor(UIColor.white, for: UIControl.State.normal)
mTopCenterTypeButton.layer.borderColor = UIColor.white.cgColor
mTopCenterTypeButton.backgroundColor = UIColor(hexString: "#1F1E20")
mTopCenterTypeButton.updateBtnEdgeInsets(style: .Right, space: 10)
//
menuView.showFooterView(isShow: false, showText: "")
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
//
func play(){
let playerItem = AVPlayerItem(asset: videoTempAsset!)
playerLay.player = AVPlayer(playerItem: playerItem)
playerLay.player!.play()
}
//MARK: - action
@objc public func navgationButtonClick2(sender:UIButton){
if sender.tag == 200 {
//
}else if sender.tag == 201 {
//
let transVC = VRVideoTransformController()
transVC.sourceVideoURL = sourceVideoURL
self.navigationController?.pushViewController(transVC, animated: true)
}else if sender.tag == 202 {
//
menuView.show()
if link {
//
if isPlaying {
// ---
menuView.showFooterView(isShow: true, showText: "结束串流")
mTopCenterTypeButton.setTitle("外部串流中", for: UIControl.State.normal)
}else{
// ---
menuView.showFooterView(isShow: true, showText: "开始串流")
mTopCenterTypeButton.setTitle("已连接外部设备", for: UIControl.State.normal)
}
}else{
mTopCenterTypeButton.setImage(UIImage.init(named: "type_button_arrow_up"), for: .normal)
}
//click
menuView.didSelectMenuBlock = { [weak self](index:Int)->Void in
print("block select \(index)")
self?.mTopCenterTypeButton.setImage(UIImage.init(named: "type_button_arrow_down"), for: .normal)
self?.selectedSpatialType(selectedIndex: index)
}
//tap
menuView.tapFooterActionBlock = {
self.startOrEndExternalVR()
}
}else if sender.tag == 203 {
//tips
let view = CCDeviceOperationListView.init(frame: CGRectMake(0, 0, KScreenWidth, KScreenHeight))
KWindow?.addSubview(view)
}
}
func startOrEndExternalVR() {
///
if(link == true){
isPlaying = !isPlaying
if(isPlaying == true){
// AirPlay
playerLay.player!.usesExternalPlaybackWhileExternalScreenIsActive = true
playerLay.player!.allowsExternalPlayback = true
}else{
playerLay.player!.usesExternalPlaybackWhileExternalScreenIsActive = false
playerLay.player!.allowsExternalPlayback = false
}
}
}
func selectedSpatialType(selectedIndex:Int) {
// if selectedIndex == 0 {
// self.selectedIndex = .monocular2D
// }else if selectedIndex == 1 {
// self.selectedIndex = .redBlueSolid
// }else if selectedIndex == 2 {
// self.selectedIndex = .crossedEyes
// }
self.selectedIndex = SpatialType(rawValue: selectedIndex) ?? .monocular2D
player.pause()
NotificationCenter.default.removeObserver(self)
//
if(selectedIndex == 0){
videoTempAsset = videoOriginalAsset
play()
}
else{
outputVideoURL = URL.documentsDirectory.appending(path:"output11112.mp4")
}
//
if(self.selectedIndex == .redBlueSolid){
Task {
convertor2.type = 3
try await convertor2.convertVideo(asset: videoOriginalAsset!, outputFile: outputVideoURL! ) { [self] progress in
print(progress)
DispatchQueue.main.async { [weak self] in
self?.progressView.setProgress(progress, animated: true)
if(progress > 0.99){
self!.videoTempAsset = AVAsset(url: self!.outputVideoURL!)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
//
self!.play()
}
}
}
}
}
}
//
if(self.selectedIndex == .crossedEyes){
Task {
convertor2.type = 2
try await convertor2.convertVideo(asset: videoOriginalAsset!, outputFile: outputVideoURL! ) { [self] progress in
print(progress)
DispatchQueue.main.async { [weak self] in
self?.progressView.setProgress(progress, animated: true)
if(progress > 0.99){
self!.videoTempAsset = AVAsset(url: self!.outputVideoURL!)
self!.play()
}
}
}
}
}
//
if(self.selectedIndex == .crossedEyes){
}
//
// if(selectedIndex == 1){
//// Task {
//// try await videoConverter.convertStereoscopicVideoToSpatialVideo(sourceVideoURL: sourceVideoURL!,outputVideoURL: outputVideoURL!){[weak self] progress in
//// print(progress)
//// DispatchQueue.main.async { [weak self] in
//// self!.btn3!.setTitle("=" + String(progress), for: UIControl.State.normal)
//// if(progress > 0.99){
//// self!.videoTempAsset = AVAsset(url: self!.outputVideoURL!)
//// self!.play()
//// }
//// }
//// }
//// }
// }
//
// if(selectedIndex == 4){
// Task {
// convertor2.type = 4
//
// try await convertor2.convertVideo(asset: videoTempAsset!, outputFile: outputVideoURL! ) { [self] progress in
// print(progress)
// DispatchQueue.main.async { [weak self] in
// self?.progressView.setProgress(progress, animated: true)
// if(progress > 0.99){
// self!.videoTempAsset = AVAsset(url: self!.outputVideoURL!)
// self!.play()
// }
// }
//
// }
// }
// }
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let mediaType = info[UIImagePickerController.InfoKey.mediaType] as? String, mediaType == "public.movie" {
let videoURL = info[.mediaURL] as? URL
print("Selected video URL: \(videoURL)")
sourceVideoURL = videoURL
videoOriginalAsset = AVAsset(url: sourceVideoURL!)
videoTempAsset = videoOriginalAsset
if(!isSpatialVideo(asset: videoTempAsset!)){
showTextAlert(title: "提示", message: "当前视频不是空间视频")
}
play()
}
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
//
func isSpatialVideo(asset: AVAsset) -> Bool {
let metadata = asset.metadata(forFormat: AVMetadataFormat.quickTimeMetadata)
let isSpatialVideo = metadata.contains { item in
if let identifier = item.identifier?.rawValue {
return identifier == "mdta/com.apple.quicktime.spatial.format-version"
}
return false
}
return isSpatialVideo
}
func showTextAlert(title: String, message: String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(okAction)
//
present(alertController, animated: true, completion: nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}