using System; using System.Collections; using System.IO; using System.Linq; using Unity.XR.XREAL.Samples.NetWork; using UnityEngine; using UnityEngine.UI; namespace Unity.XR.XREAL.Samples { #if UNITY_ANDROID && !UNITY_EDITOR using GalleryDataProvider = NativeGalleryDataProvider; #else using GalleryDataProvider = MockGalleryDataProvider; #endif /// A first person streamming cast. public class FirstPersonStreammingCast : MonoBehaviour { public delegate void OnResponse(bool result); [SerializeField] private Button m_RecordBtn; [SerializeField] private Text m_RecordText; [SerializeField] private Button m_StreamBtn; [SerializeField] private Text m_StreamText; public BlendMode m_BlendMode = BlendMode.Blend; public ResolutionLevel m_ResolutionLevel = ResolutionLevel.Middle; public LayerMask m_CullingMask = -1; public AudioState m_AudioState = AudioState.None; public bool useGreenBackGround = false; /// The net worker. private NetWorkBehaviour m_NetWorker; /// The video capture. private XREALVideoCapture m_VideoCapture = null; public XREALVideoCapture VideoCapture { get { return m_VideoCapture; } } private string m_ServerIP; /// Gets the full pathname of the rtp file. /// The full pathname of the rtp file. public string RTPPath { get { return string.Format(@"rtp://{0}:5555", m_ServerIP); } } public string VideoSavePath { get { string timeStamp = Time.time.ToString().Replace(".", "").Replace(":", ""); string filename = string.Format("Xreal_Record_{0}.mp4", timeStamp); string filepath = Path.Combine(Application.persistentDataPath, filename); return filepath; } } private bool m_IsInitialized = false; private bool m_IsStreamLock = false; private bool m_IsStreamStarted = false; private bool m_IsRecordStarted = false; private string m_VideoPath; private bool m_SavedLocal; private GalleryDataProvider galleryDataTool; public enum ResolutionLevel { High, Middle, Low, } /// Starts this object. void Start() { this.Init(); } /// Initializes this object. private void Init() { if (m_IsInitialized) { return; } m_StreamBtn.onClick.AddListener(() => { Debug.Log("m_StreamBtn.onClick"); OnStream(); }); m_RecordBtn.onClick.AddListener(() => { Debug.Log("m_RecordBtn.onClick"); OnRecord(); }); m_IsInitialized = true; } private void RefreshUI() { m_RecordText.text = m_IsRecordStarted ? "Stop Record" : "Record"; m_StreamText.text = m_IsStreamStarted ? "Stop Stream" : "Stream"; if (m_IsStreamStarted) { m_RecordBtn.gameObject.SetActive(false); m_StreamBtn.gameObject.SetActive(true); } else if (m_IsRecordStarted) { m_RecordBtn.gameObject.SetActive(true); m_StreamBtn.gameObject.SetActive(false); } else { m_RecordBtn.gameObject.SetActive(true); m_StreamBtn.gameObject.SetActive(true); } } private void OnRecord() { if (!m_IsRecordStarted) { CreateAndStart(); } else { StopVideoCapture(); } m_IsRecordStarted = !m_IsRecordStarted; RefreshUI(); } private void OnStream() { if (m_IsStreamLock) { return; } m_IsStreamLock = true; if (m_NetWorker == null) { m_NetWorker = new NetWorkBehaviour(); m_NetWorker.Listen(); } if (!m_IsStreamStarted) { LocalServerSearcher.CreateSingleton().Search((result) => { Debug.LogFormat("[FPStreammingCast] Get the server result:{0} ip:{1}:{2}", result.isSuccess, result.endPoint?.Address, result.endPoint.Port); if (result.isSuccess) { string ip = result.endPoint.Address.ToString(); int port = result.endPoint.Port; m_NetWorker.CheckServerAvailable(ip, port, (isAvailable) => { Debug.LogFormat("[FPStreammingCast] Is the server {0}:{1} ok? {2}", ip, result.endPoint.Port, isAvailable); if (isAvailable) { m_ServerIP = ip; m_IsStreamStarted = true; CreateAndStart(); RefreshUI(); } m_IsStreamLock = false; }); } else { m_IsStreamLock = false; Debug.LogError("[FPStreammingCast] Can not find the server..."); } }); } else { StopVideoCapture(); m_IsStreamStarted = false; m_IsStreamLock = false; RefreshUI(); } } /// Converts this object to a server. private void CreateAndStart() { CreateVideoCapture(delegate () { Debug.LogFormat("[FPStreammingCast] Start video capture."); StartCoroutine(StartVideoCapture()); }); } private Resolution GetResolutionByLevel(ResolutionLevel level) { var resolutions = XREALVideoCaptureUtility.SupportedResolutions.OrderByDescending((res) => res.width * res.height); Resolution resolution = new Resolution(); switch (level) { case ResolutionLevel.High: resolution = resolutions.ElementAt(0); break; case ResolutionLevel.Middle: resolution = resolutions.ElementAt(1); break; case ResolutionLevel.Low: resolution = resolutions.ElementAt(2); break; default: break; } return resolution; } #region video capture /// Creates video capture. /// The callback. private void CreateVideoCapture(Action callback) { Debug.LogFormat("[FPStreammingCast] Created VideoCapture Instance!"); if (m_VideoCapture != null) { callback?.Invoke(); return; } XREALVideoCaptureUtility.CreateAsync(false, delegate (XREALVideoCapture videoCapture) { if (videoCapture != null) { m_VideoCapture = videoCapture; callback?.Invoke(); } else { Debug.LogError("[FPStreammingCast] Failed to create VideoCapture Instance!"); } }); } /// Starts video capture. public IEnumerator StartVideoCapture() { Resolution cameraResolution = GetResolutionByLevel(m_ResolutionLevel); Debug.LogFormat("[FPStreammingCast] cameraResolution:" + cameraResolution); if (m_VideoCapture != null) { CameraParameters cameraParameters = new CameraParameters(); cameraParameters.hologramOpacity = 1f; cameraParameters.frameRate = NativeConstants.RECORD_FPS_DEFAULT; cameraParameters.cameraResolutionWidth = cameraResolution.width; cameraParameters.cameraResolutionHeight = cameraResolution.height; cameraParameters.pixelFormat = CapturePixelFormat.BGRA32; cameraParameters.blendMode = m_BlendMode; cameraParameters.audioState = m_AudioState; cameraParameters.monophonic = true; // Send the audioState to server. if (m_NetWorker != null) { LitJson.JsonData json = new LitJson.JsonData(); json["useAudio"] = (cameraParameters.audioState != AudioState.None); m_NetWorker.SendMsg(json, (response) => { bool result; if (bool.TryParse(response["success"].ToString(), out result) && result) { m_VideoCapture.StartVideoModeAsync(cameraParameters, OnStartedVideoCaptureMode, true); } else { Debug.LogError("[FPStreammingCast] Can not received response from server."); } }); } else { m_VideoCapture.StartVideoModeAsync(cameraParameters, OnStartedVideoCaptureMode, true); } } else { Debug.Log("[FPStreammingCast] VideoCapture object is null..."); } yield return new WaitForEndOfFrame(); } /// Stops video capture. public void StopVideoCapture() { Debug.LogFormat("[FPStreammingCast] Stop Video Capture!"); m_VideoCapture.StopRecordingAsync(OnStoppedRecordingVideo); } /// Executes the 'started video capture mode' action. /// The result. void OnStartedVideoCaptureMode(XREALVideoCapture.VideoCaptureResult result) { if (!result.success) { Debug.LogFormat("[FPStreammingCast] Started Video Capture Mode Faild!"); return; } Debug.LogFormat("[FPStreammingCast] Started Video Capture Mode!"); m_VideoPath = m_IsStreamStarted ? RTPPath : VideoSavePath; m_SavedLocal = !m_IsStreamStarted; m_VideoCapture.StartRecordingAsync(m_VideoPath, OnStartedRecordingVideo); m_VideoCapture.GetContext().GetBehaviour().CaptureCamera.cullingMask = m_CullingMask.value; m_VideoCapture.GetContext().GetBehaviour().CaptureCamera.backgroundColor = useGreenBackGround ? Color.green : Color.black; } /// Executes the 'stopped video capture mode' action. /// The result. void OnStoppedVideoCaptureMode(XREALVideoCapture.VideoCaptureResult result) { Debug.LogFormat("[FPStreammingCast] Stopped Video Capture Mode!"); m_VideoCapture = null; if (m_SavedLocal) { string filename = string.Format("Xreal_Shot_Video_{0}.mp4", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString()); StartCoroutine(DelayInsertVideoToGallery(m_VideoPath, filename, "Record")); m_SavedLocal = false; } } IEnumerator DelayInsertVideoToGallery(string originFilePath, string displayName, string folderName) { yield return new WaitForSeconds(0.1f); Debug.LogFormat("[FPStreammingCast] InsertVideoToGallery: {0}, {1} => {2}", displayName, originFilePath, folderName); if (galleryDataTool == null) { galleryDataTool = new GalleryDataProvider(); } galleryDataTool.InsertVideo(originFilePath, displayName, folderName); } /// Executes the 'started recording video' action. /// The result. void OnStartedRecordingVideo(XREALVideoCapture.VideoCaptureResult result) { Debug.LogFormat("[FPStreammingCast] Started Recording Video!"); } /// Executes the 'stopped recording video' action. /// The result. void OnStoppedRecordingVideo(XREALVideoCapture.VideoCaptureResult result) { Debug.LogFormat("[FPStreammingCast] Stopped Recording Video!"); m_VideoCapture.StopVideoModeAsync(OnStoppedVideoCaptureMode); if (m_NetWorker != null) { m_NetWorker?.Close(); m_NetWorker = null; } } #endregion } }