/****************************************************************************
* Copyright 2019 Nreal Techonology Limited. All rights reserved.
*
* This file is part of NRSDK.
*
* https://www.nreal.ai/
*
*****************************************************************************/
namespace NRKernal.Record
{
using System;
using System.Collections.Generic;
using UnityEngine;
/// A frame capture context.
public class FrameCaptureContext
{
/// The blender.
private BlenderBase m_Blender;
/// The encoder.
private IEncoder m_Encoder;
/// Options for controlling the camera.
private CameraParameters m_CameraParameters;
/// The frame provider.
private AbstractFrameProvider m_FrameProvider;
/// The capture behaviour.
private CaptureBehaviourBase m_CaptureBehaviour;
/// True if is initialize, false if not.
private bool m_IsInitialized = false;
private List m_FrameConsumerList;
/// Gets the preview texture.
/// The preview texture.
public Texture PreviewTexture
{
get
{
return m_Blender?.BlendTexture;
}
}
/// Gets the behaviour.
/// The behaviour.
public CaptureBehaviourBase GetBehaviour()
{
return m_CaptureBehaviour;
}
/// Gets frame provider.
/// The frame provider.
public AbstractFrameProvider GetFrameProvider()
{
return m_FrameProvider;
}
/// Gets the blender.
/// The blender.
public BlenderBase GetBlender()
{
return m_Blender;
}
/// Request camera parameter.
/// The CameraParameters.
public CameraParameters RequestCameraParam()
{
return m_CameraParameters;
}
/// Gets the encoder.
/// The encoder.
public IEncoder GetEncoder()
{
return m_Encoder;
}
/// Constructor.
public FrameCaptureContext() { }
/// Starts capture mode.
/// The parameter.
public void StartCaptureMode(CameraParameters param)
{
if (m_IsInitialized)
{
this.Release();
NRDebugger.Warning("[CaptureContext] Capture context has been started already, release it and restart a new one.");
}
NRDebugger.Info("[CaptureContext] Create...");
if (m_CaptureBehaviour == null)
{
this.m_CaptureBehaviour = this.GetCaptureBehaviourByMode(param.camMode);
}
this.m_CameraParameters = param;
this.m_Encoder = GetEncoderByMode(param.camMode);
this.m_Encoder.Config(param);
this.m_Blender = new ExtraFrameBlender();
this.m_Blender.Init(m_CaptureBehaviour.CaptureCamera, m_Encoder, param);
this.m_CaptureBehaviour.Init(this);
this.m_FrameProvider = CreateFrameProviderByMode(param.blendMode, param.frameRate);
this.m_FrameProvider.OnUpdate += UpdateFrame;
this.m_FrameConsumerList = new List();
this.Sequence(m_CaptureBehaviour)
.Sequence(m_Blender);
this.m_IsInitialized = true;
}
/// Auto adaption for BlendMode based on supported feature on current device.
/// source blendMode.
/// Fallback blendMode.
public BlendMode AutoAdaptBlendMode(BlendMode blendMode)
{
if (!NRDevice.Subsystem.IsFeatureSupported(NRSupportedFeature.NR_FEATURE_RGB_CAMERA))
return BlendMode.VirtualOnly;
return blendMode;
}
private FrameCaptureContext Sequence(IFrameConsumer consummer)
{
this.m_FrameConsumerList.Add(consummer);
return this;
}
private void UpdateFrame(UniversalTextureFrame frame)
{
for (int i = 0; i < m_FrameConsumerList.Count; i++)
{
m_FrameConsumerList[i].OnFrame(frame);
}
}
/// Gets capture behaviour by mode.
/// Thrown when an exception error condition occurs.
/// The mode.
/// The capture behaviour by mode.
private CaptureBehaviourBase GetCaptureBehaviourByMode(CamMode mode)
{
if (mode == CamMode.PhotoMode)
{
NRCaptureBehaviour capture = GameObject.FindObjectOfType();
var headParent = NRSessionManager.Instance.NRSessionBehaviour.transform.parent;
if (capture == null)
{
capture = GameObject.Instantiate(Resources.Load("Record/Prefabs/NRCaptureBehaviour"), headParent);
}
GameObject.DontDestroyOnLoad(capture.gameObject);
return capture;
}
else if (mode == CamMode.VideoMode)
{
NRRecordBehaviour capture = GameObject.FindObjectOfType();
var headParent = NRSessionManager.Instance.NRSessionBehaviour.transform.parent;
if (capture == null)
{
capture = GameObject.Instantiate(Resources.Load("Record/Prefabs/NRRecorderBehaviour"), headParent);
}
GameObject.DontDestroyOnLoad(capture.gameObject);
return capture;
}
else
{
throw new Exception("CamMode need to be set correctly for capture behaviour!");
}
}
private AbstractFrameProvider CreateFrameProviderByMode(BlendMode mode, int fps)
{
AbstractFrameProvider provider;
switch (mode)
{
case BlendMode.Blend:
case BlendMode.RGBOnly:
#if UNITY_EDITOR
provider = new EditorFrameProvider();
#else
provider = new RGBCameraFrameProvider();
#endif
break;
case BlendMode.VirtualOnly:
default:
provider = new NullDataFrameProvider(fps);
break;
}
return provider;
}
/// Gets encoder by mode.
/// Thrown when an exception error condition occurs.
/// The mode.
/// The encoder by mode.
private IEncoder GetEncoderByMode(CamMode mode)
{
if (mode == CamMode.PhotoMode)
{
return new ImageEncoder();
}
else if (mode == CamMode.VideoMode)
{
return new VideoEncoder();
}
else
{
throw new Exception("CamMode need to be set correctly for encoder!");
}
}
/// Stops capture mode.
public void StopCaptureMode()
{
this.Release();
}
/// Starts a capture.
public void StartCapture()
{
if (!m_IsInitialized)
{
return;
}
NRDebugger.Info("[CaptureContext] Start...");
m_Encoder?.Start();
m_FrameProvider?.Play();
}
/// Stops a capture.
public void StopCapture()
{
if (!m_IsInitialized)
{
return;
}
NRDebugger.Info("[CaptureContext] Stop...");
// Need stop encoder firstly.
m_Encoder?.Stop();
m_FrameProvider?.Stop();
}
/// Releases this object.
public void Release()
{
if (!m_IsInitialized)
{
return;
}
NRDebugger.Info("[CaptureContext] Release begin...");
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
if (m_FrameProvider != null)
{
m_FrameProvider.OnUpdate -= UpdateFrame;
m_FrameProvider?.Release();
m_FrameProvider = null;
}
m_Blender?.Dispose();
m_Encoder?.Release();
if (m_CaptureBehaviour != null)
{
GameObject.DestroyImmediate(m_CaptureBehaviour.gameObject);
m_CaptureBehaviour = null;
}
NRDebugger.Info("[CaptureContext] Release end, cost:{0} ms", stopwatch.ElapsedMilliseconds);
m_IsInitialized = false;
}
}
}