using EC.Helper.Onvif.Common; using EC.Helper.Onvif.Device; using EC.Helper.Onvif.Imaging; using EC.Helper.Onvif.Media; using EC.Helper.Onvif.PTZ; using System.Net; using Capabilities = EC.Helper.Onvif.Common.Capabilities; namespace EC.Helper.Onvif; public class OnvifClient { #region Attr public string Hostname { get; private set; } public string Username { get; private set; } public string Password { get; private set; } #endregion Attr #region Client Attr protected DeviceClient Device { get; set; } protected MediaClient Media { get; set; } protected PTZClient PTZ { get; set; } protected ImagingClient Imaging { get; set; } protected Capabilities Caps { get; set; } #endregion Client Attr #region Cache Attr protected string ProfileToken { get; set; } protected string SubProfileToken { get; set; } protected string ThirdProfileToken { get; set; } protected string VideoSourceToken { get; set; } protected string SteamUrl { get; set; } protected string SubSteamUrl { get; set; } protected string ThirdSteamUrl { get; set; } protected string SnapshotUrl { get; set; } #endregion Cache Attr public OnvifClient(string hostname, string username, string password) { Hostname = hostname; Username = username; Password = password; } public async Task Init() { try { Device = await OnvifClientFactory.CreateDeviceClientAsync(Hostname, Username, Password); Media = await OnvifClientFactory.CreateMediaClientAsync(Hostname, Username, Password); PTZ = await OnvifClientFactory.CreatePTZClientAsync(Hostname, Username, Password); Imaging = await OnvifClientFactory.CreateImagingClientAsync(Hostname, Username, Password); var profiles = await Media.GetProfilesAsync(); var videoSources = await Media.GetVideoSourcesAsync(); foreach (var profile in profiles.Profiles) { if (string.IsNullOrEmpty(ProfileToken)) { ProfileToken = profile.token; } else if (string.IsNullOrEmpty(SubProfileToken)) { SubProfileToken = profile.token; } else if (string.IsNullOrEmpty(ThirdProfileToken)) { ThirdProfileToken = profile.token; break; } } if (string.IsNullOrEmpty(SubProfileToken)) SubProfileToken = ProfileToken; if (string.IsNullOrEmpty(ThirdProfileToken)) ThirdProfileToken = SubProfileToken; foreach (var source in videoSources.VideoSources) { if (string.IsNullOrEmpty(VideoSourceToken)) { VideoSourceToken = source.token; break; } } Caps = (await Device.GetCapabilitiesAsync(new CapabilityCategory[] { CapabilityCategory.All })).Capabilities; } catch (Exception) { return false; throw; } return true; } #region DeviceClient public bool IsDeviceContected() { return Device != null; } #endregion DeviceClient #region MediaClient public bool IsMediaContected() { bool ret = IsDeviceContected(); return ret; } protected StreamSetup RtspStreamSetup { get; } = new() { Stream = StreamType.RTPUnicast, Transport = new() { Protocol = TransportProtocol.RTSP } }; public async Task GetStreamUrl() { if (string.IsNullOrEmpty(SteamUrl)) { MediaUri mediaUri = await Media.GetStreamUriAsync(RtspStreamSetup, ProfileToken); SteamUrl = mediaUri.Uri.Replace("://", $"://{Username}:{Password}@"); } return SteamUrl; } public async Task GetSubStreamUrl() { if (string.IsNullOrEmpty(SubSteamUrl)) { MediaUri mediaUri = await Media.GetStreamUriAsync(RtspStreamSetup, SubProfileToken); SubSteamUrl = mediaUri.Uri.Replace("://", $"://{Username}:{Password}@"); } return SubSteamUrl; } public async Task GetThirdStreamUrl() { if (string.IsNullOrEmpty(ThirdSteamUrl)) { MediaUri mediaUri = await Media.GetStreamUriAsync(RtspStreamSetup, SubProfileToken); ThirdSteamUrl = mediaUri.Uri.Replace("://", $"://{Username}:{Password}@"); } return ThirdSteamUrl; } public async Task GetSnapshotUrl() { if (string.IsNullOrEmpty(SnapshotUrl)) { MediaUri mediaUri = await Media.GetSnapshotUriAsync(ProfileToken); SnapshotUrl = mediaUri.Uri.Replace("://", $"://{Username}:{Password}@"); } return SnapshotUrl; } public async Task GetSnapshot() { string url = await GetSnapshotUrl(); WebRequest request = WebRequest.Create(url); request.Method = "GET"; request.PreAuthenticate = true; request.Credentials = new NetworkCredential(Username, Password); using HttpWebResponse response = (HttpWebResponse)request.GetResponse(); using Stream stream = response.GetResponseStream(); using MemoryStream mStream = new(); byte[] buffer = new byte[1024]; int byteCount; do { byteCount = stream.Read(buffer, 0, buffer.Length); mStream.Write(buffer, 0, byteCount); } while (byteCount > 0); mStream.Position = 0; return Convert.ToBase64String(mStream.ToArray()); } #endregion MediaClient #region PTZClient public bool IsPTZContected() { bool ret = IsDeviceContected() && (PTZ != null) && !string.IsNullOrEmpty(ProfileToken); return ret; } /// /// 绝对移动 /// /// /// /// /// /// public async Task AbsoluteMove(float pan, float tilt, float zoom, float atomDist = 0.1f) { await PTZ.AbsoluteMoveAsync(ProfileToken, new PTZVector { PanTilt = new Vector2D { x = pan, y = tilt }, Zoom = new Vector1D { x = zoom } }, new PTZSpeed { PanTilt = new Vector2D { x = atomDist, y = atomDist }, Zoom = new Vector1D { x = atomDist } }); } /// /// 相对移动 /// /// [-1,1] /// [-1,1] /// [-1,1] /// [0,1] public async Task RelativeMove(float pan, float tilt, float zoom, float atomSpeed = 0.1f) { await PTZ.RelativeMoveAsync(ProfileToken, new PTZVector { PanTilt = new Vector2D { x = pan, y = tilt }, Zoom = new Vector1D { x = zoom } }, new PTZSpeed { PanTilt = new Vector2D { x = atomSpeed, y = atomSpeed }, Zoom = new Vector1D { x = atomSpeed } }); } /// /// 持续移动 /// /// [-1,1] /// [-1,1] /// [-1,1] /// ms public async Task ContinuousMove(float pan, float tilt, float zoom, string timeout = "") { await PTZ.ContinuousMoveAsync(ProfileToken, new PTZSpeed { PanTilt = new Vector2D { x = pan, y = tilt }, Zoom = new Vector1D { x = zoom } }, timeout); } public async Task StopMove() { await PTZ.StopAsync(ProfileToken, true, true); } public async Task GetStatus() { return await PTZ.GetStatusAsync(ProfileToken); } #endregion PTZClient #region ImagingClient public bool IsImagingContected() { bool ret = IsDeviceContected(); return ret; } public async Task FocusAbsoluteMove(float position) { await Imaging.MoveAsync(VideoSourceToken, new FocusMove { Absolute = new AbsoluteFocus { Position = position, //Speed = 1f, //SpeedSpecified = true } }); } public async Task FocusRelativeMove(float distance) { await Imaging.MoveAsync(VideoSourceToken, new FocusMove { Relative = new RelativeFocus { Distance = distance, //Speed = 1f, //SpeedSpecified = true } }); } public async Task FocusContinuousMove(float speed) { await Imaging.MoveAsync(VideoSourceToken, new FocusMove { Continuous = new ContinuousFocus { Speed = speed } }); } public async Task FocusStopMove() { await Imaging.StopAsync(VideoSourceToken); } #endregion ImagingClient }