using System; using System.Diagnostics; using System.IO; using System.Net; using System.Runtime.InteropServices; using System.Text; using System.Collections; using System.Collections.Generic; using UnityEngine; // To use this, add the following entry to the dependencies in Packages\manifest.json: // "com.unity.nuget.newtonsoft-json": "2.0.0" using Newtonsoft.Json; namespace OpenSee { [Serializable] public enum OpenSeeWebcamType { Unknown = -1, DirectShow, Blackmagic }; [Serializable] public enum OpenSeeWebcamFormat { Any = 0, Unknown = 1, ARGB = 100, XRGB, I420 = 200, NV12, YV12, Y800, YVYU = 300, YUY2, UYVY, HDYC, MJPEG = 400, H264 }; [Serializable] public struct OpenSeeWebcamCapability { public int id; // DirectShow public int minCX; public int minCY; public int maxCX; public int maxCY; public int granularityCX; public int granularityCY; public int minInterval; public int maxInterval; public int rating; public OpenSeeWebcamFormat format; // Blackmagic public int bmTimescale; public int bmFrameduration; public int bmModecode; } [Serializable] public class OpenSeeWebcam { public OpenSeeWebcamType type = OpenSeeWebcamType.Unknown; public int id; public string name; // DirectShow public string path; // Blackmagic public long bmId; public int bmFlags; // General public OpenSeeWebcamCapability[] caps; public List prettyCaps = null; private List> splitCaps = null; private int CompareCaps(OpenSeeWebcamCapability a, OpenSeeWebcamCapability b) { if (a.rating < b.rating) return -1; if (a.rating > b.rating) return 1; if (a.minCX * a.minCY > b.minCX * b.minCY) return -1; if (a.minCX * a.minCY < b.minCX * b.minCY) return 1; if (a.minInterval < b.minInterval) return -1; if (a.minInterval > b.minInterval) return 1; return 0; } private string GetPrettyCapability(OpenSeeWebcamCapability cap) { float fps = 10000000f / (float)cap.minInterval; string prettyCap = cap.minCX + "x" + cap.minCY + ", " + fps.ToString("0.##") + "fps (" + cap.format.ToString() + ")"; return prettyCap; } public List GetPrettyCapabilities() { if (splitCaps != null && prettyCaps != null) return prettyCaps; splitCaps = new List>(); for (int i = 0; i < caps.Length; i++) { if (caps[i].minCX == caps[i].maxCX && caps[i].minCY == caps[i].maxCY) splitCaps.Add(new Tuple(caps[i], i)); else { OpenSeeWebcamCapability min = caps[i]; OpenSeeWebcamCapability max = caps[i]; min.maxCX = min.minCX; min.maxCY = min.minCY; max.minCX = max.maxCX; max.minCY = max.maxCY; splitCaps.Add(new Tuple(min, i)); splitCaps.Add(new Tuple(max, i)); } } splitCaps.Sort((a, b) => CompareCaps(a.Item1, b.Item1)); prettyCaps = new List(); foreach (var cap in splitCaps) { prettyCaps.Add(GetPrettyCapability(cap.Item1)); } return prettyCaps; } public OpenSeeWebcamCapability GetCapabilityByPrettyIndex(int index) { if (splitCaps == null || index >= splitCaps.Count) throw new InvalidOperationException("Invalid capability index."); return caps[splitCaps[index].Item2]; } } [DefaultExecutionOrder(-50)] public class OpenSeeWebcamInfo : MonoBehaviour { #region DllImport [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")] private static extern System.IntPtr create_capture_x64(); [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")] private static extern int get_json_length_x64(System.IntPtr cap); [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")] private static extern void get_json_x64(System.IntPtr cap, [Out] StringBuilder namebuffer, int bufferlength); [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")] private static extern void destroy_capture_x64(System.IntPtr cap); [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")] private static extern System.IntPtr create_capture_x86(); [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")] private static extern int get_json_length_x86(System.IntPtr cap); [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")] private static extern void get_json_x86(System.IntPtr cap, [Out] StringBuilder namebuffer, int bufferlength); [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")] private static extern void destroy_capture_x86(System.IntPtr cap); /* Blackmagic */ [DllImport("libminibmcapture64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")] private static extern int bm_get_json_length_x64(); [DllImport("libminibmcapture64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")] private static extern void bm_get_json_x64([Out] StringBuilder namebuffer, int bufferlength); [DllImport("libminibmcapture32", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")] private static extern int bm_get_json_length_x86(); [DllImport("libminibmcapture32", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")] private static extern void bm_get_json_x86([Out] StringBuilder namebuffer, int bufferlength); #endregion public List cameras; private bool initialized = false; static private string ListCameraDetails_x64() { System.IntPtr cap = create_capture_x64(); int length = get_json_length_x64(cap); StringBuilder buffer = new StringBuilder(length); get_json_x64(cap, buffer, length); destroy_capture_x64(cap); return buffer.ToString(); } static private string ListCameraDetails_x86() { System.IntPtr cap = create_capture_x86(); int length = get_json_length_x86(cap); StringBuilder buffer = new StringBuilder(length); get_json_x86(cap, buffer, length); destroy_capture_x86(cap); return buffer.ToString(); } static private string ListBlackMagicDetails_x64() { int length = bm_get_json_length_x64(); StringBuilder buffer = new StringBuilder(length); bm_get_json_x64(buffer, length); return buffer.ToString(); } static private string ListBlackMagicDetails_x86() { int length = bm_get_json_length_x86(); StringBuilder buffer = new StringBuilder(length); bm_get_json_x86(buffer, length); return buffer.ToString(); } static public List ListCameraDetails() { string jsonData; string bmJsonData; if (Environment.Is64BitProcess) { jsonData = ListCameraDetails_x64(); bmJsonData = ListBlackMagicDetails_x64(); } else { jsonData = ListCameraDetails_x86(); bmJsonData = ListBlackMagicDetails_x86(); } List details = JsonConvert.DeserializeObject>(jsonData); foreach (var cam in details) cam.type = OpenSeeWebcamType.DirectShow; List bmDetails = JsonConvert.DeserializeObject>(bmJsonData); foreach (var cam in bmDetails) cam.type = OpenSeeWebcamType.Blackmagic; details.AddRange(bmDetails); return details; } void Start() { Initialize(); } public void Initialize() { if (initialized) return; initialized = true; cameras = ListCameraDetails(); foreach (var camera in cameras) camera.GetPrettyCapabilities(); } } }