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.
603 lines
29 KiB
603 lines
29 KiB
using Application.Domain.Entities;
|
|
using Application.Models;
|
|
using Infrastructure.Data;
|
|
using Infrastructure.Extensions;
|
|
using IoT.Shared.Infrastructure;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace IoT.Shared.DeviceServices.Onvif
|
|
{
|
|
public class OnvifService : DeviceService
|
|
{
|
|
private readonly ConcurrentDictionary<string, (Device camera, Process local, Process remote)> _list = new ConcurrentDictionary<string, (Device camera, Process local, Process remote)>();
|
|
private readonly IWebHostEnvironment _env;
|
|
private readonly IHttpClientFactory _httpClientFactory;
|
|
private readonly IOnvifDeviceManagement _onvifDeviceManagement;
|
|
|
|
public OnvifService(IServiceProvider applicationServices, IConfiguration configuration, IWebHostEnvironment env, IHttpClientFactory httpClientFactory)
|
|
: base(applicationServices, configuration)
|
|
{
|
|
this._env = env;
|
|
this._httpClientFactory = httpClientFactory;
|
|
this._onvifDeviceManagement = new OnvifDeviceManagement(httpClientFactory);
|
|
}
|
|
|
|
public override void Execute()
|
|
{
|
|
try
|
|
{
|
|
Search();
|
|
Notify();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
|
|
public override Task StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
foreach (var item in this._list.Keys.ToList())
|
|
{
|
|
this.Remove(item);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
finally
|
|
{
|
|
Console.WriteLine($"{this.GetType().Name} Service Stopd");
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public void Search()
|
|
{
|
|
try
|
|
{
|
|
var list = this._onvifDeviceManagement.Discovery();
|
|
foreach (var ipCamera in list)
|
|
{
|
|
if (string.IsNullOrEmpty(ipCamera.Id) || string.IsNullOrEmpty(ipCamera.DeviceUrl))
|
|
{
|
|
continue;
|
|
}
|
|
Console.WriteLine(ipCamera.DeviceUrl);
|
|
try
|
|
{
|
|
using (var scope = _applicationServices.CreateScope())
|
|
{
|
|
var productNumber = "onvifcamera";
|
|
var categoryRepo = scope.ServiceProvider.GetService<IRepository<Category>>();
|
|
var productRepo = scope.ServiceProvider.GetService<IRepository<Product>>();
|
|
var product = productRepo.Table().Include(o => o.Apis).FirstOrDefault(o => o.Number == productNumber);
|
|
var category = categoryRepo.ReadOnlyTable().FirstOrDefault(o => o.Number == "10");
|
|
if (product == null)
|
|
{
|
|
product = new Product
|
|
{
|
|
Number = productNumber,
|
|
Name = "ONVIF摄像头",
|
|
ApiJson = this.GetApiJson("/Camera/"),
|
|
CategoryId = category.Id
|
|
};
|
|
OpenApiService.UpdateApi(product);
|
|
productRepo.Add(product);
|
|
productRepo.SaveChanges();
|
|
var productDto = product.To<EditProductModel>();
|
|
productDto.CategoryNumber = category.Number;
|
|
this.SendToServer(Methods.GetProductResponse, productDto);
|
|
}
|
|
var deviceNodeRepo = scope.ServiceProvider.GetService<IRepository<Node>>();
|
|
var node = deviceNodeRepo.ReadOnlyTable().FirstOrDefault();
|
|
|
|
var deviceRepo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
|
var device = deviceRepo.Table().Include(o => o.Data).FirstOrDefault(o => o.Number == ipCamera.Id);
|
|
if (device == null)
|
|
{
|
|
device = new Device
|
|
{
|
|
Name = "摄像头",
|
|
DisplayName = "摄像头",
|
|
Number = ipCamera.Id,
|
|
Ip = ipCamera.Ip,
|
|
Icon = "camera",
|
|
ProductId = product.Id,
|
|
NodeId = node.Id
|
|
};
|
|
var fileName = $"ffmpeg-{Helper.Instance.GetRunTime()}{(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "")}";
|
|
var file = Path.Combine(this._env.WebRootPath, fileName);
|
|
device.AddorUpdateData(device.CreateData("Push", "是", DeviceDataType.String, "推流"));
|
|
device.AddorUpdateData(device.CreateData("Record", "否", DeviceDataType.String, "录像"));
|
|
device.AddorUpdateData(device.CreateData("ffmpeg.file", file, DeviceDataType.String, "ffmpeg路径", hidden: true));
|
|
device.AddorUpdateData(device.CreateData("ffmpeg.args", this._configuration["ffmpeg.args"], DeviceDataType.String, "ffmpeg.args", hidden: true));
|
|
device.AddorUpdateData(device.CreateData("mainrtmp", $"rtmp://{this._configuration["stream.rtmp"]}/live/main{ipCamera.Id}", DeviceDataType.String, "主码流rtmp"));
|
|
device.AddorUpdateData(device.CreateData("mainflv", $"http://{this._configuration["stream.flv"]}/live/main{ipCamera.Id}.flv", DeviceDataType.String, "主码流flv"));
|
|
device.AddorUpdateData(device.CreateData("mainhls", $"http://{this._configuration["stream.hls"]}/live/main{ipCamera.Id}.m3u8", DeviceDataType.String, "主码流hls"));
|
|
device.AddorUpdateData(device.CreateData("subrtmp", $"rtmp://{this._configuration["stream.rtmp"]}/live/sub{ipCamera.Id}", DeviceDataType.String, "子码流rtmp"));
|
|
device.AddorUpdateData(device.CreateData("subflv", $"http://{this._configuration["stream.flv"]}/live/sub{ipCamera.Id}.flv", DeviceDataType.String, "子码流flv"));
|
|
device.AddorUpdateData(device.CreateData("subhls", $"http://{this._configuration["stream.hls"]}/live/sub{ipCamera.Id}.m3u8", DeviceDataType.String, "子码流hls"));
|
|
device.ConnectId = this._configuration["sn"];
|
|
deviceRepo.Add(device);
|
|
deviceRepo.SaveChanges();
|
|
}
|
|
var profiles = this._onvifDeviceManagement.GetProfiles(ipCamera.DeviceUrl, ipCamera.MediaUrl);
|
|
var needAuth = false;
|
|
var hasAuth = false;
|
|
if (profiles == "")
|
|
{
|
|
needAuth = true;
|
|
device.UserName = device.UserName ?? this._configuration["camera.usr"];
|
|
device.Password = device.Password ?? this._configuration["camera.pwd"];
|
|
profiles = this._onvifDeviceManagement.GetProfiles(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password);
|
|
if (profiles == "")
|
|
{
|
|
hasAuth = false;
|
|
}
|
|
else
|
|
{
|
|
hasAuth = true;
|
|
ipCamera.GetProfilesXml = profiles;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipCamera.GetProfilesXml = profiles;
|
|
}
|
|
ipCamera.ParseProfiles();
|
|
|
|
try
|
|
{
|
|
if (needAuth)
|
|
{
|
|
ipCamera.MainStreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, ipCamera.Profiles.First().Token);
|
|
ipCamera.MainSnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, ipCamera.Profiles.First().Token);
|
|
ipCamera.SubStreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, ipCamera.Profiles.Last().Token);
|
|
ipCamera.SubSnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, ipCamera.Profiles.Last().Token);
|
|
}
|
|
else
|
|
{
|
|
ipCamera.MainStreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, ipCamera.Profiles.First().Token);
|
|
ipCamera.MainSnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, ipCamera.Profiles.First().Token);
|
|
ipCamera.SubStreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, ipCamera.Profiles.Last().Token);
|
|
ipCamera.SubSnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, ipCamera.Profiles.Last().Token);
|
|
}
|
|
ipCamera.ParseStreamUri();
|
|
ipCamera.ParseSnapshotUri();
|
|
device.AddorUpdateData(device.CreateData("NeedAuth", needAuth ? "是" : "否", DeviceDataType.String, "需认证"));
|
|
device.AddorUpdateData(device.CreateData("HasAuth", hasAuth ? "是" : "否", DeviceDataType.String, "已认证"));
|
|
device.AddorUpdateData(device.CreateData("DeviceUrl", ipCamera.DeviceUrl, DeviceDataType.String, "设备地址"));
|
|
device.AddorUpdateData(device.CreateData("PtzAddress", ipCamera.PTZAddress, DeviceDataType.String, "云台地址"));
|
|
device.AddorUpdateData(device.CreateData("Ptz3DZoomSupport", ipCamera.Ptz3DZoomSupport ? "是" : "否", DeviceDataType.String, "缩放支持"));
|
|
device.AddorUpdateData(device.CreateData("MainToken", ipCamera.Profiles.First().Token, DeviceDataType.String, "主码流Token"));
|
|
device.AddorUpdateData(device.CreateData("SubToken", ipCamera.Profiles.Last().Token, DeviceDataType.String, "子码流Token"));
|
|
device.AddorUpdateData(device.CreateData("MainStreamUri", ipCamera.MainStreamUri, DeviceDataType.String, "主码流地址"));
|
|
device.AddorUpdateData(device.CreateData("MainSnapshotUri", ipCamera.MainSnapshotUri, DeviceDataType.String, "主码流截图地址"));
|
|
device.AddorUpdateData(device.CreateData("SubStreamUri", ipCamera.SubStreamUri, DeviceDataType.String, "子码流地址"));
|
|
device.AddorUpdateData(device.CreateData("SubSnapshotUri", ipCamera.SubSnapshotUri, DeviceDataType.String, "子码流截图地址"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack(ex.Message);
|
|
}
|
|
deviceRepo.SaveChanges();
|
|
var deviceDto = device.To<EditDeviceModel>();
|
|
deviceDto.ProductNumber = product.Number;
|
|
deviceDto.NodeNumber = node.Number;
|
|
this.SendToServer(Methods.EditDeviceResponse, deviceDto);
|
|
var dataList = new List<EditDataModel>();
|
|
foreach (var deviceData in device.Data.Where(o => !o.Hidden))
|
|
{
|
|
var dataDto = deviceData.To<EditDataModel>();
|
|
dataDto.DeviceNumber = device.Number;
|
|
dataList.Add(dataDto);
|
|
}
|
|
this.SendToServer(Methods.EditDataResponse, dataList);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
|
|
public void Notify()
|
|
{
|
|
using (var scope = _applicationServices.CreateScope())
|
|
{
|
|
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
|
var cameras = repo.ReadOnlyTable().Include(o => o.Data).Where(o => o.Name == "摄像头").ToList();
|
|
foreach (var key in this._list.Keys)
|
|
{
|
|
var camera = cameras.FirstOrDefault(o => o.Number == key);
|
|
var remove = false;
|
|
if (camera.Data.FirstOrDefault(o => o.Key == "Push").Value != "是")
|
|
{
|
|
remove = true;
|
|
}
|
|
if (camera.Data.FirstOrDefault(o => o.Key == "NeedAuth").Value == "是" && camera.Data.FirstOrDefault(o => o.Key == "HasAuth").Value == "否")
|
|
{
|
|
remove = true;
|
|
}
|
|
if (remove)
|
|
{
|
|
this.Remove(key);
|
|
}
|
|
}
|
|
foreach (var camera in cameras)
|
|
{
|
|
try
|
|
{
|
|
if (camera.Data.FirstOrDefault(o => o.Key == "Push").Value == "是")
|
|
{
|
|
if (camera.Data.FirstOrDefault(o => o.Key == "NeedAuth").Value == "否" || camera.Data.FirstOrDefault(o => o.Key == "HasAuth").Value == "是")
|
|
{
|
|
this.Publish(camera);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Publish(Device camera)
|
|
{
|
|
try
|
|
{
|
|
if (!this._list.Any(o => o.Key == camera.Number))
|
|
{
|
|
this.Add(camera);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
|
|
public void Add(string key)
|
|
{
|
|
using (var scope = _applicationServices.CreateScope())
|
|
{
|
|
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
|
var camera = repo.ReadOnlyTable().Include(o => o.Data).FirstOrDefault(o => o.Number == key);
|
|
if (camera != null && camera.Data.FirstOrDefault(o => o.Key == "Push").Value == "是")// && camera.Publish && (!camera.NeedAuth || (camera.NeedAuth && camera.HasAuth)))
|
|
{
|
|
if (camera.Data.FirstOrDefault(o => o.Key == "NeedAuth").Value == "否" || camera.Data.FirstOrDefault(o => o.Key == "HasAuth").Value == "是")
|
|
{
|
|
this.Add(camera);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Add(Device camera)
|
|
{
|
|
if (this._list.Any(o => o.Key == camera.Number))
|
|
{
|
|
return;
|
|
}
|
|
var needAuth = camera.Data.FirstOrDefault(o => o.Key == "NeedAuth").Value == "是";
|
|
var hasAuth = camera.Data.FirstOrDefault(o => o.Key == "HasAuth").Value == "是";
|
|
var mainStreamUri = camera.Data.FirstOrDefault(o => o.Key == "MainStreamUri").Value;
|
|
var mainRtspUrl = $"rtsp://{(needAuth ? $"{camera.UserName}:{camera.Password}@" : "")}{mainStreamUri.Substring(7)}";
|
|
var subStreamUri = camera.Data.FirstOrDefault(o => o.Key == "SubStreamUri").Value;
|
|
var subRtspUrl = $"rtsp://{(needAuth ? $"{camera.UserName}:{camera.Password}@" : "")}{subStreamUri.Substring(7)}";
|
|
var fileName = $"ffmpeg-{Helper.Instance.GetRunTime()}{(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "")}";
|
|
var file = camera.GetData("ffmpeg.file")?.Value;
|
|
var mainRtmp = camera.Data.FirstOrDefault(o => o.Key == "mainrtmp").Value;
|
|
var subRtmp = camera.Data.FirstOrDefault(o => o.Key == "subrtmp").Value;
|
|
Console.WriteLine(file);
|
|
var arguments = camera.Data.FirstOrDefault(o => o.Key == "ffmpeg.args").Value;
|
|
Process main = null, sub = null;
|
|
if (!string.IsNullOrEmpty(mainStreamUri))
|
|
{
|
|
if (!string.IsNullOrEmpty(mainRtmp))
|
|
{
|
|
main = this.SetProcess(file, string.Format(arguments, Environment.ProcessorCount, mainRtspUrl, mainRtmp));
|
|
}
|
|
if (!string.IsNullOrEmpty(subRtmp))
|
|
{
|
|
sub = this.SetProcess(file, string.Format(arguments, Environment.ProcessorCount, subRtspUrl, subRtmp));
|
|
}
|
|
}
|
|
if (this._list.TryAdd(camera.Number, (camera, main, sub)))
|
|
{
|
|
Console.WriteLine($"add {camera.Number} to list");
|
|
}
|
|
else
|
|
{
|
|
if (main != null)
|
|
{
|
|
this.CloseProcess(main);
|
|
this.CloseProcess(sub);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Remove(string key)
|
|
{
|
|
var item = this._list[key];
|
|
this.CloseProcess(item.local);
|
|
this.CloseProcess(item.remote);
|
|
if (this._list.TryRemove(key, out item))
|
|
{
|
|
Console.WriteLine($"remove {key} from list");
|
|
}
|
|
}
|
|
|
|
private Process SetProcess(string file, string arguments)
|
|
{
|
|
Console.WriteLine(file);
|
|
Console.WriteLine(arguments);
|
|
var process = new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
WorkingDirectory = this._env.WebRootPath,
|
|
FileName = file,
|
|
Arguments = arguments,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
RedirectStandardError = true
|
|
},
|
|
EnableRaisingEvents = true
|
|
};
|
|
process.Exited += (s, e) =>
|
|
{
|
|
var _process = s as Process;
|
|
Console.WriteLine($"ffmpeg processes list:{_list.Count},exit:{_process.ExitCode},args:{arguments}");
|
|
if (_process != null)
|
|
{
|
|
Thread.Sleep(10 * 1000);
|
|
_process.CancelErrorRead();
|
|
_process.Start();
|
|
_process.BeginErrorReadLine();
|
|
}
|
|
};
|
|
process.ErrorDataReceived += (s, e) =>
|
|
{
|
|
if (!string.IsNullOrEmpty(e.Data))
|
|
{
|
|
if (this._env.IsDevelopment())
|
|
{
|
|
Console.WriteLine(e.Data);
|
|
}
|
|
if (e.Data.IndexOf("forcing output") > -1)
|
|
{
|
|
process.Kill();
|
|
}
|
|
}
|
|
};
|
|
Console.WriteLine(arguments);
|
|
process.Start();
|
|
process.BeginErrorReadLine();
|
|
return process;
|
|
}
|
|
|
|
private void CloseProcess(Process process)
|
|
{
|
|
if (process != null)
|
|
{
|
|
process.EnableRaisingEvents = false;
|
|
try
|
|
{
|
|
process.Kill();
|
|
process.WaitForExit();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
}
|
|
|
|
private string GetOnoce(string deviceUrl)
|
|
{
|
|
var message = @"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"">
|
|
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
|
|
<GetDeviceInformation xmlns=""http://www.onvif.org/ver10/device/wsdl""></GetDeviceInformation>
|
|
</s:Body>
|
|
</s:Envelope>";
|
|
var hc = this._httpClientFactory.CreateClient();
|
|
hc.DefaultRequestHeaders.Add("ContentType", $"application/soap+xml; charset=utf-8; action=\"{MessageTemplate.GetDeviceInformationAction}\"");
|
|
var task = hc.PostAsync(deviceUrl, new StringContent(message));
|
|
var result = task.Result.Headers.WwwAuthenticate;
|
|
return Regex.Match(result.ToString(), "nonce=\"([^\"]+)\"").Groups[1].Value;
|
|
}
|
|
|
|
private string RequestXml(string url, string action, string body, string userName, string password, string onoce)
|
|
{
|
|
var nonce_b = Convert.FromBase64String(onoce);
|
|
var now = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddThh:mm:ss.fffZ");
|
|
var creationtime_b = Encoding.ASCII.GetBytes(now);
|
|
var password_b = Encoding.ASCII.GetBytes(password);
|
|
var concatenation_b = new byte[nonce_b.Length + creationtime_b.Length + password_b.Length];
|
|
Buffer.BlockCopy(nonce_b, 0, concatenation_b, 0, nonce_b.Length);
|
|
Buffer.BlockCopy(creationtime_b, 0, concatenation_b, nonce_b.Length, creationtime_b.Length);
|
|
Buffer.BlockCopy(password_b, 0, concatenation_b, nonce_b.Length + creationtime_b.Length, password_b.Length);
|
|
var sha = new SHA1CryptoServiceProvider();
|
|
var pdresult = sha.ComputeHash(concatenation_b);
|
|
var passworddigest = Convert.ToBase64String(pdresult);
|
|
var message = string.Format(MessageTemplate.AuthTemplate, userName, passworddigest, Convert.ToBase64String(nonce_b), now, body);
|
|
var result = SoapRequest(url, action, message);
|
|
return result;
|
|
}
|
|
|
|
private string SoapRequest(string url, string action, string message)
|
|
{
|
|
var hc = this._httpClientFactory.CreateClient();
|
|
hc.DefaultRequestHeaders.Add("ContentType", $"application/soap+xml; charset=utf-8; action=\"{action}\"");
|
|
var task = hc.PostAsync(url, new StringContent(message));
|
|
var result = task.Result.Content.ReadAsStringAsync().Result;
|
|
return result;
|
|
}
|
|
|
|
public void ZoomIn(string id, float speed)
|
|
{
|
|
this.Move(id, speed, 0, 0);
|
|
}
|
|
|
|
public void ZoomOut(string id, float speed)
|
|
{
|
|
this.Move(id, -speed, 0, 0);
|
|
}
|
|
|
|
public void Up(string id, float speed)
|
|
{
|
|
this.Move(id, 0, 0, speed);
|
|
}
|
|
|
|
public void Right(string id, float speed)
|
|
{
|
|
this.Move(id, 0, speed, 0);
|
|
}
|
|
|
|
public void Down(string id, float speed)
|
|
{
|
|
this.Move(id, 0, 0, -speed);
|
|
}
|
|
|
|
public void Left(string id, float speed)
|
|
{
|
|
this.Move(id, 0, -speed, 0);
|
|
}
|
|
|
|
public void Stop(string id)
|
|
{
|
|
var camera = this.GetCamera(id);
|
|
if (camera != null)
|
|
{
|
|
var ptzAddress = camera.GetDataValue("PtzAddress");
|
|
if (!string.IsNullOrEmpty(ptzAddress))
|
|
{
|
|
var deviceUrl = camera.GetDataValue("DeviceUrl");
|
|
RequestXml(ptzAddress, MessageTemplate.StopAction, String.Format(MessageTemplate.StopMessage, camera.GetDataValue("MainToken"), true, true), camera.UserName, camera.Password, GetOnoce(deviceUrl));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Move(string id, float zx, float px, float py)
|
|
{
|
|
var camera = this.GetCamera(id);
|
|
if (camera != null)
|
|
{
|
|
var ptzAddress = camera.GetDataValue("PtzAddress");
|
|
if (!string.IsNullOrEmpty(ptzAddress))
|
|
{
|
|
var deviceUrl = camera.GetDataValue("DeviceUrl");
|
|
RequestXml(ptzAddress, MessageTemplate.ContinuousMoveAction, String.Format(MessageTemplate.ContinuousMoveMessage, camera.GetDataValue("MainToken"), zx, px, py), camera.UserName, camera.Password, GetOnoce(deviceUrl));
|
|
}
|
|
}
|
|
}
|
|
|
|
public byte[] MainScreenShot(string id)
|
|
{
|
|
var camera = this.GetCamera(id);
|
|
var url = camera.GetDataValue("MainSubSnapshotUri");
|
|
if (string.IsNullOrEmpty(url))
|
|
{
|
|
return new byte[] { };
|
|
}
|
|
var hc = this._httpClientFactory.CreateClient();
|
|
if (camera.GetDataValue("NeedAuth") == "否")
|
|
{
|
|
return hc.GetByteArrayAsync(url).Result;
|
|
}
|
|
return hc.GetByteDigest(new Uri(url), camera.UserName, camera.Password);
|
|
}
|
|
|
|
public byte[] SubScreenShot(string id)
|
|
{
|
|
var camera = this.GetCamera(id);
|
|
var url = camera.GetDataValue("SubSnapshotUri");
|
|
if (string.IsNullOrEmpty(url))
|
|
{
|
|
return new byte[] { };
|
|
}
|
|
var hc = this._httpClientFactory.CreateClient();
|
|
if (camera.GetDataValue("NeedAuth") == "否")
|
|
{
|
|
return hc.GetByteArrayAsync(url).Result;
|
|
}
|
|
return hc.GetByteDigest(new Uri(url), camera.UserName, camera.Password);
|
|
}
|
|
|
|
public void StartPush(string number)
|
|
{
|
|
using (var scope = _applicationServices.CreateScope())
|
|
{
|
|
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
|
var device = repo.Table().Include(o => o.Data).FirstOrDefault(o => o.Number == number);
|
|
var data = device.Data.FirstOrDefault(o => o.Key == "Push");
|
|
data.Value = "是";
|
|
}
|
|
}
|
|
|
|
public void StopPush(string number)
|
|
{
|
|
using (var scope = _applicationServices.CreateScope())
|
|
{
|
|
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
|
var device = repo.Table().Include(o => o.Data).FirstOrDefault(o => o.Number == number);
|
|
var data = device.Data.FirstOrDefault(o => o.Key == "Push");
|
|
data.Value = "否";
|
|
}
|
|
}
|
|
|
|
private byte[] ScreenShot(Device camera)
|
|
{
|
|
var url = camera.GetDataValue("SubSnapshotUri");
|
|
if (string.IsNullOrEmpty(url))
|
|
{
|
|
return new byte[] { };
|
|
}
|
|
var hc = this._httpClientFactory.CreateClient();
|
|
if (camera.GetDataValue("NeedAuth") == "否")
|
|
{
|
|
return hc.GetByteArrayAsync(url).Result;
|
|
}
|
|
return hc.GetByteDigest(new Uri(url), camera.UserName, camera.Password);
|
|
}
|
|
|
|
private Device GetCamera(string number)
|
|
{
|
|
using (var scope = _applicationServices.CreateScope())
|
|
{
|
|
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
|
return repo.ReadOnlyTable().Include(o => o.Data).FirstOrDefault(o => o.Number == number);
|
|
}
|
|
}
|
|
}
|
|
} |