Commit e828ccee by liulongfei

1. 项目升级,接入通用框架

2. 添加中心轴视频插件
3. 添加云台杆值控制中心轴功能
parent 03d5bdff
......@@ -9,6 +9,10 @@
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
......@@ -5,7 +5,8 @@ using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Module;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Module;
namespace VIZ.GimbalAI.Client
......@@ -17,6 +18,16 @@ namespace VIZ.GimbalAI.Client
{
public App()
{
// 初始化 CSV
AppSetup.AppendSetup(new AppSetup_InitCSV());
// 初始化 LiteDB
AppSetup.AppendSetup(new AppSetup_InitLiteDB());
// 初始化 NDI
AppSetup.AppendSetup(new AppSetup_InitNDI());
// 初始化 UDP
AppSetup.AppendSetup(new AppSetup_InitUDP());
// 启动
AppSetupContext context = AppSetup.Setup();
if (context.Exception != null)
......
......@@ -19,6 +19,8 @@ using VIZ.GimbalAI.Storage;
using System.Diagnostics;
using VIZ.GimbalAI.Module;
using VIZ.GimbalAI.Connection;
using VIZ.Framework.Module;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Client
{
......
......@@ -164,7 +164,7 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="config\classes.xls">
<None Include="config\classes.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="config\config.ini">
......@@ -184,6 +184,34 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Common.Resource\VIZ.Framework.Common.Resource.csproj">
<Project>{76ef480a-e486-41b7-b7a5-2a849fc8d5bf}</Project>
<Name>VIZ.Framework.Common.Resource</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Common\VIZ.Framework.Common.csproj">
<Project>{92834c05-703e-4f05-9224-f36220939d8f}</Project>
<Name>VIZ.Framework.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Connection\VIZ.Framework.Connection.csproj">
<Project>{e07528dd-9dee-47c2-b79d-235ecfa6b003}</Project>
<Name>VIZ.Framework.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Module\VIZ.Framework.Module.csproj">
<Project>{47cf6fb0-e37d-4ef1-afc7-03db2bca8892}</Project>
<Name>VIZ.Framework.Module</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Common.Resource\VIZ.GimbalAI.Common.Resource.csproj">
<Project>{5d8021d1-a6b2-4784-b8fe-ff3b7f94e304}</Project>
<Name>VIZ.GimbalAI.Common.Resource</Name>
......@@ -196,10 +224,6 @@
<Project>{52ca7346-0bc0-4e03-8ca5-c00a8777f1ef}</Project>
<Name>VIZ.GimbalAI.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj">
<Project>{d4409326-3f36-4835-812a-bea8ed046e04}</Project>
<Name>VIZ.GimbalAI.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Domain\VIZ.GimbalAI.Domain.csproj">
<Project>{bbf80159-d5de-4d82-a045-a96d67d80632}</Project>
<Name>VIZ.GimbalAI.Domain</Name>
......
name,display_name,ID,sign,is_checked
person,人,0,1,1
bicycle,自行车,1,1,0
car,汽车,2,1,0
motorbike,摩托车,3,1,0
aeroplane,飞机,4,1,0
bus,公共汽车,5,1,0
train,火车,6,1,0
truck,卡车,7,1,0
boat,船,8,1,0
traffic light,交通信号灯,9,0,0
fire hydrant,消防栓,10,0,0
stop sign,停车标志,11,0,0
parking meter,停车收费表,12,0,0
bench,长凳,13,0,0
bird,鸟,14,1,0
cat,猫,15,1,0
dog,狗,16,1,0
horse,马,17,1,0
sheep,羊,18,1,0
cow,牛,19,1,0
elephant,大象,20,1,0
bear,熊,21,1,0
zebra,斑马,22,1,0
giraffe,长颈鹿,23,1,0
backpack,背包,24,0,0
umbrella,雨伞,25,0,0
handbag,手提包,26,0,0
tie,领带,27,0,0
suitcase,手提箱,28,0,0
frisbee,飞盘,29,0,0
skis,滑雪板,30,1,0
snowboard,滑雪板,31,1,0
sports ball,球,32,1,0
kite,风筝,33,1,0
baseball bat,棒球棒,34,1,0
baseball glove,棒球手套,35,1,0
skateboard,滑板,36,1,0
surfboard,冲浪板,37,1,0
tennis racket,网球拍,38,1,0
bottle,瓶子,39,0,0
wine glass,酒杯,40,0,0
cup,杯子,41,0,0
fork,叉,42,0,0
knife,刀,43,0,0
spoon,勺子,44,0,0
bowl,碗,45,0,0
banana,香蕉,46,0,0
apple,苹果,47,0,0
sandwich,三明治,48,0,0
orange,橘子,49,0,0
broccoli,西蓝花,50,0,0
carrot,胡萝卜,51,0,0
hot dog,热狗,52,0,0
pizza,披萨,53,0,0
donut,甜甜圈,54,0,0
cake,糕饼,55,0,0
chair,椅子,56,0,0
sofa,沙发,57,0,0
pottedplant,盆栽植物,58,0,0
bed,床,59,0,0
diningtable,餐桌,60,0,0
toilet,马桶,61,0,0
tvmonitor,电视显示器,62,0,0
laptop,笔记本电脑,63,0,0
mouse,鼠标,64,0,0
remote,遥控器,65,0,0
keyboard,键盘,66,0,0
cell phone,手机,67,0,0
microwave,微波炉,68,0,0
oven,烤箱,69,0,0
toaster,烤面包机,70,0,0
sink,水池,71,0,0
refrigerator,冰箱,72,0,0
book,书,73,0,0
clock,时钟,74,0,0
vase,花瓶,75,0,0
scissors,剪刀,76,0,0
teddy bear,泰迪熊,77,0,0
hair drier,吹风机,78,0,0
toothbrush,牙刷,79,0,0
......@@ -2,20 +2,8 @@
; === Client ===
; ============================================================
[Client]
;视频是否显示FPS
CLIENT_IS_VIDEO_SHOW_FPS=true
;视频渲染等待(单位:毫秒)
CLIENT_VIDEO_RENDER_WAIT=5
;视频延时(单位:帧)
CLIENT_VIDEO_DELAY=0
;算法矩形框宽度(单位:像素)
CLIENT_ALGORITHM_RECTANGLE_STROKE_WIDTH=4
;算法矩形框颜色(#AARRGGBB)
CLIENT_ALGORITHM_RECTANGLE_COLOR=#FFFF0000
;框选矩形框宽度(单位:像素)
CLIENT_FRAME_SELECTION_STROKE_WIDTH=4
;框选矩形框颜色(#AARRGGBB)
CLIENT_FRAME_SELECTION_COLOR=#FFFF6D87
;日志输出最大行数,超过该数目会清理日志
CLIENT_CONSOLE_LOG_MAX_LINE=500
; ============================================================
......@@ -49,8 +37,8 @@ NDI_STREAM_NAME=LAPTOP-6ESNHBU6 (Test Pattern)
; ============================================================
[Algorithm]
;算法启动 绝对路径 或 相对路径(相对于智能云台跟踪系统EXE文件的路径)
ALGORITHM_SETUP_PATH=..\python\python.bat
;ALGORITHM_SETUP_PATH=E:\Project\VIZ.GimbalAI\VIZ.GimbalAI.Client\bin\x64\python\python.bat
;ALGORITHM_SETUP_PATH=..\python\python.bat
ALGORITHM_SETUP_PATH=C:\Users\admin\Desktop\object_tracker\start.bat
;算法命令行窗口显示样式
;Normal | Hidden | Minimized | Maximized
ALGORITHM_CMD_WINDOW_STYLE=Minimized
......@@ -63,3 +51,43 @@ GIMBAL_SETUP_PATH=..\python\python.bat
;云台命令行窗口显示样式
;Normal | Hidden | Minimized | Maximized
GIMBAL_CMD_WINDOW_STYLE=Minimized
;云台中心轴移动速度
GIMBAL_CENTER_AXIS_SPEED=1
; ============================================================
; === Video ===
; ============================================================
[Video]
;视频是否显示FPS
VIDEO_IS_SHOW_FPS=true
;视频渲染等待(单位:毫秒)
VIDEO_RENDER_WAIT=10
;视频背景颜色
VIDEO_BACKGROUND_COLOR=#FF000000
;视频框边框宽度(单位:像素)
VIDEO_RECTANGLE_BORDER_WIDTH=4
;视频框边框颜色(格式:#AARRGGBB)
VIDEO_RECTANGLE_BORDER_COLOR=#FFFF0000
;视频跟踪框边框宽度(单位:像素)
VIDEO_TRACKING_BOX_BORDER_WIDTH=2
;视频跟踪框边框颜色
VIDEO_TRACKING_BOX_BORDER_COLOR=#FFFF0000
;视频框选边框宽度(单位:像素)
VIDEO_FRAME_SELECTION_BORDER_WIDTH=4
;视频框选边框颜色(格式:#AARRGGBB)
VIDEO_FRAME_SELECTION_BORDER_COLOR=#FFFF6D87
;视频剪切宽度(单位:像素)
VIDEO_CLIP_BOX_WIDTH=810
;视频剪切边框宽度(单位:像素)
VIDEO_CLIP_BOX_BORDER_WIDTH=4
;视频剪切边框颜色
VIDEO_CLIP_BOX_BORDER_COLOR=#FFFF0000
;视频剪切掩码颜色
VIDEO_CLIP_BOX_MASK_COLOR=#88000000
;视频边线检测多边形区域透明度
VIDEO_SIDE_CHECK_POLYGON_OPACITY=0.15
;视频人工校准区域透明度
VIDEO_MANUAL_CORRECTION_OPACITY=0.2
;中心轴宽度
VIDEO_CENTER_AXIS_WIDTH=2
;中心轴颜色
VIDEO_CENTER_AXIS_COLOR=#44000000
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VIZ.GimbalAI.Core;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 消息框
/// </summary>
[TemplatePart(Name = nameof(PART_YesButton), Type = typeof(Button))]
[TemplatePart(Name = nameof(PART_CancelButton), Type = typeof(Button))]
public class VMessageBox : ContentControl
{
static VMessageBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(VMessageBox), new FrameworkPropertyMetadata(typeof(VMessageBox)));
}
#region PART
/// <summary>
/// 确定按钮
/// </summary>
private Button PART_YesButton;
/// <summary>
/// 取消按钮
/// </summary>
private Button PART_CancelButton;
#endregion
#region Buttons -- 按钮组合
/// <summary>
/// 按钮组合
/// </summary>
public VMessageBoxButtons Buttons
{
get { return (VMessageBoxButtons)GetValue(ButtonsProperty); }
set { SetValue(ButtonsProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Buttons. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty ButtonsProperty =
DependencyProperty.Register("Buttons", typeof(VMessageBoxButtons), typeof(VMessageBox), new PropertyMetadata(VMessageBoxButtons.YES));
#endregion
#region Title -- 标题
/// <summary>
/// 标题
/// </summary>
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(VMessageBox), new PropertyMetadata(null));
#endregion
#region Message -- 消息
/// <summary>
/// 消息
/// </summary>
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Message. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(VMessageBox), new PropertyMetadata(null));
#endregion
#region Result -- 返回值
/// <summary>
/// 返回值
/// </summary>
public VMessageBoxResult Result
{
get { return (VMessageBoxResult)GetValue(ResultProperty); }
set { SetValue(ResultProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Result. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty ResultProperty =
DependencyProperty.Register("Result", typeof(VMessageBoxResult), typeof(VMessageBox), new PropertyMetadata(VMessageBoxResult.YES));
#endregion
/// <summary>
/// 创建模板时触发
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.PART_YesButton = this.Template.FindName(nameof(PART_YesButton), this) as Button;
this.PART_CancelButton = this.Template.FindName(nameof(PART_CancelButton), this) as Button;
if (this.PART_YesButton != null)
{
this.PART_YesButton.Click -= PART_YesButton_Click;
this.PART_YesButton.Click += PART_YesButton_Click;
}
if (this.PART_CancelButton != null)
{
this.PART_CancelButton.Click -= PART_CancelButton_Click;
this.PART_CancelButton.Click += PART_CancelButton_Click;
}
}
/// <summary>
/// 点击取消按钮
/// </summary>
private void PART_CancelButton_Click(object sender, RoutedEventArgs e)
{
this.Result = VMessageBoxResult.CANCEL;
Window window = WPFHelper.GetAncestorByType<Window>(this);
window?.Close();
}
/// <summary>
/// 点击确定按钮
/// </summary>
private void PART_YesButton_Click(object sender, RoutedEventArgs e)
{
this.Result = VMessageBoxResult.YES;
Window window = WPFHelper.GetAncestorByType<Window>(this);
window?.Close();
}
/// <summary>
/// 显示提示框(线程安全)
/// </summary>
/// <param name="title">标题</param>
/// <param name="message">消息</param>
/// <param name="buttons">按钮组</param>
/// <param name="ownerWindow">所属窗口</param>
/// <returns>返回值</returns>
public static VMessageBoxResult ShowDialog(string title, string message, VMessageBoxButtons buttons, Window ownerWindow)
{
VMessageBoxResult result = VMessageBoxResult.YES;
WPFHelper.Invoke(() =>
{
VMessageBoxWindow window = new VMessageBoxWindow();
window.box.Title = title;
window.box.Message = message;
window.box.Buttons = buttons;
window.Owner = ownerWindow;
window.ShowDialog();
result = window.box.Result;
});
return result;
}
/// <summary>
/// 显示提示框(线程安全)
/// </summary>
/// <param name="title">标题</param>
/// <param name="message">消息</param>
/// <param name="buttons">按钮组</param>
/// <returns>返回值</returns>
public static VMessageBoxResult ShowDialog(string title, string message, VMessageBoxButtons buttons)
{
VMessageBoxResult result = VMessageBoxResult.YES;
WPFHelper.Invoke(() =>
{
VMessageBoxWindow window = new VMessageBoxWindow();
window.box.Title = title;
window.box.Message = message;
window.box.Buttons = buttons;
window.Owner = Application.Current?.MainWindow;
window.ShowDialog();
result = window.box.Result;
});
return result;
}
/// <summary>
/// 显示提示框(线程安全)
/// </summary>
/// <param name="title">标题</param>
/// <param name="message">消息</param>
/// <returns>返回值</returns>
public static VMessageBoxResult ShowDialog(string title, string message)
{
return ShowDialog(title, message, VMessageBoxButtons.YES);
}
/// <summary>
/// 显示提示框(线程安全)
/// </summary>
/// <param name="message">消息</param>
/// <returns>返回值</returns>
public static VMessageBoxResult ShowDialog(string message)
{
return ShowDialog("提示", message);
}
}
}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="clr-namespace:VIZ.GimbalAI.Common">
<Style x:Key="VMessageBox_Button_Yes" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="140"></Setter>
<Setter Property="Height" Value="45"></Setter>
<Setter Property="Margin" Value="10,0,10,0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" CornerRadius="10" Background="#aa007cff">
<TextBlock Text="确定" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="18" Foreground="White"></TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#ff007cff"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="VMessageBox_Button_Cancel" TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="140"></Setter>
<Setter Property="Height" Value="45"></Setter>
<Setter Property="Margin" Value="10,0,10,0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" CornerRadius="10" Background="#aadcdcdc">
<TextBlock Text="取消" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="18" Foreground="Black"></TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#ffdcdcdc"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="common:VMessageBox">
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Width" Value="400"></Setter>
<Setter Property="Height" Value="300"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="common:VMessageBox">
<Border Background="White" CornerRadius="40">
<Border.Effect>
<DropShadowEffect Opacity="0.36"/>
</Border.Effect>
<Grid Margin="30,20,30,20">
<Grid.RowDefinitions>
<RowDefinition Height="80"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="80"></RowDefinition>
</Grid.RowDefinitions>
<common:DragWindowBar Grid.RowSpan="3" Background="Transparent"></common:DragWindowBar>
<TextBlock Text="{TemplateBinding Title}" Foreground="Black" FontSize="40" VerticalAlignment="Center" HorizontalAlignment="Left"
FontWeight="Black"></TextBlock>
<TextBlock Grid.Row="1" Text="{TemplateBinding Message}" Foreground="Black" FontSize="24" TextWrapping="Wrap" TextTrimming="CharacterEllipsis"></TextBlock>
<StackPanel Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Right" Orientation="Horizontal">
<Button x:Name="PART_CancelButton" Grid.Row="2" Style="{StaticResource VMessageBox_Button_Cancel}" Content="取消" Visibility="Hidden"></Button>
<Button x:Name="PART_YesButton" Grid.Row="2" Style="{StaticResource VMessageBox_Button_Yes}" Content="确定"></Button>
</StackPanel>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Buttons" Value="YES_CANCEL">
<Setter TargetName="PART_CancelButton" Property="Visibility" Value="Visible"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
\ No newline at end of file
<Window x:Class="VIZ.GimbalAI.Common.VMessageBoxWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:VIZ.GimbalAI.Common"
mc:Ignorable="d" WindowStartupLocation="CenterScreen" WindowState="Normal" WindowStyle="None" AllowsTransparency="True"
Title="VMessageBoxWindow" Height="400" Width="600" Background="Transparent">
<local:VMessageBox x:Name="box" Width="580" Height="380"></local:VMessageBox>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// VMessageBoxWindow.xaml 的交互逻辑
/// </summary>
public partial class VMessageBoxWindow : Window
{
public VMessageBoxWindow()
{
InitializeComponent();
}
}
}
using System;
namespace VIZ.GimbalAI.Common
{
public static class Disposer
{
public static void SafeDispose<T>(ref T resource) where T : class
{
if (resource == null)
{
return;
}
var disposer = resource as IDisposable;
if (disposer != null)
{
try
{
disposer.Dispose();
}
catch
{
}
}
resource = null;
}
}
}
using System;
using System.Runtime.InteropServices;
namespace VIZ.GimbalAI.Common
{
public static class NativeMethods
{
[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetDesktopWindow();
}
}
using SharpDX.Direct2D1;
using System;
using System.Collections.Generic;
namespace VIZ.GimbalAI.Common
{
public class ResourceCache
{
// - field -----------------------------------------------------------------------
private Dictionary<string, Func<RenderTarget, object>> generators = new Dictionary<string, Func<RenderTarget, object>>();
private Dictionary<string, object> resources = new Dictionary<string, object>();
private RenderTarget renderTarget = null;
// - property --------------------------------------------------------------------
public RenderTarget RenderTarget
{
get { return renderTarget; }
set { renderTarget = value; UpdateResources(); }
}
public int Count
{
get { return resources.Count; }
}
public object this[string key]
{
get { return resources[key]; }
}
public Dictionary<string, object>.KeyCollection Keys
{
get { return resources.Keys; }
}
public Dictionary<string, object>.ValueCollection Values
{
get { return resources.Values; }
}
// - public methods --------------------------------------------------------------
public void Add(string key, Func<RenderTarget, object> gen)
{
object resOld;
if (resources.TryGetValue(key, out resOld))
{
Disposer.SafeDispose(ref resOld);
generators.Remove(key);
resources.Remove(key);
}
if (renderTarget == null)
{
generators.Add(key, gen);
resources.Add(key, null);
}
else
{
var res = gen(renderTarget);
generators.Add(key, gen);
resources.Add(key, res);
}
}
public void Clear()
{
foreach (var key in resources.Keys)
{
var res = resources[key];
Disposer.SafeDispose(ref res);
}
generators.Clear();
resources.Clear();
}
public bool ContainsKey(string key)
{
return resources.ContainsKey(key);
}
public bool ContainsValue(object val)
{
return resources.ContainsValue(val);
}
public Dictionary<string, object>.Enumerator GetEnumerator()
{
return resources.GetEnumerator();
}
public bool Remove(string key)
{
object res;
if (resources.TryGetValue(key, out res))
{
Disposer.SafeDispose(ref res);
generators.Remove(key);
resources.Remove(key);
return true;
}
else
{
return false;
}
}
public bool TryGetValue(string key, out object res)
{
return resources.TryGetValue(key, out res);
}
// - private methods -------------------------------------------------------------
private void UpdateResources()
{
if (renderTarget == null) { return; }
foreach (var g in generators)
{
var key = g.Key;
var gen = g.Value;
var res = gen(renderTarget);
object resOld;
if (resources.TryGetValue(key, out resOld))
{
Disposer.SafeDispose(ref resOld);
resources.Remove(key);
}
resources.Add(key, res);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX.Mathematics.Interop;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// SharpDX颜色辅助类
/// </summary>
public static class SharpDxColorHelper
{
/// <summary>
/// 由RGBG值获取颜色
/// </summary>
/// <param name="r">红色值</param>
/// <param name="g">绿色值</param>
/// <param name="b">蓝色值</param>
/// <param name="a">透明度</param>
/// <returns>颜色</returns>
public static RawColor4 FromRGBA(float r, float g, float b, float a)
{
return new RawColor4(r, g, b, a);
}
/// <summary>
/// 由RGBG值获取颜色
/// </summary>
/// <param name="r">红色值</param>
/// <param name="g">绿色值</param>
/// <param name="b">蓝色值</param>
/// <param name="a">透明度</param>
/// <returns>颜色</returns>
public static RawColor4 FromRGBA(double r, double g, double b, double a)
{
return new RawColor4((float)r, (float)g, (float)b, (float)a);
}
/// <summary>
/// 由RGBG值获取颜色
/// </summary>
/// <param name="code">颜色码(#AARRGGBB),例如:#FFFF0000</param>
/// <returns>颜色</returns>
public static RawColor4 FromString(string code)
{
RawColor4 result = new RawColor4();
result.A = Convert.ToInt32(code.Substring(1, 2), 16) / 255f;
result.R = Convert.ToInt32(code.Substring(3, 2), 16) / 255f;
result.G = Convert.ToInt32(code.Substring(5, 2), 16) / 255f;
result.B = Convert.ToInt32(code.Substring(7, 2), 16) / 255f;
return result;
}
}
}
using SharpDX.Direct2D1;
using SharpDX.WIC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// WIC图片辅助类默认实现
/// </summary>
public class WicBitmapDefaultHelper : WicBitmapHelper
{
/// <summary>
/// WIC图片辅助类默认实现
/// </summary>
/// <param name="renderCallBack">渲染回调</param>
public WicBitmapDefaultHelper(Action<WicRenderTarget> renderCallBack)
{
this.RenderCallBack = renderCallBack;
}
/// <summary>
/// 渲染回调
/// </summary>
private Action<WicRenderTarget> RenderCallBack;
/// <summary>
/// 执行渲染
/// </summary>
/// <param name="renderTarget">渲染目标</param>
protected override void ExecuteeRender(WicRenderTarget renderTarget)
{
this.RenderCallBack?.Invoke(renderTarget);
}
/// <summary>
/// 获取保存图片格式
/// </summary>
/// <param name="factory">图片工厂</param>
protected override BitmapEncoder GetBitmapFrameEncoder(ImagingFactory factory)
{
return new JpegBitmapEncoder(factory);
}
}
}
using SharpDX.WIC;
using SharpDX.Direct2D1;
using SharpDX.DXGI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX;
using System.IO;
using SharpDX.IO;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// WIC图片辅助类
/// </summary>
public abstract class WicBitmapHelper
{
/// <summary>
/// 渲染至文件
/// </summary>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <param name="filename">文件名</param>
/// <param name="executeRender">执行渲染</param>
public void RenderToFile(int width, int height, string filename)
{
ImagingFactory wicFactory = new ImagingFactory();
SharpDX.Direct2D1.Factory d2dFactory = new SharpDX.Direct2D1.Factory();
SharpDX.WIC.Bitmap wicBitmap = new SharpDX.WIC.Bitmap(wicFactory, width, height, SharpDX.WIC.PixelFormat.Format32bppBGR, BitmapCreateCacheOption.CacheOnLoad);
RenderTargetProperties renderTargetProperties = new RenderTargetProperties(RenderTargetType.Default, new SharpDX.Direct2D1.PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Unknown), 0, 0, RenderTargetUsage.None, FeatureLevel.Level_DEFAULT);
WicRenderTarget d2dRenderTarget = new WicRenderTarget(d2dFactory, wicBitmap, renderTargetProperties);
d2dRenderTarget.BeginDraw();
this.ExecuteeRender(d2dRenderTarget);
d2dRenderTarget.EndDraw();
if (File.Exists(filename))
File.Delete(filename);
WICStream stream = new WICStream(wicFactory, filename, NativeFileAccess.Write);
// Initialize a Jpeg encoder with this stream
BitmapEncoder encoder = this.GetBitmapFrameEncoder(wicFactory);
encoder.Initialize(stream);
// Create a Frame encoder
BitmapFrameEncode bitmapFrameEncode = new BitmapFrameEncode(encoder);
bitmapFrameEncode.Initialize();
bitmapFrameEncode.SetSize(width, height);
var pixelFormatGuid = SharpDX.WIC.PixelFormat.FormatDontCare;
bitmapFrameEncode.SetPixelFormat(ref pixelFormatGuid);
bitmapFrameEncode.WriteSource(wicBitmap);
bitmapFrameEncode.Commit();
encoder.Commit();
bitmapFrameEncode.Dispose();
encoder.Dispose();
stream.Dispose();
d2dRenderTarget.Dispose();
wicBitmap.Dispose();
d2dFactory.Dispose();
wicFactory.Dispose();
}
/// <summary>
/// 执行渲染
/// </summary>
/// <param name="renderTarget">渲染目标</param>
protected abstract void ExecuteeRender(WicRenderTarget renderTarget);
/// <summary>
/// 获取保存图片格式
/// </summary>
/// <param name="factory">图片工厂</param>
/// <returns>图片格式</returns>
protected abstract BitmapEncoder GetBitmapFrameEncoder(ImagingFactory factory);
}
}
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
namespace VIZ.GimbalAI.Common
{
public abstract class D2dControl : System.Windows.Controls.Image
{
// - field -----------------------------------------------------------------------
private SharpDX.Direct3D11.Device device;
private Texture2D renderTarget;
private Dx11ImageSource d3DSurface;
private RenderTarget d2DRenderTarget;
private SharpDX.Direct2D1.Factory d2DFactory;
private readonly Stopwatch renderTimer = new Stopwatch();
protected ResourceCache resCache = new ResourceCache();
private long lastFrameTime = 0;
private long lastRenderTime = 0;
private int frameCount = 0;
private int frameCountHistTotal = 0;
private Queue<int> frameCountHist = new Queue<int>();
// - property --------------------------------------------------------------------
public static bool IsInDesignMode
{
get
{
var prop = DesignerProperties.IsInDesignModeProperty;
var isDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(prop, typeof(FrameworkElement)).Metadata.DefaultValue;
return isDesignMode;
}
}
private static readonly DependencyPropertyKey FpsPropertyKey = DependencyProperty.RegisterReadOnly(
"Fps",
typeof(int),
typeof(D2dControl),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.None)
);
public static readonly DependencyProperty FpsProperty = FpsPropertyKey.DependencyProperty;
public int Fps
{
get { return (int)GetValue(FpsProperty); }
protected set { SetValue(FpsPropertyKey, value); }
}
public static DependencyProperty RenderWaitProperty = DependencyProperty.Register(
"RenderWait",
typeof(int),
typeof(D2dControl),
new FrameworkPropertyMetadata(2, OnRenderWaitChanged)
);
public int RenderWait
{
get { return (int)GetValue(RenderWaitProperty); }
set { SetValue(RenderWaitProperty, value); }
}
// - public methods --------------------------------------------------------------
public D2dControl()
{
base.Loaded += Window_Loaded;
base.Unloaded += Window_Closing;
base.Stretch = System.Windows.Media.Stretch.Fill;
}
public abstract void Render(RenderTarget target);
// - event handler ---------------------------------------------------------------
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (D2dControl.IsInDesignMode)
{
return;
}
StartD3D();
StartRendering();
}
private void Window_Closing(object sender, RoutedEventArgs e)
{
if (D2dControl.IsInDesignMode)
{
return;
}
StopRendering();
EndD3D();
}
private void OnRendering(object sender, EventArgs e)
{
if (!renderTimer.IsRunning)
{
return;
}
PrepareAndCallRender();
d3DSurface.InvalidateD3DImage();
lastRenderTime = renderTimer.ElapsedMilliseconds;
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
CreateAndBindTargets();
base.OnRenderSizeChanged(sizeInfo);
}
private void OnIsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (d3DSurface.IsFrontBufferAvailable)
{
StartRendering();
this.CreateAndBindTargets();
}
else
{
StopRendering();
}
}
private static void OnRenderWaitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (D2dControl)d;
control.d3DSurface.RenderWait = (int)e.NewValue;
}
// - private methods -------------------------------------------------------------
private void StartD3D()
{
device = new SharpDX.Direct3D11.Device(DriverType.Hardware, DeviceCreationFlags.BgraSupport);
d3DSurface = new Dx11ImageSource();
d3DSurface.IsFrontBufferAvailableChanged += OnIsFrontBufferAvailableChanged;
CreateAndBindTargets();
base.Source = d3DSurface;
}
private void EndD3D()
{
d3DSurface.IsFrontBufferAvailableChanged -= OnIsFrontBufferAvailableChanged;
base.Source = null;
Disposer.SafeDispose(ref d2DRenderTarget);
Disposer.SafeDispose(ref d2DFactory);
Disposer.SafeDispose(ref d3DSurface);
Disposer.SafeDispose(ref renderTarget);
Disposer.SafeDispose(ref device);
}
private void CreateAndBindTargets()
{
if (d3DSurface == null)
{
return;
}
d3DSurface.SetRenderTarget(null);
Disposer.SafeDispose(ref d2DRenderTarget);
Disposer.SafeDispose(ref d2DFactory);
Disposer.SafeDispose(ref renderTarget);
var width = Math.Max((int)ActualWidth, 100);
var height = Math.Max((int)ActualHeight, 100);
var renderDesc = new Texture2DDescription
{
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
Format = Format.B8G8R8A8_UNorm,
Width = width,
Height = height,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
OptionFlags = ResourceOptionFlags.Shared,
CpuAccessFlags = CpuAccessFlags.None,
ArraySize = 1
};
renderTarget = new Texture2D(device, renderDesc);
var surface = renderTarget.QueryInterface<Surface>();
d2DFactory = new SharpDX.Direct2D1.Factory();
var rtp = new RenderTargetProperties(new PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Premultiplied));
d2DRenderTarget = new RenderTarget(d2DFactory, surface, rtp);
resCache.RenderTarget = d2DRenderTarget;
d3DSurface.SetRenderTarget(renderTarget);
device.ImmediateContext.Rasterizer.SetViewport(0, 0, width, height, 0.0f, 1.0f);
}
private void StartRendering()
{
if (renderTimer.IsRunning)
{
return;
}
System.Windows.Media.CompositionTarget.Rendering -= OnRendering;
System.Windows.Media.CompositionTarget.Rendering += OnRendering;
renderTimer.Start();
}
private void StopRendering()
{
if (!renderTimer.IsRunning)
{
return;
}
System.Windows.Media.CompositionTarget.Rendering -= OnRendering;
renderTimer.Stop();
}
private void PrepareAndCallRender()
{
if (device == null)
{
return;
}
d2DRenderTarget.BeginDraw();
Render(d2DRenderTarget);
d2DRenderTarget.EndDraw();
CalcFps();
device.ImmediateContext.Flush();
}
private void CalcFps()
{
frameCount++;
if (renderTimer.ElapsedMilliseconds - lastFrameTime > 1000)
{
frameCountHist.Enqueue(frameCount);
frameCountHistTotal += frameCount;
if (frameCountHist.Count > 5)
{
frameCountHistTotal -= frameCountHist.Dequeue();
}
Fps = frameCountHistTotal / frameCountHist.Count;
frameCount = 0;
lastFrameTime = renderTimer.ElapsedMilliseconds;
}
}
}
}
using SharpDX.Direct3D9;
using System;
using System.Threading;
using System.Windows.Interop;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Storage;
namespace VIZ.GimbalAI.Common
{
public class Dx11ImageSource : D3DImage, IDisposable
{
// - field -----------------------------------------------------------------------
private static int ActiveClients;
private static Direct3DEx D3DContext;
private static DeviceEx D3DDevice;
private Texture renderTarget;
// - property --------------------------------------------------------------------
public int RenderWait { get; set; } = 20; // default: 2ms
// - public methods --------------------------------------------------------------
public Dx11ImageSource()
{
this.RenderWait = VDataDomain.IniStorage.GetValue<ClientConfig, int>(p => p.CLIENT_VIDEO_RENDER_WAIT);
StartD3D();
Dx11ImageSource.ActiveClients++;
}
public void Dispose()
{
SetRenderTarget(null);
Disposer.SafeDispose(ref renderTarget);
Dx11ImageSource.ActiveClients--;
EndD3D();
}
public void InvalidateD3DImage()
{
if (renderTarget != null)
{
base.Lock();
if (RenderWait != 0)
{
Thread.Sleep(RenderWait);
}
base.AddDirtyRect(new System.Windows.Int32Rect(0, 0, base.PixelWidth, base.PixelHeight));
base.Unlock();
}
}
public void SetRenderTarget(SharpDX.Direct3D11.Texture2D target)
{
if (renderTarget != null)
{
renderTarget = null;
base.Lock();
base.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
base.Unlock();
}
if (target == null)
{
return;
}
var format = Dx11ImageSource.TranslateFormat(target);
var handle = GetSharedHandle(target);
if (!IsShareable(target))
{
throw new ArgumentException("Texture must be created with ResouceOptionFlags.Shared");
}
if (format == Format.Unknown)
{
throw new ArgumentException("Texture format is not compatible with OpenSharedResouce");
}
if (handle == IntPtr.Zero)
{
throw new ArgumentException("Invalid handle");
}
renderTarget = new Texture(Dx11ImageSource.D3DDevice, target.Description.Width, target.Description.Height, 1, Usage.RenderTarget, format, Pool.Default, ref handle);
using (var surface = renderTarget.GetSurfaceLevel(0))
{
base.Lock();
base.SetBackBuffer(D3DResourceType.IDirect3DSurface9, surface.NativePointer);
base.Unlock();
}
}
// - private methods -------------------------------------------------------------
private void StartD3D()
{
if (Dx11ImageSource.ActiveClients != 0)
{
return;
}
var presentParams = GetPresentParameters();
var createFlags = CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve;
Dx11ImageSource.D3DContext = new Direct3DEx();
Dx11ImageSource.D3DDevice = new DeviceEx(D3DContext, 0, DeviceType.Hardware, IntPtr.Zero, createFlags, presentParams);
}
private void EndD3D()
{
if (Dx11ImageSource.ActiveClients != 0)
{
return;
}
Disposer.SafeDispose(ref renderTarget);
Disposer.SafeDispose(ref Dx11ImageSource.D3DDevice);
Disposer.SafeDispose(ref Dx11ImageSource.D3DContext);
}
private static void ResetD3D()
{
if (Dx11ImageSource.ActiveClients == 0)
{
return;
}
var presentParams = GetPresentParameters();
Dx11ImageSource.D3DDevice.ResetEx(ref presentParams);
}
private static PresentParameters GetPresentParameters()
{
var presentParams = new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.DeviceWindowHandle = NativeMethods.GetDesktopWindow();
presentParams.PresentationInterval = PresentInterval.Default;
return presentParams;
}
private IntPtr GetSharedHandle(SharpDX.Direct3D11.Texture2D texture)
{
using (var resource = texture.QueryInterface<SharpDX.DXGI.Resource>())
{
return resource.SharedHandle;
}
}
private static Format TranslateFormat(SharpDX.Direct3D11.Texture2D texture)
{
switch (texture.Description.Format)
{
case SharpDX.DXGI.Format.R10G10B10A2_UNorm: return SharpDX.Direct3D9.Format.A2B10G10R10;
case SharpDX.DXGI.Format.R16G16B16A16_Float: return SharpDX.Direct3D9.Format.A16B16G16R16F;
case SharpDX.DXGI.Format.B8G8R8A8_UNorm: return SharpDX.Direct3D9.Format.A8R8G8B8;
default: return SharpDX.Direct3D9.Format.Unknown;
}
}
private static bool IsShareable(SharpDX.Direct3D11.Texture2D texture)
{
return (texture.Description.OptionFlags & SharpDX.Direct3D11.ResourceOptionFlags.Shared) != 0;
}
}
}
......@@ -4,7 +4,7 @@
xmlns:local="clr-namespace:VIZ.GimbalAI.Common">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/VIZ.GimbalAI.Common;component/MessageBox/VMessageBox.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
......@@ -132,30 +132,12 @@
<Reference Include="WindowsFormsIntegration" />
</ItemGroup>
<ItemGroup>
<Page Include="MessageBox\VMessageBox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MessageBox\VMessageBoxWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="VideoControl\Control\VideoControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="MessageBox\VMessageBox.cs" />
<Compile Include="MessageBox\VMessageBoxButtons.cs" />
<Compile Include="MessageBox\VMessageBoxResult.cs" />
<Compile Include="MessageBox\VMessageBoxWindow.xaml.cs">
<DependentUpon>VMessageBoxWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
......@@ -169,40 +151,6 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="SharpDx\Core\SharpDxColorHelper.cs" />
<Compile Include="SharpDx\WIC\WicBitmapHelper.cs" />
<Compile Include="SharpDx\WIC\WicBitmapDefaultHelper.cs" />
<Compile Include="SharpDx\WPF\D2dControl.cs" />
<Compile Include="SharpDx\Core\Disposer.cs" />
<Compile Include="SharpDx\WPF\Dx11ImageSource.cs" />
<Compile Include="SharpDx\Core\NativeMethods.cs" />
<Compile Include="SharpDx\Core\ResourceCache.cs" />
<Compile Include="VideoControl\Control\Drawing\VideoRectangle.cs" />
<Compile Include="VideoControl\Control\Drawing\VideoRectangleColor.cs" />
<Compile Include="VideoControl\Control\Drawing\VideoRectangleExpand.cs" />
<Compile Include="VideoControl\Control\EventArgs\VideoRectangleFrameSelectionEventArgs.cs" />
<Compile Include="VideoControl\Control\EventArgs\VideoRectangleClickEventArgs.cs" />
<Compile Include="VideoControl\Control\IVideoRender.cs" />
<Compile Include="VideoControl\Control\VideoControl.xaml.cs">
<DependentUpon>VideoControl.xaml</DependentUpon>
</Compile>
<Compile Include="VideoControl\Control\VideoCustomRender.cs" />
<Compile Include="VideoControl\Control\VideoRenderInfo.cs" />
<Compile Include="VideoControl\Stream\IVideoFrame.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIToolOption.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIToolStreamInfo.cs" />
<Compile Include="VideoControl\Stream\NDI\NDITool.cs" />
<Compile Include="VideoControl\Stream\NDI\NDITool.Static.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIToolTaskBase.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIToolTaskNames.cs" />
<Compile Include="VideoControl\Stream\NDI\NDIToolVideoFrame.cs" />
<Compile Include="VideoControl\Stream\VideoStreamManager.cs" />
<Compile Include="VideoControl\Stream\VideoFrameEventArgs.cs" />
<Compile Include="VideoControl\Stream\NDI\Task\NDIToolExecuteVideoTask.cs" />
<Compile Include="VideoControl\Stream\NDI\Task\NDIToolRecvVideoTask.cs" />
<Compile Include="VideoControl\Stream\NDI\Task\NDIToolFindStreamTask.cs" />
<Compile Include="Widgets\DragWindowBar\DragWindowBar.cs" />
<Compile Include="Widgets\NoneWindow\NoneWindow.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
......@@ -215,10 +163,6 @@
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj">
<Project>{d4409326-3f36-4835-812a-bea8ed046e04}</Project>
<Name>VIZ.GimbalAI.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Domain\VIZ.GimbalAI.Domain.csproj">
<Project>{BBF80159-D5DE-4D82-A045-A96D67D80632}</Project>
<Name>VIZ.GimbalAI.Domain</Name>
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频矩形
/// </summary>
public class VideoRectangle
{
/// <summary>
/// 算法给出的矩形框ID
/// </summary>
public int AlgorithmID { get; set; }
/// <summary>
/// 算法给出的框定位信息
/// </summary>
public List<float> AlgorithmRoi { get; set; } = new List<float>();
/// <summary>
/// 颜色
/// </summary>
public VideoRectangleColor Color { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频框颜色
/// </summary>
public enum VideoRectangleColor
{
/// <summary>
/// 红色
/// </summary>
Red,
/// <summary>
/// 蓝色
/// </summary>
Blue,
/// <summary>
/// 绿色
/// </summary>
Green
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频矩形扩展
/// </summary>
public static class VideoRectangleExpand
{
/// <summary>
/// 将算法给定的坐标信息转化为Rectangle
/// </summary>
/// <param name="info">视频矩形信息</param>
/// <returns></returns>
public static RectangleF? ConvertAlgorithmRoiToRectangle(this VideoRectangle info)
{
if (info == null || info.AlgorithmRoi == null || info.AlgorithmRoi.Count != 4)
return null;
return new RectangleF(info.AlgorithmRoi[0], info.AlgorithmRoi[1], info.AlgorithmRoi[2], info.AlgorithmRoi[3]);
}
/// <summary>
/// 命中测试
/// </summary>
/// <param name="rectangles">矩形信息</param>
/// <param name="point">视频坐标</param>
/// <returns>命中的矩形</returns>
public static List<VideoRectangle> HitTest(List<VideoRectangle> rectangles, System.Windows.Point point)
{
List<VideoRectangle> result = new List<VideoRectangle>();
if (rectangles == null || rectangles.Count == 0)
return result;
foreach (VideoRectangle item in rectangles)
{
RectangleF? rect = item.ConvertAlgorithmRoiToRectangle();
if (rect == null)
continue;
if (point.X >= rect.Value.Left && point.X <= rect.Value.Right && point.Y >= rect.Value.Top && point.Y <= rect.Value.Bottom)
{
result.Add(item);
}
}
return result;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频矩形信息点击事件参数s
/// </summary>
public class VideoRectangleClickEventArgs : EventArgs
{
/// <summary>
/// 鼠标点击位置
/// </summary>
public Point MousePosition { get; set; }
/// <summary>
/// 视频坐标
/// </summary>
public Point VideoPosition { get; set; }
/// <summary>
/// 当前渲染的视频矩形框
/// </summary>
public List<VideoRectangle> VideoRectangles { get; set; }
/// <summary>
/// 命中测试的视频矩形框
/// </summary>
public List<VideoRectangle> HitTestVideoRectangles { get; set; }
}
}
using ManageLiteAV;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频渲染
/// </summary>
public interface IVideoRender
{
/// <summary>
/// 是否启用绘制矩形框
/// </summary>
bool IsRenderRectangleEnabled { get; set; }
/// <summary>
/// 是否启用绘制框选区域
/// </summary>
bool IsRenderFrameSelectionEnabled { get; set; }
/// <summary>
/// 渲染
/// </summary>
void RenderVideo(IVideoFrame videoFrame);
/// <summary>
/// 渲染矩形框信息
/// </summary>
/// <param name="rectangles">矩形框</param>
void RenderRectangleInfo(List<VideoRectangle> rectangles);
/// <summary>
/// 渲染视频矩形区域框选
/// </summary>
/// <param name="uiRect">UI框选区域</param>
void RenderFrameSelection(RectangleF? uiRect);
/// <summary>
/// 将渲染内容保存为图片
/// ----------------------------------------------------
/// 1. 只保存视频帧 & 渲染框
/// 2. 图片保存为jpg数据
/// ----------------------------------------------------
/// </summary>
/// <param name="path">图片路径</param>
void SaveFrameImage(string path);
/// <summary>
/// 获取帧图片
/// </summary>
/// <returns>图片</returns>
Bitmap GetFrameImage();
}
}
<UserControl x:Class="VIZ.GimbalAI.Common.VideoControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:common="clr-namespace:VIZ.GimbalAI.Common"
xmlns:converter="clr-namespace:VIZ.GimbalAI.Core;assembly=VIZ.GimbalAI.Core"
mc:Ignorable="d" x:Name="uc"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converter:Bool2VisibilityConverter x:Key="Bool2VisibilityConverter"></converter:Bool2VisibilityConverter>
</UserControl.Resources>
<Grid>
<common:VideoCustomRender x:Name="videoRender"></common:VideoCustomRender>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5,5,0,0" IsHitTestVisible="False"
Visibility="{Binding Path=IsShowFPS,ElementName=uc,Converter={StaticResource Bool2VisibilityConverter}}">
<TextBlock Text="FPS:" Foreground="Red" FontSize="24"></TextBlock>
<TextBlock Text="{Binding ElementName=videoRender,Path=Fps}" Foreground="Red" FontSize="24" Margin="10,0,0,0"></TextBlock>
</StackPanel>
</Grid>
</UserControl>
using ManageLiteAV;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VIZ.GimbalAI.Core;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// VideoControl.xaml 的交互逻辑
/// </summary>
public partial class VideoControl : UserControl
{
public VideoControl()
{
InitializeComponent();
this.videoRender.OwnerVideoControl = this;
}
/// <summary>
/// 视频矩形框被选中时触发
/// </summary>
public event EventHandler<VideoRectangleClickEventArgs> VideoRectangleClick;
/// <summary>
/// 视频矩形框被框选时触发
/// </summary>
public event EventHandler<VideoRectangleFrameSelectionEventArgs> VideoRectangleFrameSelection;
// ===========================================================================================================
// === Property ===
// ===========================================================================================================
#region IsRenderRectangleEnabled -- 是否启用渲染矩形
/// <summary>
/// 是否启用渲染矩形
/// </summary>
public bool IsRenderRectangleEnabled
{
get { return (bool)GetValue(IsRenderRectangleEnabledProperty); }
set { SetValue(IsRenderRectangleEnabledProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for IsRenderRectangleEnabled. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty IsRenderRectangleEnabledProperty =
DependencyProperty.Register("IsRenderRectangleEnabled", typeof(bool), typeof(VideoControl), new PropertyMetadata(true, new PropertyChangedCallback((s, e) =>
{
IVideoRender render = (s as VideoControl).videoRender;
if (render == null)
return;
render.IsRenderRectangleEnabled = (bool)e.NewValue;
})));
#endregion
#region IsRenderFrameSelectionEnabled -- 是否渲染框选区域
/// <summary>
/// 是否渲染框选区域
/// </summary>
public bool IsRenderFrameSelectionEnabled
{
get { return (bool)GetValue(IsRenderFrameSelectionEnabledProperty); }
set { SetValue(IsRenderFrameSelectionEnabledProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for IsRenderFrameSelectionEnabled. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty IsRenderFrameSelectionEnabledProperty =
DependencyProperty.Register("IsRenderFrameSelectionEnabled", typeof(bool), typeof(VideoControl), new PropertyMetadata(false, new PropertyChangedCallback((s, e) =>
{
IVideoRender render = (s as VideoControl)?.videoRender;
if (render == null)
return;
render.IsRenderFrameSelectionEnabled = (bool)e.NewValue;
})));
#endregion
#region IsRectangleClickTrigger -- 是否触发鼠标点击事件
/// <summary>
/// 是否触发鼠标点击事件
/// </summary>
public bool IsRectangleClickTrigger
{
get { return (bool)GetValue(IsRectangleClickTriggerProperty); }
set { SetValue(IsRectangleClickTriggerProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for IsRectangleClickTrigger. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty IsRectangleClickTriggerProperty =
DependencyProperty.Register("IsRectangleClickTrigger", typeof(bool), typeof(VideoControl), new PropertyMetadata(true));
#endregion
#region IsRectangleFrameSelectionTrigger -- 是否触发框选
/// <summary>
/// 是否触发框选
/// </summary>
public bool IsRectangleFrameSelectionTrigger
{
get { return (bool)GetValue(IsRectangleFrameSelectionTriggerProperty); }
set { SetValue(IsRectangleFrameSelectionTriggerProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for IsRectangleFrameSelectionTrigger. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty IsRectangleFrameSelectionTriggerProperty =
DependencyProperty.Register("IsRectangleFrameSelectionTrigger", typeof(bool), typeof(VideoControl), new PropertyMetadata(false));
#endregion
#region IsShowFPS -- 是否显示FPS
/// <summary>
/// 是否显示FPS
/// </summary>
public bool IsShowFPS
{
get { return (bool)GetValue(IsShowFPSProperty); }
set { SetValue(IsShowFPSProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for IsShowFPS. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty IsShowFPSProperty =
DependencyProperty.Register("IsShowFPS", typeof(bool), typeof(VideoControl), new PropertyMetadata(false));
#endregion
// ===========================================================================================================
// === Public Function ===
// ===========================================================================================================
/// <summary>
/// 渲染
/// </summary>
public void RenderVideo(IVideoFrame videoFrame)
{
this.videoRender?.RenderVideo(videoFrame);
}
/// <summary>
/// 渲染矩形框信息
/// </summary>
/// <param name="rectangles">矩形框</param>
public void RenderRectangleInfo(List<VideoRectangle> rectangles)
{
this.videoRender?.RenderRectangleInfo(rectangles);
}
/// <summary>
/// 清理矩形框信息
/// </summary>
public void ClearRectangleInfo()
{
this.videoRender?.RenderRectangleInfo(null);
}
/// <summary>
/// 清理框选区域
/// </summary>
public void ClearFrameSelection()
{
this.videoRender.RenderFrameSelection(null);
}
/// <summary>
/// 保存图片
/// </summary>
/// <param name="path">图片路径</param>
public void SaveFrameImage(string path)
{
this.videoRender.SaveFrameImage(path);
}
/// <summary>
/// 获取帧图片
/// </summary>
/// <returns>图片</returns>
public Bitmap GetFrameImage()
{
return this.videoRender.GetFrameImage();
}
// ===========================================================================================================
/// <summary>
/// 执行视频矩形框点击事件
/// </summary>
/// <param name="args">视频矩形框被选中事件参数</param>
internal void ExecuteVideoRectangleClick(VideoRectangleClickEventArgs args)
{
if (!this.IsRectangleClickTrigger)
return;
this.VideoRectangleClick?.Invoke(this, args);
}
/// <summary>
/// 执行视频矩形框选事件
/// </summary>
/// <param name="args">视频矩形框框选事件参数</param>
internal void ExecuteVideoRectangleFrameSelection(VideoRectangleFrameSelectionEventArgs args)
{
if (!this.IsRectangleFrameSelectionTrigger)
return;
// 宽度或高度为0的矩形框为无效数据
if (args.VideoRectangle.Width == 0 || args.VideoRectangle.Height == 0)
{
this.ClearFrameSelection();
return;
}
this.VideoRectangleFrameSelection?.Invoke(this, args);
}
}
}
using ManageLiteAV;
using SharpDX.Direct2D1;
using SharpDX.DXGI;
using SharpDX.Windows;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using VIZ.GimbalAI.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Storage;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频自定义渲染
/// ---------------------------------------------
/// 1. 视频帧渲染
/// 2. 矩形框信息渲染
/// 3. 渲染帧至图片
/// ---------------------------------------------
/// </summary>
public class VideoCustomRender : D2dControl, IVideoRender
{
public VideoCustomRender()
{
if (WPFHelper.IsInDesignMode(this))
return;
// 算法矩形框宽度(单位:像素)
this.AlgorithmRectangleStrokeWidth = VDataDomain.IniStorage.GetValue<ClientConfig, float>(p => p.CLIENT_ALGORITHM_RECTANGLE_STROKE_WIDTH);
// 框选矩形框宽度(单位:像素)
this.FrameSelectionStrokeWidth = VDataDomain.IniStorage.GetValue<ClientConfig, float>(p => p.CLIENT_FRAME_SELECTION_STROKE_WIDTH);
// 算法矩形框颜色
this.AlgorithmRectangleColor = SharpDxColorHelper.FromString(VDataDomain.IniStorage.GetValue<ClientConfig, string>(p => p.CLIENT_ALGORITHM_RECTANGLE_COLOR));
// 框选矩形框颜色
this.FrameSelectionColor = SharpDxColorHelper.FromString(VDataDomain.IniStorage.GetValue<ClientConfig, string>(p => p.CLIENT_FRAME_SELECTION_COLOR));
}
// ========================================================================================================
// === Property ===
// ========================================================================================================
/// <summary>
/// 是否启用绘制视频
/// </summary>
public bool IsRenderVideoEnabled { get; set; } = true;
/// <summary>
/// 是否启用绘制矩形框
/// </summary>
public bool IsRenderRectangleEnabled { get; set; } = true;
/// <summary>
/// 是否启用绘制框选区域
/// </summary>
public bool IsRenderFrameSelectionEnabled { get; set; } = false;
// ------------------------------------------------------------------------------------------------------
// INI Config
/// <summary>
/// 算法矩形框宽度(单位:像素)
/// </summary>
public float AlgorithmRectangleStrokeWidth { get; set; } = 4f;
/// <summary>
/// 框选矩形框宽度(单位:像素)
/// </summary>
public float FrameSelectionStrokeWidth { get; set; } = 4f;
/// <summary>
/// 算法矩形框颜色
/// </summary>
public SharpDX.Mathematics.Interop.RawColor4 AlgorithmRectangleColor { get; set; }
/// <summary>
/// 框选矩形框颜色
/// </summary>
public SharpDX.Mathematics.Interop.RawColor4 FrameSelectionColor { get; set; }
// ========================================================================================================
/// <summary>
/// 所属渲染控件
/// </summary>
internal VideoControl OwnerVideoControl { get; set; }
/// <summary>
/// 待渲染信息
/// </summary>
private volatile VideoRenderInfo renderInfo;
/// <summary>
/// 矩形信息
/// </summary>
private List<VideoRectangle> rectangleInfos = new List<VideoRectangle>();
/// <summary>
/// 视频矩形区域框选
/// </summary>
private RectangleF? videoRectangleFrameSelection;
/// <summary>
/// 渲染锁对象
/// </summary>
private object bitmap_render_lock_object = new object();
// ========================================================================================================
// === Public Function ===
// ========================================================================================================
/// <summary>
/// 渲染
/// </summary>
/// <param name="videoFrame">视频帧</param>
public void RenderVideo(IVideoFrame videoFrame)
{
// ----------------------------------------------------------------------------------------
// 计算绘制区域与大小
int width;
int height;
BitmapHelper.AdjustSize((int)this.ActualWidth, (int)this.ActualHeight, videoFrame.Width, videoFrame.Height, out width, out height);
int x = (int)((this.ActualWidth - width) / 2);
int y = (int)((this.ActualHeight - height) / 2);
RectangleF rectangle = new RectangleF(x, y, width, height);
// ----------------------------------------------------------------------------------------
// 绘制帧画面
VideoRenderInfo info = new VideoRenderInfo();
info.DataStream = videoFrame.DataStream;
info.BitmapWidth = videoFrame.Width;
info.BitmapHeight = videoFrame.Height;
info.Rectangle = rectangle;
lock (this.bitmap_render_lock_object)
{
this.renderInfo?.Dispose();
this.renderInfo = info;
}
}
/// <summary>
/// 渲染矩形框信息
/// </summary>
/// <param name="rectangles">矩形框</param>
public void RenderRectangleInfo(List<VideoRectangle> rectangles)
{
this.rectangleInfos = rectangles;
}
/// <summary>
/// 渲染视频矩形区域框选
/// </summary>
/// <param name="uiRect">UI框选区域</param>
public void RenderFrameSelection(RectangleF? uiRect)
{
this.videoRectangleFrameSelection = uiRect;
}
/// <summary>
/// 渲染视频至文件
/// </summary>
/// <param name="target">渲染目标</param>
public void RenderVideoToFile(RenderTarget target)
{
VideoRenderInfo info = this.renderInfo;
if (info == null)
return;
// BLACK
target.Clear(new SharpDX.Mathematics.Interop.RawColor4(0, 0, 0, 1));
BitmapProperties properties = new BitmapProperties(new SharpDX.Direct2D1.PixelFormat(Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied));
SharpDX.Direct2D1.Bitmap bmp = new SharpDX.Direct2D1.Bitmap(target, new SharpDX.Size2(info.BitmapWidth, info.BitmapHeight), info.DataStream, info.BitmapWidth * 4, properties);
RectangleF dstRect = BitmapHelper.Resize(info.BitmapWidth, info.BitmapHeight, 400, null);
SharpDX.Mathematics.Interop.RawRectangleF rect = new SharpDX.Mathematics.Interop.RawRectangleF(0, 0, dstRect.Width, dstRect.Height);
target.DrawBitmap(bmp, rect, 1f, BitmapInterpolationMode.Linear, null);
bmp.Dispose();
}
/// <summary>
/// 将帧内容保存为图片
/// ----------------------------------------------------
/// 1. 只保存视频帧 & 渲染框
/// 2. 图片保存为jpg数据
/// ----------------------------------------------------
/// </summary>
/// <param name="path">图片路径</param>
public void SaveFrameImage(string path)
{
lock (this.bitmap_render_lock_object)
{
VideoRenderInfo info = this.renderInfo;
if (renderInfo == null)
return;
RectangleF rect = BitmapHelper.Resize(info.BitmapWidth, info.BitmapHeight, 400, null);
WicBitmapDefaultHelper helper = new WicBitmapDefaultHelper(this.RenderVideoToFile);
helper.RenderToFile((int)rect.Width, (int)rect.Height, path);
}
}
/// <summary>
/// 获取帧图片
/// </summary>
/// <returns>图片</returns>
public System.Drawing.Bitmap GetFrameImage()
{
string fileName = System.IO.Path.GetTempFileName();
this.SaveFrameImage(fileName);
if (!System.IO.File.Exists(fileName))
return null;
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fileName);
return bmp;
}
// ========================================================================================================
/// <summary>
/// 绘制
/// </summary>
/// <param name="target">渲染目标</param>
public override void Render(RenderTarget target)
{
lock (this.bitmap_render_lock_object)
{
// BLACK
target.Clear(new SharpDX.Mathematics.Interop.RawColor4(0, 0, 0, 1));
// 绘制视频
this.OnPaintVideo(target);
// 绘制矩形区域
this.OnPaintRectangleInfo(target);
// 绘制矩形框选区域
this.OnPaintFrameSelection(target);
}
}
/// <summary>
/// 绘制视频
/// </summary>
/// <param name="target">渲染目标</param>
private void OnPaintVideo(RenderTarget target)
{
VideoRenderInfo info = this.renderInfo;
if (info == null || !this.IsRenderVideoEnabled)
return;
BitmapProperties properties = new BitmapProperties(new SharpDX.Direct2D1.PixelFormat(Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied));
SharpDX.Direct2D1.Bitmap bmp = new SharpDX.Direct2D1.Bitmap(target, new SharpDX.Size2(info.BitmapWidth, info.BitmapHeight), info.DataStream, info.BitmapWidth * 4, properties);
SharpDX.Mathematics.Interop.RawRectangleF rect = new SharpDX.Mathematics.Interop.RawRectangleF(info.Rectangle.Left, info.Rectangle.Top, info.Rectangle.Right, info.Rectangle.Bottom);
target.DrawBitmap(bmp, rect, 1f, BitmapInterpolationMode.Linear, null);
bmp.Dispose();
}
/// <summary>
/// 绘制矩形框信息
/// </summary>
/// <param name="target">渲染目标</param>
private void OnPaintRectangleInfo(RenderTarget target)
{
// 画面渲染区域
VideoRenderInfo renderInfo = this.renderInfo;
if (renderInfo == null || !this.IsRenderRectangleEnabled)
return;
if (this.rectangleInfos == null || this.rectangleInfos.Count == 0)
return;
foreach (VideoRectangle info in this.rectangleInfos)
{
RectangleF? srcRect = info.ConvertAlgorithmRoiToRectangle();
if (srcRect == null)
{
// 获取算法给定坐标异常
continue;
}
// 将图片矩形区域转化为UI矩形区域
RectangleF rectangle = BitmapHelper.ConvertBitmapRectToUiRect(renderInfo.BitmapWidth, renderInfo.BitmapHeight, renderInfo.Rectangle, srcRect.Value);
SharpDX.Mathematics.Interop.RawRectangleF rect = new SharpDX.Mathematics.Interop.RawRectangleF(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom);
SharpDX.Direct2D1.SolidColorBrush brush = new SolidColorBrush(target, this.AlgorithmRectangleColor);
target.DrawRectangle(rect, brush, this.AlgorithmRectangleStrokeWidth);
}
}
/// <summary>
/// 绘制框选
/// </summary>
/// <param name="target">渲染目标</param>
private void OnPaintFrameSelection(RenderTarget target)
{
// 款选区域
RectangleF? videoRectangleFrameSelection = this.videoRectangleFrameSelection;
if (videoRectangleFrameSelection == null || !this.IsRenderFrameSelectionEnabled)
return;
SharpDX.Mathematics.Interop.RawRectangleF rect = new SharpDX.Mathematics.Interop.RawRectangleF(
videoRectangleFrameSelection.Value.Left, videoRectangleFrameSelection.Value.Top,
videoRectangleFrameSelection.Value.Right, videoRectangleFrameSelection.Value.Bottom);
SolidColorBrush brush = new SolidColorBrush(target, this.FrameSelectionColor);
target.DrawRectangle(rect, brush, this.FrameSelectionStrokeWidth);
}
// ==============================================================================================================================
// === Event ===
// ==============================================================================================================================
// ------------------------------------------------------------------------------------------
// --- 矩形框点击事件 ---
// ------------------------------------------------------------------------------------------
/// <summary>
/// 鼠标左键按下
/// </summary>
/// <param name="e"></param>
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
// 画面渲染区域
VideoRenderInfo renderInfo = this.renderInfo;
List<VideoRectangle> rectangleInfos = this.rectangleInfos;
this.mouseLeftButtonDownPoint = e.GetPosition(this);
if (renderInfo == null)
return;
VideoRectangleClickEventArgs args = new VideoRectangleClickEventArgs();
args.MousePosition = this.mouseLeftButtonDownPoint.Value;
PointF point = BitmapHelper.ConvertUiPointToBitmapPoint(renderInfo.BitmapWidth, renderInfo.BitmapHeight, renderInfo.Rectangle,
new PointF((float)args.MousePosition.X, (float)args.MousePosition.Y));
args.VideoPosition = new System.Windows.Point(point.X, point.Y);
args.VideoRectangles = rectangleInfos;
args.HitTestVideoRectangles = VideoRectangleExpand.HitTest(rectangleInfos, args.VideoPosition);
// 触发视频矩形框点击事件
this.OwnerVideoControl?.ExecuteVideoRectangleClick(args);
}
// ------------------------------------------------------------------------------------------
// --- 矩形框框选事件 ---
// ------------------------------------------------------------------------------------------
/// <summary>
/// 鼠标左键点击的位置
/// </summary>
private System.Windows.Point? mouseLeftButtonDownPoint;
/// <summary>
/// 鼠标释放
/// </summary>
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
{
if (this.mouseLeftButtonDownPoint == null)
return;
System.Windows.Point mousePoint = this.mouseLeftButtonDownPoint.Value;
this.mouseLeftButtonDownPoint = null;
VideoRenderInfo renderInfo = this.renderInfo;
if (renderInfo == null)
{
this.OwnerVideoControl.ClearFrameSelection();
return;
}
VideoRectangleFrameSelectionEventArgs args = new VideoRectangleFrameSelectionEventArgs();
System.Windows.Point point = e.GetPosition(this);
float left = (float)Math.Min(point.X, mousePoint.X);
float top = (float)Math.Min(point.Y, mousePoint.Y);
float right = (float)Math.Max(point.X, mousePoint.X);
float bottom = (float)Math.Max(point.Y, mousePoint.Y);
args.MouseRectangle = new RectangleF(left, top, right - left, bottom - top);
args.VideoRectangle = BitmapHelper.ConvertUiRectToBitmapRect(renderInfo.BitmapWidth, renderInfo.BitmapHeight, renderInfo.Rectangle, args.MouseRectangle);
// 触发视频矩形框选事件
this.OwnerVideoControl?.ExecuteVideoRectangleFrameSelection(args);
}
/// <summary>
/// 鼠标移动
/// </summary>
/// <param name="e"></param>
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
if (this.mouseLeftButtonDownPoint == null)
return;
System.Windows.Point point = e.GetPosition(this);
float left = (float)Math.Min(point.X, this.mouseLeftButtonDownPoint.Value.X);
float top = (float)Math.Min(point.Y, this.mouseLeftButtonDownPoint.Value.Y);
float right = (float)Math.Max(point.X, this.mouseLeftButtonDownPoint.Value.X);
float bottom = (float)Math.Max(point.Y, this.mouseLeftButtonDownPoint.Value.Y);
RectangleF rect = new RectangleF(left, top, right - left, bottom - top);
this.videoRectangleFrameSelection = rect;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using SharpDX;
using SharpDX.Direct2D1;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频渲染信息
/// </summary>
public class VideoRenderInfo : IDisposable
{
/// <summary>
/// 图片数据
/// </summary>
public DataStream DataStream { get; set; }
/// <summary>
/// 视频帧信息
/// </summary>
public IVideoFrame Frame { get; set; }
/// <summary>
/// 渲染图片宽度
/// </summary>
public int BitmapWidth { get; set; }
/// <summary>
/// 渲染图片高度
/// </summary>
public int BitmapHeight { get; set; }
/// <summary>
/// 渲染区域
/// </summary>
public System.Drawing.RectangleF Rectangle { get; set; }
/// <summary>
/// 该对象是否已经被销毁
/// </summary>
private bool IsDisopsed { get; set; }
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
if (this.IsDisopsed)
return;
this.IsDisopsed = true;
this.DataStream?.Dispose();
this.DataStream = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX;
using SharpDX.Direct2D1;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频帧
/// </summary>
public interface IVideoFrame
{
/// <summary>
/// 宽度
/// </summary>
int Width { get; set; }
/// <summary>
/// 高度
/// </summary>
int Height { get; set; }
/// <summary>
/// 数据长度
/// </summary>
int Length { get; set; }
/// <summary>
/// 时间粗
/// </summary>
long TimeStamp { get; set; }
/// <summary>
/// 画面数据
/// </summary>
DataStream DataStream { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NewTek;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// NDI工具 静态部分
/// </summary>
public partial class NDITool
{
/// <summary>
/// 是否完成了初始化
/// </summary>
public static bool IsInited { get; private set; }
/// <summary>
/// 初始化
/// </summary>
/// <returns>是否初始化成功</returns>
public static bool Init()
{
if (!NDIlib.initialize())
return false;
IsInited = true;
return true;
}
public static void Destroy()
{
if (!IsInited)
return;
NDIlib.destroy();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using NewTek;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using NewTek.NDI;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// NDI工具
/// </summary>
public partial class NDITool : IDisposable
{
/// <summary>
/// NDI工具
/// </summary>
/// <param name="localRecevierName">本地接收者名称</param>
/// <param name="remoteSenderName">远程发送者名称</param>
/// <param name="option">设置</param>
public NDITool(string localRecevierName, string remoteSenderName, NDIToolOption option)
{
this.LocalRecevierName = localRecevierName;
this.RemoteSenderName = remoteSenderName;
this.Option = option;
// 查找NDI流任务
this.TaskDic.Add(NDIToolTaskNames.FIND_STREAM, new NDIToolFindStreamTask());
// 接收视频帧任务
this.TaskDic.Add(NDIToolTaskNames.RECV_VIDEO, new NDIToolRecvVideoTask());
// 处理视频帧任务
this.TaskDic.Add(NDIToolTaskNames.EXECUTE_VIDEO, new NDIToolExecuteVideoTask());
}
/* ========================================================================================================= */
/* === Const === */
/* ========================================================================================================= */
/// <summary>
/// 视频帧队列最大容量
/// 如果超过该容量,那么会抛弃对队列头部的处理
/// </summary>
public const int VIDEO_FRAME_QUEUE_MAX_COUNT = 8;
/// <summary>
/// the size of an NDIlib.source_t, for pointer offsets
/// </summary>
public readonly int SOURCE_SIZE_IN_BYTES = Marshal.SizeOf(typeof(NDIlib.source_t));
/* ========================================================================================================= */
/* === Property === */
/* ========================================================================================================= */
/// <summary>
/// NDI流信息集合
/// </summary>
public List<NDIToolStreamInfo> StreamInfos { get; private set; } = new List<NDIToolStreamInfo>();
/// <summary>
/// 远程NDI发送者名称
/// </summary>
public string RemoteSenderName { get; private set; }
/// <summary>
/// 本地NDI接收者名称
/// </summary>
public string LocalRecevierName { get; private set; }
/// <summary>
/// 设置
/// </summary>
public NDIToolOption Option { get; private set; }
/* ========================================================================================================= */
/* === Event === */
/* ========================================================================================================= */
/// <summary>
/// 处理视频帧事件
/// </summary>
public event EventHandler<VideoFrameEventArgs> ExecuteVideoFrame;
/* ========================================================================================================= */
/* === Internal Field === */
/* ========================================================================================================= */
/// <summary>
/// 查找NDI流实例句柄
/// </summary>
internal IntPtr FindInstancePtr;
/// <summary>
/// 当前正在处理的NDI流源
/// </summary>
internal NDIlib.source_t? CurrentRemoteSenderSource;
/// <summary>
/// 接收NDI流实例句柄
/// </summary>
internal IntPtr RecvInstancePtr;
/// <summary>
/// 接收NDI流同步信息实例句柄
/// </summary>
internal IntPtr RecvSyncInstancePtr;
/// <summary>
/// 视频帧队列
/// </summary>
internal ConcurrentQueue<IVideoFrame> VideoFrameQueue = new ConcurrentQueue<IVideoFrame>();
/* ========================================================================================================= */
/* === Field === */
/* ========================================================================================================= */
/// <summary>
/// 任务池
/// </summary>
private Dictionary<NDIToolTaskNames, NDIToolTaskBase> TaskDic = new Dictionary<NDIToolTaskNames, NDIToolTaskBase>();
/* ========================================================================================================= */
/* === Function === */
/* ========================================================================================================= */
/// <summary>
/// 开始
/// </summary>
public void Start()
{
NDIlib.find_create_t findCreateDesc = new NDIlib.find_create_t();
findCreateDesc.p_groups = IntPtr.Zero;
findCreateDesc.show_local_sources = true;
findCreateDesc.p_extra_ips = IntPtr.Zero;
// 创建NDI流查找实例句柄
this.FindInstancePtr = NDIlib.find_create_v2(ref findCreateDesc);
// 启动NDI流查找任务
this.TaskDic[NDIToolTaskNames.FIND_STREAM].Start(this);
// 启动NDI视频帧接收任务
this.TaskDic[NDIToolTaskNames.RECV_VIDEO].Start(this);
// 启动NDI视频帧处理任务
this.TaskDic[NDIToolTaskNames.EXECUTE_VIDEO].Start(this);
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
// 停止所有任务
foreach (var task in this.TaskDic.Values)
{
task.Stop();
}
// 重置当前NDI流信息
this.CurrentRemoteSenderSource = null;
// 清理流信息
lock (this.StreamInfos)
{
this.StreamInfos.Clear();
}
// 释放查找NDI流句柄
if (this.FindInstancePtr != IntPtr.Zero)
{
NDIlib.find_destroy(this.FindInstancePtr);
this.FindInstancePtr = IntPtr.Zero;
}
// 释放接收NDI流实例句柄
if (this.RecvInstancePtr != IntPtr.Zero)
{
NDIlib.recv_destroy(this.RecvInstancePtr);
this.RecvInstancePtr = IntPtr.Zero;
}
// 释放NDI流同步接收实例句柄
if (this.RecvSyncInstancePtr != IntPtr.Zero)
{
NDIlib.framesync_destroy(this.RecvSyncInstancePtr);
this.RecvSyncInstancePtr = IntPtr.Zero;
}
}
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this.Stop();
}
/// <summary>
/// 切换远程发送者名称
/// </summary>
/// <param name="remoteSenderName">远程发送者名称</param>
/// <returns>是否成功切换</returns>
public bool ChangeRemoteSenderName(string remoteSenderName)
{
// -------------------------------------------------------------------------------
// 获取将要切换的NDI流信息
// 获取要切换的NDI流信息
NDIToolStreamInfo info = null;
lock (this.StreamInfos)
{
info = this.StreamInfos.FirstOrDefault(p => p.FullName == remoteSenderName);
}
if (info == null)
{
return false;
}
// -------------------------------------------------------------------------------
// 释放
// 释放接收NDI流实例句柄
if (this.RecvInstancePtr != IntPtr.Zero)
{
NDIlib.recv_destroy(this.RecvInstancePtr);
this.RecvInstancePtr = IntPtr.Zero;
}
// 释放NDI流同步接收实例句柄
if (this.RecvSyncInstancePtr != IntPtr.Zero)
{
NDIlib.framesync_destroy(this.RecvSyncInstancePtr);
this.RecvSyncInstancePtr = IntPtr.Zero;
}
// -------------------------------------------------------------------------------
// 初始化
// 设置NDI发送者名称
this.RemoteSenderName = remoteSenderName;
// 设置当前NDI发送源
this.CurrentRemoteSenderSource = info.Source;
// 创建NDI接收实例句柄 & NDI同步接收实例对象
NDIlib.recv_create_v3_t recvCreateDesc = new NDIlib.recv_create_v3_t();
recvCreateDesc.source_to_connect_to = info.Source;
recvCreateDesc.color_format = NDIlib.recv_color_format_e.recv_color_format_BGRX_BGRA;
recvCreateDesc.bandwidth = NDIlib.recv_bandwidth_e.recv_bandwidth_highest;
recvCreateDesc.allow_video_fields = false;
recvCreateDesc.p_ndi_recv_name = UTF.StringToUtf8(this.LocalRecevierName);
this.RecvInstancePtr = NDIlib.recv_create_v3(ref recvCreateDesc);
this.RecvSyncInstancePtr = NDIlib.framesync_create(this.RecvInstancePtr);
// -------------------------------------------------------------------------------
// 切换成功
return true;
}
/// <summary>
/// 设置视频帧延时
/// </summary>
/// <param name="delayFrame">延时帧</param>
public void SetVideoFrameDelay(int delayFrame)
{
this.Option.DelayFrame = delayFrame;
while (this.VideoFrameQueue.Count > NDITool.VIDEO_FRAME_QUEUE_MAX_COUNT + this.Option.DelayFrame)
{
this.VideoFrameQueue.TryDequeue(out IVideoFrame remove);
remove?.DataStream?.Dispose();
}
}
/* ========================================================================================================= */
/* === Internal Function === */
/* ========================================================================================================= */
/// <summary>
/// 触发执行视频帧事件
/// </summary>
/// <param name="frame">视频帧</param>
internal void TriggerExecuteVideoFrame(IVideoFrame frame)
{
if (this.ExecuteVideoFrame == null)
return;
VideoFrameEventArgs args = new VideoFrameEventArgs();
args.Frame = frame;
this.ExecuteVideoFrame.Invoke(this, args);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NewTek;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// NDI流信息
/// </summary>
public class NDIToolStreamInfo
{
/// <summary>
/// 机器
/// </summary>
public string Machine { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 完整名称
/// </summary>
public string FullName { get; set; }
/// <summary>
/// NDI流信息
/// </summary>
public NDIlib.source_t Source { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// NDI工具任务
/// </summary>
public abstract class NDIToolTaskBase : IDisposable
{
/// <summary>
/// 任务名称
/// </summary>
public abstract NDIToolTaskNames Name { get; }
/// <summary>
/// NDI工具
/// </summary>
public NDITool Tool { get; private set; }
/// <summary>
/// 是否开启
/// </summary>
public bool IsStarted { get; set; }
/// <summary>
/// 任务线程
/// </summary>
private Thread Thread;
/// <summary>
/// 开始
/// </summary>
public void Start(NDITool tool)
{
if (this.IsStarted)
throw new Exception("task is already started.");
this.Tool = tool;
this.IsStarted = true;
this.Thread = new Thread(this.Execute);
this.Thread.IsBackground = true;
this.Thread.Start();
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
this.IsStarted = false;
this.Thread = null;
}
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this.Stop();
}
/// <summary>
/// 执行
/// </summary>
protected abstract void Execute();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// NDI工具任务名称
/// </summary>
public enum NDIToolTaskNames
{
/// <summary>
/// 查找NDI流
/// </summary>
FIND_STREAM,
/// <summary>
/// 接收视频
/// </summary>
RECV_VIDEO,
/// <summary>
/// 处理视频帧
/// </summary>
EXECUTE_VIDEO
}
}
using NewTek;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX;
using SharpDX.Direct2D1;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// NDI视频帧
/// </summary>
public class NDIToolVideoFrame : IVideoFrame
{
/// <summary>
/// 宽度
/// </summary>
public int Width { get; set; }
/// <summary>
/// 高度
/// </summary>
public int Height { get; set; }
/// <summary>
/// 数据长度
/// </summary>
public int Length { get; set; }
/// <summary>
/// 时间粗
/// </summary>
public long TimeStamp { get; set; }
/// <summary>
/// 画面数据
/// </summary>
public DataStream DataStream { get; set; }
}
}
using NewTek;
using NewTek.NDI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 查找NDI流任务
/// </summary>
public class NDIToolFindStreamTask : NDIToolTaskBase
{
/// <summary>
/// 任务名称
/// </summary>
public override NDIToolTaskNames Name => NDIToolTaskNames.FIND_STREAM;
/// <summary>
/// the size of an NDIlib.source_t, for pointer offsets
/// </summary>
private readonly int SOURCE_SIZE_IN_BYTES = Marshal.SizeOf(typeof(NDIlib.source_t));
/// <summary>
/// 执行
/// </summary>
protected override void Execute()
{
while (this.IsStarted)
{
this._Execute();
}
}
/// <summary>
/// 执行
/// </summary>
private void _Execute()
{
if (!NDIlib.find_wait_for_sources(this.Tool.FindInstancePtr, 500))
return;
lock (this.Tool.StreamInfos)
{
this.Tool.StreamInfos.Clear();
}
uint numSources = 0;
IntPtr sourcesPtr = NDIlib.find_get_current_sources(this.Tool.FindInstancePtr, ref numSources);
for (int i = 0; i < numSources; i++)
{
// 连续的数据结构
IntPtr p = IntPtr.Add(sourcesPtr, (i * SOURCE_SIZE_IN_BYTES));
// 指针转化为 NDIlib.source_t 数据结构
NDIlib.source_t src = (NDIlib.source_t)Marshal.PtrToStructure(p, typeof(NDIlib.source_t));
// NDI流名称
string ndiName = UTF.Utf8ToString(src.p_ndi_name);
// 添加NDI流信息
NDIToolStreamInfo info = new NDIToolStreamInfo();
info.FullName = ndiName;
info.Machine = ndiName.Split(new char[] { ' ' }, 2)[0];
info.Name = ndiName.Substring(ndiName.IndexOf(' ') + 1);
info.Source = src;
lock (this.Tool.StreamInfos)
{
this.Tool.StreamInfos.Add(info);
}
}
// 如果当前没有正在处理的流信息那么切换为当前RemoteSenderName指定的流信息
if (this.Tool.CurrentRemoteSenderSource == null)
{
this.Tool.ChangeRemoteSenderName(this.Tool.RemoteSenderName);
}
}
}
}
using NewTek;
using NewTek.NDI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 查找NDI流任务
/// </summary>
public class NDIToolRecvVideoTask : NDIToolTaskBase
{
/// <summary>
/// 任务名称
/// </summary>
public override NDIToolTaskNames Name => NDIToolTaskNames.RECV_VIDEO;
/// <summary>
/// 之前的视频帧时间戳
/// </summary>
private long old_video_timestamp = 0;
/// <summary>
/// 执行
/// </summary>
protected override void Execute()
{
while (this.IsStarted)
{
if (this.Tool.RecvInstancePtr == IntPtr.Zero || this.Tool.RecvSyncInstancePtr == IntPtr.Zero)
{
Thread.Sleep(1);
continue;
}
// 执行
this._Execute();
}
}
/// <summary>
/// 执行
/// </summary>
private void _Execute()
{
// 获取NDI视频帧
NDIlib.video_frame_v2_t frame = new NDIlib.video_frame_v2_t();
NDIlib.framesync_capture_video(this.Tool.RecvSyncInstancePtr, ref frame, NDIlib.frame_format_type_e.frame_format_type_progressive);
// 如果该帧的时间戳与之前的帧时间戳一致
// 那么认为没有获取到新的一帧画面
if (this.old_video_timestamp == frame.timestamp)
{
NDIlib.framesync_free_video(this.Tool.RecvSyncInstancePtr, ref frame);
Thread.Sleep(1);
return;
}
// 否则
// 获取到新的一帧画面
this.old_video_timestamp = frame.timestamp;
// 如果新的一帧画面的时间戳为0 || 帧没有数据
if (frame.timestamp == 0 || frame.p_data == IntPtr.Zero || frame.p_data == null)
{
NDIlib.framesync_free_video(this.Tool.RecvSyncInstancePtr, ref frame);
Thread.Sleep(1);
return;
}
// 视频帧队列最大容量
// 如果超过该容量,那么会抛弃对队列头部的处理
if (this.Tool.VideoFrameQueue.Count > NDITool.VIDEO_FRAME_QUEUE_MAX_COUNT + this.Tool.Option.DelayFrame)
{
this.Tool.VideoFrameQueue.TryDequeue(out IVideoFrame remove);
remove?.DataStream?.Dispose();
}
NDIToolVideoFrame videoFrame = new NDIToolVideoFrame();
videoFrame.Width = frame.xres;
videoFrame.Height = frame.yres;
videoFrame.Length = frame.xres * frame.yres * 4;
videoFrame.TimeStamp = frame.timestamp;
videoFrame.DataStream = new SharpDX.DataStream(videoFrame.Length, true, true);
unsafe
{
Buffer.MemoryCopy(frame.p_data.ToPointer(), videoFrame.DataStream.DataPointer.ToPointer(), videoFrame.Length, videoFrame.Length);
}
this.Tool.VideoFrameQueue.Enqueue(videoFrame);
// 尝试释放帧数据
NDIlib.framesync_free_video(this.Tool.RecvSyncInstancePtr, ref frame);
Thread.Sleep(5);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频帧事件参数
/// </summary>
public class VideoFrameEventArgs : EventArgs
{
/// <summary>
/// 视频帧数据
/// </summary>
public IVideoFrame Frame { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 视频流管理器
/// </summary>
public static class VideoStreamManager
{
/// <summary>
/// NDI工具
/// </summary>
public static NDITool NDITool { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using VIZ.GimbalAI.Core;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 拖拽窗口区域
/// </summary>
public class DragWindowBar : Border
{
/// <summary>
/// 鼠标按下的坐标
/// </summary>
private Point? mouseLeftButtonDownPoint;
/// <summary>
/// 所属窗口
/// </summary>
private Window ownerWindow;
/// <summary>
/// 获取所属窗口
/// </summary>
/// <returns>所属窗口</returns>
private Window GetOwnerWindow()
{
if (this.ownerWindow != null)
return this.ownerWindow;
this.ownerWindow = WPFHelper.GetAncestorByType<Window>(this);
return this.ownerWindow;
}
/// <summary>
/// 鼠标按下
/// </summary>
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonDown(e);
this.mouseLeftButtonDownPoint = e.GetPosition(this);
}
/// <summary>
/// 鼠标移动
/// </summary>
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnPreviewMouseMove(e);
if (e.LeftButton != MouseButtonState.Pressed || this.mouseLeftButtonDownPoint == null)
return;
Point point = e.GetPosition(this);
if (Math.Abs(point.X - this.mouseLeftButtonDownPoint.Value.X) >= 5 || Math.Abs(point.Y - this.mouseLeftButtonDownPoint.Value.Y) >= 5)
{
Window window = this.GetOwnerWindow();
window.DragMove();
}
}
/// <summary>
/// 鼠标释放
/// </summary>
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonUp(e);
this.mouseLeftButtonDownPoint = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
namespace VIZ.GimbalAI.Common
{
/// <summary>
/// 空窗口
/// </summary>
public class NoneWindow : Window
{
/// <summary>
/// 窗口
/// </summary>
/// <param name="width">窗口宽度</param>
/// <param name="height">窗口高度</param>
/// <param name="content">窗口内容</param>
public NoneWindow(double width, double height, Control content)
{
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
this.WindowState = WindowState.Normal;
this.WindowStyle = WindowStyle.None;
this.Background = new SolidColorBrush(Colors.Transparent);
this.AllowsTransparency = true;
this.Width = width;
this.Height = height;
this.Content = content;
content.Margin = new Thickness(10, 10, 10, 10);
}
}
}
......@@ -6,6 +6,10 @@
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
......@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Connection
{
......@@ -34,35 +35,16 @@ namespace VIZ.GimbalAI.Connection
/// <summary>
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
public void Execute(UdpPackageInfo packageInfo)
/// <param name="info">信息</param>
public void Execute(ConnSingleJsonInfo info)
{
Task.Run(() =>
{
try
{
this._Execute(packageInfo);
}
catch (Exception ex)
{
log.Error(ex);
}
});
}
/// <summary>
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
private void _Execute(UdpPackageInfo packageInfo)
{
AlgorithmPackageBase @base = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmPackageBase>(packageInfo.Message);
AlgorithmPackageBase @base = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmPackageBase>(info.Json);
foreach (IAlgorithmPackageProvider provider in this.providers)
{
if (string.Equals(provider.Signal, @base.signal))
{
provider.Execute(packageInfo);
provider.Execute(info);
break;
}
......
......@@ -45,5 +45,10 @@ namespace VIZ.GimbalAI.Connection
/// 算法初始化完成
/// </summary>
public const string tracking_init_complete = "tracking_init_complete";
/// <summary>
/// 设置中心轴位置
/// </summary>
public const string tx_ty = "tx_ty";
}
}
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Connection
{
......@@ -20,7 +21,7 @@ namespace VIZ.GimbalAI.Connection
/// <summary>
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
void Execute(UdpPackageInfo packageInfo);
/// <param name="info">信息</param>
void Execute(ConnSingleJsonInfo info);
}
}
......@@ -4,7 +4,8 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
using VIZ.Framework.Connection;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
......@@ -25,15 +26,15 @@ namespace VIZ.GimbalAI.Connection
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
public void Execute(UdpPackageInfo packageInfo)
public void Execute(ConnSingleJsonInfo packageInfo)
{
AlgorithmDetectRecvPackage package = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmDetectRecvPackage>(packageInfo.Message);
AlgorithmDetectRecvPackage package = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmDetectRecvPackage>(packageInfo.Json);
VideoRenderRectangleMessage msg = new VideoRenderRectangleMessage();
msg.signal = package.signal;
msg.roi = package.roi;
VAppDomain.AlgorithmMessageManager.Send(msg);
ApplicationDomainEx.MessageManager.Send(msg);
}
}
}
......@@ -4,7 +4,7 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Connection;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
......@@ -25,16 +25,16 @@ namespace VIZ.GimbalAI.Connection
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
public void Execute(UdpPackageInfo packageInfo)
public void Execute(ConnSingleJsonInfo packageInfo)
{
// 更新界面
AlgorithmTargetLostRecvPackage package = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmTargetLostRecvPackage>(packageInfo.Message);
AlgorithmTargetLostRecvPackage package = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmTargetLostRecvPackage>(packageInfo.Json);
VideoRenderRectangleMessage msg = new VideoRenderRectangleMessage();
msg.signal = package.signal;
msg.roi = new Dictionary<int, List<float>>();
VAppDomain.AlgorithmMessageManager.Send(msg);
ApplicationDomainEx.MessageManager.Send(msg);
}
}
}
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Connection;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
......@@ -23,11 +24,11 @@ namespace VIZ.GimbalAI.Connection
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
public void Execute(UdpPackageInfo packageInfo)
public void Execute(ConnSingleJsonInfo packageInfo)
{
AlgorithmInitCompleteMessage msg = new AlgorithmInitCompleteMessage();
VAppDomain.UiMessageManager.Send(msg);
ApplicationDomainEx.MessageManager.Send(msg);
}
}
}
\ No newline at end of file
......@@ -4,7 +4,7 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Connection;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
......@@ -25,16 +25,16 @@ namespace VIZ.GimbalAI.Connection
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
public void Execute(UdpPackageInfo packageInfo)
public void Execute(ConnSingleJsonInfo packageInfo)
{
AlgorithmTrackingRecvPackage package = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmTrackingRecvPackage>(packageInfo.Message);
AlgorithmTrackingRecvPackage package = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmTrackingRecvPackage>(packageInfo.Json);
VideoRenderRectangleMessage msg = new VideoRenderRectangleMessage();
msg.signal = package.signal;
msg.roi = new Dictionary<int, List<float>>();
msg.roi.Add(0, package.roi);
VAppDomain.AlgorithmMessageManager.Send(msg);
ApplicationDomainEx.MessageManager.Send(msg);
}
}
}
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Connection;
using VIZ.GimbalAI.Domain;
namespace VIZ.GimbalAI.Connection
......@@ -21,10 +22,10 @@ namespace VIZ.GimbalAI.Connection
AlgorithmAutoDetectPackage package = new AlgorithmAutoDetectPackage();
package.signal = AlgorithmPackageSignal.detect;
package.mode = AlgorithmPackageMode.auto;
package.scene = VDataDomain.AlgorithmAutoSetting.Scene.Value;
package.classes = VDataDomain.AlgorithmAutoSetting.Classes.Where(p => p.IsChecked).Select(p => p.Value).ToList();
package.scene = ApplicationDomainEx.AlgorithmAutoSetting.Scene.Value;
package.classes = ApplicationDomainEx.AlgorithmAutoSetting.Classes.Where(p => p.IsChecked).Select(p => p.Value).ToList();
manager.Send(package);
manager.SendJson(package);
}
/// <summary>
......@@ -39,7 +40,7 @@ namespace VIZ.GimbalAI.Connection
package.mode = AlgorithmPackageMode.manual;
package.roi = roi;
manager.Send(package);
manager.SendJson(package);
}
/// <summary>
......@@ -52,11 +53,11 @@ namespace VIZ.GimbalAI.Connection
AlgorithmAutoTrackingPackage package = new AlgorithmAutoTrackingPackage();
package.signal = AlgorithmPackageSignal.tracking;
package.mode = AlgorithmPackageMode.auto;
package.scene = VDataDomain.AlgorithmAutoSetting.Scene.Value;
package.classes = VDataDomain.AlgorithmAutoSetting.Classes.Where(p => p.IsChecked).Select(p => p.Value).ToList();
package.scene = ApplicationDomainEx.AlgorithmAutoSetting.Scene.Value;
package.classes = ApplicationDomainEx.AlgorithmAutoSetting.Classes.Where(p => p.IsChecked).Select(p => p.Value).ToList();
package.id = id;
manager.Send(package);
manager.SendJson(package);
}
/// <summary>
......@@ -70,7 +71,7 @@ namespace VIZ.GimbalAI.Connection
package.signal = AlgorithmPackageSignal.mode_change;
package.mode = mode;
manager.Send(package);
manager.SendJson(package);
}
/// <summary>
......@@ -84,7 +85,7 @@ namespace VIZ.GimbalAI.Connection
package.signal = AlgorithmPackageSignal.stop;
package.mode = mode;
manager.Send(package);
manager.SendJson(package);
}
/// <summary>
......@@ -96,7 +97,21 @@ namespace VIZ.GimbalAI.Connection
AlgorithmExitPackage package = new AlgorithmExitPackage();
package.signal = AlgorithmPackageSignal.exit;
manager.Send(package);
manager.SendJson(package);
}
/// <summary>
/// 发送中心轴位置
/// </summary>
/// <param name="manager">UDP终结点管理器</param>
public static void CenterAxis(UdpEndpointManager manager)
{
AlgorithmCenterAxisPackage package = new AlgorithmCenterAxisPackage();
package.signal = AlgorithmPackageSignal.tx_ty;
package.tx = ApplicationDomainEx.GimbalControlModel.CenterAxisX;
package.ty = ApplicationDomainEx.GimbalControlModel.CenterAxisY;
manager.SendJson(package);
}
}
}
......@@ -7,13 +7,18 @@ using System.Threading.Tasks;
namespace VIZ.GimbalAI.Connection
{
/// <summary>
/// 链接管理器
/// 算法自动检测包
/// </summary>
public static class ConnectionManager
public class AlgorithmCenterAxisPackage : AlgorithmPackageBase
{
/// <summary>
/// Udp连接
/// 中心轴X坐标
/// </summary>
public static UdpConnection UdpConnection { get; set; }
public double tx { get; set; }
/// <summary>
/// 中心轴Y坐标
/// </summary>
public double ty { get; set; }
}
}
......@@ -27,5 +27,10 @@ namespace VIZ.GimbalAI.Connection
/// 云台预设指令
/// </summary>
public const string preset = "preset";
/// <summary>
/// 中心轴指令
/// </summary>
public const string center_axis = "center axis";
}
}
......@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Connection
{
......@@ -15,50 +16,32 @@ namespace VIZ.GimbalAI.Connection
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AlgorithmPackageProvider));
private readonly static ILog log = LogManager.GetLogger(typeof(AlgorithmPackageProvider));
public GimbalPackageProvider()
{
this.providers.Add(new GimbalCenterAxisProvider());
this.providers.Add(new GimbalPtzSnapshotProvider());
}
/// <summary>
/// 算法数据包处理器
/// </summary>
private List<IGimbalPackageProvider> providers = new List<IGimbalPackageProvider>();
private readonly List<IGimbalPackageProvider> providers = new List<IGimbalPackageProvider>();
/// <summary>
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
public void Execute(UdpPackageInfo packageInfo)
/// <param name="info">信息</param>
public void Execute(ConnSingleJsonInfo info)
{
Task.Run(() =>
{
try
{
this._Execute(packageInfo);
}
catch (Exception ex)
{
log.Error(ex);
}
});
}
/// <summary>
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
private void _Execute(UdpPackageInfo packageInfo)
{
GimbalPackageBase @base = Newtonsoft.Json.JsonConvert.DeserializeObject<GimbalPackageBase>(packageInfo.Message);
AlgorithmPackageBase @base = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmPackageBase>(info.Json);
foreach (IGimbalPackageProvider provider in this.providers)
{
if (string.Equals(provider.Signal, @base.signal))
{
provider.Execute(packageInfo);
provider.Execute(info);
break;
}
......@@ -66,4 +49,3 @@ namespace VIZ.GimbalAI.Connection
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Connection
{
......@@ -21,6 +22,6 @@ namespace VIZ.GimbalAI.Connection
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
void Execute(UdpPackageInfo packageInfo);
void Execute(ConnSingleJsonInfo packageInfo);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Connection;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Storage;
namespace VIZ.GimbalAI.Connection
{
/// <summary>
/// 设置中心轴指令
/// </summary>
public class GimbalCenterAxisProvider : IGimbalPackageProvider
{
/// <summary>
/// 信号
/// <see cref="GimbalPackageSignal"/>
/// </summary>
public string Signal { get; } = GimbalPackageSignal.center_axis;
/// <summary>
/// 云台中心轴移动速度
/// </summary>
private static readonly double GIMBAL_CENTER_AXIS_SPEED = ApplicationDomainEx.IniStorage.GetValue<GimbalConfig, double>(p => p.GIMBAL_CENTER_AXIS_SPEED);
/// <summary>
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
public void Execute(ConnSingleJsonInfo packageInfo)
{
GimbalCenterAxisRecvPackage package = Newtonsoft.Json.JsonConvert.DeserializeObject<GimbalCenterAxisRecvPackage>(packageInfo.Json);
if (package == null)
return;
// 更新坐标位置
double x = ApplicationDomainEx.GimbalControlModel.CenterAxisX + (package.h > 0 ? 1 : -1) * GIMBAL_CENTER_AXIS_SPEED;
double y = ApplicationDomainEx.GimbalControlModel.CenterAxisY + (package.v > 0 ? 1 : -1) * GIMBAL_CENTER_AXIS_SPEED;
x = MathHelper.Clip(0, 1920, x);
y = MathHelper.Clip(0, 1080, y);
ApplicationDomainEx.GimbalControlModel.CenterAxisX = x;
ApplicationDomainEx.GimbalControlModel.CenterAxisY = y;
// 向算法发送最新的中心轴位置
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(UdpEndpointKeys.algorithm);
AlgorithmSender.CenterAxis(manager);
// 向界面发送更新轴信息消息
GimbalCenterAxisMessage message = new GimbalCenterAxisMessage();
message.X = x;
message.Y = y;
ApplicationDomainEx.MessageManager.Send(message);
}
}
}
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Connection;
using VIZ.GimbalAI.Domain;
namespace VIZ.GimbalAI.Connection
......@@ -22,14 +23,14 @@ namespace VIZ.GimbalAI.Connection
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
public void Execute(UdpPackageInfo packageInfo)
public void Execute(ConnSingleJsonInfo packageInfo)
{
GimbalPtzSnapshotRecvPackage package = Newtonsoft.Json.JsonConvert.DeserializeObject<GimbalPtzSnapshotRecvPackage>(packageInfo.Message);
GimbalPtzSnapshotRecvPackage package = Newtonsoft.Json.JsonConvert.DeserializeObject<GimbalPtzSnapshotRecvPackage>(packageInfo.Json);
GimbalPtzSnapshotMessage msg = new GimbalPtzSnapshotMessage();
msg.Data = package.Data;
VAppDomain.UiMessageManager.Send(msg);
ApplicationDomainEx.MessageManager.Send(msg);
}
}
}
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Connection
{
......@@ -22,7 +23,7 @@ namespace VIZ.GimbalAI.Connection
GimbalRresetSavePackage package = new GimbalRresetSavePackage();
package.signal = GimbalPackageSignal.preset_save;
manager.Send(package);
manager.SendJson(package);
}
/// <summary>
......@@ -36,7 +37,7 @@ namespace VIZ.GimbalAI.Connection
package.signal = GimbalPackageSignal.preset;
package.data = data;
manager.Send(package);
manager.SendJson(package);
}
}
}
......@@ -4,20 +4,21 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
namespace VIZ.GimbalAI.Connection
{
/// <summary>
/// 消息框按钮组
/// 云台预设返回包
/// </summary>
public enum VMessageBoxButtons
public class GimbalCenterAxisRecvPackage : GimbalPackageBase
{
/// <summary>
/// 确定
/// 俯仰值
/// </summary>
YES,
public double v { get; set; }
/// <summary>
/// 确定 & 取消
/// 旋转值
/// </summary>
YES_CANCEL
public double h { get; set; }
}
}
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Connection
{
......@@ -14,7 +15,7 @@ namespace VIZ.GimbalAI.Connection
/// <summary>
/// 执行
/// </summary>
/// <param name="packageInfo">包信息</param>
void Execute(UdpPackageInfo packageInfo);
/// <param name="info">信息</param>
void Execute(ConnSingleJsonInfo info);
}
}
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
namespace VIZ.GimbalAI.Connection
{
/// <summary>
/// UDP连接
/// </summary>
public class UdpConnection : IDisposable
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(UdpConnection));
/// <summary>
/// 最大数据长度
/// </summary>
public const int MAX_BUFFER_SIZE = 1024 * 10;
/// <summary>
/// UDP客户端
/// </summary>
public UdpClient UdpClient { get; private set; }
/// <summary>
/// IP地址
/// </summary>
public string IP { get; private set; }
/// <summary>
/// 端口
/// </summary>
public int Port { get; private set; }
/// <summary>
/// 终结点管理器集合
/// </summary>
private Dictionary<string, UdpEndpointManager> endpointManagers = new Dictionary<string, UdpEndpointManager>();
/// <summary>
/// 数据接收线程
/// </summary>
private Thread recvTrhead;
/// <summary>
/// 是否已经开始接收数据
/// </summary>
private bool IsRecvStart;
/// <summary>
/// 绑定IP和端口
/// </summary>
/// <param name="ip">IP</param>
/// <param name="port">端口</param>
public void Binding(string ip, int port)
{
this.IP = ip;
this.Port = port;
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), port);
this.UdpClient = new UdpClient(ipep);
}
/// <summary>
/// 连接
/// </summary>
public void Start()
{
this.IsRecvStart = true;
this.recvTrhead = new Thread(this.ReceiveMessage);
this.recvTrhead.Start();
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
try
{
this.IsRecvStart = false;
this.UdpClient?.Close();
this.UdpClient?.Dispose();
this.recvTrhead = null;
}
catch (Exception ex)
{
log.Error(ex);
}
}
/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
this.Stop();
}
/// <summary>
/// 获取UDP终结点管理器
/// </summary>
/// <param name="key">终结点管理器键<see cref="UdpEndpointKeys"/></param>
/// <returns>终结点管理器</returns>
public UdpEndpointManager GetEndpointManager(string key)
{
this.endpointManagers.TryGetValue(key, out UdpEndpointManager manager);
return manager;
}
/// <summary>
/// 添加UDP终结点管理器
/// </summary>
/// <param name="manager">终结点管理器</param>
public void AddEndpointManager(UdpEndpointManager manager)
{
manager.UdpClient = this.UdpClient;
this.endpointManagers[manager.Key] = manager;
}
/// <summary>
/// 接收数据
/// </summary>
/// <param name="obj"></param>
private void ReceiveMessage(object obj)
{
while (this.IsRecvStart)
{
try
{
IPEndPoint endport = new IPEndPoint(IPAddress.Any, 0);
byte[] buffer = this.UdpClient.Receive(ref endport);
UdpPackageInfo info = new UdpPackageInfo();
info.IP = this.IP;
info.Port = this.Port;
info.Message = Encoding.UTF8.GetString(buffer);
foreach (var manager in this.endpointManagers.Values)
{
manager.Execute(info);
}
string consoleMsg = $"{DateTime.Now} 【接收】 {info.Message}";
#if DEBUG
Debug.WriteLine(consoleMsg);
#endif
UdpConsoleMessage msg = new UdpConsoleMessage();
msg.Message = info.Message;
msg.IsSender = false;
VAppDomain.UiMessageManager.Send(msg);
}
catch (Exception ex)
{
log.Error(ex);
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Diagnostics;
using log4net;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
namespace VIZ.GimbalAI.Connection
{
/// <summary>
/// UDP网络终结点管理器
/// </summary>
public class UdpEndpointManager
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(UdpEndpointManager));
/// <summary>
/// 网络终结点键<see cref="UdpEndpointKeys"/>
/// </summary>
public string Key { get; private set; }
/// <summary>
/// 监听IP
/// </summary>
public string IP { get; private set; }
/// <summary>
/// 监听端口
/// </summary>
public int Port { get; private set; }
/// <summary>
/// UDP客户端
/// </summary>
public UdpClient UdpClient { get; internal set; }
/// <summary>
/// 包处理器
/// </summary>
internal List<IUdpPackageProvider> PackageProviders = new List<IUdpPackageProvider>();
/// <summary>
/// UDP终结点管理器
/// </summary>
/// <param name="key">网络终结点键<see cref="UdpEndpointKeys"/></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
public UdpEndpointManager(string key, string ip, int port)
{
this.Key = key;
this.IP = ip;
this.Port = port;
}
/// <summary>
/// 添加包处理器
/// </summary>
/// <param name="provider">包处理器</param>
public void AddProvider(IUdpPackageProvider provider)
{
this.PackageProviders.Add(provider);
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="data">数据</param>
public void Send(string data)
{
byte[] buffer = Encoding.UTF8.GetBytes(data);
this.UdpClient.Send(buffer, buffer.Length, this.IP, this.Port);
string consoleMsg = $"{DateTime.Now} 【发送】 {data}";
#if DEBUG
Debug.WriteLine(consoleMsg);
#endif
UdpConsoleMessage msg = new UdpConsoleMessage();
msg.Message = data;
msg.IsSender = true;
VAppDomain.UiMessageManager.Send(msg);
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="data">数据</param>
public void Send(object data)
{
string str = Newtonsoft.Json.JsonConvert.SerializeObject(data);
this.Send(str);
}
/// <summary>
/// 處理UDP消息
/// </summary>
/// <param name="info">UDP消息信息</param>
public void Execute(UdpPackageInfo info)
{
foreach (IUdpPackageProvider provider in this.PackageProviders)
{
provider.Execute(info);
}
}
}
}
using System;
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using NewTek;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Common
namespace VIZ.GimbalAI.Connection
{
/// <summary>
/// 处理NDI视频帧任务
/// UDP包解析器
/// </summary>
public class NDIToolExecuteVideoTask : NDIToolTaskBase
public class UdpPackageProvider : ConnSingleJsonPackageProvider
{
/// <summary>
/// 任务名称
/// 日志
/// </summary>
public override NDIToolTaskNames Name => NDIToolTaskNames.EXECUTE_VIDEO;
private readonly static ILog log = LogManager.GetLogger(typeof(UdpPackageProvider));
public UdpPackageProvider()
{
this.providers.Add(new AlgorithmPackageProvider());
this.providers.Add(new GimbalPackageProvider());
}
private List<IUdpPackageProvider> providers = new List<IUdpPackageProvider>();
/// <summary>
/// 执行
/// </summary>
protected override void Execute()
/// <param name="info">信息</param>
protected override void Execute(ConnSingleJsonInfo info)
{
while (this.IsStarted)
Task.Run(() =>
{
if (this.Tool.VideoFrameQueue.Count <= this.Tool.Option.DelayFrame)
try
{
Thread.Sleep(2);
continue;
}
AlgorithmPackageBase @base = Newtonsoft.Json.JsonConvert.DeserializeObject<AlgorithmPackageBase>(info.Json);
if (!this.Tool.VideoFrameQueue.TryDequeue(out IVideoFrame frame))
foreach (IUdpPackageProvider provider in this.providers)
{
continue;
provider.Execute(info);
}
// 触发视频帧处理事件
this.Tool.TriggerExecuteVideoFrame(frame);
Thread.Sleep(10);
}
catch (Exception ex)
{
log.Error(ex);
}
});
}
}
}
......@@ -85,7 +85,6 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ConnectionManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UDP\Algorithm\AlgorithmPackageBase.cs" />
<Compile Include="UDP\Algorithm\Enum\AlgorithmPackageSignal.cs" />
......@@ -100,6 +99,7 @@
<Compile Include="UDP\Algorithm\Signal\Recv\AlgorithmTargetLostRecvPackage.cs" />
<Compile Include="UDP\Algorithm\Signal\Recv\AlgorithmTrackingRecvPackage.cs" />
<Compile Include="UDP\Algorithm\Signal\Recv\AlgorithmDetectRecvPackage.cs" />
<Compile Include="UDP\Algorithm\Signal\Send\AlgorithmCenterAxisPackage.cs" />
<Compile Include="UDP\Algorithm\Signal\Send\AlgorithmAutoDetectPackage.cs" />
<Compile Include="UDP\Algorithm\Signal\Send\AlgorithmAutoTrackingPackage.cs" />
<Compile Include="UDP\Algorithm\Signal\Send\AlgorithmManualTrackingPackage.cs" />
......@@ -111,26 +111,43 @@
<Compile Include="UDP\Gimbal\GimbalPackageBase.cs" />
<Compile Include="UDP\Gimbal\GimbalPackageProvider.cs" />
<Compile Include="UDP\Gimbal\IGimbalPackageProvider.cs" />
<Compile Include="UDP\Gimbal\Provider\GimbalCenterAxisProvider.cs" />
<Compile Include="UDP\Gimbal\Provider\GimbalPtzSnapshotProvider.cs" />
<Compile Include="UDP\Gimbal\Sender\GimbalSender.cs" />
<Compile Include="UDP\Gimbal\Signal\Recv\GimbalCenterAxisRecvPackage.cs" />
<Compile Include="UDP\Gimbal\Signal\Recv\GimbalPtzSnapshotRecvPackage.cs" />
<Compile Include="UDP\Gimbal\Signal\Send\GimbalRresetPackage.cs" />
<Compile Include="UDP\Gimbal\Signal\Send\GimbalRresetSavePackage.cs" />
<Compile Include="UDP\IUdpPackageProvider.cs" />
<Compile Include="UDP\UdpEndpointKeys.cs" />
<Compile Include="UDP\UdpPackageInfo.cs" />
<Compile Include="UDP\UdpConnection.cs" />
<Compile Include="UDP\UdpEndpointManager.cs" />
<Compile Include="UDP\UdpPackageProvider.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj">
<Project>{d4409326-3f36-4835-812a-bea8ed046e04}</Project>
<Name>VIZ.GimbalAI.Core</Name>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Connection\VIZ.Framework.Connection.csproj">
<Project>{e07528dd-9dee-47c2-b79d-235ecfa6b003}</Project>
<Name>VIZ.Framework.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Domain\VIZ.GimbalAI.Domain.csproj">
<Project>{bbf80159-d5de-4d82-a045-a96d67d80632}</Project>
<Name>VIZ.GimbalAI.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Storage\VIZ.GimbalAI.Storage.csproj">
<Project>{fb44d2c0-5a08-4b87-b3c7-745471a0d868}</Project>
<Name>VIZ.GimbalAI.Storage</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
......
......@@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
......
......@@ -3,33 +3,35 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
using VIZ.Framework.Domain;
using VIZ.GimbalAI.Storage;
namespace VIZ.GimbalAI.Domain
{
/// <summary>
/// 数据
/// 应用程序
/// </summary>
public static class VDataDomain
public class ApplicationDomainEx : ApplicationDomain
{
/// <summary>
/// 本地Config
/// CSV数据上下文
/// </summary>
public static DataManager dataManager { get; set; }
public static CsvContext CsvContext { get; set; }
/// <summary>
/// 算法自动设置
/// LiteDb数据
/// </summary>
public static AlgorithmAutoSetting AlgorithmAutoSetting { get; set; } = new AlgorithmAutoSetting();
public static LiteDbContext LiteDbContext { get; set; }
/// <summary>
/// LiteDb数据
/// 算法自动设置
/// </summary>
public static LiteDbContext LiteDbContext { get; set; }
public static AlgorithmAutoSetting AlgorithmAutoSetting { get; private set; } = new AlgorithmAutoSetting();
/// <summary>
/// Ini仓储
/// 云台控制模型
/// </summary>
public static IniStorage IniStorage { get; set; }
public static GimbalControlModel GimbalControlModel { get; private set; } = new GimbalControlModel();
}
}
......@@ -4,16 +4,16 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
namespace VIZ.GimbalAI.Domain
{
/// <summary>
/// NDI工具设置
/// NDI视图键
/// </summary>
public class NDIToolOption
public static class NDIViewKeys
{
/// <summary>
/// 延时帧(视频显示将在该延时帧之后处理)
/// 主视图
/// </summary>
public int DelayFrame { get; set; }
public const string Main = "Main";
}
}
......@@ -4,21 +4,21 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Domain.Message
namespace VIZ.GimbalAI.Domain
{
/// <summary>
/// UDP控制台消息
/// 服务键
/// </summary>
public class UdpConsoleMessage
public static class ServiceKeys
{
/// <summary>
/// 消息
/// 控制视图
/// </summary>
public string Message { get; set; }
public const string ControlView = "ControlView";
/// <summary>
/// 该消息是否是发送消息,否则为接收到的消息
/// 视频视图
/// </summary>
public bool IsSender { get; set; }
public const string VideoView = "VideoView";
}
}
......@@ -4,21 +4,21 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Common
namespace VIZ.GimbalAI.Domain
{
/// <summary>
/// 消息框返回
/// 云台中心轴消息
/// </summary>
public enum VMessageBoxResult
public class GimbalCenterAxisMessage
{
/// <summary>
/// 确定
/// 中心轴X坐标
/// </summary>
YES,
/// <summary>
public double X { get; set; }
/// <summary>
/// 取消
/// 中心轴Y坐标
/// </summary>
CANCEL
public double Y { get; set; }
}
}
......@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Domain
{
......@@ -63,7 +63,6 @@ namespace VIZ.GimbalAI.Domain
set { classes = value; this.RaisePropertyChanged(nameof(Classes)); }
}
#endregion
}
}
......@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Domain
{
......
......@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Domain
{
......
......@@ -3,23 +3,23 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Common
namespace VIZ.GimbalAI.Domain
{
/// <summary>
/// 视频矩形框选事件参数
/// 云台控制模型
/// </summary>
public class VideoRectangleFrameSelectionEventArgs : EventArgs
public class GimbalControlModel : ModelBase
{
/// <summary>
/// 鼠标款选区域
/// 中心轴X坐标
/// </summary>
public RectangleF MouseRectangle { get; set; }
public double CenterAxisX { get; set; }
/// <summary>
/// 视频框选区域
/// 中心轴Y坐标
/// </summary>
public RectangleF VideoRectangle { get; set; }
public double CenterAxisY { get; set; }
}
}
......@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
using System.Drawing;
using VIZ.GimbalAI.Storage;
......
......@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Domain
{
......
......@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Domain
{
......
......@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Domain
{
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Domain
{
/// <summary>
/// 视音频帧数据参数
/// </summary>
public static class VAConstants
{
/// <summary>
/// 视频帧的最大长度
/// 1936*1088 1920*1088安卓与IOS端会因为H264硬件编码造成数据向16位补不起
/// 正常数据最大应为1920*1080 或 1080*1920
/// </summary>
public const int VideoFrameLengthMax = 3159552;
/// <summary>
/// 1920*1080帧大小
/// </summary>
public const int VideoFrameLength1080 = 3110400;
public const int Video1920 = 1920;
public const int Video1080 = 1080;
public const int Video1936 = 1936;
public const int Video1088 = 1088;
/// <summary>
/// 40ms
/// </summary>
public const int AudioFrameLengthMax = 7680;
/// <summary>
/// 20ms
/// </summary>
public const int AudioFrameLengthMin = 3840;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
namespace VIZ.GimbalAI.Domain
{
/// <summary>
/// 应用程序域
/// </summary>
public static class VAppDomain
{
/// <summary>
/// 算法消息管理
/// </summary>
public static IVMessageManager AlgorithmMessageManager { get; } = new VMessageManager();
/// <summary>
/// UI消息管理
/// </summary>
public static IVMessageManager UiMessageManager { get; } = new VMessageManager();
/// <summary>
/// 视图模型服务管理
/// </summary>
public static IViewModelServiceManager ViewModelServiceManager { get; } = new ViewModelServiceManager();
/// <summary>
/// 延时管理器
/// </summary>
public static IVDelayManager DelayManager { get; } = new VDelayManager();
}
}
......@@ -83,32 +83,41 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Enum\NDIViewKeys.cs" />
<Compile Include="Enum\ServiceKeys.cs" />
<Compile Include="Message\Gimbal\GimbalCenterAxisMessage.cs" />
<Compile Include="Message\Gimbal\GimbalInitCompleteMessage.cs" />
<Compile Include="Model\Gimbal\GimbalControlModel.cs" />
<Compile Include="Model\NDI\NdiStreamGroupModel.cs" />
<Compile Include="Model\NDI\NdiStreamModel.cs" />
<Compile Include="Model\NDI\NdiVideoFrameDelayModel.cs" />
<Compile Include="VDataDomain.cs" />
<Compile Include="Message\Algorithm\AlgorithmInitCompleteMessage.cs" />
<Compile Include="Message\Algorithm\VideoRenderRectangleMessage.cs" />
<Compile Include="Enum\Video\VideoViewStatus.cs" />
<Compile Include="Message\Gimbal\GimbalPtzSnapshotMessage.cs" />
<Compile Include="Message\UDP\UdpConsoleMessage.cs" />
<Compile Include="Model\Algorithm\AlgorithmClassModel.cs" />
<Compile Include="Model\Algorithm\AlgorithmSceneModel.cs" />
<Compile Include="Model\Algorithm\AlgorithmAutoSetting.cs" />
<Compile Include="Model\Gimbal\GimbalPresetModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VAConstants.cs" />
<Compile Include="VAppDomain.cs" />
<Compile Include="ApplicationDomainEx.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj">
<Project>{d4409326-3f36-4835-812a-bea8ed046e04}</Project>
<Name>VIZ.GimbalAI.Core</Name>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Common\VIZ.Framework.Common.csproj">
<Project>{92834c05-703e-4f05-9224-f36220939d8f}</Project>
<Name>VIZ.Framework.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Storage\VIZ.GimbalAI.Storage.csproj">
<Project>{FB44D2C0-5A08-4B87-B3C7-745471A0D868}</Project>
......
......@@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
......
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converter="clr-namespace:VIZ.GimbalAI.Core;assembly=VIZ.GimbalAI.Core">
xmlns:converter="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core">
<converter:Bitmap2ImageSourceConverter x:Key="Bitmap2ImageSourceConverter"></converter:Bitmap2ImageSourceConverter>
......
......@@ -133,14 +133,18 @@
<Resource Include="Icons\down_24x24.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Common\VIZ.Framework.Common.csproj">
<Project>{92834c05-703e-4f05-9224-f36220939d8f}</Project>
<Name>VIZ.Framework.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Common.Resource\VIZ.GimbalAI.Common.Resource.csproj">
<Project>{5d8021d1-a6b2-4784-b8fe-ff3b7f94e304}</Project>
<Name>VIZ.GimbalAI.Common.Resource</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj">
<Project>{d4409326-3f36-4835-812a-bea8ed046e04}</Project>
<Name>VIZ.GimbalAI.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
......@@ -3,7 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Connection;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
using VIZ.GimbalAI.Storage;
......@@ -27,7 +28,7 @@ namespace VIZ.GimbalAI.Module
/// <summary>
/// 最大行数
/// </summary>
private readonly int MAX_LINE = VDataDomain.IniStorage.GetValue<ClientConfig, int>(p => p.CLIENT_CONSOLE_LOG_MAX_LINE);
private readonly int MAX_LINE = ApplicationDomainEx.IniStorage.GetValue<ClientConfig, int>(p => p.CLIENT_CONSOLE_LOG_MAX_LINE);
/// <summary>
/// 当前行数
......@@ -47,7 +48,8 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void InitMessage()
{
VAppDomain.UiMessageManager.Register<UdpConsoleMessage>(this, this.UdpConsole);
ApplicationDomainEx.MessageManager.Register<ConnSingleJsonMessage>(this, this.UdpConsole);
ApplicationDomainEx.MessageManager.Register<ConnSendMessage>(this, this.UdpConsole);
}
// ======================================================================================
......@@ -83,10 +85,10 @@ namespace VIZ.GimbalAI.Module
#region UdpConsoleMessage -- UDP控制台消息
/// <summary>
/// UDP控制台消息
/// UDP控制台消息 -- 接收的消息
/// </summary>
/// <param name="msg">消息</param>
public void UdpConsole(UdpConsoleMessage msg)
public void UdpConsole(ConnSingleJsonMessage msg)
{
WPFHelper.BeginInvoke(() =>
{
......@@ -100,7 +102,31 @@ namespace VIZ.GimbalAI.Module
this.Line = 1;
}
view.lb.AppendText("\r\n" + msg.Message);
view.lb.AppendText("\r\n接收: " + msg.Json);
view.lb.ScrollToEnd();
});
}
/// <summary>
/// UDP控制台消息 -- 发送的消息
/// </summary>
/// <param name="msg">消息</param>
private void UdpConsole(ConnSendMessage msg)
{
WPFHelper.BeginInvoke(() =>
{
ConsoleView view = this.GetView<ConsoleView>();
if (view == null)
return;
if (this.Line++ % MAX_LINE == 0)
{
view.lb.Clear();
this.Line = 1;
}
string text = Encoding.UTF8.GetString(msg.Buffer);
view.lb.AppendText("\r\n发送: " + text);
view.lb.ScrollToEnd();
});
}
......
......@@ -3,14 +3,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 控制器视图服务
/// </summary>
public interface IControlViewService : IViewModelService
public interface IControlViewService : IService
{
/// <summary>
/// 是否是手动模式
......
......@@ -5,8 +5,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:VIZ.GimbalAI.Module"
xmlns:common="clr-namespace:VIZ.GimbalAI.Common;assembly=VIZ.GimbalAI.Common"
xmlns:converter="clr-namespace:VIZ.GimbalAI.Core;assembly=VIZ.GimbalAI.Core"
xmlns:common="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
xmlns:converter="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
d:DataContext="{d:DesignInstance Type=local:ChangeNdiStreamViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
......
......@@ -5,8 +5,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:VIZ.GimbalAI.Module"
xmlns:common="clr-namespace:VIZ.GimbalAI.Common;assembly=VIZ.GimbalAI.Common"
xmlns:converter="clr-namespace:VIZ.GimbalAI.Core;assembly=VIZ.GimbalAI.Core"
xmlns:common="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
xmlns:converter="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
mc:Ignorable="d"
d:DesignHeight="520" d:DesignWidth="420">
<UserControl.Resources>
......
......@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VIZ.GimbalAI.Module"
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:converter="clr-namespace:VIZ.GimbalAI.Core;assembly=VIZ.GimbalAI.Core"
xmlns:converter="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
d:DataContext="{d:DesignInstance Type=local:ControlViewModel}"
mc:Ignorable="d" x:Name="uc"
d:DesignHeight="800" d:DesignWidth="300">
......
......@@ -12,7 +12,7 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Connection;
namespace VIZ.GimbalAI.Module
......@@ -29,9 +29,7 @@ namespace VIZ.GimbalAI.Module
if (WPFHelper.IsInDesignMode(this))
return;
ControlViewModel vm = new ControlViewModel();
vm.SetView(this);
this.DataContext = vm;
WPFHelper.BindingViewModel(this, new ControlViewModel());
}
}
}
......@@ -3,12 +3,13 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Common;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Storage;
using System.Windows;
using System.Windows.Controls;
using VIZ.Framework.Common;
namespace VIZ.GimbalAI.Module
{
......@@ -68,18 +69,20 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void Loaded()
{
if (VideoStreamManager.NDITool == null || VideoStreamManager.NDITool.StreamInfos == null || VideoStreamManager.NDITool.StreamInfos.Count == 0)
NDIStream ndiStream = VideoStreamManager.Get<NDIStream>(NDIViewKeys.Main);
if (ndiStream == null || ndiStream.StreamInfos == null || ndiStream.StreamInfos.Count == 0)
return;
string currentNdiStreamName = VDataDomain.IniStorage.GetValue<NdiConfig, string>(p => p.NDI_STREAM_NAME);
string currentNdiStreamName = ApplicationDomainEx.IniStorage.GetValue<NdiConfig, string>(p => p.NDI_STREAM_NAME);
string groupName = currentNdiStreamName.Split(new char[] { ' ' }, 2)[0];
string streamName = currentNdiStreamName.Substring(currentNdiStreamName.IndexOf(' ') + 1);
List<NdiStreamGroupModel> groupModels = new List<NdiStreamGroupModel>();
lock (VideoStreamManager.NDITool.StreamInfos)
lock (ndiStream.StreamInfos)
{
var groups = VideoStreamManager.NDITool.StreamInfos.GroupBy(p => p.Machine);
var groups = ndiStream.StreamInfos.GroupBy(p => p.Machine);
foreach (var group in groups)
{
......@@ -87,7 +90,7 @@ namespace VIZ.GimbalAI.Module
groupModel.Name = group.Key;
groupModel.DisplayName = group.Key;
foreach (NDIToolStreamInfo info in group)
foreach (NDIStreamInfo info in group)
{
NdiStreamModel model = new NdiStreamModel();
model.Name = info.Name;
......@@ -124,7 +127,7 @@ namespace VIZ.GimbalAI.Module
/// </summary>
public void Apply()
{
string currentNdiStreamName = VDataDomain.IniStorage.GetValue<NdiConfig, string>(p => p.NDI_STREAM_NAME);
string currentNdiStreamName = ApplicationDomainEx.IniStorage.GetValue<NdiConfig, string>(p => p.NDI_STREAM_NAME);
string groupName = currentNdiStreamName.Split(new char[] { ' ' }, 2)[0];
string streamName = currentNdiStreamName.Substring(currentNdiStreamName.IndexOf(' ') + 1);
......@@ -139,7 +142,7 @@ namespace VIZ.GimbalAI.Module
if (groupName == group.Name && streamName == item.Name)
return;
IVideoViewService service = VAppDomain.ViewModelServiceManager.GetService<IVideoViewService>();
IVideoViewService service = ApplicationDomainEx.ServiceManager.GetService<IVideoViewService>(ServiceKeys.VideoView);
if (service == null)
return;
......@@ -148,7 +151,7 @@ namespace VIZ.GimbalAI.Module
service.ChangeNdiStream($"{group.Name} {item.Name}");
// ------------------------------------------------------------------------------------------------
// 更新到配置文件
VDataDomain.IniStorage.SetValue<NdiConfig>(p => p.NDI_STREAM_NAME, $"{group.Name} {item.Name}");
ApplicationDomainEx.IniStorage.SetValue<NdiConfig>(p => p.NDI_STREAM_NAME, $"{group.Name} {item.Name}");
// ------------------------------------------------------------------------------------------------
// 刷新UI
NdiStreamGroupModel beforeGroup = this.NdiStreamGroups.FirstOrDefault(p => p.IsCurrentStream);
......@@ -196,6 +199,5 @@ namespace VIZ.GimbalAI.Module
#endregion
// ==============================================================================================
}
}
......@@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Storage;
......@@ -47,7 +47,7 @@ namespace VIZ.GimbalAI.Module
this.ItemsSource.Add(new NdiVideoFrameDelayModel($"60 帧", 60));
this.ItemsSource.Add(new NdiVideoFrameDelayModel($"90 帧", 90));
int value = VDataDomain.IniStorage.GetValue<ClientConfig, int>(p => p.CLIENT_VIDEO_DELAY);
int value = ApplicationDomainEx.IniStorage.GetValue<ClientConfig, int>(p => p.CLIENT_VIDEO_DELAY);
NdiVideoFrameDelayModel current = this.ItemsSource.FirstOrDefault(p => p.Value == value);
if (current == null)
......@@ -107,13 +107,13 @@ namespace VIZ.GimbalAI.Module
if (this.SelectedValue == null)
return;
IVideoViewService service = VAppDomain.ViewModelServiceManager.GetService<IVideoViewService>();
IVideoViewService service = ApplicationDomainEx.ServiceManager.GetService<IVideoViewService>(ServiceKeys.VideoView);
if (service == null)
return;
service.ChangeNdiVideoFrameDelay(this.SelectedValue.Value);
VDataDomain.IniStorage.SetValue<ClientConfig>(p => p.CLIENT_VIDEO_DELAY, this.SelectedValue.Value);
ApplicationDomainEx.IniStorage.SetValue<ClientConfig>(p => p.CLIENT_VIDEO_DELAY, this.SelectedValue.Value);
foreach (NdiVideoFrameDelayModel model in this.ItemsSource)
{
......
......@@ -3,10 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Connection;
using VIZ.GimbalAI.Domain.Message;
using VIZ.GimbalAI.Domain;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Module
{
......@@ -18,7 +19,7 @@ namespace VIZ.GimbalAI.Module
public ControlViewModel()
{
// 注册视图模型服务
VAppDomain.ViewModelServiceManager.AddService(this);
ApplicationDomainEx.ServiceManager.AddService(ServiceKeys.ControlView, this);
// 初始化数据
this.InitData();
......@@ -48,9 +49,9 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void InitData()
{
this.AlgorithmSceneItems = VDataDomain.AlgorithmAutoSetting.Scenes;
this.AlgorithmScene = VDataDomain.AlgorithmAutoSetting.Scene;
this.AlgorithmClassItems = VDataDomain.AlgorithmAutoSetting.Classes;
this.AlgorithmSceneItems = ApplicationDomainEx.AlgorithmAutoSetting.Scenes;
this.AlgorithmScene = ApplicationDomainEx.AlgorithmAutoSetting.Scene;
this.AlgorithmClassItems = ApplicationDomainEx.AlgorithmAutoSetting.Classes;
}
/// <summary>
......@@ -58,8 +59,8 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void InitMessage()
{
VAppDomain.AlgorithmMessageManager.Register<VideoRenderRectangleMessage>(this, this.VideoRenderRectangle);
VAppDomain.UiMessageManager.Register<AlgorithmInitCompleteMessage>(this, this.AlgorithmInitComplete);
ApplicationDomainEx.MessageManager.Register<VideoRenderRectangleMessage>(this, this.VideoRenderRectangle);
ApplicationDomainEx.MessageManager.Register<AlgorithmInitCompleteMessage>(this, this.AlgorithmInitComplete);
}
// ==============================================================================================
......@@ -164,7 +165,7 @@ namespace VIZ.GimbalAI.Module
{
algorithmScene = value;
this.RaisePropertyChanged(nameof(AlgorithmScene));
VDataDomain.AlgorithmAutoSetting.Scene = value;
ApplicationDomainEx.AlgorithmAutoSetting.Scene = value;
}
}
......@@ -355,7 +356,7 @@ namespace VIZ.GimbalAI.Module
// -------------------------------------------------------------------------------------------------
// UI逻辑调整
IVideoViewService viewService = VAppDomain.ViewModelServiceManager.GetService<IVideoViewService>();
IVideoViewService viewService = ApplicationDomainEx.ServiceManager.GetService<IVideoViewService>(ServiceKeys.VideoView);
if (viewService == null)
return;
......@@ -391,7 +392,7 @@ namespace VIZ.GimbalAI.Module
// -------------------------------------------------------------------------------------------------
// UI逻辑调整
IVideoViewService viewService = VAppDomain.ViewModelServiceManager.GetService<IVideoViewService>();
IVideoViewService viewService = ApplicationDomainEx.ServiceManager.GetService<IVideoViewService>(ServiceKeys.VideoView);
if (viewService == null)
return;
......@@ -445,7 +446,7 @@ namespace VIZ.GimbalAI.Module
// -------------------------------------------------------------------------------------------------
// UI逻辑调整
IVideoViewService viewService = VAppDomain.ViewModelServiceManager.GetService<IVideoViewService>();
IVideoViewService viewService = ApplicationDomainEx.ServiceManager.GetService<IVideoViewService>(ServiceKeys.VideoView);
if (viewService == null)
return;
......
......@@ -54,9 +54,9 @@
</StackPanel>
<!-- 预设区域 -->
<module:PresetView Grid.Row="1"></module:PresetView>
<!--<module:PresetView Grid.Row="1"></module:PresetView>-->
<!-- 视频区域 -->
<module:VideoView Grid.Row="1" Grid.Column="1" Margin="0,0,30,0"></module:VideoView>
<module:VideoView Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="15,0,30,0"></module:VideoView>
<!-- 控制区域 -->
<module:ControlView Grid.Row="1" Grid.Column="2"></module:ControlView>
<!-- 底栏 -->
......
......@@ -12,7 +12,7 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Module
{
......@@ -28,9 +28,7 @@ namespace VIZ.GimbalAI.Module
if (WPFHelper.IsInDesignMode(this))
return;
MainViewModel vm = new MainViewModel();
vm.SetView(this);
this.DataContext = vm;
WPFHelper.BindingViewModel(this, new MainViewModel());
}
}
}
......@@ -6,10 +6,12 @@ using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using VIZ.GimbalAI.Connection;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
using VIZ.GimbalAI.Common;
using VIZ.Framework.Module;
using VIZ.Framework.Common;
namespace VIZ.GimbalAI.Module
{
......@@ -44,7 +46,7 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void InitMessage()
{
VAppDomain.AlgorithmMessageManager.Register<VideoRenderRectangleMessage>(this, this.VideoRenderRectangle);
ApplicationDomainEx.MessageManager.Register<VideoRenderRectangleMessage>(this, this.VideoRenderRectangle);
}
// ======================================================================================
......@@ -96,14 +98,14 @@ namespace VIZ.GimbalAI.Module
private void Loaded()
{
// 加载完成后3秒执行加载流程
VAppDomain.DelayManager.Wait("VIZ.GimbalAI.Module.MainViewModel.Loaded", 3, () =>
ApplicationDomainEx.DelayManager.Wait("VIZ.GimbalAI.Module.MainViewModel.Loaded", 3, () =>
{
// 执行加载流程
AppSetupContext context = AppSetup.Load();
AppSetupContext context = AppSetup.Load(this.GetWindow());
if (!context.IsSuccess)
{
VMessageBox.ShowDialog($"执行 {context.ProviderDetail} 失败");
MessageBoxEx.ShowDialog($"执行 {context.ProviderDetail} 失败");
}
});
}
......@@ -126,8 +128,8 @@ namespace VIZ.GimbalAI.Module
if (view == null)
return;
VMessageBoxResult result = VMessageBox.ShowDialog("提示", "确定退出?", VMessageBoxButtons.YES_CANCEL);
if (result != VMessageBoxResult.YES)
MessageBoxExResult result = MessageBoxEx.ShowDialog("提示", "确定退出?", MessageBoxExButtons.YES_CANCEL);
if (result != MessageBoxExResult.YES)
return;
Window window = WPFHelper.GetAncestorByType<Window>(view);
......@@ -201,13 +203,9 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void ChangeNdiVideoDelay()
{
MainView mainView = this.GetView<MainView>();
if (mainView == null)
return;
ChangeVideoFrameDelayView view = new ChangeVideoFrameDelayView();
NoneWindow window = new NoneWindow(400, 650, view);
window.Owner = WPFHelper.GetAncestorByType<Window>(mainView);
window.Owner = this.GetWindow();
window.ShowDialog();
}
......
......@@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VIZ.GimbalAI.Module"
xmlns:converter="clr-namespace:VIZ.GimbalAI.Core;assembly=VIZ.GimbalAI.Core"
xmlns:converter="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
d:DataContext="{d:DesignInstance Type=local:PresetViewModel}"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="400">
......
......@@ -12,7 +12,7 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Module
{
......@@ -28,9 +28,7 @@ namespace VIZ.GimbalAI.Module
if (WPFHelper.IsInDesignMode(this))
return;
PresetViewModel vm = new PresetViewModel();
vm.SetView(this);
this.DataContext = vm;
WPFHelper.BindingViewModel(this, new PresetViewModel());
}
}
}
......@@ -4,14 +4,16 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Storage;
using VIZ.GimbalAI.Connection;
using System.Windows;
using log4net;
using System.Drawing.Imaging;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Common;
using VIZ.Framework.Common;
using VIZ.Framework.Connection;
namespace VIZ.GimbalAI.Module
{
......@@ -23,7 +25,7 @@ namespace VIZ.GimbalAI.Module
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(PresetViewModel));
private readonly static ILog log = LogManager.GetLogger(typeof(PresetViewModel));
/// <summary>
/// 延时健
......@@ -49,7 +51,7 @@ namespace VIZ.GimbalAI.Module
{
ObservableCollection<GimbalPresetModel> items = new ObservableCollection<GimbalPresetModel>();
var query = VDataDomain.LiteDbContext.GimbalPresets.FindAll();
var query = ApplicationDomainEx.LiteDbContext.GimbalPresets.FindAll();
Dictionary<int, GimbalPreset> dic = query.ToDictionary(p => p.ID);
for (int i = 1; i <= 4; ++i)
......@@ -93,7 +95,7 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void InitMessage()
{
VAppDomain.UiMessageManager.Register<GimbalPtzSnapshotMessage>(this, this.GimbalPtzSnapshot);
ApplicationDomainEx.MessageManager.Register<GimbalPtzSnapshotMessage>(this, this.GimbalPtzSnapshot);
}
// ========================================================================================
......@@ -203,7 +205,7 @@ namespace VIZ.GimbalAI.Module
{
if (this.SelectedPreset == null)
{
VMessageBox.ShowDialog("请选择要保存的预设项!");
MessageBoxEx.ShowDialog("请选择要保存的预设项!");
return;
}
......@@ -217,7 +219,7 @@ namespace VIZ.GimbalAI.Module
// -------------------------------------------------------------------------------------------------
// UI调整
IVideoViewService service = VAppDomain.ViewModelServiceManager.GetService<IVideoViewService>();
IVideoViewService service = ApplicationDomainEx.ServiceManager.GetService<IVideoViewService>(ServiceKeys.VideoView);
if (service == null)
return;
......@@ -228,7 +230,7 @@ namespace VIZ.GimbalAI.Module
// 3. 如果在15秒内没有收到恢复那么认为超时
this.IsEnabled = false;
VAppDomain.DelayManager.Wait(DELAY_KEY_PRESET_SAVE, 15, () =>
ApplicationDomainEx.DelayManager.Wait(DELAY_KEY_PRESET_SAVE, 15, () =>
{
this.IsEnabled = true;
});
......@@ -252,22 +254,22 @@ namespace VIZ.GimbalAI.Module
if (model == null)
return;
VMessageBoxResult result = VMessageBox.ShowDialog("提示", $"确定重置云台 预设{model.ID}", VMessageBoxButtons.YES_CANCEL);
if (result != VMessageBoxResult.YES)
MessageBoxExResult result = MessageBoxEx.ShowDialog("提示", $"确定重置云台 预设{model.ID}", MessageBoxExButtons.YES_CANCEL);
if (result != MessageBoxExResult.YES)
return;
model.Bitmap = null;
model.Data = null;
// 更新缓存
GimbalPreset entity = VDataDomain.LiteDbContext.GimbalPresets.FindById(model.ID);
GimbalPreset entity = ApplicationDomainEx.LiteDbContext.GimbalPresets.FindById(model.ID);
if (entity == null)
return;
entity.Data = null;
entity.Bitmap = null;
VDataDomain.LiteDbContext.GimbalPresets.Update(entity);
ApplicationDomainEx.LiteDbContext.GimbalPresets.Update(entity);
}
#endregion
......@@ -304,7 +306,7 @@ namespace VIZ.GimbalAI.Module
/// <param name="msg">消息</param>
private void GimbalPtzSnapshot(GimbalPtzSnapshotMessage msg)
{
VAppDomain.DelayManager.Release(DELAY_KEY_PRESET_SAVE);
ApplicationDomainEx.DelayManager.Release(DELAY_KEY_PRESET_SAVE);
// 该判断处理如果收到恢复超时的情况
if (this.IsEnabled)
......@@ -330,9 +332,9 @@ namespace VIZ.GimbalAI.Module
model.Entity.ID = model.ID;
model.Entity.Data = model.Data;
model.Entity.Bitmap = BitmapHelper.GetBuffer(model.Bitmap, ImageFormat.Jpeg);
//model.Entity.Bitmap = BitmapHelper.GetBuffer(model.Bitmap, ImageFormat.Jpeg);
VDataDomain.LiteDbContext.GimbalPresets.Upsert(model.Entity);
ApplicationDomainEx.LiteDbContext.GimbalPresets.Upsert(model.Entity);
this.IsEnabled = true;
}
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using log4net;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动
/// </summary>
public static class AppSetup
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup));
/// <summary>
/// 应用程序启动
/// </summary>
private static List<IAppSetup> appSetups = new List<IAppSetup>();
/// <summary>
/// 应用程序加载
/// </summary>
private static List<IAppSetup> appLoads = new List<IAppSetup>();
/// <summary>
/// 是否已经启动
/// </summary>
public static bool IsSetup { get; private set; }
static AppSetup()
{
// 初始化应用程序启动
InitSetup();
// 初始化应用程序加载
InitLoad();
}
/// <summary>
/// 应用程序启动
/// </summary>
private static void InitSetup()
{
// Step 1. 单例启动
appSetups.Add(new AppSetup_Single());
// Step 2. 捕获未处理异常
appSetups.Add(new AppSetup_CatchUnhandledException());
// Step 3. 初始化日志
appSetups.Add(new AppSetup_LogInit());
// Step 4. 初始化数据域
appSetups.Add(new AppSetup_DtoDoainIInit());
// Step 5. 初始化延时
appSetups.Add(new AppSetup_DelayInit());
// Step 6. 读取算法Excel配置文件
appSetups.Add(new AppSetup_ExcelInit());
// Step 7. 初始化NDI
appSetups.Add(new AppSetup_NdiInit());
// Step 8. 初始化UDP链接
appSetups.Add(new AppSetup_UdpConnectionIInit());
}
/// <summary>
/// 应用程序加载
/// </summary>
private static void InitLoad()
{
// Step 1. 启动算法进程
appLoads.Add(new AppSetup_SetupAlgorithm());
// Step 2. 启动云台进程
//appLoads.Add(new AppSetup_SetupGimbal());
}
/// <summary>
/// 执行
/// </summary>
/// <returns>应用程序启动上下文</returns>
public static AppSetupContext Setup()
{
AppSetupContext context = new AppSetupContext();
if (IsSetup)
{
context.IsSuccess = false;
context.Remarks.Add("app is already setup.");
return context;
}
foreach (IAppSetup setup in appSetups)
{
try
{
if (setup.Setup(context))
continue;
context.IsSuccess = false;
context.ProviderDetail = setup.Detail;
return context;
}
catch (Exception ex)
{
log.Error(ex);
context.IsSuccess = false;
context.ProviderDetail = setup.Detail;
context.Exception = ex;
return context;
}
}
context.IsSuccess = true;
IsSetup = true;
return context;
}
/// <summary>
/// 关闭
/// </summary>
public static void ShutDown()
{
if (!IsSetup)
return;
AppSetupContext context = new AppSetupContext();
foreach (IAppSetup setup in appSetups)
{
try
{
setup.Shutdown(context);
}
catch (Exception ex)
{
log.Error(ex);
}
}
IsSetup = false;
}
/// <summary>
/// 加载
/// </summary>
/// <returns>启动上下文</returns>
public static AppSetupContext Load()
{
AppSetupContext context = new AppSetupContext();
foreach (IAppSetup setup in appLoads)
{
try
{
if (setup.Setup(context))
continue;
context.IsSuccess = false;
context.ProviderDetail = setup.Detail;
return context;
}
catch (Exception ex)
{
log.Error(ex);
context.IsSuccess = false;
context.ProviderDetail = setup.Detail;
context.Exception = ex;
return context;
}
}
context.IsSuccess = true;
return context;
}
/// <summary>
/// 卸载
/// </summary>
public static void UnLoad()
{
AppSetupContext context = new AppSetupContext();
foreach (IAppSetup setup in appLoads)
{
try
{
setup.Shutdown(context);
}
catch (Exception ex)
{
log.Error(ex);
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动上下文
/// </summary>
public class AppSetupContext
{
/// <summary>
/// 执行器描述信息
/// </summary>
public string ProviderDetail { get; set; }
/// <summary>
/// 备注
/// </summary>
public List<string> Remarks { get; set; }
/// <summary>
/// 异常信息
/// </summary>
public Exception Exception { get; set; }
/// <summary>
/// 是否执行成功
/// </summary>
public bool IsSuccess { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动
/// </summary>
public interface IAppSetup
{
/// <summary>
/// 描述
/// </summary>
string Detail { get; }
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
bool Setup(AppSetupContext context);
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
void Shutdown(AppSetupContext context);
}
}
......@@ -6,6 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using VIZ.Framework.Module;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Storage;
......@@ -14,27 +15,27 @@ namespace VIZ.GimbalAI.Module
/// <summary>
/// 应用程序启动 -- 启动算法
/// </summary>
public class AppSetup_SetupAlgorithm : IAppSetup
public class AppSetup_SetupAlgorithm : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_SetupAlgorithm));
private readonly static ILog log = LogManager.GetLogger(typeof(AppSetup_SetupAlgorithm));
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- 启动算法";
public override string Detail { get; } = "应用程序启动 -- 启动算法";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
public override bool Setup(AppSetupContext context)
{
string path = VDataDomain.IniStorage.GetValue<AlgorithmConfig, string>(p => p.ALGORITHM_SETUP_PATH);
ProcessWindowStyle style = (ProcessWindowStyle)Enum.Parse(typeof(ProcessWindowStyle), VDataDomain.IniStorage.GetValue<AlgorithmConfig, string>(p => p.ALGORITHM_CMD_WINDOW_STYLE));
string path = ApplicationDomainEx.IniStorage.GetValue<AlgorithmConfig, string>(p => p.ALGORITHM_SETUP_PATH);
ProcessWindowStyle style = (ProcessWindowStyle)Enum.Parse(typeof(ProcessWindowStyle), ApplicationDomainEx.IniStorage.GetValue<AlgorithmConfig, string>(p => p.ALGORITHM_CMD_WINDOW_STYLE));
string fullPath = null;
Uri uri = new Uri(path, UriKind.RelativeOrAbsolute);
......@@ -69,7 +70,7 @@ namespace VIZ.GimbalAI.Module
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
public override void Shutdown(AppSetupContext context)
{
}
......
......@@ -6,6 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using VIZ.Framework.Module;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Storage;
......@@ -14,27 +15,27 @@ namespace VIZ.GimbalAI.Module
/// <summary>
/// 应用程序启动 -- 启动云台
/// </summary>
public class AppSetup_SetupGimbal : IAppSetup
public class AppSetup_SetupGimbal : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_SetupGimbal));
private readonly static ILog log = LogManager.GetLogger(typeof(AppSetup_SetupGimbal));
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- 启动云台";
public override string Detail { get; } = "应用程序启动 -- 启动云台";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
public override bool Setup(AppSetupContext context)
{
string path = VDataDomain.IniStorage.GetValue<GimbalConfig, string>(p => p.GIMBAL_SETUP_PATH);
ProcessWindowStyle style = (ProcessWindowStyle)Enum.Parse(typeof(ProcessWindowStyle), VDataDomain.IniStorage.GetValue<GimbalConfig, string>(p => p.GIMBAL_CMD_WINDOW_STYLE));
string path = ApplicationDomainEx.IniStorage.GetValue<GimbalConfig, string>(p => p.GIMBAL_SETUP_PATH);
ProcessWindowStyle style = (ProcessWindowStyle)Enum.Parse(typeof(ProcessWindowStyle), ApplicationDomainEx.IniStorage.GetValue<GimbalConfig, string>(p => p.GIMBAL_CMD_WINDOW_STYLE));
string fullPath = null;
Uri uri = new Uri(path, UriKind.RelativeOrAbsolute);
......@@ -69,7 +70,7 @@ namespace VIZ.GimbalAI.Module
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
public override void Shutdown(AppSetupContext context)
{
}
......
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动 -- 捕获未处理异常
/// </summary>
public class AppSetup_CatchUnhandledException : IAppSetup
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_CatchUnhandledException));
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- 捕获未处理异常";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
{
Application.Current.DispatcherUnhandledException -= App_DispatcherUnhandledException;
Application.Current.DispatcherUnhandledException += App_DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
{
}
/// <summary>
/// 应用程序未处理异常
/// </summary>
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Debug.WriteLine(e.ExceptionObject);
log.Error(e.ExceptionObject);
}
/// <summary>
/// WPF应用程序未处理异常
/// </summary>
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
Debug.WriteLine(e.Exception.Message);
log.Error(e.Exception);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.GimbalAI.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Connection;
using VIZ.GimbalAI.Storage;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动 -- 初始化延时
/// </summary>
public class AppSetup_DelayInit : IAppSetup
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_DelayInit));
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- 初始化延时";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
{
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
{
VAppDomain.DelayManager?.Dispose();
}
}
}
......@@ -4,39 +4,48 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.GimbalAI.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Connection;
using VIZ.GimbalAI.Storage;
using VIZ.Framework.Module;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动 -- 初始化Excel数据
/// 应用程序启动 -- 初始化CSV数据
/// </summary>
public class AppSetup_ExcelInit : IAppSetup
public class AppSetup_InitCSV : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_ExcelInit));
private readonly static ILog log = LogManager.GetLogger(typeof(AppSetup_InitCSV));
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- 初始化Excel数据";
public override string Detail { get; } = "应用程序启动 -- 初始化CSV数据";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
public override bool Setup(AppSetupContext context)
{
// 读取场景配置
string scenePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "scene.xls");
string scenePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "scene.csv");
string classPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "classes.csv");
ApplicationDomainEx.CsvContext = new CsvContext();
// 加载场景
ApplicationDomainEx.CsvContext.LoadScenes(scenePath);
// 加载模式
ApplicationDomainEx.CsvContext.LoadClasses(classPath);
// 初始化算法场景模型
List<AlgorithmSceneModel> sceneItems = new List<AlgorithmSceneModel>();
foreach (AlgorithmScene item in ExcelManager.GetScenes(scenePath))
foreach (AlgorithmScene item in ApplicationDomainEx.CsvContext.AlgorithmScenes)
{
AlgorithmSceneModel model = new AlgorithmSceneModel();
model.Label = item.name;
......@@ -44,25 +53,24 @@ namespace VIZ.GimbalAI.Module
sceneItems.Add(model);
}
VDataDomain.AlgorithmAutoSetting.Scenes = sceneItems;
VDataDomain.AlgorithmAutoSetting.Scene = sceneItems.First();
ApplicationDomainEx.AlgorithmAutoSetting.Scenes = sceneItems;
ApplicationDomainEx.AlgorithmAutoSetting.Scene = sceneItems.First();
// 读取模式配置
string classPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "classes.xls");
// 初始化算法模式模型
List<AlgorithmClassModel> classItems = new List<AlgorithmClassModel>();
foreach (AlgorithmClass item in ExcelManager.GetClasses(classPath))
foreach (AlgorithmClass item in ApplicationDomainEx.CsvContext.AlgorithmClasses)
{
if (item.sign?.Trim() == "0")
if (item.sign == 0)
continue;
AlgorithmClassModel model = new AlgorithmClassModel();
model.Label = item.display_name;
model.Value = int.Parse(item.ID);
model.IsChecked = string.IsNullOrWhiteSpace(item.is_checked) ? false : (int.Parse(item.is_checked) == 1);
model.Value = item.ID;
model.IsChecked = item.is_checked == 1;
classItems.Add(model);
}
VDataDomain.AlgorithmAutoSetting.Classes = classItems;
ApplicationDomainEx.AlgorithmAutoSetting.Classes = classItems;
return true;
}
......@@ -71,10 +79,9 @@ namespace VIZ.GimbalAI.Module
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
public override void Shutdown(AppSetupContext context)
{
}
}
}
......@@ -4,36 +4,34 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Module;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Storage;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动 -- 数据域初始化
/// 应用程序启动 -- 初始化LiteDB
/// </summary>
public class AppSetup_DtoDoainIInit : IAppSetup
public class AppSetup_InitLiteDB : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_DtoDoainIInit));
private readonly static ILog log = LogManager.GetLogger(typeof(AppSetup_InitLiteDB));
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- 数据域初始化";
public override string Detail { get; } = "应用程序启动 -- 初始化LiteDB";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
public override bool Setup(AppSetupContext context)
{
VDataDomain.dataManager = DataManager.GetInstance(string.Empty);
// LiteDB
string liteDbDir = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "db");
if (!System.IO.Directory.Exists(liteDbDir))
......@@ -42,11 +40,7 @@ namespace VIZ.GimbalAI.Module
}
string liteDbPath = System.IO.Path.Combine(liteDbDir, "cache.db");
VDataDomain.LiteDbContext = new LiteDbContext(liteDbPath);
// ini
string iniPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "config.ini");
VDataDomain.IniStorage = new IniStorage(iniPath);
ApplicationDomainEx.LiteDbContext = new LiteDbContext(liteDbPath);
return true;
}
......@@ -55,9 +49,9 @@ namespace VIZ.GimbalAI.Module
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
public override void Shutdown(AppSetupContext context)
{
VDataDomain.LiteDbContext?.Dispose();
ApplicationDomainEx.LiteDbContext?.Dispose();
}
}
......
......@@ -4,44 +4,45 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.GimbalAI.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Connection;
using VIZ.GimbalAI.Storage;
using VIZ.GimbalAI.Common;
using VIZ.Framework.Common;
using VIZ.Framework.Module;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动 -- 初始化NDI
/// </summary>
public class AppSetup_NdiInit : IAppSetup
public class AppSetup_InitNDI : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_NdiInit));
private readonly static ILog log = LogManager.GetLogger(typeof(AppSetup_InitNDI));
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- 初始化NDI";
public override string Detail { get; } = "应用程序启动 -- 初始化NDI";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
public override bool Setup(AppSetupContext context)
{
string remoteSenderName = VDataDomain.IniStorage.GetValue<NdiConfig, string>(p => p.NDI_STREAM_NAME);
string remoteSenderName = ApplicationDomainEx.IniStorage.GetValue<NdiConfig, string>(p => p.NDI_STREAM_NAME);
string localrecvname = System.Net.Dns.GetHostName() + "_TRTC_0";
NDIToolOption option = new NDIToolOption();
option.DelayFrame = VDataDomain.IniStorage.GetValue<ClientConfig, int>(p => p.CLIENT_VIDEO_DELAY);
NDIStreamOption option = new NDIStreamOption();
option.DelayFrame = ApplicationDomainEx.IniStorage.GetValue<ClientConfig, int>(p => p.CLIENT_VIDEO_DELAY);
NDIStream ndiStream = new NDIStream(localrecvname, remoteSenderName, option);
VideoStreamManager.NDITool = new NDITool(localrecvname, remoteSenderName, option);
VideoStreamManager.NDITool.Start();
VideoStreamManager.Append(NDIViewKeys.Main, ndiStream);
return true;
}
......@@ -50,10 +51,9 @@ namespace VIZ.GimbalAI.Module
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
public override void Shutdown(AppSetupContext context)
{
VideoStreamManager.NDITool?.Dispose();
VideoStreamManager.NDITool = null;
VideoStreamManager.Get<NDIStream>(NDIViewKeys.Main)?.Dispose();
}
}
}
......@@ -4,58 +4,58 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.GimbalAI.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Connection;
using VIZ.GimbalAI.Storage;
using System.Collections;
using VIZ.Framework.Connection;
using VIZ.Framework.Module;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动 -- Udp连接初始化
/// 应用程序启动 -- 初始化UDP
/// </summary>
public class AppSetup_UdpConnectionIInit : IAppSetup
public class AppSetup_InitUDP : AppSetupBase
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_UdpConnectionIInit));
private readonly static ILog log = LogManager.GetLogger(typeof(AppSetup_InitUDP));
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- Udp连接初始化";
public override string Detail { get; } = "应用程序启动 -- 初始化UDP";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
public override bool Setup(AppSetupContext context)
{
UdpConnection conn = new UdpConnection();
conn.PackageProvider = new UdpPackageProvider();
// -----------------------------------------------------------------
// 客户端
string clientIP = VDataDomain.IniStorage.GetValue<UdpConfig, string>(p => p.CLIENT_BINDING_IP);
string clientPort = VDataDomain.IniStorage.GetValue<UdpConfig, string>(p => p.CLIENT_BINDING_PORT);
string clientIP = ApplicationDomainEx.IniStorage.GetValue<UdpConfig, string>(p => p.CLIENT_BINDING_IP);
string clientPort = ApplicationDomainEx.IniStorage.GetValue<UdpConfig, string>(p => p.CLIENT_BINDING_PORT);
conn.Binding(clientIP, int.Parse(clientPort));
// -----------------------------------------------------------------
// 算法
string algorithmIP = VDataDomain.IniStorage.GetValue<UdpConfig, string>(p => p.ALGORITHM_BINDING_IP);
string algorithmPort = VDataDomain.IniStorage.GetValue<UdpConfig, string>(p => p.ALGORITHM_BINDING_PORT);
string algorithmIP = ApplicationDomainEx.IniStorage.GetValue<UdpConfig, string>(p => p.ALGORITHM_BINDING_IP);
string algorithmPort = ApplicationDomainEx.IniStorage.GetValue<UdpConfig, string>(p => p.ALGORITHM_BINDING_PORT);
UdpEndpointManager algorithmManager = new UdpEndpointManager(UdpEndpointKeys.algorithm, algorithmIP, int.Parse(algorithmPort));
algorithmManager.AddProvider(new AlgorithmPackageProvider());
conn.AddEndpointManager(algorithmManager);
// -----------------------------------------------------------------
// 云台
string gimbalIP = VDataDomain.IniStorage.GetValue<UdpConfig, string>(p => p.GIMBAL_BINDING_IP);
string gimbalPort = VDataDomain.IniStorage.GetValue<UdpConfig, string>(p => p.GIMBAL_BINDING_PORT);
string gimbalIP = ApplicationDomainEx.IniStorage.GetValue<UdpConfig, string>(p => p.GIMBAL_BINDING_IP);
string gimbalPort = ApplicationDomainEx.IniStorage.GetValue<UdpConfig, string>(p => p.GIMBAL_BINDING_PORT);
UdpEndpointManager gimbalManager = new UdpEndpointManager(UdpEndpointKeys.gimbal, gimbalIP, int.Parse(gimbalPort));
gimbalManager.AddProvider(new GimbalPackageProvider());
conn.AddEndpointManager(gimbalManager);
// -----------------------------------------------------------------
......@@ -70,7 +70,7 @@ namespace VIZ.GimbalAI.Module
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
public override void Shutdown(AppSetupContext context)
{
ConnectionManager.UdpConnection?.Dispose();
}
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.GimbalAI.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Connection;
using VIZ.GimbalAI.Storage;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动 -- 日志初始化
/// </summary>
public class AppSetup_LogInit : IAppSetup
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_LogInit));
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- 日志初始化";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
{
string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "log.config");
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(path));
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using VIZ.GimbalAI.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Connection;
using VIZ.GimbalAI.Storage;
using System.Threading;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 应用程序启动 -- 单例启动
/// </summary>
public class AppSetup_Single : IAppSetup
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AppSetup_Single));
/// <summary>
///
/// </summary>
private EventWaitHandle ProgramStarted;
/// <summary>
/// 描述
/// </summary>
public string Detail { get; } = "应用程序启动 -- 单例启动";
/// <summary>
/// 执行启动
/// </summary>
/// <param name="context">应用程序启动上下文</param>
/// <returns>是否成功执行</returns>
public bool Setup(AppSetupContext context)
{
bool createNew;
this.ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, "VIZ_GIMBALAI_CLIENT_START_EVENT", out createNew);
if (!createNew)
{
ProgramStarted.Set();
return false;
}
return true;
}
/// <summary>
/// 执行关闭
/// </summary>
/// <param name="context">应用程序启动上下文</param>
public void Shutdown(AppSetupContext context)
{
}
}
}
......@@ -81,11 +81,43 @@
<Reference Include="Microsoft.Xaml.Behaviors, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.39\lib\net45\Microsoft.Xaml.Behaviors.dll</HintPath>
</Reference>
<Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp4.4.6.0.20220608\lib\net48\OpenCvSharp.dll</HintPath>
</Reference>
<Reference Include="OpenCvSharp.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp4.Extensions.4.6.0.20220608\lib\net48\OpenCvSharp.Extensions.dll</HintPath>
</Reference>
<Reference Include="OpenCvSharp.WpfExtensions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp4.WpfExtensions.4.6.0.20220608\lib\net48\OpenCvSharp.WpfExtensions.dll</HintPath>
</Reference>
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Drawing.Common, Version=4.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Drawing.Common.5.0.3\lib\net461\System.Drawing.Common.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Security" />
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
......@@ -148,7 +180,6 @@
<Compile Include="ControlView\View\ChangeNdiStreamView.xaml.cs">
<DependentUpon>ChangeNdiStreamView.xaml</DependentUpon>
</Compile>
<Compile Include="Setup\AppSetup.cs" />
<Compile Include="ControlView\ViewModel\ControlViewModel.cs" />
<Compile Include="ControlView\View\ControlView.xaml.cs">
<DependentUpon>ControlView.xaml</DependentUpon>
......@@ -174,18 +205,12 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="Setup\AppSetupContext.cs" />
<Compile Include="Setup\IAppSetup.cs" />
<Compile Include="Setup\Provider\Load\AppSetup_SetupGimbal.cs" />
<Compile Include="Setup\Provider\Load\AppSetup_SetupAlgorithm.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_CatchUnhandledException.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_NdiInit.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_Single.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_DelayInit.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_LogInit.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_ExcelInit.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_UdpConnectionIInit.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_DtoDoainIInit.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_InitNDI.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_InitCSV.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_InitUDP.cs" />
<Compile Include="Setup\Provider\Setup\AppSetup_InitLiteDB.cs" />
<Compile Include="VideoView\Service\IVideoViewService.cs" />
<Compile Include="VideoView\ViewModel\VideoViewModel.cs" />
<Compile Include="VideoView\View\VideoView.xaml.cs">
......@@ -203,6 +228,34 @@
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Common.Resource\VIZ.Framework.Common.Resource.csproj">
<Project>{76ef480a-e486-41b7-b7a5-2a849fc8d5bf}</Project>
<Name>VIZ.Framework.Common.Resource</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Common\VIZ.Framework.Common.csproj">
<Project>{92834c05-703e-4f05-9224-f36220939d8f}</Project>
<Name>VIZ.Framework.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Connection\VIZ.Framework.Connection.csproj">
<Project>{e07528dd-9dee-47c2-b79d-235ecfa6b003}</Project>
<Name>VIZ.Framework.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Module\VIZ.Framework.Module.csproj">
<Project>{47cf6fb0-e37d-4ef1-afc7-03db2bca8892}</Project>
<Name>VIZ.Framework.Module</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Common.Resource\VIZ.GimbalAI.Common.Resource.csproj">
<Project>{5d8021d1-a6b2-4784-b8fe-ff3b7f94e304}</Project>
<Name>VIZ.GimbalAI.Common.Resource</Name>
......@@ -215,10 +268,6 @@
<Project>{52ca7346-0bc0-4e03-8ca5-c00a8777f1ef}</Project>
<Name>VIZ.GimbalAI.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj">
<Project>{d4409326-3f36-4835-812a-bea8ed046e04}</Project>
<Name>VIZ.GimbalAI.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Domain\VIZ.GimbalAI.Domain.csproj">
<Project>{bbf80159-d5de-4d82-a045-a96d67d80632}</Project>
<Name>VIZ.GimbalAI.Domain</Name>
......
......@@ -4,14 +4,14 @@ using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Module
{
/// <summary>
/// 视频视图服务
/// </summary>
public interface IVideoViewService : IViewModelService
public interface IVideoViewService : IService
{
/// <summary>
/// 矩形渲染是否开启
......
......@@ -4,27 +4,29 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VIZ.GimbalAI.Module"
xmlns:common="clr-namespace:VIZ.GimbalAI.Common;assembly=VIZ.GimbalAI.Common"
xmlns:common="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
d:DataContext="{d:DesignInstance Type=local:VideoViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="Loaded">
<behaviors:InvokeCommandAction Command="{Binding LoadedCommand}" />
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
<Grid>
<Border BorderBrush="#ff313139" BorderThickness="1">
<common:VideoControl x:Name="videoControl" Loaded="videoControl_Loaded"
IsRenderRectangleEnabled="{Binding Path=IsRenderRectangleEnabled}"
IsRenderFrameSelectionEnabled="{Binding Path=IsRenderFrameSelectionEnabled}"
IsRectangleClickTrigger="{Binding Path=IsRectangleClickTrigger}"
IsRectangleFrameSelectionTrigger="{Binding Path=IsRectangleFrameSelectionTrigger}"
<common:VideoControl x:Name="videoControl"
IsShowFPS="{Binding Path=IsShowVideoFPS}">
<behaviors:Interaction.Triggers>
<!--<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="VideoRectangleClick">
<behaviors:InvokeCommandAction Command="{Binding VideoRectangleClickCommand}" PassEventArgsToCommand="True" />
</behaviors:EventTrigger>
<behaviors:EventTrigger EventName="VideoRectangleFrameSelection">
<behaviors:InvokeCommandAction Command="{Binding VideoRectangleFrameSelectionCommand}" PassEventArgsToCommand="True" />
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
</behaviors:Interaction.Triggers>-->
</common:VideoControl>
</Border>
</Grid>
......
......@@ -13,7 +13,9 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VIZ.GimbalAI.Common;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Core;
using VIZ.Framework.Storage;
using VIZ.GimbalAI.Domain;
namespace VIZ.GimbalAI.Module
{
......@@ -29,17 +31,9 @@ namespace VIZ.GimbalAI.Module
if (WPFHelper.IsInDesignMode(this))
return;
VideoViewModel vm = new VideoViewModel();
vm.SetView(this);
this.DataContext = vm;
}
WPFHelper.BindingViewModel(this, new VideoViewModel());
/// <summary>
/// 设置16 * 9 尺寸
/// </summary>
private void videoControl_Loaded(object sender, RoutedEventArgs e)
{
//this.videoControl.Height = this.videoControl.ActualWidth / 18d * 9d;
this.videoControl.IsShowFPS = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, bool>(p => p.VIDEO_IS_SHOW_FPS);
}
}
}
......@@ -3,14 +3,21 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Common;
using VIZ.GimbalAI.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
using VIZ.GimbalAI.Connection;
using ManageLiteAV;
using System.Drawing;
using VIZ.GimbalAI.Storage;
using VIZ.Framework.Common;
using VIZ.Framework.Connection;
using OpenCvSharp;
using OpenCvSharp.WpfExtensions;
using OpenCvSharp.Extensions;
using SharpDX.Mathematics.Interop;
using VIZ.Framework.Storage;
namespace VIZ.GimbalAI.Module
{
......@@ -22,7 +29,7 @@ namespace VIZ.GimbalAI.Module
public VideoViewModel()
{
// 注册视图模型服务
VAppDomain.ViewModelServiceManager.AddService(this);
ApplicationDomainEx.ServiceManager.AddService(ServiceKeys.VideoView, this);
// 初始化命令
this.InitCommand();
......@@ -33,9 +40,45 @@ namespace VIZ.GimbalAI.Module
// 初始化属性
this.InitProperty();
// 初始化NDI
this.InitNDI();
}
/// <summary>
/// 初始化NDI
/// </summary>
private void InitNDI()
{
// 注册NDI事件
VideoStreamManager.NDITool.ExecuteVideoFrame -= NdiTool_ExecuteVideoFrame;
VideoStreamManager.NDITool.ExecuteVideoFrame += NdiTool_ExecuteVideoFrame;
this.ndiStream = VideoStreamManager.Get<NDIStream>(NDIViewKeys.Main);
this.ndiStream.ExecuteVideoFrame -= NDIStream_ExecuteVideoFrame;
this.ndiStream.ExecuteVideoFrame += NDIStream_ExecuteVideoFrame;
this.ndiStream.Start();
}
/// <summary>
/// 初始化视频控件
/// </summary>
private void InitVideoControl()
{
VideoView view = this.GetView<VideoView>();
if (view == null)
return;
// 跟踪框插件
this.trackingBoxPlugin = new TrackingBoxPlugin(view.videoControl);
this.trackingBoxPlugin.TrackingBoxClick += TrackingBoxPlugin_TrackingBoxClick;
this.trackingBoxPlugin.IsEnabled = this.IsRenderRectangleEnabled;
view.videoControl.AttachPlugin(this.trackingBoxPlugin);
// 框选插件
this.selectionBoxPlugin = new SelectionBoxPlugin(view.videoControl);
this.selectionBoxPlugin.Selected += SelectionBoxPlugin_Selected;
this.selectionBoxPlugin.IsEnabled = this.IsRenderFrameSelectionEnabled;
view.videoControl.AttachPlugin(this.selectionBoxPlugin);
// 中心轴位置插件
// TODO : 中心轴位置插件
}
/// <summary>
......@@ -43,8 +86,7 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void InitCommand()
{
this.VideoRectangleClickCommand = new VCommand<VideoRectangleClickEventArgs>(this.VideoRectangleClick);
this.VideoRectangleFrameSelectionCommand = new VCommand<VideoRectangleFrameSelectionEventArgs>(this.VideoRectangleFrameSelection);
this.LoadedCommand = new VCommand(this.Loaded);
}
/// <summary>
......@@ -52,7 +94,8 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void InitMessage()
{
VAppDomain.AlgorithmMessageManager.Register<VideoRenderRectangleMessage>(this, this.VideoRenderRectangle);
ApplicationDomainEx.MessageManager.Register<VideoRenderRectangleMessage>(this, this.VideoRenderRectangle);
ApplicationDomainEx.MessageManager.Register<GimbalCenterAxisMessage>(this, this.GimbalCenterAxis);
}
/// <summary>
......@@ -60,20 +103,47 @@ namespace VIZ.GimbalAI.Module
/// </summary>
private void InitProperty()
{
this.IsShowVideoFPS = VDataDomain.IniStorage.GetValue<ClientConfig, bool>(p => p.CLIENT_IS_VIDEO_SHOW_FPS);
}
// ======================================================================================
// === Field ===
// ======================================================================================
/// <summary>
/// 处理视频帧信息
/// 信息
/// </summary>
private void NdiTool_ExecuteVideoFrame(object sender, VideoFrameEventArgs e)
{
VideoView view = this.GetView<VideoView>();
if (view == null)
return;
private NDIStream ndiStream;
view.videoControl.RenderVideo(e.Frame);
}
/// <summary>
/// 跟踪框插件
/// </summary>
private TrackingBoxPlugin trackingBoxPlugin;
/// <summary>
/// 框选框插件
/// </summary>
private SelectionBoxPlugin selectionBoxPlugin;
/// <summary>
/// 算法矩形框宽度(单位:像素)
/// </summary>
private readonly int VIDEO_TRACKING_BOX_BORDER_WIDTH = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, int>(p => p.VIDEO_TRACKING_BOX_BORDER_WIDTH);
/// <summary>
/// 算法矩形框颜色
/// </summary>
private readonly RawColor4 VIDEO_TRACKING_BOX_BORDER_COLOR = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, RawColor4>(p => p.VIDEO_TRACKING_BOX_BORDER_COLOR);
/// <summary>
/// 中心轴宽度
/// </summary>
private readonly int VIDEO_CENTER_AXIS_WIDTH = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, int>(p => p.VIDEO_CENTER_AXIS_WIDTH);
/// <summary>
/// 中心轴颜色
/// </summary>
private RawColor4 VIDEO_CENTER_AXIS_COLOR = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, RawColor4>(p => p.VIDEO_CENTER_AXIS_COLOR);
// ======================================================================================
// === Property ===
......@@ -88,7 +158,15 @@ namespace VIZ.GimbalAI.Module
public bool IsRenderRectangleEnabled
{
get { return isRenderRectangleEnabled; }
set { isRenderRectangleEnabled = value; this.RaisePropertyChanged(nameof(IsRenderRectangleEnabled)); }
set
{
isRenderRectangleEnabled = value;
this.RaisePropertyChanged(nameof(IsRenderRectangleEnabled));
if (this.trackingBoxPlugin != null)
{
this.trackingBoxPlugin.IsEnabled = value;
}
}
}
#endregion
......@@ -102,7 +180,15 @@ namespace VIZ.GimbalAI.Module
public bool IsRenderFrameSelectionEnabled
{
get { return isRenderFrameSelectionEnabled; }
set { isRenderFrameSelectionEnabled = value; this.RaisePropertyChanged(nameof(IsRenderFrameSelectionEnabled)); }
set
{
isRenderFrameSelectionEnabled = value;
this.RaisePropertyChanged(nameof(IsRenderFrameSelectionEnabled));
if (this.selectionBoxPlugin != null)
{
this.selectionBoxPlugin.IsEnabled = value;
}
}
}
#endregion
......@@ -149,85 +235,24 @@ namespace VIZ.GimbalAI.Module
#endregion
#region IsShowVideoFPS -- 是否显示视频FPS
private bool isShowVideoFPS;
/// <summary>
/// 是否显示视频FPS
/// </summary>
public bool IsShowVideoFPS
{
get { return isShowVideoFPS; }
set { isShowVideoFPS = value; this.RaisePropertyChanged(nameof(IsShowVideoFPS)); }
}
#endregion
// ======================================================================================
// === Command ===
// ======================================================================================
#region VideoRectangleClickCommand -- 视频矩形框被选中命令
#region LoadedCommand -- 加载命令
/// <summary>
/// 视频矩形框被选中命令
/// 加载命令
/// </summary>
public VCommand<VideoRectangleClickEventArgs> VideoRectangleClickCommand { get; set; }
public VCommand LoadedCommand { get; set; }
/// <summary>
/// 矩形框被选中
/// 加载
/// </summary>
/// <param name="args">事件参数</param>
private void VideoRectangleClick(VideoRectangleClickEventArgs args)
private void Loaded()
{
if (args.HitTestVideoRectangles == null || args.HitTestVideoRectangles.Count == 0)
return;
// 向算法发送 UDP 消息
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(UdpEndpointKeys.algorithm);
if (manager == null)
return;
AlgorithmSender.AutoTracking(manager, args.HitTestVideoRectangles.First().AlgorithmID);
}
#endregion
#region VideoRectangleFrameSelectionCommand -- 视频框选命令
/// <summary>
/// 视频框选命令
/// </summary>
public VCommand<VideoRectangleFrameSelectionEventArgs> VideoRectangleFrameSelectionCommand { get; set; }
/// <summary>
/// 视频框选命令
/// </summary>
/// <param name="args">事件参数</param>
private void VideoRectangleFrameSelection(VideoRectangleFrameSelectionEventArgs args)
{
// 清理框选
VAppDomain.DelayManager.Wait("VideoViewModel.VideoRectangleFrameSelection", 0.5, () =>
{
WPFHelper.BeginInvoke(() =>
{
VideoView view = this.GetView<VideoView>();
if (view == null)
return;
view.videoControl.ClearFrameSelection();
});
});
this.isVideoRectangleFrameSelectionEnd = true;
// 向算法发送 UDP 消息
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(UdpEndpointKeys.algorithm);
if (manager == null)
return;
List<float> roi = new List<float> { args.VideoRectangle.Left, args.VideoRectangle.Top, args.VideoRectangle.Width, args.VideoRectangle.Height };
AlgorithmSender.ManualDetect(manager, roi);
// 初始化视频控件
this.InitVideoControl();
}
#endregion
......@@ -254,24 +279,31 @@ namespace VIZ.GimbalAI.Module
// ------------------------------------------------------------------------------
// 绘制算法推送矩形框
List<VideoRectangle> rectangles = new List<VideoRectangle>();
List<TrackingBoxInfo> boxInfos = new List<TrackingBoxInfo>();
if (msg.roi != null)
{
VideoRectangleColor color = VideoRectangleColor.Red;
foreach (var kv in msg.roi)
{
VideoRectangle r = new VideoRectangle();
r.AlgorithmID = kv.Key;
r.AlgorithmRoi = kv.Value;
r.Color = color;
if (kv.Value == null || kv.Value.Count != 4)
continue;
float x = kv.Value[0];
float y = kv.Value[1];
float w = kv.Value[2];
float h = kv.Value[3];
TrackingBoxInfo r = new TrackingBoxInfo();
r.ID = kv.Key.ToString();
r.SrcRect = new SharpDX.Mathematics.Interop.RawRectangleF(x, y, x + w, y + h);
r.DrawingBorderWidth = this.VIDEO_TRACKING_BOX_BORDER_WIDTH;
r.DrawingBorderColor = this.VIDEO_TRACKING_BOX_BORDER_COLOR;
rectangles.Add(r);
boxInfos.Add(r);
}
}
view.videoControl.RenderRectangleInfo(rectangles);
view.videoControl.UpdateTrackingBox(boxInfos);
// ------------------------------------------------------------------------------
// UI逻辑调整
......@@ -298,6 +330,30 @@ namespace VIZ.GimbalAI.Module
#endregion
#region GimbalCenterAxisMessage -- 中心轴更新消息
/// <summary>
/// 中心轴更新消息
/// </summary>
/// <param name="msg">消息</param>
private void GimbalCenterAxis(GimbalCenterAxisMessage msg)
{
VideoView view = this.GetView<VideoView>();
if (view == null)
return;
CenterAxisInfo info = new CenterAxisInfo();
info.SrcCenter = new RawVector2((float)msg.X, (float)msg.Y);
info.AxisWidth = this.VIDEO_CENTER_AXIS_WIDTH;
info.AxisColor = this.VIDEO_CENTER_AXIS_COLOR;
view.videoControl.UpdateCenterAxis(info);
}
#endregion
// ======================================================================================
// === Public Function ===
// ======================================================================================
/// <summary>
......@@ -310,7 +366,11 @@ namespace VIZ.GimbalAI.Module
if (view == null)
return null;
return view.videoControl.GetFrameImage();
Mat mat = view.videoControl.RenderVideoToMat();
Bitmap bitmap = mat.ToBitmap();
mat.Dispose();
return bitmap;
}
/// <summary>
......@@ -322,7 +382,7 @@ namespace VIZ.GimbalAI.Module
if (view == null)
return;
view.videoControl.ClearFrameSelection();
view.videoControl.ClearSelectionBox();
}
/// <summary>
......@@ -334,7 +394,7 @@ namespace VIZ.GimbalAI.Module
if (view == null)
return;
view.videoControl.ClearRectangleInfo();
view.videoControl.ClearTrackingBox();
}
/// <summary>
......@@ -343,7 +403,7 @@ namespace VIZ.GimbalAI.Module
/// <param name="name">流名称</param>
public void ChangeNdiStream(string name)
{
VideoStreamManager.NDITool?.ChangeRemoteSenderName(name);
this.ndiStream?.ChangeRemoteSenderName(name);
}
/// <summary>
......@@ -352,7 +412,72 @@ namespace VIZ.GimbalAI.Module
/// <param name="delayFrame">帧延时</param>
public void ChangeNdiVideoFrameDelay(int delayFrame)
{
VideoStreamManager.NDITool?.SetVideoFrameDelay(delayFrame);
this.ndiStream.SetVideoFrameDelay(delayFrame);
}
// ======================================================================================
// === Private Function ===
// ======================================================================================
/// <summary>
/// 处理视频帧信息
/// </summary>
private void NDIStream_ExecuteVideoFrame(object sender, VideoFrameEventArgs e)
{
VideoView view = this.GetView<VideoView>();
if (view == null)
return;
view.videoControl.UpdateVideoFrame(e.Frame);
}
/// <summary>
/// 处理视频点击跟踪框事件
/// </summary>
private void TrackingBoxPlugin_TrackingBoxClick(object sender, TrackingBoxClickEventArgs e)
{
if (!this.IsRectangleClickTrigger || e.HitTrackingBoxInfo == null)
return;
// 向算法发送 UDP 消息
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(UdpEndpointKeys.algorithm);
if (manager == null)
return;
AlgorithmSender.AutoTracking(manager, int.Parse(e.HitTrackingBoxInfo.ID));
}
/// <summary>
/// 处理视频框选事件
/// </summary>
private void SelectionBoxPlugin_Selected(object sender, SelectionBoxSelectedEventArgs e)
{
// 清理框选
ApplicationDomainEx.DelayManager.Wait("VideoViewModel.VideoRectangleFrameSelection", 0.5, () =>
{
WPFHelper.BeginInvoke(() =>
{
VideoView view = this.GetView<VideoView>();
if (view == null)
return;
view.videoControl.ClearSelectionBox();
});
});
this.isVideoRectangleFrameSelectionEnd = true;
// 不触发框选
if (!this.IsRectangleFrameSelectionTrigger)
return;
// 向算法发送 UDP 消息
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(UdpEndpointKeys.algorithm);
if (manager == null)
return;
List<float> roi = new List<float> { e.SrcRect.Left, e.SrcRect.Top, e.SrcRect.Right - e.SrcRect.Left, e.SrcRect.Bottom - e.SrcRect.Top };
AlgorithmSender.ManualDetect(manager, roi);
}
}
}
......@@ -6,6 +6,10 @@
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
......@@ -3,4 +3,14 @@
<package id="LiteDB" version="5.0.11" targetFramework="net48" />
<package id="log4net" version="2.0.14" targetFramework="net48" />
<package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.39" targetFramework="net48" />
<package id="OpenCvSharp4" version="4.6.0.20220608" targetFramework="net48" />
<package id="OpenCvSharp4.Extensions" version="4.6.0.20220608" targetFramework="net48" />
<package id="OpenCvSharp4.WpfExtensions" version="4.6.0.20220608" targetFramework="net48" />
<package id="SharpDX" version="4.2.0" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Drawing.Common" version="5.0.3" targetFramework="net48" />
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
</packages>
\ No newline at end of file
......@@ -24,20 +24,21 @@ namespace VIZ.GimbalAI.Storage
/// <summary>
/// ID
/// </summary>
public string ID { get; set; }
public int ID { get; set; }
/// <summary>
/// 是否启用
///
/// 1: 启用
/// 0: 不启用
/// </summary>
public string sign { get; set; }
public int sign { get; set; }
/// <summary>
/// 是否选中
/// 1: 选中
/// 0: 没选中
/// </summary>
public string is_checked { get; set; }
public int is_checked { get; set; }
}
}
......@@ -4,29 +4,42 @@ using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using NPOI;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using VIZ.Framework.Storage;
using CsvHelper;
using System.Globalization;
using VIZ.Framework.Core;
namespace VIZ.GimbalAI.Storage
{
/// <summary>
/// Excel管理器
/// CSV上下文
/// </summary>
public static class ExcelManager
public class CsvContext
{
/// <summary>
/// 场景集合
/// </summary>
[Csv(Scene = CsvScene.Read)]
public List<AlgorithmScene> AlgorithmScenes { get; private set; }
/// <summary>
/// 模式集合
/// </summary>
[Csv(Scene = CsvScene.Read)]
public List<AlgorithmClass> AlgorithmClasses { get; private set; }
/// <summary>
/// 获取场景集合
/// </summary>
/// <param name="path">场景配置文件路径</param>
/// <returns>场景集合</returns>
public static List<AlgorithmScene> GetScenes(string path)
public void LoadScenes(string path)
{
List<AlgorithmScene> result = new List<AlgorithmScene>();
List<AlgorithmScene> list = new List<AlgorithmScene>();
result.Add(new AlgorithmScene { ID = "general", name = "通用" });
list.Add(new AlgorithmScene { ID = "general", name = "通用" });
return result;
this.AlgorithmScenes = list;
}
/// <summary>
......@@ -34,33 +47,13 @@ namespace VIZ.GimbalAI.Storage
/// </summary>
/// <param name="path">模式文件路径</param>
/// <returns>模式集合</returns>
public static List<AlgorithmClass> GetClasses(string path)
public void LoadClasses(string path)
{
List<AlgorithmClass> result = new List<AlgorithmClass>();
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (StreamReader sr = new StreamReader(path, Encoding.Default))
using (CsvReader reader = new CsvReader(sr, CultureInfo.InvariantCulture))
{
IWorkbook workbook = new HSSFWorkbook(fs);
ISheet sheet = workbook.GetSheet("Sheet1");
for (int i = 1; i < sheet.LastRowNum; i++)
{
IRow row = sheet.GetRow(i);
AlgorithmClass @class = new AlgorithmClass();
@class.name = row.GetCell(0).StringCellValue;
@class.display_name = row.GetCell(1).StringCellValue;
@class.ID = row.GetCell(2).NumericCellValue.ToString();
@class.sign = row.GetCell(3).NumericCellValue.ToString();
@class.is_checked = row.GetCell(4).NumericCellValue.ToString();
result.Add(@class);
}
this.AlgorithmClasses = reader.GetRecords<AlgorithmClass>()?.ToList();
}
return result;
}
}
}
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Storage;
namespace VIZ.GimbalAI.Storage
{
......
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Storage;
namespace VIZ.GimbalAI.Storage
{
......@@ -12,18 +13,6 @@ namespace VIZ.GimbalAI.Storage
public class ClientConfig : IniConfigBase
{
/// <summary>
/// 视频是否显示FPS
/// </summary>
[Ini(Section = "Client", DefaultValue = @"false")]
public string CLIENT_IS_VIDEO_SHOW_FPS { get; set; }
/// <summary>
/// 视频渲染等待(单位:毫秒)
/// </summary>
[Ini(Section = "Client", DefaultValue = @"10")]
public string CLIENT_VIDEO_RENDER_WAIT { get; set; }
/// <summary>
/// 视频延时(单位:帧)
/// </summary>
[Ini(Section = "Client", DefaultValue = @"0")]
......@@ -32,7 +21,7 @@ namespace VIZ.GimbalAI.Storage
/// <summary>
/// 算法矩形框宽度(单位:像素)
/// </summary>
[Ini(Section = "Client", DefaultValue = @"4")]
[Ini(Section = "Client", DefaultValue = @"4", Type = typeof(int))]
public string CLIENT_ALGORITHM_RECTANGLE_STROKE_WIDTH { get; set; }
/// <summary>
......@@ -44,7 +33,7 @@ namespace VIZ.GimbalAI.Storage
/// <summary>
/// 框选矩形框宽度(单位:像素)
/// </summary>
[Ini(Section = "Client", DefaultValue = @"4")]
[Ini(Section = "Client", DefaultValue = @"4", Type = typeof(int))]
public string CLIENT_FRAME_SELECTION_STROKE_WIDTH { get; set; }
/// <summary>
......
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Storage;
namespace VIZ.GimbalAI.Storage
{
......@@ -14,13 +15,19 @@ namespace VIZ.GimbalAI.Storage
/// <summary>
/// 云台启动相对路径
/// </summary>
[Ini(Section = "Gimbal", DefaultValue = @"..\python\python.bat")]
[Ini(Section = "Gimbal", DefaultValue = @"..\python\python.bat", Type = typeof(string))]
public string GIMBAL_SETUP_PATH { get; set; }
/// <summary>
/// 云台CMD窗口样式
/// </summary>
[Ini(Section = "Gimbal", DefaultValue = "Minimized")]
[Ini(Section = "Gimbal", DefaultValue = "Minimized", Type = typeof(string))]
public string GIMBAL_CMD_WINDOW_STYLE { get; set; }
/// <summary>
/// 云台中心轴移动速度
/// </summary>
[Ini(Section = "Gimbal", DefaultValue = "1", Type = typeof(int))]
public string GIMBAL_CENTER_AXIS_SPEED { get; set; }
}
}
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Storage;
namespace VIZ.GimbalAI.Storage
{
......
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Storage;
namespace VIZ.GimbalAI.Storage
{
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Storage
{
/// <summary>
/// SDK 的 Local 数据信息,使用 ini 本地存储
/// </summary>
public class DataManager
{
/// <summary>
/// Ini文件仓储
/// </summary>
private IniStorage storage;
/// <summary>
/// 单例
/// </summary>
private static DataManager mInstance = new DataManager();
/// <summary>
/// 用户昵称
/// 默认值为: ""
/// </summary>
/// <param name="OneMachineName"></param>
/// <returns>数据管理器</returns>
public static DataManager GetInstance(string OneMachineName)
{
return mInstance;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Storage
{
/// <summary>
/// Ini配置
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class IniAttribute : Attribute
{
/// <summary>
/// 区域
/// </summary>
public string Section { get; set; }
/// <summary>
/// 默认值
/// </summary>
public string DefaultValue { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Storage
{
/// <summary>
/// INI配置基类
/// </summary>
public abstract class IniConfigBase
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.GimbalAI.Storage
{
/// <summary>
/// Ini仓储
/// </summary>
public class IniStorage
{
/// <summary>
/// 每次读取最大值
/// </summary>
public const int MAX_READ_SIZE = 255;
/// <summary>
/// 声明INI文件的写操作函数
/// </summary>
/// <param name="section">配置节</param>
/// <param name="key">键</param>
/// <param name="val">值</param>
/// <param name="filePath">Ini文件路径</param>
/// <returns></returns>
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
/// <summary>
/// 声明INI文件的读操作函数
/// </summary>
/// <param name="section">配置节</param>
/// <param name="key">键</param>
/// <param name="def">默认值</param>
/// <param name="retVal">返回值</param>
/// <param name="size">目标缓存器大小</param>
/// <param name="filePath">Ini文件路径</param>
/// <returns></returns>
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key, string def, System.Text.StringBuilder retVal, int size, string filePath);
private string sPath = null;
/// <summary>
/// Ini文件仓储
/// </summary>
/// <param name="path">Ini文件路径</param>
public IniStorage(string path)
{
this.sPath = path;
}
/// <summary>
/// 设置值
/// </summary>
/// <param name="section">配置节</param>
/// <param name="key">键</param>
/// <param name="value">值</param>
public void SetValue(string section, string key, string value)
{
// section=配置节,key=键名,value=键值,path=路径
WritePrivateProfileString(section, key, value, sPath);
}
/// <summary>
/// 获取值
/// </summary>
/// <param name="section">配置节</param>
/// <param name="key">键</param>
/// <returns>值</returns>
public string GetValue(string section, string key)
{
// 每次从ini中读取多少字节
StringBuilder temp = new StringBuilder(MAX_READ_SIZE);
// section=配置节,key=键名,temp=上面,path=路径
GetPrivateProfileString(section, key, string.Empty, temp, MAX_READ_SIZE, sPath);
return temp.ToString();
}
/// <summary>
/// 获取值
/// </summary>
/// <typeparam name="TConfig">配置对象类型</typeparam>
/// <typeparam name="TValue">配置值类型</typeparam>
/// <typeparam name="TProperty">属性类型</typeparam>
/// <param name="property">属性选择器</param>
/// <returns>配置值</returns>
public TValue GetValue<TConfig, TValue>(Expression<Func<TConfig, string>> property) where TConfig : IniConfigBase
{
Type type = typeof(TConfig);
string str_property = property.ToString();
string propertyName = str_property.Substring(str_property.IndexOf('.') + 1);
PropertyInfo propertyInfo = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
throw new Exception($"{str_property} is not found.");
IniAttribute attribute = propertyInfo.GetCustomAttribute<IniAttribute>(true);
if (attribute == null)
throw new Exception($"{str_property} no IniAttribute.");
// 每次从ini中读取多少字节
StringBuilder temp = new StringBuilder(MAX_READ_SIZE);
// section=配置节,key=键名,temp=上面,path=路径
GetPrivateProfileString(attribute.Section, propertyName, attribute.DefaultValue, temp, MAX_READ_SIZE, sPath);
TValue result = this.ConvertValue<TValue>(temp?.ToString());
return result;
}
/// <summary>
/// 设置值
/// </summary>
/// <typeparam name="T">配置对象类型</typeparam>
/// <param name="property">属性选择器</param>
/// <param name="value">属性值</param>
public void SetValue<T>(Expression<Func<T, string>> property, object value) where T : IniConfigBase
{
Type type = typeof(T);
string str_property = property.ToString();
string propertyName = str_property.Substring(str_property.IndexOf('.') + 1);
PropertyInfo propertyInfo = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
throw new Exception($"{str_property} is not found.");
IniAttribute attribute = propertyInfo.GetCustomAttribute<IniAttribute>(true);
if (attribute == null)
throw new Exception($"{str_property} no IniAttribute.");
// section=配置节,key=键名,value=键值,path=路径
WritePrivateProfileString(attribute.Section, propertyName, (value == null ? string.Empty : value.ToString()), sPath);
}
/// <summary>
/// 转化类型
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
private TValue ConvertValue<TValue>(string value)
{
if (string.IsNullOrEmpty(value))
return default;
Type type = typeof(TValue);
// String
if (type == typeof(string))
return (TValue)(object)value;
// Int32
if (type == typeof(Int32))
return (TValue)(object)Convert.ToInt32(value);
// Int64
if (type == typeof(Int64))
return (TValue)(object)Convert.ToInt64(value);
// Float
if (type == typeof(float))
return (TValue)(object)(float)Convert.ToDouble(value);
// Double
if (type == typeof(double))
return (TValue)(object)Convert.ToDouble(value);
// Bool
if (type == typeof(bool))
return (TValue)(object)Convert.ToBoolean(value);
return default;
}
}
}
......@@ -70,6 +70,9 @@
<Reference Include="BouncyCastle.Crypto, Version=1.8.9.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL">
<HintPath>..\packages\Portable.BouncyCastle.1.8.9\lib\net40\BouncyCastle.Crypto.dll</HintPath>
</Reference>
<Reference Include="CsvHelper, Version=28.0.0.0, Culture=neutral, PublicKeyToken=8c4959082be5c823, processorArchitecture=MSIL">
<HintPath>..\packages\CsvHelper.28.0.1\lib\net47\CsvHelper.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=1.3.3.11, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.1.3.3\lib\net45\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
......@@ -79,22 +82,32 @@
<Reference Include="log4net, Version=2.0.14.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.14\lib\net45\log4net.dll</HintPath>
</Reference>
<Reference Include="NPOI, Version=2.5.6.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
<HintPath>..\packages\NPOI.2.5.6\lib\net45\NPOI.dll</HintPath>
</Reference>
<Reference Include="NPOI.OOXML, Version=2.5.6.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
<HintPath>..\packages\NPOI.2.5.6\lib\net45\NPOI.OOXML.dll</HintPath>
</Reference>
<Reference Include="NPOI.OpenXml4Net, Version=2.5.6.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
<HintPath>..\packages\NPOI.2.5.6\lib\net45\NPOI.OpenXml4Net.dll</HintPath>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="NPOI.OpenXmlFormats, Version=2.5.6.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
<HintPath>..\packages\NPOI.2.5.6\lib\net45\NPOI.OpenXmlFormats.dll</HintPath>
<Reference Include="Microsoft.Bcl.HashCode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.HashCode.1.0.0\lib\net461\Microsoft.Bcl.HashCode.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.0\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
......@@ -104,25 +117,31 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Excel\Algorithm\AlgorithmClass.cs" />
<Compile Include="Excel\Algorithm\AlgorithmScene.cs" />
<Compile Include="Excel\ExcelManager.cs" />
<Compile Include="CSV\Algorithm\AlgorithmClass.cs" />
<Compile Include="CSV\Algorithm\AlgorithmScene.cs" />
<Compile Include="CSV\CsvContext.cs" />
<Compile Include="Ini\Config\ClientConfig.cs" />
<Compile Include="Ini\Config\GimbalConfig.cs" />
<Compile Include="Ini\Config\AlgorithmConfig.cs" />
<Compile Include="Ini\Config\NdiConfig.cs" />
<Compile Include="Ini\Config\UdpConfig.cs" />
<Compile Include="Ini\DataManager.cs" />
<Compile Include="Ini\IniAttribute.cs" />
<Compile Include="Ini\IniConfigBase.cs" />
<Compile Include="Ini\IniStorage.cs" />
<Compile Include="LiteDB\Gimbal\GimbalPreset.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="LiteDB\LiteDbContext.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CsvHelper" version="28.0.1" targetFramework="net48" />
<package id="LiteDB" version="5.0.11" targetFramework="net48" />
<package id="log4net" version="2.0.14" targetFramework="net48" />
<package id="NPOI" version="2.5.6" targetFramework="net48" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.0.0" targetFramework="net48" />
<package id="Microsoft.Bcl.HashCode" version="1.0.0" targetFramework="net48" />
<package id="Microsoft.CSharp" version="4.3.0" targetFramework="net48" />
<package id="Portable.BouncyCastle" version="1.8.9" targetFramework="net48" />
<package id="SharpZipLib" version="1.3.3" targetFramework="net48" />
<package id="System.Buffers" version="4.4.0" targetFramework="net48" />
<package id="System.Memory" version="4.5.0" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net48" />
<package id="System.Threading.Tasks.Extensions" version="4.5.2" targetFramework="net48" />
</packages>
\ No newline at end of file
......@@ -7,7 +7,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
......
......@@ -24,7 +24,7 @@ namespace VIZ.GimbalAI.UdpTestTool
base.OnExit(e);
SendControlStatic.Stop();
VAppDomain.DelayManager?.Dispose();
ApplicationDomainEx.DelayManager?.Dispose();
}
}
}
......@@ -12,7 +12,8 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VIZ.GimbalAI.Core;
using VIZ.Framework.Connection;
using VIZ.Framework.Core;
using VIZ.GimbalAI.Domain;
using VIZ.GimbalAI.Domain.Message;
......@@ -27,18 +28,18 @@ namespace VIZ.GimbalAI.UdpTestTool
{
InitializeComponent();
VAppDomain.UiMessageManager.Register<UdpConsoleMessage>(this, this.UdpConsole);
ApplicationDomainEx.MessageManager.Register<ConnSingleJsonMessage>(this, this.UdpConsole);
}
/// <summary>
/// UDP控制台消息
/// </summary>
/// <param name="msg">消息</param>
public void UdpConsole(UdpConsoleMessage msg)
public void UdpConsole(ConnSingleJsonMessage msg)
{
WPFHelper.BeginInvoke(() =>
{
this.tbConsole.AppendText($"\r\n" + (msg.IsSender ? "发送: " : "接收: ") + msg.Message);
this.tbConsole.AppendText($"\r\n" + msg.Json);
this.tbConsole.ScrollToEnd();
});
}
......
......@@ -124,6 +124,30 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Common\VIZ.Framework.Common.csproj">
<Project>{92834c05-703e-4f05-9224-f36220939d8f}</Project>
<Name>VIZ.Framework.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Connection\VIZ.Framework.Connection.csproj">
<Project>{E07528DD-9DEE-47C2-B79D-235ECFA6B003}</Project>
<Name>VIZ.Framework.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Core\VIZ.Framework.Core.csproj">
<Project>{75b39591-4bc3-4b09-bd7d-ec9f67efa96e}</Project>
<Name>VIZ.Framework.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj">
<Project>{28661e82-c86a-4611-a028-c34f6ac85c97}</Project>
<Name>VIZ.Framework.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Module\VIZ.Framework.Module.csproj">
<Project>{47cf6fb0-e37d-4ef1-afc7-03db2bca8892}</Project>
<Name>VIZ.Framework.Module</Name>
</ProjectReference>
<ProjectReference Include="..\..\VIZ.Framework\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj">
<Project>{06b80c09-343d-4bb2-aeb1-61cfbfbf5cad}</Project>
<Name>VIZ.Framework.Storage</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Common.Resource\VIZ.GimbalAI.Common.Resource.csproj">
<Project>{5d8021d1-a6b2-4784-b8fe-ff3b7f94e304}</Project>
<Name>VIZ.GimbalAI.Common.Resource</Name>
......@@ -132,10 +156,6 @@
<Project>{52ca7346-0bc0-4e03-8ca5-c00a8777f1ef}</Project>
<Name>VIZ.GimbalAI.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj">
<Project>{d4409326-3f36-4835-812a-bea8ed046e04}</Project>
<Name>VIZ.GimbalAI.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Domain\VIZ.GimbalAI.Domain.csproj">
<Project>{bbf80159-d5de-4d82-a045-a96d67d80632}</Project>
<Name>VIZ.GimbalAI.Domain</Name>
......
......@@ -106,10 +106,6 @@
<Project>{52ca7346-0bc0-4e03-8ca5-c00a8777f1ef}</Project>
<Name>VIZ.GimbalAI.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj">
<Project>{d4409326-3f36-4835-812a-bea8ed046e04}</Project>
<Name>VIZ.GimbalAI.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
......
......@@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
......
......@@ -9,6 +9,10 @@
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
......@@ -145,10 +145,6 @@
<Project>{52ca7346-0bc0-4e03-8ca5-c00a8777f1ef}</Project>
<Name>VIZ.GimbalAI.Connection</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj">
<Project>{d4409326-3f36-4835-812a-bea8ed046e04}</Project>
<Name>VIZ.GimbalAI.Core</Name>
</ProjectReference>
<ProjectReference Include="..\VIZ.GimbalAI.Domain\VIZ.GimbalAI.Domain.csproj">
<Project>{bbf80159-d5de-4d82-a045-a96d67d80632}</Project>
<Name>VIZ.GimbalAI.Domain</Name>
......
......@@ -21,8 +21,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "70-Product", "70-Product",
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "90-Test", "90-Test", "{E2102B74-E7D4-4DCD-85B3-8E541EA58F05}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.GimbalAI.Core", "VIZ.GimbalAI.Core\VIZ.GimbalAI.Core.csproj", "{D4409326-3F36-4835-812A-BEA8ED046E04}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.GimbalAI.Storage", "VIZ.GimbalAI.Storage\VIZ.GimbalAI.Storage.csproj", "{FB44D2C0-5A08-4B87-B3C7-745471A0D868}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.GimbalAI.Domain", "VIZ.GimbalAI.Domain\VIZ.GimbalAI.Domain.csproj", "{BBF80159-D5DE-4D82-A045-A96D67D80632}"
......@@ -39,8 +37,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.GimbalAI.Common", "VIZ.
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "05-Lib", "05-Lib", "{360185D9-C0CE-478E-817E-66BE38CBB3B3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.GimbalAI.WpfTest", "VIZ.GimbalAI.WpfTest\VIZ.GimbalAI.WpfTest.csproj", "{216115A3-D425-4FF1-9748-F2415455C468}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.GimbalAI.Common.Resource", "VIZ.GimbalAI.Common.Resource\VIZ.GimbalAI.Common.Resource.csproj", "{5D8021D1-A6B2-4784-B8FE-FF3B7F94E304}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.GimbalAI.Module.Resource", "VIZ.GimbalAI.Module.Resource\VIZ.GimbalAI.Module.Resource.csproj", "{EA21B6C1-2942-4034-AD91-9F5932E4C5B9}"
......@@ -49,6 +45,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "80-Tool", "80-Tool", "{7096
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.GimbalAI.UdpTestTool", "VIZ.GimbalAI.UdpTestTool\VIZ.GimbalAI.UdpTestTool.csproj", "{05CA9781-0F07-4E14-9115-64C3A903048E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Core", "..\VIZ.Framework\VIZ.Framework.Core\VIZ.Framework.Core.csproj", "{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Storage", "..\VIZ.Framework\VIZ.Framework.Storage\VIZ.Framework.Storage.csproj", "{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Domain", "..\VIZ.Framework\VIZ.Framework.Domain\VIZ.Framework.Domain.csproj", "{28661E82-C86A-4611-A028-C34F6AC85C97}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Common", "..\VIZ.Framework\VIZ.Framework.Common\VIZ.Framework.Common.csproj", "{92834C05-703E-4F05-9224-F36220939D8F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Common.Resource", "..\VIZ.Framework\VIZ.Framework.Common.Resource\VIZ.Framework.Common.Resource.csproj", "{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Connection", "..\VIZ.Framework\VIZ.Framework.Connection\VIZ.Framework.Connection.csproj", "{E07528DD-9DEE-47C2-B79D-235ECFA6B003}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.Module", "..\VIZ.Framework\VIZ.Framework.Module\VIZ.Framework.Module.csproj", "{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VIZ.Framework.WpfTest", "..\VIZ.Framework\VIZ.Framework.WpfTest\VIZ.Framework.WpfTest.csproj", "{B62C822E-701F-480F-BBB1-0E02217D622C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
......@@ -59,18 +71,6 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D4409326-3F36-4835-812A-BEA8ED046E04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4409326-3F36-4835-812A-BEA8ED046E04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4409326-3F36-4835-812A-BEA8ED046E04}.Debug|x64.ActiveCfg = Debug|x64
{D4409326-3F36-4835-812A-BEA8ED046E04}.Debug|x64.Build.0 = Debug|x64
{D4409326-3F36-4835-812A-BEA8ED046E04}.Debug|x86.ActiveCfg = Debug|x86
{D4409326-3F36-4835-812A-BEA8ED046E04}.Debug|x86.Build.0 = Debug|x86
{D4409326-3F36-4835-812A-BEA8ED046E04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4409326-3F36-4835-812A-BEA8ED046E04}.Release|Any CPU.Build.0 = Release|Any CPU
{D4409326-3F36-4835-812A-BEA8ED046E04}.Release|x64.ActiveCfg = Release|x64
{D4409326-3F36-4835-812A-BEA8ED046E04}.Release|x64.Build.0 = Release|x64
{D4409326-3F36-4835-812A-BEA8ED046E04}.Release|x86.ActiveCfg = Release|x86
{D4409326-3F36-4835-812A-BEA8ED046E04}.Release|x86.Build.0 = Release|x86
{FB44D2C0-5A08-4B87-B3C7-745471A0D868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FB44D2C0-5A08-4B87-B3C7-745471A0D868}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB44D2C0-5A08-4B87-B3C7-745471A0D868}.Debug|x64.ActiveCfg = Debug|x64
......@@ -155,18 +155,6 @@ Global
{4E6D108A-373D-498E-944D-F93A668E732A}.Release|x64.Build.0 = Release|x64
{4E6D108A-373D-498E-944D-F93A668E732A}.Release|x86.ActiveCfg = Release|Any CPU
{4E6D108A-373D-498E-944D-F93A668E732A}.Release|x86.Build.0 = Release|Any CPU
{216115A3-D425-4FF1-9748-F2415455C468}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{216115A3-D425-4FF1-9748-F2415455C468}.Debug|Any CPU.Build.0 = Debug|Any CPU
{216115A3-D425-4FF1-9748-F2415455C468}.Debug|x64.ActiveCfg = Debug|x64
{216115A3-D425-4FF1-9748-F2415455C468}.Debug|x64.Build.0 = Debug|x64
{216115A3-D425-4FF1-9748-F2415455C468}.Debug|x86.ActiveCfg = Debug|Any CPU
{216115A3-D425-4FF1-9748-F2415455C468}.Debug|x86.Build.0 = Debug|Any CPU
{216115A3-D425-4FF1-9748-F2415455C468}.Release|Any CPU.ActiveCfg = Release|Any CPU
{216115A3-D425-4FF1-9748-F2415455C468}.Release|Any CPU.Build.0 = Release|Any CPU
{216115A3-D425-4FF1-9748-F2415455C468}.Release|x64.ActiveCfg = Release|x64
{216115A3-D425-4FF1-9748-F2415455C468}.Release|x64.Build.0 = Release|x64
{216115A3-D425-4FF1-9748-F2415455C468}.Release|x86.ActiveCfg = Release|Any CPU
{216115A3-D425-4FF1-9748-F2415455C468}.Release|x86.Build.0 = Release|Any CPU
{5D8021D1-A6B2-4784-B8FE-FF3B7F94E304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5D8021D1-A6B2-4784-B8FE-FF3B7F94E304}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D8021D1-A6B2-4784-B8FE-FF3B7F94E304}.Debug|x64.ActiveCfg = Debug|x64
......@@ -203,12 +191,107 @@ Global
{05CA9781-0F07-4E14-9115-64C3A903048E}.Release|x64.Build.0 = Release|x64
{05CA9781-0F07-4E14-9115-64C3A903048E}.Release|x86.ActiveCfg = Release|Any CPU
{05CA9781-0F07-4E14-9115-64C3A903048E}.Release|x86.Build.0 = Release|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|x64.ActiveCfg = Debug|x64
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|x64.Build.0 = Debug|x64
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|x86.ActiveCfg = Debug|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Debug|x86.Build.0 = Debug|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|Any CPU.Build.0 = Release|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|x64.ActiveCfg = Release|x64
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|x64.Build.0 = Release|x64
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|x86.ActiveCfg = Release|Any CPU
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E}.Release|x86.Build.0 = Release|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|x64.ActiveCfg = Debug|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|x64.Build.0 = Debug|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|x86.ActiveCfg = Debug|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Debug|x86.Build.0 = Debug|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|Any CPU.Build.0 = Release|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|x64.ActiveCfg = Release|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|x64.Build.0 = Release|x64
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|x86.ActiveCfg = Release|Any CPU
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD}.Release|x86.Build.0 = Release|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|x64.ActiveCfg = Debug|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|x64.Build.0 = Debug|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|x86.ActiveCfg = Debug|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Debug|x86.Build.0 = Debug|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|Any CPU.Build.0 = Release|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|x64.ActiveCfg = Release|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|x64.Build.0 = Release|x64
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|x86.ActiveCfg = Release|Any CPU
{28661E82-C86A-4611-A028-C34F6AC85C97}.Release|x86.Build.0 = Release|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|x64.ActiveCfg = Debug|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|x64.Build.0 = Debug|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|x86.ActiveCfg = Debug|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Debug|x86.Build.0 = Debug|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Release|Any CPU.Build.0 = Release|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Release|x64.ActiveCfg = Release|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Release|x64.Build.0 = Release|x64
{92834C05-703E-4F05-9224-F36220939D8F}.Release|x86.ActiveCfg = Release|Any CPU
{92834C05-703E-4F05-9224-F36220939D8F}.Release|x86.Build.0 = Release|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|x64.ActiveCfg = Debug|x64
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|x64.Build.0 = Debug|x64
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|x86.ActiveCfg = Debug|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Debug|x86.Build.0 = Debug|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|Any CPU.Build.0 = Release|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|x64.ActiveCfg = Release|x64
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|x64.Build.0 = Release|x64
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|x86.ActiveCfg = Release|Any CPU
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF}.Release|x86.Build.0 = Release|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|x64.ActiveCfg = Debug|x64
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|x64.Build.0 = Debug|x64
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|x86.ActiveCfg = Debug|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Debug|x86.Build.0 = Debug|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|Any CPU.Build.0 = Release|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|x64.ActiveCfg = Release|x64
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|x64.Build.0 = Release|x64
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|x86.ActiveCfg = Release|Any CPU
{E07528DD-9DEE-47C2-B79D-235ECFA6B003}.Release|x86.Build.0 = Release|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|x64.ActiveCfg = Debug|x64
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|x64.Build.0 = Debug|x64
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|x86.ActiveCfg = Debug|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Debug|x86.Build.0 = Debug|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|Any CPU.Build.0 = Release|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|x64.ActiveCfg = Release|x64
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|x64.Build.0 = Release|x64
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|x86.ActiveCfg = Release|Any CPU
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892}.Release|x86.Build.0 = Release|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|x64.ActiveCfg = Debug|x64
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|x64.Build.0 = Debug|x64
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|x86.ActiveCfg = Debug|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Debug|x86.Build.0 = Debug|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|Any CPU.Build.0 = Release|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|x64.ActiveCfg = Release|x64
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|x64.Build.0 = Release|x64
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|x86.ActiveCfg = Release|Any CPU
{B62C822E-701F-480F-BBB1-0E02217D622C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{D4409326-3F36-4835-812A-BEA8ED046E04} = {37CCD392-5CED-45A4-94D2-39F0A12D74CD}
{FB44D2C0-5A08-4B87-B3C7-745471A0D868} = {597D31CE-2BD9-45E0-BD77-B2BAFDA2320D}
{BBF80159-D5DE-4D82-A045-A96D67D80632} = {E6D29904-B9C1-47D8-8BC0-1ECEE89D33CF}
{629A6742-D7C0-4B34-B1CB-C0D516E3AF9A} = {52FA7E81-274D-45B1-82CC-A74C1FE17883}
......@@ -216,10 +299,17 @@ Global
{53F18A25-CEDA-4346-9168-1A5765C8A1A6} = {1A413643-996F-4259-8662-197A4499FDC8}
{FF118CC2-588C-49C1-A403-19F1EF66A607} = {E2102B74-E7D4-4DCD-85B3-8E541EA58F05}
{4E6D108A-373D-498E-944D-F93A668E732A} = {EF8C0E55-7C90-4AA1-9627-F5C50C8393C3}
{216115A3-D425-4FF1-9748-F2415455C468} = {E2102B74-E7D4-4DCD-85B3-8E541EA58F05}
{5D8021D1-A6B2-4784-B8FE-FF3B7F94E304} = {EF8C0E55-7C90-4AA1-9627-F5C50C8393C3}
{EA21B6C1-2942-4034-AD91-9F5932E4C5B9} = {52FA7E81-274D-45B1-82CC-A74C1FE17883}
{05CA9781-0F07-4E14-9115-64C3A903048E} = {70969284-4822-4F11-A29D-3ABF7EE2E54E}
{75B39591-4BC3-4B09-BD7D-EC9F67EFA96E} = {37CCD392-5CED-45A4-94D2-39F0A12D74CD}
{06B80C09-343D-4BB2-AEB1-61CFBFBF5CAD} = {597D31CE-2BD9-45E0-BD77-B2BAFDA2320D}
{28661E82-C86A-4611-A028-C34F6AC85C97} = {E6D29904-B9C1-47D8-8BC0-1ECEE89D33CF}
{92834C05-703E-4F05-9224-F36220939D8F} = {EF8C0E55-7C90-4AA1-9627-F5C50C8393C3}
{76EF480A-E486-41B7-B7A5-2A849FC8D5BF} = {EF8C0E55-7C90-4AA1-9627-F5C50C8393C3}
{E07528DD-9DEE-47C2-B79D-235ECFA6B003} = {D666867B-1D34-4A1B-95E4-122933170A78}
{47CF6FB0-E37D-4EF1-AFC7-03DB2BCA8892} = {52FA7E81-274D-45B1-82CC-A74C1FE17883}
{B62C822E-701F-480F-BBB1-0E02217D622C} = {E2102B74-E7D4-4DCD-85B3-8E541EA58F05}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F3F91885-FD9F-4CB5-B384-3E90F98B2F62}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment