Decompiled source of CineCamUnlimited v0.8.0

CineCamOverload.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using CineCamUnlimited;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.XR;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(CineCamMod), "CineCam Unlimited", "0.8.0", "NovaVR", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("CineCamOverload")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CineCamOverload")]
[assembly: AssemblyTitle("CineCamOverload")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CineCamUnlimited
{
	public enum CameraPreset
	{
		Custom,
		Action,
		Smooth,
		Handheld,
		Tripod,
		Drone,
		Orbit,
		Chase,
		Bodycam,
		Selfie,
		SlowPan,
		Dolly
	}
	public sealed class CineCamMod : MelonMod
	{
		internal static CineCamMod Instance;

		internal readonly CameraManager Cameras = new CameraManager();

		internal readonly VideoSettings Video = new VideoSettings();

		internal readonly Recorder Recorder = new Recorder();

		private Page _root;

		public override void OnInitializeMelon()
		{
			Instance = this;
			MelonLogger.Msg("CineCam Unlimited initializing...");
			BuildMenu();
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			Cameras.Clear();
			Recorder.EmergencyStop();
		}

		public override void OnUpdate()
		{
			Cameras.Tick();
			Recorder.Tick(Cameras.Active, Video);
		}

		public override void OnDeinitializeMelon()
		{
			Recorder.EmergencyStop();
			Cameras.Clear();
		}

		private void BuildMenu()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0431: Unknown result type (might be due to invalid IL or missing references)
			//IL_044a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0463: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Color val = default(Color);
				((Color)(ref val))..ctor(0.55f, 0.3f, 1f);
				Color val2 = default(Color);
				((Color)(ref val2))..ctor(0.85f, 0.85f, 0.92f);
				Color val3 = default(Color);
				((Color)(ref val3))..ctor(0.55f, 0.95f, 0.65f);
				Color val4 = default(Color);
				((Color)(ref val4))..ctor(1f, 0.38f, 0.38f);
				_root = Page.Root.CreatePage("CineCam Unlimited", val, 0, true);
				Page obj = _root.CreatePage("Cameras", val, 0, true);
				obj.CreateFunction("Spawn Camera", val3, (Action)delegate
				{
					Notify(Cameras.SpawnNearPlayer());
				});
				obj.CreateFunction("Next Camera", val2, (Action)delegate
				{
					Notify(Cameras.SelectNext());
				});
				obj.CreateFunction("Previous Camera", val2, (Action)delegate
				{
					Notify(Cameras.SelectPrevious());
				});
				obj.CreateFunction("Delete Active", val4, (Action)delegate
				{
					Notify(Cameras.DeleteActive());
				});
				obj.CreateFunction("Delete All", val4, (Action)delegate
				{
					Recorder.EmergencyStop();
					Cameras.Clear();
					Notify("All cameras removed.");
				});
				obj.CreateFunction("Toggle Monitor", val2, (Action)delegate
				{
					Notify(Cameras.ToggleMonitor());
				});
				obj.CreateFunction("Toggle Mirror View", val2, (Action)delegate
				{
					Notify(Cameras.ToggleMirrorView());
				});
				Page obj2 = _root.CreatePage("Presets", val, 0, true);
				obj2.CreateEnum("Camera Preset", val2, (Enum)CameraPreset.Custom, (Action<Enum>)delegate(Enum value)
				{
					CameraPreset preset = (CameraPreset)(object)value;
					Cameras.ApplyPreset(preset);
					Notify("Preset: " + preset);
				});
				obj2.CreateFunction("Action", val3, (Action)delegate
				{
					Cameras.ApplyPreset(CameraPreset.Action);
				});
				obj2.CreateFunction("Smooth", val3, (Action)delegate
				{
					Cameras.ApplyPreset(CameraPreset.Smooth);
				});
				obj2.CreateFunction("Handheld", val3, (Action)delegate
				{
					Cameras.ApplyPreset(CameraPreset.Handheld);
				});
				obj2.CreateFunction("Tripod", val3, (Action)delegate
				{
					Cameras.ApplyPreset(CameraPreset.Tripod);
				});
				obj2.CreateFunction("Drone", val3, (Action)delegate
				{
					Cameras.ApplyPreset(CameraPreset.Drone);
				});
				obj2.CreateFunction("Selfie", val3, (Action)delegate
				{
					Cameras.ApplyPreset(CameraPreset.Selfie);
				});
				Page obj3 = _root.CreatePage("Advanced Tuning", val, 0, true);
				obj3.CreateFloat("FOV", val2, 70f, 1f, 30f, 120f, (Action<float>)delegate(float value)
				{
					Cameras.SetFov(value);
				});
				obj3.CreateFloat("Position Smooth", val2, 8f, 0.5f, 0f, 30f, (Action<float>)delegate(float value)
				{
					Cameras.SetPositionSmooth(value);
				});
				obj3.CreateFloat("Rotation Smooth", val2, 10f, 0.5f, 0f, 30f, (Action<float>)delegate(float value)
				{
					Cameras.SetRotationSmooth(value);
				});
				obj3.CreateFloat("Shake", val2, 0f, 0.01f, 0f, 0.35f, (Action<float>)delegate(float value)
				{
					Cameras.SetShake(value);
				});
				obj3.CreateFloat("Near Clip", val2, 0.03f, 0.01f, 0.01f, 1f, (Action<float>)delegate(float value)
				{
					Cameras.SetNearClip(value);
				});
				obj3.CreateFloat("Far Clip", val2, 1000f, 25f, 50f, 4000f, (Action<float>)delegate(float value)
				{
					Cameras.SetFarClip(value);
				});
				Page obj4 = _root.CreatePage("Video", val, 0, true);
				obj4.CreateEnum("Resolution", val2, (Enum)ResolutionPreset.Q2Safe, (Action<Enum>)delegate(Enum value)
				{
					Video.ApplyPreset((ResolutionPreset)(object)value);
				});
				obj4.CreateFloat("Custom Width", val2, (float)Video.Width, 16f, 320f, 3840f, (Action<float>)delegate(float value)
				{
					Video.Width = MakeEven((int)value);
				});
				obj4.CreateFloat("Custom Height", val2, (float)Video.Height, 16f, 180f, 2160f, (Action<float>)delegate(float value)
				{
					Video.Height = MakeEven((int)value);
				});
				obj4.CreateFloat("FPS", val2, (float)Video.Fps, 1f, 15f, 120f, (Action<float>)delegate(float value)
				{
					Video.Fps = Mathf.Clamp((int)value, 15, 120);
				});
				obj4.CreateFloat("Bitrate Mbps", val2, Video.BitrateMbps, 0.5f, 1f, 80f, (Action<float>)delegate(float value)
				{
					Video.BitrateMbps = Mathf.Clamp(value, 1f, 80f);
				});
				Page obj5 = _root.CreatePage("Recording", val, 0, true);
				obj5.CreateFunction("QUICK RECORD / STOP", val3, (Action)ToggleRecording);
				obj5.CreateFunction("Stop + Save", val4, (Action)delegate
				{
					Recorder.Stop();
					Notify(Recorder.Status);
				});
				obj5.CreateFunction("Recording Status", val2, (Action)delegate
				{
					Notify(Recorder.Status);
				});
				obj5.CreateFunction("Open Camera Folder Info", val2, (Action)delegate
				{
					Notify("Clips: /sdcard/Movies/CineCamUnlimited/");
				});
			}
			catch (Exception ex)
			{
				MelonLogger.Error("BoneMenu setup failed: " + ex);
			}
		}

		private void ToggleRecording()
		{
			if (Recorder.IsRecording)
			{
				Recorder.Stop();
				Notify(Recorder.Status);
			}
			else if (Cameras.Active == null)
			{
				Notify("Spawn a camera first.");
			}
			else
			{
				Recorder.Start(Cameras.Active, Video);
				Notify(Recorder.Status);
			}
		}

		private static int MakeEven(int value)
		{
			return Math.Max(2, value & -2);
		}

		internal static void Notify(string message)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			if (string.IsNullOrWhiteSpace(message))
			{
				return;
			}
			MelonLogger.Msg(message);
			try
			{
				Notifier.Send(new Notification
				{
					Title = NotificationText.op_Implicit("CineCam Unlimited"),
					Message = NotificationText.op_Implicit(message),
					Type = (NotificationType)0,
					PopupLength = 3f,
					ShowTitleOnPopup = true
				});
			}
			catch
			{
			}
		}
	}
	public enum ResolutionPreset
	{
		Q2Safe,
		Q3Balanced,
		HD720,
		HD1080,
		Custom
	}
	public sealed class VideoSettings
	{
		public int Width = 960;

		public int Height = 540;

		public int Fps = 30;

		public float BitrateMbps = 8f;

		public void ApplyPreset(ResolutionPreset preset)
		{
			switch (preset)
			{
			case ResolutionPreset.Q2Safe:
				Width = 960;
				Height = 540;
				Fps = 30;
				BitrateMbps = 8f;
				break;
			case ResolutionPreset.Q3Balanced:
				Width = 1280;
				Height = 720;
				Fps = 60;
				BitrateMbps = 16f;
				break;
			case ResolutionPreset.HD720:
				Width = 1280;
				Height = 720;
				Fps = 30;
				BitrateMbps = 12f;
				break;
			case ResolutionPreset.HD1080:
				Width = 1920;
				Height = 1080;
				Fps = 30;
				BitrateMbps = 20f;
				break;
			case ResolutionPreset.Custom:
				break;
			}
		}
	}
	public sealed class CameraManager
	{
		private readonly List<CineCamera> _cameras = new List<CineCamera>();

		private int _activeIndex = -1;

		public CineCamera Active
		{
			get
			{
				if (_activeIndex < 0 || _activeIndex >= _cameras.Count)
				{
					return null;
				}
				return _cameras[_activeIndex];
			}
		}

		public int Count => _cameras.Count;

		public string SpawnNearPlayer()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return "Could not find the player camera.";
			}
			int num = _cameras.Count + 1;
			Vector3 position = ((Component)main).transform.position + ((Component)main).transform.forward * 1.1f + Vector3.up * -0.08f;
			Quaternion rotation = ((Component)main).transform.rotation;
			CineCamera cineCamera = CineCamera.Create("Camera " + num, position, rotation);
			_cameras.Add(cineCamera);
			_activeIndex = _cameras.Count - 1;
			return $"Spawned {cineCamera.Name}. Cameras: {_cameras.Count}";
		}

		public string SelectNext()
		{
			if (_cameras.Count == 0)
			{
				return "No cameras.";
			}
			_activeIndex = (_activeIndex + 1) % _cameras.Count;
			return "Active: " + Active.Name;
		}

		public string SelectPrevious()
		{
			if (_cameras.Count == 0)
			{
				return "No cameras.";
			}
			_activeIndex--;
			if (_activeIndex < 0)
			{
				_activeIndex = _cameras.Count - 1;
			}
			return "Active: " + Active.Name;
		}

		public string DeleteActive()
		{
			if (Active == null)
			{
				return "No active camera.";
			}
			string name = Active.Name;
			Active.Dispose();
			_cameras.RemoveAt(_activeIndex);
			if (_cameras.Count == 0)
			{
				_activeIndex = -1;
			}
			else
			{
				_activeIndex = Mathf.Clamp(_activeIndex, 0, _cameras.Count - 1);
			}
			return "Removed " + name;
		}

		public string ToggleMonitor()
		{
			if (Active == null)
			{
				return "No active camera.";
			}
			Active.MonitorEnabled = !Active.MonitorEnabled;
			Active.RefreshMonitor();
			return "Live monitor: " + (Active.MonitorEnabled ? "ON" : "OFF");
		}

		public string ToggleMirrorView()
		{
			if (Active == null)
			{
				return "No active camera.";
			}
			Active.MirrorPreview = !Active.MirrorPreview;
			Active.RefreshMonitor();
			return "Mirror view: " + (Active.MirrorPreview ? "ON" : "OFF");
		}

		public void ApplyPreset(CameraPreset preset)
		{
			Active?.ApplyPreset(preset);
		}

		public void SetFov(float v)
		{
			if (Active != null)
			{
				Active.Fov = v;
			}
		}

		public void SetPositionSmooth(float v)
		{
			if (Active != null)
			{
				Active.PositionSmooth = v;
			}
		}

		public void SetRotationSmooth(float v)
		{
			if (Active != null)
			{
				Active.RotationSmooth = v;
			}
		}

		public void SetShake(float v)
		{
			if (Active != null)
			{
				Active.Shake = v;
			}
		}

		public void SetNearClip(float v)
		{
			if (Active != null)
			{
				Active.UnityCamera.nearClipPlane = v;
			}
		}

		public void SetFarClip(float v)
		{
			if (Active != null)
			{
				Active.UnityCamera.farClipPlane = v;
			}
		}

		public void Tick()
		{
			for (int i = 0; i < _cameras.Count; i++)
			{
				_cameras[i].Tick();
			}
		}

		public void Clear()
		{
			for (int i = 0; i < _cameras.Count; i++)
			{
				_cameras[i].Dispose();
			}
			_cameras.Clear();
			_activeIndex = -1;
		}
	}
	public sealed class CineCamera : IDisposable
	{
		public string Name;

		public GameObject Root;

		public Camera UnityCamera;

		public RenderTexture Preview;

		public GameObject Monitor;

		public bool MonitorEnabled = true;

		public bool MirrorPreview;

		public TextMesh MonitorStatusText;

		public TextMesh MonitorModeText;

		private bool _recording;

		private float _recordingStartedAt;

		public float Fov = 70f;

		public float PositionSmooth = 8f;

		public float RotationSmooth = 10f;

		public float Shake;

		public CameraPreset Preset;

		private Vector3 _baseLocalPos;

		private Quaternion _baseLocalRot;

		private bool _disposed;

		private XRNode? _heldBy;

		private bool _lastTriggerPressed;

		private bool _lastGripPressedLeft;

		private bool _lastGripPressedRight;

		private Rigidbody _rigidbody;

		private Transform _sideGripPoint;

		private Transform _topGripPoint;

		public static CineCamera Create(string name, Vector3 position, Quaternion rotation)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Expected O, but got Unknown
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a9: Expected O, but got Unknown
			//IL_051d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0541: Unknown result type (might be due to invalid IL or missing references)
			//IL_0565: Unknown result type (might be due to invalid IL or missing references)
			//IL_0605: Unknown result type (might be due to invalid IL or missing references)
			//IL_060c: Expected O, but got Unknown
			//IL_063a: Unknown result type (might be due to invalid IL or missing references)
			//IL_064b: Unknown result type (might be due to invalid IL or missing references)
			//IL_065c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0666: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_06de: Expected O, but got Unknown
			//IL_070c: Unknown result type (might be due to invalid IL or missing references)
			//IL_071d: Unknown result type (might be due to invalid IL or missing references)
			//IL_072e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0738: Unknown result type (might be due to invalid IL or missing references)
			//IL_078a: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_07cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cc: Expected O, but got Unknown
			//IL_05e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f6: Unknown result type (might be due to invalid IL or missing references)
			CineCamera cineCamera = new CineCamera();
			cineCamera.Name = name;
			cineCamera.Root = new GameObject("CineCam_" + name.Replace(" ", "_"));
			cineCamera.Root.transform.position = position;
			cineCamera.Root.transform.rotation = rotation;
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)obj).name = "CameraBody";
			obj.transform.SetParent(cineCamera.Root.transform, false);
			obj.transform.localScale = new Vector3(0.2f, 0.11f, 0.32f);
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				component.isTrigger = false;
			}
			cineCamera._rigidbody = cineCamera.Root.AddComponent<Rigidbody>();
			cineCamera._rigidbody.mass = 0.75f;
			cineCamera._rigidbody.interpolation = (RigidbodyInterpolation)1;
			cineCamera._rigidbody.collisionDetectionMode = (CollisionDetectionMode)2;
			GameObject obj2 = GameObject.CreatePrimitive((PrimitiveType)2);
			((Object)obj2).name = "Lens";
			obj2.transform.SetParent(cineCamera.Root.transform, false);
			obj2.transform.localPosition = new Vector3(0f, 0f, 0.19f);
			obj2.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
			obj2.transform.localScale = new Vector3(0.07f, 0.045f, 0.07f);
			Collider component2 = obj2.GetComponent<Collider>();
			if ((Object)(object)component2 != (Object)null)
			{
				Object.Destroy((Object)(object)component2);
			}
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)val).name = "SideGrip";
			val.transform.SetParent(cineCamera.Root.transform, false);
			val.transform.localPosition = new Vector3(0.145f, -0.015f, -0.025f);
			val.transform.localScale = new Vector3(0.055f, 0.115f, 0.18f);
			cineCamera._sideGripPoint = val.transform;
			GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)val2).name = "TopHandle";
			val2.transform.SetParent(cineCamera.Root.transform, false);
			val2.transform.localPosition = new Vector3(0f, 0.105f, -0.01f);
			val2.transform.localScale = new Vector3(0.13f, 0.035f, 0.18f);
			cineCamera._topGripPoint = val2.transform;
			GameObject obj3 = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)obj3).name = "TopHandlePostA";
			obj3.transform.SetParent(cineCamera.Root.transform, false);
			obj3.transform.localPosition = new Vector3(0f, 0.068f, 0.055f);
			obj3.transform.localScale = new Vector3(0.035f, 0.075f, 0.035f);
			GameObject obj4 = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)obj4).name = "TopHandlePostB";
			obj4.transform.SetParent(cineCamera.Root.transform, false);
			obj4.transform.localPosition = new Vector3(0f, 0.068f, -0.075f);
			obj4.transform.localScale = new Vector3(0.035f, 0.075f, 0.035f);
			GameObject obj5 = GameObject.CreatePrimitive((PrimitiveType)2);
			((Object)obj5).name = "RecordButton";
			obj5.transform.SetParent(cineCamera.Root.transform, false);
			obj5.transform.localPosition = new Vector3(0.178f, 0.025f, 0.055f);
			obj5.transform.localRotation = Quaternion.Euler(0f, 0f, 90f);
			obj5.transform.localScale = new Vector3(0.018f, 0.01f, 0.018f);
			Collider component3 = obj5.GetComponent<Collider>();
			if ((Object)(object)component3 != (Object)null)
			{
				Object.Destroy((Object)(object)component3);
			}
			Renderer component4 = obj5.GetComponent<Renderer>();
			if ((Object)(object)component4 != (Object)null)
			{
				component4.material.color = Color.red;
			}
			GameObject val3 = new GameObject("CaptureCamera");
			val3.transform.SetParent(cineCamera.Root.transform, false);
			val3.transform.localPosition = new Vector3(0f, 0f, 0.17f);
			cineCamera.UnityCamera = val3.AddComponent<Camera>();
			if ((Object)(object)Camera.main != (Object)null)
			{
				cineCamera.UnityCamera.CopyFrom(Camera.main);
			}
			cineCamera.UnityCamera.stereoTargetEye = (StereoTargetEyeMask)0;
			((Behaviour)cineCamera.UnityCamera).enabled = false;
			cineCamera.UnityCamera.fieldOfView = cineCamera.Fov;
			cineCamera.Preview = new RenderTexture(640, 360, 16, (RenderTextureFormat)0);
			((Object)cineCamera.Preview).name = name + "_Preview";
			cineCamera.Preview.Create();
			cineCamera.Monitor = GameObject.CreatePrimitive((PrimitiveType)5);
			((Object)cineCamera.Monitor).name = "SelfieMonitor";
			cineCamera.Monitor.transform.SetParent(cineCamera.Root.transform, false);
			cineCamera.Monitor.transform.localPosition = new Vector3(0f, 0.09f, -0.18f);
			cineCamera.Monitor.transform.localRotation = Quaternion.Euler(0f, 180f, 0f);
			cineCamera.Monitor.transform.localScale = new Vector3(0.22f, 0.13f, 1f);
			Collider component5 = cineCamera.Monitor.GetComponent<Collider>();
			if ((Object)(object)component5 != (Object)null)
			{
				Object.Destroy((Object)(object)component5);
			}
			MeshRenderer component6 = cineCamera.Monitor.GetComponent<MeshRenderer>();
			if ((Object)(object)component6 != (Object)null)
			{
				Shader val4 = Shader.Find("Unlit/Texture") ?? Shader.Find("Sprites/Default");
				((Renderer)component6).material = new Material(val4);
				((Renderer)component6).material.mainTexture = (Texture)(object)cineCamera.Preview;
				((Renderer)component6).material.mainTextureScale = Vector2.one;
				((Renderer)component6).material.mainTextureOffset = Vector2.zero;
			}
			GameObject val5 = new GameObject("MonitorRECStatus");
			val5.transform.SetParent(cineCamera.Monitor.transform, false);
			val5.transform.localPosition = new Vector3(-0.43f, 0.33f, -0.01f);
			val5.transform.localRotation = Quaternion.identity;
			val5.transform.localScale = Vector3.one * 0.06f;
			cineCamera.MonitorStatusText = val5.AddComponent<TextMesh>();
			cineCamera.MonitorStatusText.anchor = (TextAnchor)0;
			cineCamera.MonitorStatusText.alignment = (TextAlignment)0;
			cineCamera.MonitorStatusText.fontSize = 48;
			cineCamera.MonitorStatusText.characterSize = 0.18f;
			cineCamera.MonitorStatusText.color = Color.white;
			cineCamera.MonitorStatusText.text = "STBY 00:00:00";
			GameObject val6 = new GameObject("MonitorViewMode");
			val6.transform.SetParent(cineCamera.Monitor.transform, false);
			val6.transform.localPosition = new Vector3(0.43f, 0.33f, -0.01f);
			val6.transform.localRotation = Quaternion.identity;
			val6.transform.localScale = Vector3.one * 0.06f;
			cineCamera.MonitorModeText = val6.AddComponent<TextMesh>();
			cineCamera.MonitorModeText.anchor = (TextAnchor)2;
			cineCamera.MonitorModeText.alignment = (TextAlignment)2;
			cineCamera.MonitorModeText.fontSize = 48;
			cineCamera.MonitorModeText.characterSize = 0.18f;
			cineCamera.MonitorModeText.color = Color.white;
			cineCamera.MonitorModeText.text = "VIEW";
			cineCamera._baseLocalPos = ((Component)cineCamera.UnityCamera).transform.localPosition;
			cineCamera._baseLocalRot = ((Component)cineCamera.UnityCamera).transform.localRotation;
			return cineCamera;
		}

		public void ApplyPreset(CameraPreset preset)
		{
			Preset = preset;
			switch (preset)
			{
			case CameraPreset.Action:
				Fov = 82f;
				PositionSmooth = 4f;
				RotationSmooth = 5f;
				Shake = 0.015f;
				break;
			case CameraPreset.Smooth:
				Fov = 65f;
				PositionSmooth = 14f;
				RotationSmooth = 16f;
				Shake = 0f;
				break;
			case CameraPreset.Handheld:
				Fov = 72f;
				PositionSmooth = 7f;
				RotationSmooth = 8f;
				Shake = 0.012f;
				break;
			case CameraPreset.Tripod:
				Fov = 55f;
				PositionSmooth = 30f;
				RotationSmooth = 30f;
				Shake = 0f;
				break;
			case CameraPreset.Drone:
				Fov = 75f;
				PositionSmooth = 10f;
				RotationSmooth = 12f;
				Shake = 0.003f;
				break;
			case CameraPreset.Orbit:
				Fov = 62f;
				PositionSmooth = 12f;
				RotationSmooth = 15f;
				Shake = 0f;
				break;
			case CameraPreset.Chase:
				Fov = 78f;
				PositionSmooth = 6f;
				RotationSmooth = 9f;
				Shake = 0.006f;
				break;
			case CameraPreset.Bodycam:
				Fov = 95f;
				PositionSmooth = 2f;
				RotationSmooth = 3f;
				Shake = 0.022f;
				break;
			case CameraPreset.Selfie:
				Fov = 74f;
				PositionSmooth = 8f;
				RotationSmooth = 10f;
				Shake = 0.004f;
				MonitorEnabled = true;
				MirrorPreview = true;
				break;
			case CameraPreset.SlowPan:
				Fov = 58f;
				PositionSmooth = 18f;
				RotationSmooth = 22f;
				Shake = 0f;
				break;
			case CameraPreset.Dolly:
				Fov = 52f;
				PositionSmooth = 16f;
				RotationSmooth = 18f;
				Shake = 0f;
				break;
			}
			RefreshMonitor();
		}

		public void Tick()
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if (!_disposed && !((Object)(object)UnityCamera == (Object)null))
			{
				TickPhysicalControls();
				UnityCamera.fieldOfView = Fov;
				if (Shake > 0.0001f)
				{
					float num = Time.unscaledTime * 3.7f;
					Vector3 val = new Vector3(Mathf.PerlinNoise(num, 1.1f) - 0.5f, Mathf.PerlinNoise(2.2f, num) - 0.5f, 0f) * Shake;
					Vector3 val2 = new Vector3(Mathf.PerlinNoise(num, 5.5f) - 0.5f, Mathf.PerlinNoise(7.7f, num) - 0.5f, Mathf.PerlinNoise(num, 9.9f) - 0.5f) * (Shake * 45f);
					((Component)UnityCamera).transform.localPosition = _baseLocalPos + val;
					((Component)UnityCamera).transform.localRotation = _baseLocalRot * Quaternion.Euler(val2);
				}
				else
				{
					((Component)UnityCamera).transform.localPosition = _baseLocalPos;
					((Component)UnityCamera).transform.localRotation = _baseLocalRot;
				}
				if (MonitorEnabled && (Object)(object)Preview != (Object)null)
				{
					RenderTexture targetTexture = UnityCamera.targetTexture;
					UnityCamera.targetTexture = Preview;
					UnityCamera.Render();
					UnityCamera.targetTexture = targetTexture;
				}
				UpdateMonitorOverlay();
			}
		}

		private void TickPhysicalControls()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Invalid comparison between Unknown and I4
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Invalid comparison between Unknown and I4
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			InputDevice deviceAtXRNode = InputDevices.GetDeviceAtXRNode((XRNode)4);
			InputDevice deviceAtXRNode2 = InputDevices.GetDeviceAtXRNode((XRNode)5);
			bool flag = ReadButton(deviceAtXRNode, CommonUsages.gripButton);
			bool flag2 = ReadButton(deviceAtXRNode2, CommonUsages.gripButton);
			if (!_heldBy.HasValue)
			{
				TryBeginHold((XRNode)4, deviceAtXRNode, flag, _lastGripPressedLeft);
				if (!_heldBy.HasValue)
				{
					TryBeginHold((XRNode)5, deviceAtXRNode2, flag2, _lastGripPressedRight);
				}
			}
			else
			{
				XRNode value = _heldBy.Value;
				InputDevice device = (((int)value == 4) ? deviceAtXRNode : deviceAtXRNode2);
				if (!(((int)value == 4) ? flag : flag2))
				{
					_heldBy = null;
					_lastTriggerPressed = false;
					if ((Object)(object)_rigidbody != (Object)null)
					{
						_rigidbody.isKinematic = false;
					}
				}
				else
				{
					Vector3 val = default(Vector3);
					Quaternion val2 = default(Quaternion);
					if (((InputDevice)(ref device)).TryGetFeatureValue(CommonUsages.devicePosition, ref val) && ((InputDevice)(ref device)).TryGetFeatureValue(CommonUsages.deviceRotation, ref val2))
					{
						if ((Object)(object)_rigidbody != (Object)null)
						{
							_rigidbody.isKinematic = true;
						}
						Root.transform.position = val + val2 * new Vector3(0f, -0.035f, 0.08f);
						Root.transform.rotation = val2;
					}
					bool flag3 = ReadButton(device, CommonUsages.triggerButton);
					if (flag3 && !_lastTriggerPressed)
					{
						CineCamMod instance = CineCamMod.Instance;
						if (instance != null)
						{
							if (instance.Recorder.IsRecording)
							{
								instance.Recorder.Stop();
								CineCamMod.Notify(instance.Recorder.Status);
							}
							else
							{
								instance.Recorder.Start(this, instance.Video);
								CineCamMod.Notify(instance.Recorder.Status);
							}
						}
					}
					_lastTriggerPressed = flag3;
				}
			}
			_lastGripPressedLeft = flag;
			_lastGripPressedRight = flag2;
		}

		private void TryBeginHold(XRNode node, InputDevice device, bool grip, bool previousGrip)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			if (!grip || previousGrip || !((InputDevice)(ref device)).isValid || !((InputDevice)(ref device)).TryGetFeatureValue(CommonUsages.devicePosition, ref val))
			{
				return;
			}
			float num = (((Object)(object)_sideGripPoint != (Object)null) ? Vector3.Distance(val, _sideGripPoint.position) : 999f);
			float num2 = (((Object)(object)_topGripPoint != (Object)null) ? Vector3.Distance(val, _topGripPoint.position) : 999f);
			if (!(Mathf.Min(num, num2) > 0.18f))
			{
				_heldBy = node;
				_lastTriggerPressed = ReadButton(device, CommonUsages.triggerButton);
				if ((Object)(object)_rigidbody != (Object)null)
				{
					_rigidbody.velocity = Vector3.zero;
					_rigidbody.angularVelocity = Vector3.zero;
					_rigidbody.isKinematic = true;
				}
			}
		}

		private static bool ReadButton(InputDevice device, InputFeatureUsage<bool> usage)
		{
			bool flag = default(bool);
			return ((InputDevice)(ref device)).isValid && ((InputDevice)(ref device)).TryGetFeatureValue(usage, ref flag) && flag;
		}

		public void SetRecordingState(bool recording)
		{
			_recording = recording;
			if (recording)
			{
				_recordingStartedAt = Time.unscaledTime;
			}
			UpdateMonitorOverlay();
		}

		private void UpdateMonitorOverlay()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)MonitorStatusText != (Object)null)
			{
				int num = Mathf.FloorToInt(_recording ? Mathf.Max(0f, Time.unscaledTime - _recordingStartedAt) : 0f);
				int value = num / 3600;
				int value2 = num % 3600 / 60;
				int value3 = num % 60;
				MonitorStatusText.color = (_recording ? Color.red : Color.white);
				MonitorStatusText.text = (_recording ? "● REC " : "STBY ") + $"{value:00}:{value2:00}:{value3:00}";
			}
			if ((Object)(object)MonitorModeText != (Object)null)
			{
				MonitorModeText.text = (MirrorPreview ? "MIRROR" : "VIEW");
			}
		}

		public void RefreshMonitor()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Monitor != (Object)null)
			{
				Monitor.SetActive(MonitorEnabled);
			}
			MeshRenderer val = (((Object)(object)Monitor != (Object)null) ? Monitor.GetComponent<MeshRenderer>() : null);
			if ((Object)(object)val != (Object)null && (Object)(object)((Renderer)val).material != (Object)null)
			{
				((Renderer)val).material.mainTextureScale = (Vector2)(MirrorPreview ? new Vector2(-1f, 1f) : Vector2.one);
				((Renderer)val).material.mainTextureOffset = (Vector2)(MirrorPreview ? new Vector2(1f, 0f) : Vector2.zero);
			}
			UpdateMonitorOverlay();
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				if ((Object)(object)Preview != (Object)null)
				{
					Preview.Release();
					Object.Destroy((Object)(object)Preview);
				}
				if ((Object)(object)Root != (Object)null)
				{
					Object.Destroy((Object)(object)Root);
				}
			}
		}
	}
	public sealed class Recorder
	{
		private CineCamera _bound;

		private VideoSettings _settings;

		private RenderTexture _capture;

		private Texture2D _readback;

		private float _nextFrame;

		private long _frameIndex;

		private QuestVideoEncoder _encoder;

		public bool IsRecording { get; private set; }

		public string Status { get; private set; } = "Idle";

		public void Start(CineCamera camera, VideoSettings settings)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			if (IsRecording || camera == null)
			{
				return;
			}
			try
			{
				_bound = camera;
				_settings = settings;
				Directory.CreateDirectory("/sdcard/Movies/CineCamUnlimited/");
				string text = "CineCam_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".mp4";
				string path = "/sdcard/Movies/CineCamUnlimited/" + text;
				_capture = new RenderTexture(settings.Width, settings.Height, 0, (RenderTextureFormat)0);
				_capture.Create();
				_readback = new Texture2D(settings.Width, settings.Height, (TextureFormat)4, false, false);
				_encoder = new QuestVideoEncoder();
				_encoder.Start(path, settings.Width, settings.Height, settings.Fps, (int)(settings.BitrateMbps * 1000000f));
				_frameIndex = 0L;
				_nextFrame = Time.unscaledTime;
				IsRecording = true;
				_bound.SetRecordingState(recording: true);
				Status = $"REC {settings.Width}x{settings.Height} {settings.Fps}fps {settings.BitrateMbps:0.#}Mbps";
			}
			catch (Exception ex)
			{
				Status = "Start failed: " + ex.Message;
				EmergencyStop();
			}
		}

		public void Tick(CineCamera active, VideoSettings settings)
		{
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			if (!IsRecording || _bound == null || _encoder == null)
			{
				return;
			}
			float num = 1f / (float)Mathf.Max(1, _settings.Fps);
			if (Time.unscaledTime < _nextFrame)
			{
				return;
			}
			_nextFrame += num;
			if (Time.unscaledTime - _nextFrame > num * 3f)
			{
				_nextFrame = Time.unscaledTime + num;
			}
			try
			{
				Camera unityCamera = _bound.UnityCamera;
				RenderTexture targetTexture = unityCamera.targetTexture;
				RenderTexture active2 = RenderTexture.active;
				unityCamera.targetTexture = _capture;
				unityCamera.Render();
				RenderTexture.active = _capture;
				_readback.ReadPixels(new Rect(0f, 0f, (float)_settings.Width, (float)_settings.Height), 0, 0, false);
				_readback.Apply(false, false);
				byte[] rgba = Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)_readback.GetRawTextureData());
				long ptsUs = _frameIndex * 1000000 / Math.Max(1, _settings.Fps);
				_encoder.PushRgba(rgba, ptsUs);
				_frameIndex++;
				unityCamera.targetTexture = targetTexture;
				RenderTexture.active = active2;
				Status = $"REC {(float)_frameIndex / (float)_settings.Fps:0.0}s | {_settings.Width}x{_settings.Height}";
			}
			catch (Exception ex)
			{
				Status = "Recording error: " + ex.Message;
				EmergencyStop();
			}
		}

		public void Stop()
		{
			if (IsRecording)
			{
				try
				{
					_encoder?.Stop();
				}
				catch (Exception ex)
				{
					Status = "Finalize error: " + ex.Message;
				}
				Cleanup();
				if (!Status.StartsWith("Finalize error"))
				{
					Status = "Saved recording.";
				}
			}
		}

		public void EmergencyStop()
		{
			try
			{
				_encoder?.Abort();
			}
			catch
			{
			}
			Cleanup();
			if (Status == null || Status == "Idle")
			{
				Status = "Stopped.";
			}
		}

		private void Cleanup()
		{
			if (_bound != null)
			{
				_bound.SetRecordingState(recording: false);
			}
			IsRecording = false;
			_bound = null;
			_settings = null;
			_encoder = null;
			if ((Object)(object)_capture != (Object)null)
			{
				_capture.Release();
				Object.Destroy((Object)(object)_capture);
				_capture = null;
			}
			if ((Object)(object)_readback != (Object)null)
			{
				Object.Destroy((Object)(object)_readback);
				_readback = null;
			}
		}
	}
	public sealed class QuestVideoEncoder
	{
		private const string MimeAvc = "video/avc";

		private const int ConfigureFlagEncode = 1;

		private const int ColorFormatYuv420SemiPlanar = 21;

		private const int BufferFlagCodecConfig = 2;

		private const int BufferFlagEndOfStream = 4;

		private const int InfoTryAgainLater = -1;

		private const int InfoOutputFormatChanged = -2;

		private AndroidJavaObject _codec;

		private AndroidJavaObject _muxer;

		private AndroidJavaObject _bufferInfo;

		private bool _codecStarted;

		private bool _muxerStarted;

		private bool _started;

		private int _trackIndex = -1;

		private int _width;

		private int _height;

		private long _lastPtsUs;

		private byte[] _nv12;

		public void Start(string path, int width, int height, int fps, int bitrate)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Expected O, but got Unknown
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Expected O, but got Unknown
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Expected O, but got Unknown
			if ((int)Application.platform != 11)
			{
				throw new PlatformNotSupportedException("CineCam recording requires Android/Quest. Runtime platform: " + ((object)Application.platform/*cast due to .constrained prefix*/).ToString());
			}
			if ((width & 1) != 0 || (height & 1) != 0)
			{
				throw new ArgumentException("Video width and height must be even for YUV420 encoding.");
			}
			_width = width;
			_height = height;
			_lastPtsUs = 0L;
			_nv12 = new byte[width * height * 3 / 2];
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(path));
				AndroidJavaClass val = new AndroidJavaClass("android.media.MediaFormat");
				AndroidJavaObject val2 = null;
				try
				{
					val2 = ((AndroidJavaObject)val).CallStatic<AndroidJavaObject>("createVideoFormat", (Object[])(object)new Object[3]
					{
						Object.op_Implicit("video/avc"),
						Object.op_Implicit(width),
						Object.op_Implicit(height)
					});
				}
				finally
				{
					try
					{
						((AndroidJavaObject)val).Dispose();
					}
					catch
					{
					}
				}
				if (val2 == null)
				{
					throw new Exception("MediaFormat.createVideoFormat returned null.");
				}
				try
				{
					val2.Call("setInteger", (Object[])(object)new Object[2]
					{
						Object.op_Implicit("color-format"),
						Object.op_Implicit(21)
					});
					val2.Call("setInteger", (Object[])(object)new Object[2]
					{
						Object.op_Implicit("bitrate"),
						Object.op_Implicit(bitrate)
					});
					val2.Call("setInteger", (Object[])(object)new Object[2]
					{
						Object.op_Implicit("frame-rate"),
						Object.op_Implicit(fps)
					});
					val2.Call("setInteger", (Object[])(object)new Object[2]
					{
						Object.op_Implicit("i-frame-interval"),
						Object.op_Implicit(1)
					});
					AndroidJavaClass val3 = new AndroidJavaClass("android.media.MediaCodec");
					try
					{
						_codec = ((AndroidJavaObject)val3).CallStatic<AndroidJavaObject>("createEncoderByType", (Object[])(object)new Object[1] { Object.op_Implicit("video/avc") });
					}
					finally
					{
						try
						{
							((AndroidJavaObject)val3).Dispose();
						}
						catch
						{
						}
					}
					if (_codec == null)
					{
						throw new Exception("MediaCodec.createEncoderByType(video/avc) returned null.");
					}
					IntPtr methodID = AndroidJNI.GetMethodID(_codec.GetRawClass(), "configure", "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V");
					if (methodID == IntPtr.Zero)
					{
						throw new Exception("Could not resolve MediaCodec.configure().");
					}
					jvalue[] array = (jvalue[])(object)new jvalue[4];
					array[0].l = val2.GetRawObject();
					array[1].l = IntPtr.Zero;
					array[2].l = IntPtr.Zero;
					array[3].i = 1;
					AndroidJNI.CallVoidMethod(_codec.GetRawObject(), methodID, Il2CppStructArray<jvalue>.op_Implicit(array));
					_codec.Call("start", (Il2CppReferenceArray<Object>)null);
					_codecStarted = true;
				}
				finally
				{
					try
					{
						val2.Dispose();
					}
					catch
					{
					}
				}
				_muxer = new AndroidJavaObject("android.media.MediaMuxer", (Object[])(object)new Object[2]
				{
					Object.op_Implicit(path),
					Object.op_Implicit(0)
				});
				_bufferInfo = new AndroidJavaObject("android.media.MediaCodec$BufferInfo", (Il2CppReferenceArray<Object>)null);
				if (_muxer == null || _bufferInfo == null)
				{
					throw new Exception("Could not create MediaMuxer or MediaCodec.BufferInfo.");
				}
				_trackIndex = -1;
				_muxerStarted = false;
				_started = true;
			}
			catch (Exception ex)
			{
				Abort();
				throw new Exception("Direct Quest MediaCodec encoder failed to start: " + ex.Message);
			}
		}

		public void PushRgba(byte[] rgba, long ptsUs)
		{
			if (!_started || !_codecStarted || _codec == null || rgba == null)
			{
				return;
			}
			int num = _width * _height * 4;
			if (rgba.Length < num)
			{
				throw new ArgumentException("RGBA frame is smaller than expected.");
			}
			RgbaToNv12Flipped(rgba, _nv12, _width, _height);
			_lastPtsUs = ptsUs;
			int num2 = DequeueInputBuffer(10000L);
			if (num2 >= 0)
			{
				IntPtr codecBuffer = GetCodecBuffer("getInputBuffer", num2);
				if (codecBuffer == IntPtr.Zero)
				{
					throw new Exception("MediaCodec.getInputBuffer returned null.");
				}
				try
				{
					PutBytesIntoByteBuffer(codecBuffer, _nv12);
					QueueInputBuffer(num2, _nv12.Length, ptsUs, 0);
				}
				finally
				{
					AndroidJNI.DeleteLocalRef(codecBuffer);
				}
			}
			DrainEncoder(endOfStream: false);
		}

		public void Stop()
		{
			if (!_started)
			{
				ReleaseAll();
				return;
			}
			try
			{
				int num = -1;
				for (int i = 0; i < 50; i++)
				{
					if (num >= 0)
					{
						break;
					}
					num = DequeueInputBuffer(10000L);
				}
				if (num >= 0)
				{
					QueueInputBuffer(num, 0, _lastPtsUs + 1, 4);
				}
				DrainEncoder(endOfStream: true);
			}
			finally
			{
				ReleaseAll();
			}
		}

		public void Abort()
		{
			ReleaseAll();
		}

		private int DequeueInputBuffer(long timeoutUs)
		{
			IntPtr methodID = AndroidJNI.GetMethodID(_codec.GetRawClass(), "dequeueInputBuffer", "(J)I");
			if (methodID == IntPtr.Zero)
			{
				throw new Exception("Could not resolve MediaCodec.dequeueInputBuffer().");
			}
			jvalue[] array = (jvalue[])(object)new jvalue[1];
			array[0].j = timeoutUs;
			return AndroidJNI.CallIntMethod(_codec.GetRawObject(), methodID, Il2CppStructArray<jvalue>.op_Implicit(array));
		}

		private IntPtr GetCodecBuffer(string methodName, int index)
		{
			IntPtr methodID = AndroidJNI.GetMethodID(_codec.GetRawClass(), methodName, "(I)Ljava/nio/ByteBuffer;");
			if (methodID == IntPtr.Zero)
			{
				throw new Exception("Could not resolve MediaCodec." + methodName + "().");
			}
			jvalue[] array = (jvalue[])(object)new jvalue[1];
			array[0].i = index;
			return AndroidJNI.CallObjectMethod(_codec.GetRawObject(), methodID, Il2CppStructArray<jvalue>.op_Implicit(array));
		}

		private void QueueInputBuffer(int index, int size, long ptsUs, int flags)
		{
			IntPtr methodID = AndroidJNI.GetMethodID(_codec.GetRawClass(), "queueInputBuffer", "(IIIJI)V");
			if (methodID == IntPtr.Zero)
			{
				throw new Exception("Could not resolve MediaCodec.queueInputBuffer().");
			}
			jvalue[] array = (jvalue[])(object)new jvalue[5];
			array[0].i = index;
			array[1].i = 0;
			array[2].i = size;
			array[3].j = ptsUs;
			array[4].i = flags;
			AndroidJNI.CallVoidMethod(_codec.GetRawObject(), methodID, Il2CppStructArray<jvalue>.op_Implicit(array));
		}

		private void DrainEncoder(bool endOfStream)
		{
			if (_codec == null || _bufferInfo == null)
			{
				return;
			}
			IntPtr methodID = AndroidJNI.GetMethodID(_codec.GetRawClass(), "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I");
			if (methodID == IntPtr.Zero)
			{
				throw new Exception("Could not resolve MediaCodec.dequeueOutputBuffer().");
			}
			int num = (endOfStream ? 400 : 32);
			for (int i = 0; i < num; i++)
			{
				jvalue[] array = (jvalue[])(object)new jvalue[2];
				array[0].l = _bufferInfo.GetRawObject();
				array[1].j = (endOfStream ? 10000 : 0);
				int num2 = AndroidJNI.CallIntMethod(_codec.GetRawObject(), methodID, Il2CppStructArray<jvalue>.op_Implicit(array));
				if (num2 == -1)
				{
					if (!endOfStream)
					{
						break;
					}
				}
				else if (num2 == -2)
				{
					if (_muxerStarted)
					{
						throw new Exception("MediaCodec output format changed twice.");
					}
					IntPtr codecOutputFormat = GetCodecOutputFormat();
					try
					{
						_trackIndex = AddMuxerTrack(codecOutputFormat);
						_muxer.Call("start", (Il2CppReferenceArray<Object>)null);
						_muxerStarted = true;
					}
					finally
					{
						if (codecOutputFormat != IntPtr.Zero)
						{
							AndroidJNI.DeleteLocalRef(codecOutputFormat);
						}
					}
				}
				else
				{
					if (num2 < 0)
					{
						continue;
					}
					int num3 = _bufferInfo.Get<int>("offset");
					int num4 = _bufferInfo.Get<int>("size");
					int num5 = _bufferInfo.Get<int>("flags");
					if ((num5 & 2) != 0)
					{
						num4 = 0;
					}
					if (num4 > 0)
					{
						if (!_muxerStarted)
						{
							throw new Exception("Encoded video arrived before MediaMuxer started.");
						}
						IntPtr codecBuffer = GetCodecBuffer("getOutputBuffer", num2);
						if (codecBuffer == IntPtr.Zero)
						{
							throw new Exception("MediaCodec.getOutputBuffer returned null.");
						}
						try
						{
							SetByteBufferPositionLimit(codecBuffer, num3, num3 + num4);
							WriteMuxerSample(codecBuffer);
						}
						finally
						{
							AndroidJNI.DeleteLocalRef(codecBuffer);
						}
					}
					ReleaseOutputBuffer(num2);
					if ((num5 & 4) != 0)
					{
						break;
					}
				}
			}
		}

		private IntPtr GetCodecOutputFormat()
		{
			IntPtr methodID = AndroidJNI.GetMethodID(_codec.GetRawClass(), "getOutputFormat", "()Landroid/media/MediaFormat;");
			if (methodID == IntPtr.Zero)
			{
				throw new Exception("Could not resolve MediaCodec.getOutputFormat().");
			}
			return AndroidJNI.CallObjectMethod(_codec.GetRawObject(), methodID, Il2CppStructArray<jvalue>.op_Implicit((jvalue[])(object)new jvalue[0]));
		}

		private int AddMuxerTrack(IntPtr mediaFormat)
		{
			if (mediaFormat == IntPtr.Zero)
			{
				throw new Exception("Output MediaFormat is null.");
			}
			IntPtr methodID = AndroidJNI.GetMethodID(_muxer.GetRawClass(), "addTrack", "(Landroid/media/MediaFormat;)I");
			if (methodID == IntPtr.Zero)
			{
				throw new Exception("Could not resolve MediaMuxer.addTrack().");
			}
			jvalue[] array = (jvalue[])(object)new jvalue[1];
			array[0].l = mediaFormat;
			return AndroidJNI.CallIntMethod(_muxer.GetRawObject(), methodID, Il2CppStructArray<jvalue>.op_Implicit(array));
		}

		private void WriteMuxerSample(IntPtr byteBuffer)
		{
			IntPtr methodID = AndroidJNI.GetMethodID(_muxer.GetRawClass(), "writeSampleData", "(ILjava/nio/ByteBuffer;Landroid/media/MediaCodec$BufferInfo;)V");
			if (methodID == IntPtr.Zero)
			{
				throw new Exception("Could not resolve MediaMuxer.writeSampleData().");
			}
			jvalue[] array = (jvalue[])(object)new jvalue[3];
			array[0].i = _trackIndex;
			array[1].l = byteBuffer;
			array[2].l = _bufferInfo.GetRawObject();
			AndroidJNI.CallVoidMethod(_muxer.GetRawObject(), methodID, Il2CppStructArray<jvalue>.op_Implicit(array));
		}

		private void ReleaseOutputBuffer(int index)
		{
			IntPtr methodID = AndroidJNI.GetMethodID(_codec.GetRawClass(), "releaseOutputBuffer", "(IZ)V");
			if (methodID == IntPtr.Zero)
			{
				throw new Exception("Could not resolve MediaCodec.releaseOutputBuffer().");
			}
			jvalue[] array = (jvalue[])(object)new jvalue[2];
			array[0].i = index;
			array[1].z = false;
			AndroidJNI.CallVoidMethod(_codec.GetRawObject(), methodID, Il2CppStructArray<jvalue>.op_Implicit(array));
		}

		private static void PutBytesIntoByteBuffer(IntPtr byteBuffer, byte[] bytes)
		{
			IntPtr objectClass = AndroidJNI.GetObjectClass(byteBuffer);
			IntPtr intPtr = IntPtr.Zero;
			try
			{
				IntPtr methodID = AndroidJNI.GetMethodID(objectClass, "clear", "()Ljava/nio/Buffer;");
				if (methodID != IntPtr.Zero)
				{
					IntPtr intPtr2 = AndroidJNI.CallObjectMethod(byteBuffer, methodID, Il2CppStructArray<jvalue>.op_Implicit((jvalue[])(object)new jvalue[0]));
					if (intPtr2 != IntPtr.Zero)
					{
						AndroidJNI.DeleteLocalRef(intPtr2);
					}
				}
				sbyte[] array = new sbyte[bytes.Length];
				Buffer.BlockCopy(bytes, 0, array, 0, bytes.Length);
				intPtr = AndroidJNI.ToSByteArray(Il2CppStructArray<sbyte>.op_Implicit(array));
				IntPtr methodID2 = AndroidJNI.GetMethodID(objectClass, "put", "([B)Ljava/nio/ByteBuffer;");
				if (methodID2 == IntPtr.Zero)
				{
					throw new Exception("Could not resolve ByteBuffer.put(byte[]).");
				}
				jvalue[] array2 = (jvalue[])(object)new jvalue[1];
				array2[0].l = intPtr;
				IntPtr intPtr3 = AndroidJNI.CallObjectMethod(byteBuffer, methodID2, Il2CppStructArray<jvalue>.op_Implicit(array2));
				if (intPtr3 != IntPtr.Zero)
				{
					AndroidJNI.DeleteLocalRef(intPtr3);
				}
			}
			finally
			{
				if (intPtr != IntPtr.Zero)
				{
					AndroidJNI.DeleteLocalRef(intPtr);
				}
				if (objectClass != IntPtr.Zero)
				{
					AndroidJNI.DeleteLocalRef(objectClass);
				}
			}
		}

		private static void SetByteBufferPositionLimit(IntPtr byteBuffer, int position, int limit)
		{
			IntPtr objectClass = AndroidJNI.GetObjectClass(byteBuffer);
			try
			{
				IntPtr methodID = AndroidJNI.GetMethodID(objectClass, "position", "(I)Ljava/nio/Buffer;");
				IntPtr methodID2 = AndroidJNI.GetMethodID(objectClass, "limit", "(I)Ljava/nio/Buffer;");
				if (methodID == IntPtr.Zero || methodID2 == IntPtr.Zero)
				{
					throw new Exception("Could not resolve ByteBuffer position/limit methods.");
				}
				jvalue[] array = (jvalue[])(object)new jvalue[1];
				array[0].i = position;
				IntPtr intPtr = AndroidJNI.CallObjectMethod(byteBuffer, methodID, Il2CppStructArray<jvalue>.op_Implicit(array));
				if (intPtr != IntPtr.Zero)
				{
					AndroidJNI.DeleteLocalRef(intPtr);
				}
				jvalue[] array2 = (jvalue[])(object)new jvalue[1];
				array2[0].i = limit;
				IntPtr intPtr2 = AndroidJNI.CallObjectMethod(byteBuffer, methodID2, Il2CppStructArray<jvalue>.op_Implicit(array2));
				if (intPtr2 != IntPtr.Zero)
				{
					AndroidJNI.DeleteLocalRef(intPtr2);
				}
			}
			finally
			{
				if (objectClass != IntPtr.Zero)
				{
					AndroidJNI.DeleteLocalRef(objectClass);
				}
			}
		}

		private void ReleaseAll()
		{
			_started = false;
			if (_codec != null)
			{
				try
				{
					if (_codecStarted)
					{
						_codec.Call("stop", (Il2CppReferenceArray<Object>)null);
					}
				}
				catch
				{
				}
				try
				{
					_codec.Call("release", (Il2CppReferenceArray<Object>)null);
				}
				catch
				{
				}
				try
				{
					_codec.Dispose();
				}
				catch
				{
				}
			}
			_codec = null;
			_codecStarted = false;
			if (_muxer != null)
			{
				try
				{
					if (_muxerStarted)
					{
						_muxer.Call("stop", (Il2CppReferenceArray<Object>)null);
					}
				}
				catch
				{
				}
				try
				{
					_muxer.Call("release", (Il2CppReferenceArray<Object>)null);
				}
				catch
				{
				}
				try
				{
					_muxer.Dispose();
				}
				catch
				{
				}
			}
			_muxer = null;
			_muxerStarted = false;
			_trackIndex = -1;
			if (_bufferInfo != null)
			{
				try
				{
					_bufferInfo.Dispose();
				}
				catch
				{
				}
				_bufferInfo = null;
			}
			_nv12 = null;
		}

		private static void RgbaToNv12Flipped(byte[] rgba, byte[] nv12, int width, int height)
		{
			int num = width * height;
			for (int i = 0; i < height; i++)
			{
				int num2 = (height - 1 - i) * width * 4;
				int num3 = i * width;
				for (int j = 0; j < width; j++)
				{
					int num4 = num2 + j * 4;
					int num5 = rgba[num4];
					int num6 = rgba[num4 + 1];
					int num7 = rgba[num4 + 2];
					int value = (66 * num5 + 129 * num6 + 25 * num7 + 128 >> 8) + 16;
					nv12[num3 + j] = (byte)ClampByte(value);
				}
			}
			int num8 = num;
			for (int k = 0; k < height; k += 2)
			{
				int y = height - 1 - k;
				int y2 = Math.Max(0, height - 2 - k);
				for (int l = 0; l < width; l += 2)
				{
					int r = 0;
					int g = 0;
					int b = 0;
					AddRgb(rgba, width, y, l, ref r, ref g, ref b);
					AddRgb(rgba, width, y, Math.Min(l + 1, width - 1), ref r, ref g, ref b);
					AddRgb(rgba, width, y2, l, ref r, ref g, ref b);
					AddRgb(rgba, width, y2, Math.Min(l + 1, width - 1), ref r, ref g, ref b);
					int num9 = r >> 2;
					int num10 = g >> 2;
					int num11 = b >> 2;
					int value2 = (-38 * num9 - 74 * num10 + 112 * num11 + 128 >> 8) + 128;
					int value3 = (112 * num9 - 94 * num10 - 18 * num11 + 128 >> 8) + 128;
					nv12[num8++] = (byte)ClampByte(value2);
					nv12[num8++] = (byte)ClampByte(value3);
				}
			}
		}

		private static void AddRgb(byte[] rgba, int width, int y, int x, ref int r, ref int g, ref int b)
		{
			int num = (y * width + x) * 4;
			r += rgba[num];
			g += rgba[num + 1];
			b += rgba[num + 2];
		}

		private static int ClampByte(int value)
		{
			if (value < 0)
			{
				return 0;
			}
			if (value > 255)
			{
				return 255;
			}
			return value;
		}
	}
}