Camera Information System
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

286 lines
7.7 KiB

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 VideoSourceToken { get; set; }
protected string SteamUrl { 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<bool> 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;
break;
}
}
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<string> GetStreamUrl()
{
if (string.IsNullOrEmpty(SteamUrl))
{
MediaUri mediaUri = await Media.GetStreamUriAsync(RtspStreamSetup, ProfileToken);
SteamUrl = mediaUri.Uri.Replace("://", $"://{Username}:{Password}@");
}
return SteamUrl;
}
public async Task<string> GetSnapshotUrl()
{
if (string.IsNullOrEmpty(SnapshotUrl))
{
MediaUri mediaUri = await Media.GetSnapshotUriAsync(ProfileToken);
SnapshotUrl = mediaUri.Uri.Replace("://", $"://{Username}:{Password}@");
}
return SnapshotUrl;
}
public async Task<string> 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;
}
/// <summary>
/// 绝对移动
/// </summary>
/// <param name="pan"></param>
/// <param name="tilt"></param>
/// <param name="zoom"></param>
/// <param name="atomDist"></param>
/// <returns></returns>
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 }
});
}
/// <summary>
/// 相对移动
/// </summary>
/// <param name="pan">[-1,1]</param>
/// <param name="tilt">[-1,1]</param>
/// <param name="zoom">[-1,1]</param>
/// <param name="atomSpeed">[0,1]</param>
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 }
});
}
/// <summary>
/// 持续移动
/// </summary>
/// <param name="pan">[-1,1]</param>
/// <param name="tilt">[-1,1]</param>
/// <param name="zoom">[-1,1]</param>
/// <param name="timeout">ms</param>
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<PTZStatus> 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
}