Exemplo n.º 1
0
        public async Task RefreshVideoCaptureFormatsAsync(VideoCaptureDeviceInfo item)
        {
            var formats = new CollectionViewModel <VideoCaptureFormatViewModel>();

            if (item != null)
            {
                IReadOnlyList <VideoCaptureFormat> formatsList;
                string profileId = VideoProfiles.SelectedItem?.uniqueId;
                if (string.IsNullOrEmpty(profileId))
                {
                    // Device doesn't support video profiles; fall back on flat list of capture formats.
                    formatsList = await DeviceVideoTrackSource.GetCaptureFormatsAsync(item.Id);
                }
                else
                {
                    // Enumerate formats for the specified profile only
                    formatsList = await DeviceVideoTrackSource.GetCaptureFormatsAsync(item.Id, profileId);
                }
                foreach (var format in formatsList)
                {
                    formats.Add(new VideoCaptureFormatViewModel
                    {
                        Format = format,
                        FormatEncodingDisplayName = FourCCToString(format.fourcc)
                    });
                }
            }
            VideoCaptureFormats = formats;

            // Select first item for convenience
            VideoCaptureFormats.SelectFirstItemIfAny();
        }
Exemplo n.º 2
0
    async void Start()
    {
        deviceList = await DeviceVideoTrackSource.GetCaptureDevicesAsync();

        Debug.Log($"Found {deviceList.Count} devices.");
        foreach (var device in deviceList)
        {
            Debug.Log($"Found webcam {device.name} (id: {device.id}):");
            var profiles = await DeviceVideoTrackSource.GetCaptureProfilesAsync(device.id);

            if (profiles.Count > 0)
            {
                foreach (var profile in profiles)
                {
                    Debug.Log($"+ Profile '{profile.uniqueId}'");
                    var configs = await DeviceVideoTrackSource.GetCaptureFormatsAsync(device.id, profile.uniqueId);

                    foreach (var config in configs)
                    {
                        Debug.Log($"  - {config.width}x{config.height}@{config.framerate}");
                    }
                }
            }
            else
            {
                var configs = await DeviceVideoTrackSource.GetCaptureFormatsAsync(device.id);

                foreach (var config in configs)
                {
                    Debug.Log($"- {config.width}x{config.height}@{config.framerate}");
                }
            }
        }

        // Setup signaling
        Debug.Log("Starting signaling...");
        switch (ConnectionType)
        {
        case SignalerType.TCP:
            signaler = new TCPSignaler(Port);
            break;

        case SignalerType.WebSocket:
            signaler = new WebSocketSignaler(Port);
            break;

        default:
            throw new System.Exception($"Signaler connection type {ConnectionType} is not valid!");
        }
        signaler.ClientConnected    += OnClientConnected;
        signaler.ClientDisconnected += OnClientDisconnected;
        if (UseRemoteStun)
        {
            signaler.IceServers.Add(new IceServer {
                Urls = { "stun:stun.l.google.com:19302" }
            });
        }
        signaler.Start();
    }
Exemplo n.º 3
0
        public async Task VideoDeviceSelection()
        {
            Console.WriteLine("Select availiable video device:");
            var devices_list = await DeviceVideoTrackSource.GetCaptureDevicesAsync();

            var VideoDevice = ApplicationInterface.VideoDeviceSelector(devices_list);

            Console.WriteLine("Select video format:");
            var formats_list = await DeviceVideoTrackSource.GetCaptureFormatsAsync(VideoDevice.id);

            var SelectedFormat = ApplicationInterface.CapturingFormatSelector(formats_list);

            SystemConfiguration.VideoDeviceSettings.framerate = SelectedFormat.framerate;
            SystemConfiguration.VideoDeviceSettings.height    = SelectedFormat.height;
            SystemConfiguration.VideoDeviceSettings.width     = SelectedFormat.width;
            Source = await Camera.CreateAsync(SystemConfiguration.VideoDeviceSettings);
        }
