private static string GetInputFps(LocalVideoSourceCapability cap, int fps) { int result = -1; if (cap.MinF <= fps && fps <= cap.MaxF) { result = fps; } else if (cap.MinF > fps && cap.MinF == Math.Round(cap.MinF, 0)) { result = (int)Math.Round(cap.MinF, 0); } else if (fps > cap.MaxF && cap.MaxF == Math.Round(cap.MaxF, 0)) { result = (int)Math.Round(cap.MaxF, 0); } if (result > 0) { return($"framerate{Eq}{result}{Sep}"); } else { return(""); } }
private static string GetVideoOptions(LocalVideoSourceCapability cap, int fps) { return($"video_size{Eq}{cap.W}x{cap.H}{Sep}" + GetInputFps(cap, fps) + $"fflags{Eq}nobuffer{Sep}" + GetFormatString(cap) + $"rtbufsize{Eq}{GetVideoBufferSize(cap.Fmt, cap.W)}"); }
private static int GetScore(LocalVideoSourceCapability c, int fps, Resolution resolution) { int score = 0; if (fps < c.MinF) { score -= ((int)c.MinF - fps); } else if (fps > c.MaxF) { score -= (fps - (int)c.MaxF) * 2; } if ((double)resolution.Height / resolution.Width != (double)c.H / c.W) { score -= 10; } double diff = (double)c.W / resolution.Width; if (diff < 1.0) //cap lower { score -= (int)((1.0 - diff) * 30); // half of width = -15 score } else { score -= (int)((diff - 1.0) * 15); // twice bigger = -15 score } switch (c.Fmt) { case LocalVideoSourceCapabilityFormat.Raw: break; case LocalVideoSourceCapabilityFormat.MJpeg: score -= 2; break; case LocalVideoSourceCapabilityFormat.I420: case LocalVideoSourceCapabilityFormat.NV12: score -= 3; break; case LocalVideoSourceCapabilityFormat.Empty: score -= 100; break; default: score -= 200; break; } return(score); }
private static string GetFormatString(LocalVideoSourceCapability cap) { switch (cap.Fmt) { case LocalVideoSourceCapabilityFormat.Raw: return($"pixel_format{Eq}yuyv422{Sep}"); case LocalVideoSourceCapabilityFormat.Empty: return($"pixel_format{Eq}bgr24{Sep}"); case LocalVideoSourceCapabilityFormat.MJpeg: return($"vcodec{Eq}mjpeg{Sep}"); case LocalVideoSourceCapabilityFormat.I420: return($"pixel_format{Eq}yuv420p{Sep}"); case LocalVideoSourceCapabilityFormat.NV12: return($"pixel_format{Eq}nv12{Sep}"); default: return(""); } }
private (LocalVideoSourceCapability[] caps, InputDeviceState state) GetCapabilities(DsDevice device) { if (_initialLogging) { Log.Information($"Caps {device.Name}: getting"); } var list = new List <LocalVideoSourceCapability>(); IntPtr pCaps = IntPtr.Zero; IFilterGraph2 filterGraph2 = null; IBaseFilter sourceFilter = null; IAMStreamConfig streamConfig = null; object pin = null; InputDeviceState state = InputDeviceState.Ready; try { filterGraph2 = new FilterGraph() as IFilterGraph2; if (filterGraph2 == null) { throw new NotSupportedException("filter2 is null"); } LocalVideoSourceManager.AddCaptureFilter(filterGraph2, device, out sourceFilter); pin = DsFindPin.ByCategory(sourceFilter, PinCategory.Capture, 0); if (pin == null) { pin = sourceFilter; } streamConfig = pin as IAMStreamConfig; if (streamConfig == null) { throw new NotSupportedException("pin is null"); } int count = 0; int size = 0; Checked(() => streamConfig.GetNumberOfCapabilities(out count, out size), "GetNumberOfCapabilities", null); if (count <= 0) { throw new NotSupportedException("This video source does not report capabilities."); } if (size != Marshal.SizeOf(typeof(VideoStreamConfigCaps))) { throw new NotSupportedException("Unable to retrieve video source capabilities. This video source requires a larger VideoStreamConfigCaps structure."); } // Alloc memory for structure pCaps = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(VideoStreamConfigCaps))); for (int i = 0; i < count; i++) { AMMediaType mediaType = null; Checked(() => streamConfig.GetStreamCaps(i, out mediaType, pCaps), "GetStreamCaps", null); VideoStreamConfigCaps caps = (VideoStreamConfigCaps)Marshal.PtrToStructure(pCaps, typeof(VideoStreamConfigCaps)); var format = GetMediaTypeInfo(mediaType, out var height, out var width, out var compression, out var videoInfoHeader, out var videoInfoHeader2); var result = new LocalVideoSourceCapability() { MaxF = GetFps(caps.MinFrameInterval), MinF = GetFps(caps.MaxFrameInterval), Fmt = format, W = width, H = height, }; list.Add(result); } } catch (UnauthorizedAccessException e) { Log.Warning(e, $"Error during retreiving caps for '{device.Name}' (Locked)"); state = InputDeviceState.Locked; } catch (Exception e) { Log.Error(e, $"Error during retreiving caps for '{device.Name}'"); state = InputDeviceState.Failed; } finally { if (pCaps != IntPtr.Zero) { Marshal.FreeCoTaskMem(pCaps); } } try { ReleaseComObject(sourceFilter); ReleaseComObject(filterGraph2); ReleaseComObject(streamConfig); ReleaseComObject(pin); } catch (Exception e) { Log.Error(e, $"ReleaseComObject('{device.Name}') failed"); } if (_initialLogging) { Log.Information($"Caps {device.Name}: {string.Join("; ", list.Select(s => s.ToString()))}"); } return(list.ToArray(), state); }