本地优化
This commit is contained in:
260
Assets/Script/Recorder/EditorServerRecorder.cs
Normal file
260
Assets/Script/Recorder/EditorServerRecorder.cs
Normal file
@@ -0,0 +1,260 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using RenderStreaming;
|
||||
using Stary.Evo;
|
||||
using Unity.RenderStreaming;
|
||||
using Unity.WebRTC;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Script.Recorder
|
||||
{
|
||||
public class EditorServerRecorder : IVideoRecorder, IController
|
||||
{
|
||||
public bool IsRecording { get; }
|
||||
public Action OnStartedRecordingVideo { get; set; }
|
||||
public Action<string> OnStoppedRecordingVideoAction { get; set; }
|
||||
|
||||
private string recordingId;
|
||||
|
||||
private readonly Dictionary<string, RTCPeerConnection> recordingPeers = new();
|
||||
|
||||
public WebcamToRenderTexture sourceRenderTexture;
|
||||
public string microphoneDeviceName = ""; // 留空使用默认麦克风
|
||||
public int microphoneSampleRate = 48000;
|
||||
|
||||
private AudioSource microphoneAudioSource;
|
||||
private bool microphoneStarted;
|
||||
|
||||
private VideoStreamTrack videoTrack;
|
||||
private AudioStreamTrack audioTrack;
|
||||
|
||||
public async void StartRecording()
|
||||
{
|
||||
await CreateLocalTracks();
|
||||
|
||||
var messageChannel = GameObject.FindObjectOfType<MessageChannel>();
|
||||
messageChannel.OnRecordingPeerRequestReceived += OnRecordingPeerRequestReceived;
|
||||
messageChannel.OnRecordingAnswerReceived += OnRecordingAnswerReceived;
|
||||
messageChannel.OnRecordingCandidateReceived += OnRecordingCandidateReceived;
|
||||
messageChannel.OnRecordingStoppedReceived += OnRecordingStoppedReceived;
|
||||
|
||||
var data = new
|
||||
{
|
||||
connectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId(),
|
||||
layout = "grid",
|
||||
format = "webm",
|
||||
};
|
||||
|
||||
var result = await WebRequestSystem.Post(
|
||||
this.GetSystem<IGlobalConfigSystem>().IP + "/api/recording-sessions",
|
||||
JsonConvert.SerializeObject(data));
|
||||
if (result != null)
|
||||
{
|
||||
RecordingSession session = JsonConvert.DeserializeObject<RecordingSession>(result);
|
||||
if (string.IsNullOrEmpty(session.success))
|
||||
{
|
||||
Debug.LogError($"[ServerMixedRecorder] StartRecording 失败: {session}");
|
||||
return;
|
||||
}
|
||||
|
||||
recordingId = session.session.id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async UniTask CreateLocalTracks()
|
||||
{
|
||||
if (sourceRenderTexture == null)
|
||||
{
|
||||
sourceRenderTexture =new GameObject("WebcamToRenderTexture").AddComponent<WebcamToRenderTexture>();
|
||||
videoTrack = new VideoStreamTrack(sourceRenderTexture.renderTexture);
|
||||
}
|
||||
|
||||
microphoneAudioSource =
|
||||
GameObject.Find("RenderStreaming/microphoneAudioSource").GetComponent<AudioSource>();
|
||||
microphoneAudioSource.loop = true;
|
||||
microphoneAudioSource.mute = true;
|
||||
|
||||
string device = string.IsNullOrEmpty(microphoneDeviceName)
|
||||
? null
|
||||
: microphoneDeviceName;
|
||||
|
||||
microphoneAudioSource.clip = Microphone.Start(
|
||||
device,
|
||||
true,
|
||||
1,
|
||||
microphoneSampleRate
|
||||
);
|
||||
|
||||
microphoneStarted = true;
|
||||
|
||||
await CreateMicrophoneTrackWhenReady(device);
|
||||
}
|
||||
|
||||
public async UniTask CreateMicrophoneTrackWhenReady(string device)
|
||||
{
|
||||
while (Microphone.GetPosition(device) <= 0)
|
||||
await UniTask.NextFrame();
|
||||
|
||||
microphoneAudioSource.Play();
|
||||
audioTrack = new AudioStreamTrack(microphoneAudioSource);
|
||||
}
|
||||
|
||||
|
||||
public async void OnRecordingPeerRequestReceived(RecordingRequest request)
|
||||
{
|
||||
if (string.IsNullOrEmpty(request.recordingId))
|
||||
return;
|
||||
|
||||
OnRecordingStoppedReceived(request.recordingId);
|
||||
|
||||
var config = new RTCConfiguration
|
||||
{
|
||||
iceServers = new[]
|
||||
{
|
||||
new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } }
|
||||
}
|
||||
};
|
||||
|
||||
var pc = new RTCPeerConnection(ref config);
|
||||
recordingPeers[request.recordingId] = pc;
|
||||
|
||||
pc.OnIceCandidate = candidate =>
|
||||
{
|
||||
if (candidate == null) return;
|
||||
|
||||
Send("recording-candidate", new RecordingCandidate
|
||||
{
|
||||
recordingId = request.recordingId,
|
||||
connectionId = request.connectionId,
|
||||
participantId = this.GetSystem<IGlobalConfigSystem>().GetParticipantId(),
|
||||
candidate = candidate.Candidate,
|
||||
sdpMid = candidate.SdpMid,
|
||||
sdpMLineIndex = candidate.SdpMLineIndex ?? 0
|
||||
});
|
||||
};
|
||||
|
||||
if (videoTrack != null)
|
||||
pc.AddTransceiver(videoTrack,
|
||||
new RTCRtpTransceiverInit { direction = RTCRtpTransceiverDirection.SendOnly });
|
||||
|
||||
if (audioTrack != null)
|
||||
pc.AddTransceiver(audioTrack,
|
||||
new RTCRtpTransceiverInit { direction = RTCRtpTransceiverDirection.SendOnly });
|
||||
|
||||
var offerOp = pc.CreateOffer();
|
||||
await offerOp;
|
||||
|
||||
var offer = offerOp.Desc;
|
||||
var localOp = pc.SetLocalDescription(ref offer);
|
||||
await localOp;
|
||||
|
||||
Send("recording-offer", new RecordingOffer
|
||||
{
|
||||
recordingId = request.recordingId,
|
||||
connectionId = request.connectionId,
|
||||
participantId = this.GetSystem<IGlobalConfigSystem>().GetParticipantId(),
|
||||
sdp = offer.sdp
|
||||
});
|
||||
}
|
||||
|
||||
public async void OnRecordingAnswerReceived(RecordingAnswer answer)
|
||||
{
|
||||
if (!recordingPeers.TryGetValue(answer.recordingId, out var pc))
|
||||
return;
|
||||
|
||||
var desc = new RTCSessionDescription
|
||||
{
|
||||
type = RTCSdpType.Answer,
|
||||
sdp = answer.sdp
|
||||
};
|
||||
|
||||
var op = pc.SetRemoteDescription(ref desc);
|
||||
await op;
|
||||
}
|
||||
|
||||
public void OnRecordingCandidateReceived(RecordingCandidate data)
|
||||
{
|
||||
if (!recordingPeers.TryGetValue(data.recordingId, out var pc))
|
||||
return;
|
||||
|
||||
var candidate = new RTCIceCandidate(new RTCIceCandidateInit
|
||||
{
|
||||
candidate = data.candidate,
|
||||
sdpMid = data.sdpMid,
|
||||
sdpMLineIndex = data.sdpMLineIndex
|
||||
});
|
||||
|
||||
pc.AddIceCandidate(candidate);
|
||||
}
|
||||
|
||||
public void OnRecordingStoppedReceived(string recordingId)
|
||||
{
|
||||
if (!recordingPeers.TryGetValue(recordingId, out var pc))
|
||||
return;
|
||||
|
||||
pc.Close();
|
||||
recordingPeers.Remove(recordingId);
|
||||
}
|
||||
|
||||
void Send(string type, object data)
|
||||
{
|
||||
var connectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId();
|
||||
|
||||
var json = JsonConvert.SerializeObject(new Dictionary<string, object>
|
||||
{
|
||||
["type"] = "on-message",
|
||||
["data"] = new Dictionary<string, object>
|
||||
{
|
||||
["connectionId"] = connectionId,
|
||||
["message"] = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = type,
|
||||
["data"] = data
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
SignalingMessageHelper.SendMessage(json);
|
||||
}
|
||||
|
||||
public async void StopRecording()
|
||||
{
|
||||
await WebRequestSystem.Delete(this.GetSystem<IGlobalConfigSystem>().IP,
|
||||
$"/api/recording-sessions/{recordingId}");
|
||||
var messageChannel = GameObject.FindObjectOfType<MessageChannel>();
|
||||
messageChannel.OnRecordingPeerRequestReceived -= OnRecordingPeerRequestReceived;
|
||||
messageChannel.OnRecordingAnswerReceived -= OnRecordingAnswerReceived;
|
||||
messageChannel.OnRecordingCandidateReceived -= OnRecordingCandidateReceived;
|
||||
messageChannel.OnRecordingStoppedReceived -= OnRecordingStoppedReceived;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
foreach (var pc in recordingPeers.Values)
|
||||
pc.Close();
|
||||
|
||||
recordingPeers.Clear();
|
||||
|
||||
videoTrack?.Dispose();
|
||||
audioTrack?.Dispose();
|
||||
|
||||
if (microphoneStarted)
|
||||
{
|
||||
string device = string.IsNullOrEmpty(microphoneDeviceName)
|
||||
? null
|
||||
: microphoneDeviceName;
|
||||
|
||||
Microphone.End(device);
|
||||
}
|
||||
}
|
||||
|
||||
public IArchitecture GetArchitecture()
|
||||
{
|
||||
return MainArchitecture.Interface;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Script/Recorder/EditorServerRecorder.cs.meta
Normal file
3
Assets/Script/Recorder/EditorServerRecorder.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3583d180c5d94451bea6ead323d96021
|
||||
timeCreated: 1780402391
|
||||
381
Assets/Script/Recorder/ServerMixedRecorder.cs
Normal file
381
Assets/Script/Recorder/ServerMixedRecorder.cs
Normal file
@@ -0,0 +1,381 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using RenderStreaming;
|
||||
using Stary.Evo;
|
||||
using Unity.RenderStreaming;
|
||||
using Unity.WebRTC;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Script.Recorder
|
||||
{
|
||||
public class ServerMixedRecorder : IVideoRecorder, IController
|
||||
{
|
||||
public bool IsRecording { get; }
|
||||
public Action OnStartedRecordingVideo { get; set; }
|
||||
public Action<string> OnStoppedRecordingVideoAction { get; set; }
|
||||
|
||||
private string recordingId;
|
||||
|
||||
private readonly Dictionary<string, RTCPeerConnection> recordingPeers = new();
|
||||
|
||||
|
||||
// [Header("Tracks")] public RenderTexture sourceRenderTexture;
|
||||
// public string microphoneDeviceName = ""; // 留空使用默认麦克风
|
||||
// public int microphoneSampleRate = 48000;
|
||||
//
|
||||
// private AudioSource microphoneAudioSource;
|
||||
// private bool microphoneStarted;
|
||||
|
||||
private VideoStreamTrack videoTrack;
|
||||
private AudioStreamTrack audioTrack;
|
||||
|
||||
public async void StartRecording()
|
||||
{
|
||||
await CreateLocalTracks();
|
||||
|
||||
var messageChannel = GameObject.FindObjectOfType<MessageChannel>();
|
||||
messageChannel.OnRecordingPeerRequestReceived += OnRecordingPeerRequestReceived;
|
||||
messageChannel.OnRecordingAnswerReceived += OnRecordingAnswerReceived;
|
||||
messageChannel.OnRecordingCandidateReceived += OnRecordingCandidateReceived;
|
||||
messageChannel.OnRecordingStoppedReceived += OnRecordingStoppedReceived;
|
||||
|
||||
var data = new
|
||||
{
|
||||
connectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId(),
|
||||
layout = "grid",
|
||||
format = "webm",
|
||||
};
|
||||
|
||||
var result = await WebRequestSystem.Post(
|
||||
this.GetSystem<IGlobalConfigSystem>().IP + "/api/recording-sessions",
|
||||
JsonConvert.SerializeObject(data));
|
||||
if (result != null)
|
||||
{
|
||||
RecordingSession session = JsonConvert.DeserializeObject<RecordingSession>(result);
|
||||
if (string.IsNullOrEmpty(session.success))
|
||||
{
|
||||
Debug.LogError($"[ServerMixedRecorder] StartRecording 失败: {session}");
|
||||
return;
|
||||
}
|
||||
|
||||
recordingId = session.session.id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async UniTask CreateLocalTracks()
|
||||
{
|
||||
var RenderStreaming =GameObject.Find("RenderStreaming");
|
||||
VideoStreamSender videoStreamSender = RenderStreaming.GetComponent<VideoStreamSender>();
|
||||
videoTrack = videoStreamSender.Track as VideoStreamTrack;
|
||||
|
||||
|
||||
AudioStreamSender audioStreamSender = RenderStreaming.GetComponent<AudioStreamSender>();
|
||||
audioTrack = audioStreamSender.Track as AudioStreamTrack;
|
||||
// sourceRenderTexture = this.GetSystem<IRenderStreamingSystem>().GetRenderStreamingTexture();
|
||||
// if (sourceRenderTexture != null)
|
||||
// {
|
||||
// videoTrack = new VideoStreamTrack(sourceRenderTexture);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// microphoneAudioSource =
|
||||
// GameObject.Find("RenderStreaming/microphoneAudioSource").GetComponent<AudioSource>();
|
||||
// microphoneAudioSource.loop = true;
|
||||
// microphoneAudioSource.mute = true;
|
||||
//
|
||||
// string device = string.IsNullOrEmpty(microphoneDeviceName)
|
||||
// ? null
|
||||
// : microphoneDeviceName;
|
||||
//
|
||||
// microphoneAudioSource.clip = Microphone.Start(
|
||||
// device,
|
||||
// true,
|
||||
// 1,
|
||||
// microphoneSampleRate
|
||||
// );
|
||||
//
|
||||
// microphoneStarted = true;
|
||||
|
||||
//await CreateMicrophoneTrackWhenReady(device);
|
||||
}
|
||||
|
||||
// public async UniTask CreateMicrophoneTrackWhenReady(string device)
|
||||
// {
|
||||
// while (Microphone.GetPosition(device) <= 0)
|
||||
// await UniTask.NextFrame();
|
||||
//
|
||||
// microphoneAudioSource.Play();
|
||||
// audioTrack = new AudioStreamTrack(microphoneAudioSource);
|
||||
// }
|
||||
|
||||
|
||||
public async void OnRecordingPeerRequestReceived(RecordingRequest request)
|
||||
{
|
||||
if (string.IsNullOrEmpty(request.recordingId))
|
||||
return;
|
||||
|
||||
OnRecordingStoppedReceived(request.recordingId);
|
||||
|
||||
var config = new RTCConfiguration
|
||||
{
|
||||
iceServers = new[]
|
||||
{
|
||||
new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } }
|
||||
}
|
||||
};
|
||||
|
||||
var pc = new RTCPeerConnection(ref config);
|
||||
recordingPeers[request.recordingId] = pc;
|
||||
|
||||
pc.OnIceCandidate = candidate =>
|
||||
{
|
||||
if (candidate == null) return;
|
||||
|
||||
Send("recording-candidate", new RecordingCandidate
|
||||
{
|
||||
recordingId = request.recordingId,
|
||||
connectionId = request.connectionId,
|
||||
participantId = this.GetSystem<IGlobalConfigSystem>().GetParticipantId(),
|
||||
candidate = candidate.Candidate,
|
||||
sdpMid = candidate.SdpMid,
|
||||
sdpMLineIndex = candidate.SdpMLineIndex ?? 0
|
||||
});
|
||||
};
|
||||
|
||||
if (videoTrack != null)
|
||||
pc.AddTransceiver(videoTrack,
|
||||
new RTCRtpTransceiverInit { direction = RTCRtpTransceiverDirection.SendOnly });
|
||||
|
||||
if (audioTrack != null)
|
||||
pc.AddTransceiver(audioTrack,
|
||||
new RTCRtpTransceiverInit { direction = RTCRtpTransceiverDirection.SendOnly });
|
||||
|
||||
var offerOp = pc.CreateOffer();
|
||||
await offerOp;
|
||||
|
||||
var offer = offerOp.Desc;
|
||||
var localOp = pc.SetLocalDescription(ref offer);
|
||||
await localOp;
|
||||
|
||||
Send("recording-offer", new RecordingOffer
|
||||
{
|
||||
recordingId = request.recordingId,
|
||||
connectionId = request.connectionId,
|
||||
participantId = this.GetSystem<IGlobalConfigSystem>().GetParticipantId(),
|
||||
sdp = offer.sdp
|
||||
});
|
||||
}
|
||||
|
||||
public async void OnRecordingAnswerReceived(RecordingAnswer answer)
|
||||
{
|
||||
if (!recordingPeers.TryGetValue(answer.recordingId, out var pc))
|
||||
return;
|
||||
|
||||
var desc = new RTCSessionDescription
|
||||
{
|
||||
type = RTCSdpType.Answer,
|
||||
sdp = answer.sdp
|
||||
};
|
||||
|
||||
var op = pc.SetRemoteDescription(ref desc);
|
||||
await op;
|
||||
}
|
||||
|
||||
public void OnRecordingCandidateReceived(RecordingCandidate data)
|
||||
{
|
||||
if (!recordingPeers.TryGetValue(data.recordingId, out var pc))
|
||||
return;
|
||||
|
||||
var candidate = new RTCIceCandidate(new RTCIceCandidateInit
|
||||
{
|
||||
candidate = data.candidate,
|
||||
sdpMid = data.sdpMid,
|
||||
sdpMLineIndex = data.sdpMLineIndex
|
||||
});
|
||||
|
||||
pc.AddIceCandidate(candidate);
|
||||
}
|
||||
|
||||
public void OnRecordingStoppedReceived(string recordingId)
|
||||
{
|
||||
if (!recordingPeers.TryGetValue(recordingId, out var pc))
|
||||
return;
|
||||
|
||||
pc.Close();
|
||||
recordingPeers.Remove(recordingId);
|
||||
}
|
||||
|
||||
void Send(string type, object data)
|
||||
{
|
||||
var connectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId();
|
||||
|
||||
var json = JsonConvert.SerializeObject(new Dictionary<string, object>
|
||||
{
|
||||
["type"] = "on-message",
|
||||
["data"] = new Dictionary<string, object>
|
||||
{
|
||||
["connectionId"] = connectionId,
|
||||
["message"] = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = type,
|
||||
["data"] = data
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
SignalingMessageHelper.SendMessage(json);
|
||||
}
|
||||
|
||||
public async void StopRecording()
|
||||
{
|
||||
await WebRequestSystem.Delete(this.GetSystem<IGlobalConfigSystem>().IP,
|
||||
$"/api/recording-sessions/{recordingId}");
|
||||
var messageChannel = GameObject.FindObjectOfType<MessageChannel>();
|
||||
messageChannel.OnRecordingPeerRequestReceived -= OnRecordingPeerRequestReceived;
|
||||
messageChannel.OnRecordingAnswerReceived -= OnRecordingAnswerReceived;
|
||||
messageChannel.OnRecordingCandidateReceived -= OnRecordingCandidateReceived;
|
||||
messageChannel.OnRecordingStoppedReceived -= OnRecordingStoppedReceived;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
foreach (var pc in recordingPeers.Values)
|
||||
pc.Close();
|
||||
|
||||
recordingPeers.Clear();
|
||||
|
||||
videoTrack?.Dispose();
|
||||
audioTrack?.Dispose();
|
||||
|
||||
// if (microphoneStarted)
|
||||
// {
|
||||
// string device = string.IsNullOrEmpty(microphoneDeviceName)
|
||||
// ? null
|
||||
// : microphoneDeviceName;
|
||||
//
|
||||
// Microphone.End(device);
|
||||
// }
|
||||
}
|
||||
|
||||
public IArchitecture GetArchitecture()
|
||||
{
|
||||
return MainArchitecture.Interface;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Session
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string connectionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string layout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string format { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string createdAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string startedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string updatedAt { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Agent
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string recordingId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string connectionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string mediaMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string createdAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string updatedAt { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RecordingSession
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string success { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Session session { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Agent agent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string notified { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string peerRequestNotified { get; set; }
|
||||
}
|
||||
}
|
||||
3
Assets/Script/Recorder/ServerMixedRecorder.cs.meta
Normal file
3
Assets/Script/Recorder/ServerMixedRecorder.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9d49eabfbbd4b4d8b4b88f082441596
|
||||
timeCreated: 1780371636
|
||||
47
Assets/Script/Recorder/WebcamToRenderTexture.cs
Normal file
47
Assets/Script/Recorder/WebcamToRenderTexture.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Unity.WebRTC;
|
||||
using UnityEngine;
|
||||
|
||||
public class WebcamToRenderTexture : MonoBehaviour
|
||||
{
|
||||
public RenderTexture renderTexture;
|
||||
|
||||
private WebCamTexture webcamTexture;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (renderTexture == null)
|
||||
{
|
||||
RenderTextureFormat supportedFormat = WebRTC.GetSupportedRenderTextureFormat(SystemInfo.graphicsDeviceType);
|
||||
|
||||
// 创建新的RenderTexture
|
||||
renderTexture = new RenderTexture(1920, 1200, 0, supportedFormat);
|
||||
renderTexture.enableRandomWrite = true;
|
||||
renderTexture.Create();
|
||||
//_textureImage.texture = localRenderTexture;
|
||||
}
|
||||
|
||||
webcamTexture = new WebCamTexture();
|
||||
webcamTexture.Play();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (webcamTexture != null && webcamTexture.didUpdateThisFrame)
|
||||
{
|
||||
Graphics.Blit(webcamTexture, renderTexture);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (webcamTexture != null)
|
||||
{
|
||||
webcamTexture.Stop();
|
||||
}
|
||||
|
||||
if (renderTexture != null)
|
||||
{
|
||||
renderTexture.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Script/Recorder/WebcamToRenderTexture.cs.meta
Normal file
3
Assets/Script/Recorder/WebcamToRenderTexture.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63353e4a29ff45c9803dae86c9590d72
|
||||
timeCreated: 1780403919
|
||||
@@ -14,7 +14,7 @@ using CameraType = Unity.XR.XREAL.CameraType;
|
||||
using GalleryDataProvider = Unity.XR.XREAL.MockGalleryDataProvider;
|
||||
#endif
|
||||
|
||||
public class XrealMixedRecorder : IVideoRecorder, IController
|
||||
public class XrealMixedRecorder : IVideoRecorder, IController , IDisposable
|
||||
{
|
||||
public enum ResolutionLevel
|
||||
{
|
||||
@@ -25,7 +25,7 @@ public class XrealMixedRecorder : IVideoRecorder, IController
|
||||
|
||||
public ResolutionLevel resolutionLevel = ResolutionLevel.High;
|
||||
public BlendMode blendMode = BlendMode.Blend;
|
||||
public AudioState audioState = AudioState.MicAudio;
|
||||
public AudioState audioState = AudioState.ApplicationAndMicAudio;
|
||||
public CaptureSide captureside = CaptureSide.Single;
|
||||
public bool useGreenBackGround = false;
|
||||
|
||||
@@ -82,7 +82,7 @@ public class XrealMixedRecorder : IVideoRecorder, IController
|
||||
}
|
||||
|
||||
Debug.Log("Stop Video Capture!");
|
||||
_videoCapture.StopRecordingAsync(OnStoppedRecordingVideo);
|
||||
_videoCapture.StopRecordingAsync(OnStoppedVideoCaptureMode);
|
||||
}
|
||||
|
||||
/// <summary> Executes the 'stopped recording video' action. </summary>
|
||||
@@ -103,6 +103,11 @@ public class XrealMixedRecorder : IVideoRecorder, IController
|
||||
/// <param name="result"> The result.</param>
|
||||
private async void OnStoppedVideoCaptureMode(XREALVideoCapture.VideoCaptureResult result)
|
||||
{
|
||||
if (!result.success)
|
||||
{
|
||||
Debug.Log("Stopped Recording Video Faild!");
|
||||
return;
|
||||
}
|
||||
Debug.Log("Stopped Video Capture Mode!");
|
||||
|
||||
var encoder = _videoCapture.GetContext().GetEncoder() as VideoEncoder;
|
||||
@@ -114,8 +119,6 @@ public class XrealMixedRecorder : IVideoRecorder, IController
|
||||
await DelayInsertVideoToGallery(path, filename, "Record");
|
||||
OnStoppedRecordingVideoAction?.Invoke(path);
|
||||
// Release video capture resource.
|
||||
_videoCapture.Dispose();
|
||||
_videoCapture = null;
|
||||
}
|
||||
|
||||
/// <summary> 延迟将视频插入相册,确保视频文件已完全写入 </summary>
|
||||
@@ -235,4 +238,19 @@ public class XrealMixedRecorder : IVideoRecorder, IController
|
||||
{
|
||||
return MainArchitecture.Interface;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_videoCapture.StopVideoModeAsync((result) =>
|
||||
{
|
||||
if (!result.success)
|
||||
{
|
||||
Debug.Log("Stopped Video Capture Mode faild!");
|
||||
return;
|
||||
}
|
||||
_videoCapture?.Dispose();
|
||||
_videoCapture = null;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user