/**************************************************************************** * 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; } } }