Exemplo n.º 4
0
        public async Task EnumVideoFormats()
        {
            List <VideoCaptureDevice> devices = await DeviceVideoTrackSource.GetCaptureDevicesAsync();

            if (devices.Count == 0)
            {
                Assert.Inconclusive("Host device has no available video capture device.");
            }
            foreach (var device in devices)
            {
                List <VideoCaptureFormat> formats = await DeviceVideoTrackSource.GetCaptureFormatsAsync(device.id);

                foreach (var format in formats)
                {
                    Assert.That(format.width, Is.GreaterThan(0));
                    Assert.That(format.height, Is.GreaterThan(0));
                    Assert.That(format.framerate, Is.GreaterThan(0.0));
                }
            }
        }
Exemplo n.º 5
0
        private static async Task VideoDeviceSelection()
        {
            Console.WriteLine("Select availiable video device:");
            SystemConfiguration.VideoDeviceSettings = new LocalVideoDeviceInitConfig();
            int i           = 0;
            var device_list = (await DeviceVideoTrackSource.GetCaptureDevicesAsync()).ToList();

            foreach (var device in device_list)
            {
                Console.WriteLine("{0}: Name: {1} ID: ", i, device.name, device.id);
                i++;
            }
            int Selected = 0;

            while ((Selected = Convert.ToInt32(Console.ReadLine())) >= device_list.Count() && Selected < 0)
            {
                Console.WriteLine("Unknown device, try again.");
            }
            Console.WriteLine("Select video format");
            var formats_list = (await DeviceVideoTrackSource.GetCaptureFormatsAsync(device_list[0].id)).ToList();

            SystemConfiguration.VideoDeviceSettings.videoDevice = device_list[Selected];
            i        = 0;
            Selected = 0;
            foreach (var format in await DeviceVideoTrackSource.GetCaptureFormatsAsync(device_list[0].id))
            {
                Console.WriteLine("{0}: Framerate: {1} Width: {2}, Height: {3}", i, format.framerate, format.width, format.height);
                i++;
            }
            while ((Selected = Convert.ToInt32(Console.ReadLine())) >= formats_list.Count() && Selected < 0)
            {
                Console.WriteLine("Unknown format, try again.");
            }
            var SelectedFormat = formats_list[Selected];

            SystemConfiguration.VideoDeviceSettings.framerate = SelectedFormat.framerate;
            SystemConfiguration.VideoDeviceSettings.height    = SelectedFormat.height;
            SystemConfiguration.VideoDeviceSettings.width     = SelectedFormat.width;
        }
        public async Task RefreshVideoCaptureFormatsAsync(VideoCaptureDeviceInfo item)
        {
            var formats = new CollectionViewModel <VideoCaptureFormatViewModel>();

            if (item != null)
            {
                if (MediaCapture.IsVideoProfileSupported(item.Id))
                {
                    foreach (var desc in VideoProfiles.SelectedItem?.SupportedRecordMediaDescription)
                    {
                        var formatVM = new VideoCaptureFormatViewModel();
                        formatVM.Format.width     = desc.Width;
                        formatVM.Format.height    = desc.Height;
                        formatVM.Format.framerate = desc.FrameRate;
                        //formatVM.Format.fourcc = desc.Subtype; // TODO: string => FOURCC
                        formatVM.FormatEncodingDisplayName = desc.Subtype;
                        formats.Add(formatVM);
                    }
                }
                else
                {
                    // Device doesn't support video profiles; fall back on flat list of capture formats.
                    List <VideoCaptureFormat> formatsList = await DeviceVideoTrackSource.GetCaptureFormatsAsync(item.Id);

                    foreach (var format in formatsList)
                    {
                        formats.Add(new VideoCaptureFormatViewModel
                        {
                            Format = format,
                            FormatEncodingDisplayName = FourCCToString(format.fourcc)
                        });
                    }
                }
            }
            VideoCaptureFormats = formats;

            // Select first item for convenience
            VideoCaptureFormats.SelectFirstItemIfAny();
        }
