Files
webRtc/Assets/Script/Recorder/XrealMixedRecorder.cs

231 lines
7.9 KiB
C#
Raw Normal View History

2026-05-27 00:05:32 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Cysharp.Threading.Tasks;
using RenderStreaming;
using Stary.Evo;
using UnityEngine;
using Unity.XR.XREAL;
using CameraType = Unity.XR.XREAL.CameraType;
#if UNITY_ANDROID && !UNITY_EDITOR
2026-06-01 00:23:11 +08:00
using GalleryDataProvider = Unity.XR.XREAL.NativeGalleryDataProvider;
2026-05-27 00:05:32 +08:00
#else
using GalleryDataProvider = Unity.XR.XREAL.MockGalleryDataProvider;
#endif
public class XrealMixedRecorder : IVideoRecorder, IController
{
public enum ResolutionLevel
{
High,
Middle,
Low
}
public ResolutionLevel resolutionLevel = ResolutionLevel.High;
public BlendMode blendMode = BlendMode.Blend;
public AudioState audioState = AudioState.ApplicationAndMicAudio;
public CaptureSide captureside = CaptureSide.Single;
public bool useGreenBackGround = false;
private XREALVideoCapture _videoCapture;
public bool IsRecording => _videoCapture != null && _videoCapture.IsRecording;
public Action OnStartedRecordingVideo { get; set; }
public Action<string> OnStoppedRecordingVideoAction { get; set; }
private GalleryDataProvider _galleryDataTool;
/// <summary> Save the video to Application.persistentDataPath. </summary>
/// <value> The full pathname of the video save file. </value>
private string VideoSaveExtension => Path.Combine(Application.persistentDataPath, "Recording");
private string VideoSavePath
{
get
{
var timeStamp = Time.time.ToString().Replace(".", "").Replace(":", "");
var filename =
$"{this.GetSystem<IGlobalConfigSystem>().GetConnectionId()}{timeStamp}.mp4";
return Path.Combine(Application.persistentDataPath, VideoSaveExtension, filename);
}
}
private string _videoSavePath;
public void StartRecording()
{
_videoSavePath = VideoSavePath;
if (_videoCapture == null)
CreateVideoCapture(StartVideoCapture);
else if (_videoCapture.IsRecording)
StopVideoCapture();
else
StartVideoCapture();
}
public void StopRecording()
{
if (_videoCapture == null || !_videoCapture.IsRecording)
{
Debug.LogError("当前没有正在进行的 XREAL 录制");
return;
}
StopVideoCapture();
}
/// <summary> Stops video capture. </summary>
public void StopVideoCapture()
{
if (_videoCapture == null || !_videoCapture.IsRecording)
{
Debug.LogWarning("Can not stop video capture!");
return;
}
Debug.Log("Stop Video Capture!");
_videoCapture.StopRecordingAsync(OnStoppedRecordingVideo);
}
/// <summary> Executes the 'stopped recording video' action. </summary>
/// <param name="result"> The result.</param>
private void OnStoppedRecordingVideo(XREALVideoCapture.VideoCaptureResult result)
{
if (!result.success)
{
Debug.Log("Stopped Recording Video Faild!");
return;
}
Debug.Log("Stopped Recording Video!");
_videoCapture.StopVideoModeAsync(OnStoppedVideoCaptureMode);
}
/// <summary> Executes the 'stopped video capture mode' action. </summary>
/// <param name="result"> The result.</param>
private async void OnStoppedVideoCaptureMode(XREALVideoCapture.VideoCaptureResult result)
{
Debug.Log("Stopped Video Capture Mode!");
var encoder = _videoCapture.GetContext().GetEncoder() as VideoEncoder;
var path = encoder.EncodeConfig.outPutPath;
var filename = string.Format("Xreal_Shot_Video_{0}.mp4",
DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString());
await DelayInsertVideoToGallery(path, filename, "Record");
OnStoppedRecordingVideoAction?.Invoke(path);
// Release video capture resource.
_videoCapture.Dispose();
_videoCapture = null;
}
/// <summary> 延迟将视频插入相册,确保视频文件已完全写入 </summary>
/// <param name="originFilePath"> 视频文件路径 </param>
/// <param name="displayName"> 显示名称 </param>
/// <param name="folderName"> 文件夹名称 </param>
private async UniTask DelayInsertVideoToGallery(string originFilePath, string displayName, string folderName)
{
await UniTask.DelayFrame(100);
InsertVideoToGallery(originFilePath, displayName, folderName);
}
/// <summary> 将视频插入到系统相册中 </summary>
/// <param name="originFilePath"> 视频文件的原始路径 </param>
/// <param name="displayName"> 视频在相册中显示的名称 </param>
/// <param name="folderName"> 相册文件夹名称 </param>
public void InsertVideoToGallery(string originFilePath, string displayName, string folderName)
{
Debug.LogFormat("InsertVideoToGallery: {0}, {1} => {2}", displayName, originFilePath, folderName);
if (_galleryDataTool == null) _galleryDataTool = new GalleryDataProvider();
_galleryDataTool.InsertVideo(originFilePath, displayName, folderName);
}
private void CreateVideoCapture(Action callback)
{
XREALVideoCaptureUtility.CreateAsync(false, delegate(XREALVideoCapture videoCapture)
{
Debug.Log("Created VideoCapture Instance!");
if (videoCapture != null)
{
_videoCapture = videoCapture;
callback?.Invoke();
}
else
{
Debug.LogError("Failed to create VideoCapture Instance!");
}
});
}
public void StartVideoCapture()
{
if (_videoCapture.IsRecording)
{
Debug.LogWarning("Can not start video capture!");
return;
}
var cameraParameters = new CameraParameters();
var cameraResolution = GetResolutionByLevel(resolutionLevel);
cameraParameters.cameraType = CameraType.RGB;
cameraParameters.hologramOpacity = 0.0f;
cameraParameters.frameRate = NativeConstants.RECORD_FPS_DEFAULT;
cameraParameters.cameraResolutionWidth = cameraResolution.width;
cameraParameters.cameraResolutionHeight = cameraResolution.height;
cameraParameters.pixelFormat = CapturePixelFormat.PNG;
cameraParameters.blendMode = blendMode;
// Set audio state, audio record needs the permission of "android.permission.RECORD_AUDIO",
// Add it to your "AndroidManifest.xml" file in "Assets/Plugin".
cameraParameters.audioState = audioState;
cameraParameters.captureSide = captureside;
cameraParameters.backgroundColor = useGreenBackGround ? Color.green : Color.black;
_videoCapture.StartVideoModeAsync(cameraParameters, OnStartedVideoCaptureMode, true);
}
private Resolution GetResolutionByLevel(ResolutionLevel level)
{
var resolutions =
XREALVideoCaptureUtility.SupportedResolutions.OrderByDescending((res) => res.width * res.height);
var 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;
}
private void OnStartedVideoCaptureMode(XREALVideoCapture.VideoCaptureResult result)
{
if (!result.success)
{
Debug.Log("Started Video Capture Mode faild!");
return;
}
Debug.Log("Started Video Capture Mode!");
_videoCapture.StartRecordingAsync(_videoSavePath, (a) => OnStartedRecordingVideo?.Invoke());
}
public IArchitecture GetArchitecture()
{
return MainArchitecture.Interface;
}
}