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)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)delegate(float value) { Cameras.SetFov(value); }); obj3.CreateFloat("Position Smooth", val2, 8f, 0.5f, 0f, 30f, (Action)delegate(float value) { Cameras.SetPositionSmooth(value); }); obj3.CreateFloat("Rotation Smooth", val2, 10f, 0.5f, 0f, 30f, (Action)delegate(float value) { Cameras.SetRotationSmooth(value); }); obj3.CreateFloat("Shake", val2, 0f, 0.01f, 0f, 0.35f, (Action)delegate(float value) { Cameras.SetShake(value); }); obj3.CreateFloat("Near Clip", val2, 0.03f, 0.01f, 0.01f, 1f, (Action)delegate(float value) { Cameras.SetNearClip(value); }); obj3.CreateFloat("Far Clip", val2, 1000f, 25f, 50f, 4000f, (Action)delegate(float value) { Cameras.SetFarClip(value); }); Page obj4 = _root.CreatePage("Video", val, 0, true); obj4.CreateEnum("Resolution", val2, (Enum)ResolutionPreset.Q2Safe, (Action)delegate(Enum value) { Video.ApplyPreset((ResolutionPreset)(object)value); }); obj4.CreateFloat("Custom Width", val2, (float)Video.Width, 16f, 320f, 3840f, (Action)delegate(float value) { Video.Width = MakeEven((int)value); }); obj4.CreateFloat("Custom Height", val2, (float)Video.Height, 16f, 180f, 2160f, (Action)delegate(float value) { Video.Height = MakeEven((int)value); }); obj4.CreateFloat("FPS", val2, (float)Video.Fps, 1f, 15f, 120f, (Action)delegate(float value) { Video.Fps = Mathf.Clamp((int)value, 15, 120); }); obj4.CreateFloat("Bitrate Mbps", val2, Video.BitrateMbps, 0.5f, 1f, 80f, (Action)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 _cameras = new List(); 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(); if ((Object)(object)component != (Object)null) { component.isTrigger = false; } cineCamera._rigidbody = cineCamera.Root.AddComponent(); 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(); 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(); if ((Object)(object)component3 != (Object)null) { Object.Destroy((Object)(object)component3); } Renderer component4 = obj5.GetComponent(); 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(); 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(); if ((Object)(object)component5 != (Object)null) { Object.Destroy((Object)(object)component5); } MeshRenderer component6 = cineCamera.Monitor.GetComponent(); 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(); 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(); 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 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() : 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.op_Implicit((Il2CppArrayBase)(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("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("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.op_Implicit(array)); _codec.Call("start", (Il2CppReferenceArray)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)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.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.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.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.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)null); _muxerStarted = true; } finally { if (codecOutputFormat != IntPtr.Zero) { AndroidJNI.DeleteLocalRef(codecOutputFormat); } } } else { if (num2 < 0) { continue; } int num3 = _bufferInfo.Get("offset"); int num4 = _bufferInfo.Get("size"); int num5 = _bufferInfo.Get("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.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.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.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.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.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.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.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.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.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)null); } } catch { } try { _codec.Call("release", (Il2CppReferenceArray)null); } catch { } try { _codec.Dispose(); } catch { } } _codec = null; _codecStarted = false; if (_muxer != null) { try { if (_muxerStarted) { _muxer.Call("stop", (Il2CppReferenceArray)null); } } catch { } try { _muxer.Call("release", (Il2CppReferenceArray)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; } } }