Exemplo n.º 7
0
        protected async void OnEnable()
        {
            if (Source != null)
            {
                return;
            }

#if PLATFORM_ANDROID
            // Ensure Android binding is initialized before accessing the native implementation
            Android.Initialize();

            // Check for permission to access the camera
            if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
            {
                if (!_androidCameraRequestPending)
                {
                    // Monitor the OnApplicationFocus(true) event during the next 5 minutes,
                    // and check for permission again each time (see below why).
                    _androidCameraRequestPending        = true;
                    _androidCameraRequestRetryUntilTime = Time.time + 300;

                    // Display dialog requesting user permission. This will return immediately,
                    // and unfortunately there's no good way to tell when this completes. As a rule
                    // of thumb, application should lose focus, so check when focus resumes should
                    // be sufficient without having to poll every frame.
                    Permission.RequestUserPermission(Permission.Camera);
                }
                return;
            }
#elif UNITY_WSA && !UNITY_EDITOR
            // Request UWP access to video capture. The OS may show some popup dialog to the
            // user to request permission. This will succeed only if the user grants permission.
            try
            {
                // Note that the UWP UI thread and the main Unity app thread are always different.
                // https://docs.unity3d.com/Manual/windowsstore-appcallbacks.html
                // We leave the code below as an example of generic handling in case this would be used in
                // some other place, and in case a future version of Unity decided to change that assumption,
                // but currently OnEnable() is always invoked from the main Unity app thread so here the first
                // branch is never taken.
                if (UnityEngine.WSA.Application.RunningOnUIThread())
                {
                    await RequestAccessAsync();
                }
                else
                {
                    UnityEngine.WSA.Application.InvokeOnUIThread(() => RequestAccessAsync(), waitUntilDone: true);
                }
            }
            catch (Exception ex)
            {
                // Log an error and prevent activation
                Debug.LogError($"Video access failure: {ex.Message}.");
                this.enabled = false;
                return;
            }
#endif

            // Handle automatic capture format constraints
            string videoProfileId   = VideoProfileId;
            var    videoProfileKind = VideoProfileKind;
            int    width            = Constraints.width;
            int    height           = Constraints.height;
            double framerate        = Constraints.framerate;
#if ENABLE_WINMD_SUPPORT
            if (FormatMode == LocalVideoSourceFormatMode.Automatic)
            {
                // Do not constrain resolution by default, unless the device calls for it (see below).
                width  = 0; // auto
                height = 0; // auto

                // Avoid constraining the framerate; this is generally not necessary (formats are listed
                // with higher framerates first) and is error-prone as some formats report 30.0 FPS while
                // others report 29.97 FPS.
                framerate = 0; // auto

                // For HoloLens, use video profile to reduce resolution and save power/CPU/bandwidth
                if (global::Windows.Graphics.Holographic.HolographicSpace.IsAvailable)
                {
                    if (!global::Windows.Graphics.Holographic.HolographicDisplay.GetDefault().IsOpaque)
                    {
                        if (global::Windows.ApplicationModel.Package.Current.Id.Architecture == global::Windows.System.ProcessorArchitecture.X86)
                        {
                            // Holographic AR (transparent) x86 platform - Assume HoloLens 1
                            videoProfileKind = WebRTC.VideoProfileKind.VideoRecording; // No profile in VideoConferencing
                            width            = 896;                                    // Target 896 x 504
                        }
                        else
                        {
                            // Holographic AR (transparent) non-x86 platform - Assume HoloLens 2
                            videoProfileKind = WebRTC.VideoProfileKind.VideoConferencing;
                            width            = 960; // Target 960 x 540
                        }
                    }
                }
            }
#elif PLATFORM_ANDROID
            if (FormatMode == LocalVideoSourceFormatMode.Automatic)
            {
                // Avoid constraining the framerate; this is generally not necessary (formats are listed
                // with higher framerates first) and is error-prone as some formats report 30.0 FPS while
                // others report 29.97 FPS.
                framerate = 0; // auto

                string deviceId = WebcamDevice.id;
                if (string.IsNullOrEmpty(deviceId))
                {
                    List <VideoCaptureDevice> listedDevices = await PeerConnection.GetVideoCaptureDevicesAsync();

                    if (listedDevices.Count > 0)
                    {
                        deviceId = listedDevices[0].id;
                    }
                }
                if (!string.IsNullOrEmpty(deviceId))
                {
                    // Find the closest format to 720x480, independent of framerate
                    List <VideoCaptureFormat> formats = await DeviceVideoTrackSource.GetCaptureFormatsAsync(deviceId);

                    double smallestDiff = double.MaxValue;
                    bool   hasFormat    = false;
                    foreach (var fmt in formats)
                    {
                        double diff = Math.Abs(fmt.width - 720) + Math.Abs(fmt.height - 480);
                        if ((diff < smallestDiff) || !hasFormat)
                        {
                            hasFormat    = true;
                            smallestDiff = diff;
                            width        = (int)fmt.width;
                            height       = (int)fmt.height;
                        }
                    }
                    if (hasFormat)
                    {
                        Debug.Log($"WebcamSource automated mode selected resolution {width}x{height} for Android video capture device #{deviceId}.");
                    }
                }
            }
#endif

            // TODO - Fix codec selection (was as below before change)

            // Force again PreferredVideoCodec right before starting the local capture,
            // so that modifications to the property done after OnPeerInitialized() are
            // accounted for.
            //< FIXME
            //PeerConnection.Peer.PreferredVideoCodec = PreferredVideoCodec;

            // Check H.264 requests on Desktop (not supported)
            //#if !ENABLE_WINMD_SUPPORT
            //            if (PreferredVideoCodec == "H264")
            //            {
            //                Debug.LogError("H.264 encoding is not supported on Desktop platforms. Using VP8 instead.");
            //                PreferredVideoCodec = "VP8";
            //            }
            //#endif

            // Create the track
            var deviceConfig = new LocalVideoDeviceInitConfig
            {
                videoDevice                 = WebcamDevice,
                videoProfileId              = videoProfileId,
                videoProfileKind            = videoProfileKind,
                width                       = (width > 0 ? (uint?)width : null),
                height                      = (height > 0 ? (uint?)height : null),
                framerate                   = (framerate > 0 ? (double?)framerate : null),
                enableMrc                   = EnableMixedRealityCapture,
                enableMrcRecordingIndicator = EnableMRCRecordingIndicator
            };
            try
            {
                var source = await DeviceVideoTrackSource.CreateAsync(deviceConfig);

                AttachSource(source);
            }
            catch (Exception ex)
            {
                Debug.LogError($"Failed to create device track source for {nameof(WebcamSource)} component '{name}'.");
                Debug.LogException(ex, this);
                return;
            }
        }
        // This method might be run outside the app thread and should not access the Unity API.
        private static async Task <WebRTC.VideoTrackSource> CreateSourceAsync(
            LocalVideoSourceFormatMode formatMode, LocalVideoDeviceInitConfig deviceConfig)
        {
            // Handle automatic capture format constraints
#if ENABLE_WINMD_SUPPORT
            if (formatMode == LocalVideoSourceFormatMode.Automatic)
            {
                // Do not constrain resolution by default, unless the device calls for it (see below).
                deviceConfig.width  = 0; // auto
                deviceConfig.height = 0; // auto

                // Avoid constraining the framerate; this is generally not necessary (formats are listed
                // with higher framerates first) and is error-prone as some formats report 30.0 FPS while
                // others report 29.97 FPS.
                deviceConfig.framerate = 0; // auto

                // For HoloLens, use video profile to reduce resolution and save power/CPU/bandwidth
                if (global::Windows.Graphics.Holographic.HolographicSpace.IsAvailable)
                {
                    if (!global::Windows.Graphics.Holographic.HolographicDisplay.GetDefault().IsOpaque)
                    {
                        if (global::Windows.ApplicationModel.Package.Current.Id.Architecture == global::Windows.System.ProcessorArchitecture.X86)
                        {
                            // Holographic AR (transparent) x86 platform - Assume HoloLens 1
                            deviceConfig.videoProfileKind = WebRTC.VideoProfileKind.VideoRecording; // No profile in VideoConferencing
                            deviceConfig.width            = 896;                                    // Target 896 x 504
                        }
                        else
                        {
                            // Holographic AR (transparent) non-x86 platform - Assume HoloLens 2
                            deviceConfig.videoProfileKind = WebRTC.VideoProfileKind.VideoConferencing;
                            deviceConfig.width            = 960; // Target 960 x 540
                        }
                    }
                }
            }
#elif !UNITY_EDITOR && UNITY_ANDROID
            if (formatMode == LocalVideoSourceFormatMode.Automatic)
            {
                // Avoid constraining the framerate; this is generally not necessary (formats are listed
                // with higher framerates first) and is error-prone as some formats report 30.0 FPS while
                // others report 29.97 FPS.
                deviceConfig.framerate = 0; // auto

                string deviceId = deviceConfig.videoDevice.id;
                if (string.IsNullOrEmpty(deviceId))
                {
                    // Continue the task outside the Unity app context, in order to avoid deadlock
                    // if OnDisable waits on this task.
                    IReadOnlyList <VideoCaptureDevice> listedDevices =
                        await PeerConnection.GetVideoCaptureDevicesAsync()
                        .ConfigureAwait(continueOnCapturedContext: false);

                    if (listedDevices.Count > 0)
                    {
                        deviceId = listedDevices[0].id;
                    }
                }
                if (!string.IsNullOrEmpty(deviceId))
                {
                    // Find the closest format to 720x480, independent of framerate
                    // Continue the task outside the Unity app context, in order to avoid deadlock
                    // if OnDisable waits on this task.
                    IReadOnlyList <VideoCaptureFormat> formats =
                        await DeviceVideoTrackSource.GetCaptureFormatsAsync(deviceId)
                        .ConfigureAwait(continueOnCapturedContext: false);

                    double smallestDiff = double.MaxValue;
                    bool   hasFormat    = false;
                    foreach (var fmt in formats)
                    {
                        double diff = Math.Abs(fmt.width - 720) + Math.Abs(fmt.height - 480);
                        if ((diff < smallestDiff) || !hasFormat)
                        {
                            hasFormat           = true;
                            smallestDiff        = diff;
                            deviceConfig.width  = fmt.width;
                            deviceConfig.height = fmt.height;
                        }
                    }
                    if (hasFormat)
                    {
                        Debug.Log($"WebcamSource automated mode selected resolution {deviceConfig.width}x{deviceConfig.height} for Android video capture device #{deviceId}.");
                    }
                }
            }
#endif

            // TODO - Fix codec selection (was as below before change)

            // Force again PreferredVideoCodec right before starting the local capture,
            // so that modifications to the property done after OnPeerInitialized() are
            // accounted for.
            //< FIXME
            //PeerConnection.Peer.PreferredVideoCodec = PreferredVideoCodec;

            // Check H.264 requests on Desktop (not supported)
            //#if !ENABLE_WINMD_SUPPORT
            //            if (PreferredVideoCodec == "H264")
            //            {
            //                Debug.LogError("H.264 encoding is not supported on Desktop platforms. Using VP8 instead.");
            //                PreferredVideoCodec = "VP8";
            //            }
            //#endif

            // Create the track
            var createTask = DeviceVideoTrackSource.CreateAsync(deviceConfig);

            // Continue the task outside the Unity app context, in order to avoid deadlock
            // if OnDisable waits on this task.
            return(await createTask.ConfigureAwait(continueOnCapturedContext : false));
        }