Commit 4a171c48 by liulongfei

1. 添加算法错误标记按钮

2. 修复仅显示本地NDI流按钮失效的bug
parent 85f2863b
...@@ -55,5 +55,10 @@ namespace VIZ.H2V.Connection ...@@ -55,5 +55,10 @@ namespace VIZ.H2V.Connection
/// 1. 单人机位 Single /// 1. 单人机位 Single
/// </remarks> /// </remarks>
public const string manual_correction = "manual_correction"; public const string manual_correction = "manual_correction";
/// <summary>
/// 错误标记
/// </summary>
public const string wrong_target = "wrong_target";
} }
} }
...@@ -90,6 +90,8 @@ namespace VIZ.H2V.Connection ...@@ -90,6 +90,8 @@ namespace VIZ.H2V.Connection
{ {
package.id = option.id; package.id = option.id;
package.enable_sendto_crop = option.enable_sendto_crop ? 1 : 0; package.enable_sendto_crop = option.enable_sendto_crop ? 1 : 0;
package.target_bbox = option.target_bbox;
package.timecode = option.timecode;
manager.SendJson(package); manager.SendJson(package);
} }
......
...@@ -26,5 +26,15 @@ namespace VIZ.H2V.Connection ...@@ -26,5 +26,15 @@ namespace VIZ.H2V.Connection
/// 手动校准(x,y,r) /// 手动校准(x,y,r)
/// </summary> /// </summary>
public List<int> correction_area { get; set; } public List<int> correction_area { get; set; }
/// <summary>
/// 错误目标框(left,top,right,bottom)
/// </summary>
public List<int> target_bbox { get; set; }
/// <summary>
/// 时间码
/// </summary>
public long timecode { get; set; }
} }
} }
...@@ -47,5 +47,15 @@ namespace VIZ.H2V.Connection ...@@ -47,5 +47,15 @@ namespace VIZ.H2V.Connection
/// 是否启用边线检测 /// 是否启用边线检测
/// </summary> /// </summary>
public int border_on { get; set; } public int border_on { get; set; }
/// <summary>
/// 错误目标框
/// </summary>
public List<int> target_bbox { get; set; }
/// <summary>
/// 时间码
/// </summary>
public long timecode { get; set; }
} }
} }
...@@ -127,7 +127,7 @@ ...@@ -127,7 +127,7 @@
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter> <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="Foreground" Value="White"></Setter> <Setter Property="Foreground" Value="White"></Setter>
<Setter Property="BorderBrush" Value="White"></Setter> <Setter Property="BorderBrush" Value="White"></Setter>
<Setter Property="BorderThickness" Value="2"></Setter> <Setter Property="BorderThickness" Value="4"></Setter>
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="RadioButton"> <ControlTemplate TargetType="RadioButton">
......
...@@ -164,11 +164,11 @@ namespace VIZ.H2V.Module ...@@ -164,11 +164,11 @@ namespace VIZ.H2V.Module
#endregion #endregion
#region IsShowLocalStream -- 是否显示本地流 #region IsShowLocalStream -- 是否仅显示本机输入源
private bool isShowLocalStream = true; private bool isShowLocalStream = true;
/// <summary> /// <summary>
/// 是否显示本地流 /// 是否仅显示本机输入源
/// </summary> /// </summary>
public bool IsShowLocalStream public bool IsShowLocalStream
{ {
...@@ -177,7 +177,7 @@ namespace VIZ.H2V.Module ...@@ -177,7 +177,7 @@ namespace VIZ.H2V.Module
{ {
isShowLocalStream = value; isShowLocalStream = value;
this.RaisePropertyChanged(nameof(IsShowLocalStream)); this.RaisePropertyChanged(nameof(IsShowLocalStream));
this.RaisePropertyChanged(nameof(NDIStreamInfosView)); this.NDIStreamInfosView.Refresh();
} }
} }
......
...@@ -201,6 +201,13 @@ namespace VIZ.H2V.Module ...@@ -201,6 +201,13 @@ namespace VIZ.H2V.Module
public abstract void BorderPoint(AlgorithmInfo_borderpoint boarderpoint); public abstract void BorderPoint(AlgorithmInfo_borderpoint boarderpoint);
/// <summary> /// <summary>
/// 错误标记
/// </summary>
/// <param name="target_bbox">目标框</param>
/// <param name="timeCode">时间码</param>
public abstract void ErrorTag(List<int> target_bbox, long timeCode);
/// <summary>
/// 手动校准 /// 手动校准
/// </summary> /// </summary>
/// <param name="info">手动校准信息</param> /// <param name="info">手动校准信息</param>
......
...@@ -71,6 +71,13 @@ namespace VIZ.H2V.Module ...@@ -71,6 +71,13 @@ namespace VIZ.H2V.Module
void ManualCorrection(ManualCorrectionInfo info); void ManualCorrection(ManualCorrectionInfo info);
/// <summary> /// <summary>
/// 错误标记
/// </summary>
/// <param name="target_bbox">目标框</param>
/// <param name="timeCode">时间码</param>
void ErrorTag(List<int> target_bbox, long timeCode);
/// <summary>
/// 初始化算法 /// 初始化算法
/// </summary> /// </summary>
/// <remarks> /// <remarks>
......
...@@ -111,6 +111,27 @@ namespace VIZ.H2V.Module ...@@ -111,6 +111,27 @@ namespace VIZ.H2V.Module
} }
/// <summary> /// <summary>
/// 错误标记
/// </summary>
/// <param name="target_bbox">目标框</param>
/// <param name="timeCode">时间码</param>
public override void ErrorTag(List<int> target_bbox, long timeCode)
{
if (target_bbox == null || target_bbox.Count != 4 || timeCode <= 0)
return;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSenderOption option = new AlgorithmSenderOption();
option.id = this.Support.ID;
option.enable_sendto_crop = this.Support.ViewConfig.IsSendToCrop;
option.target_bbox = target_bbox;
option.timecode = timeCode;
AlgorithmSender.AutoMode(manager, this.BuildPackage(AlgorithmAutoModeCmd.wrong_target, null), option);
}
/// <summary>
/// 手动校准 /// 手动校准
/// </summary> /// </summary>
/// <param name="info">手动校准信息</param> /// <param name="info">手动校准信息</param>
......
...@@ -121,6 +121,27 @@ namespace VIZ.H2V.Module ...@@ -121,6 +121,27 @@ namespace VIZ.H2V.Module
} }
/// <summary> /// <summary>
/// 错误标记
/// </summary>
/// <param name="target_bbox">目标框</param>
/// <param name="timeCode">时间码</param>
public override void ErrorTag(List<int> target_bbox, long timeCode)
{
if (target_bbox == null || target_bbox.Count != 4 || timeCode <= 0)
return;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSenderOption option = new AlgorithmSenderOption();
option.id = this.Support.ID;
option.enable_sendto_crop = this.Support.ViewConfig.IsSendToCrop;
option.target_bbox = target_bbox;
option.timecode = timeCode;
AlgorithmSender.AutoMode(manager, this.BuildPackage(AlgorithmAutoModeCmd.wrong_target, null, null), option);
}
/// <summary>
/// 手动校准 /// 手动校准
/// </summary> /// </summary>
/// <param name="info">手动校准信息</param> /// <param name="info">手动校准信息</param>
......
...@@ -158,6 +158,27 @@ namespace VIZ.H2V.Module ...@@ -158,6 +158,27 @@ namespace VIZ.H2V.Module
} }
/// <summary> /// <summary>
/// 错误标记
/// </summary>
/// <param name="target_bbox">目标框</param>
/// <param name="timeCode">时间码</param>
public override void ErrorTag(List<int> target_bbox, long timeCode)
{
if (target_bbox == null || target_bbox.Count != 4 || timeCode <= 0)
return;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSenderOption option = new AlgorithmSenderOption();
option.id = this.Support.ID;
option.enable_sendto_crop = this.Support.ViewConfig.IsSendToCrop;
option.target_bbox = target_bbox;
option.timecode = timeCode;
AlgorithmSender.AutoMode(manager, this.BuildPackage(AlgorithmAutoModeCmd.wrong_target, null), option);
}
/// <summary>
/// 手动校准 /// 手动校准
/// </summary> /// </summary>
/// <param name="info">手动校准信息</param> /// <param name="info">手动校准信息</param>
......
...@@ -121,6 +121,27 @@ namespace VIZ.H2V.Module ...@@ -121,6 +121,27 @@ namespace VIZ.H2V.Module
} }
/// <summary> /// <summary>
/// 错误标记
/// </summary>
/// <param name="target_bbox">目标框</param>
/// <param name="timeCode">时间码</param>
public override void ErrorTag(List<int> target_bbox, long timeCode)
{
if (target_bbox == null || target_bbox.Count != 4 || timeCode <= 0)
return;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSenderOption option = new AlgorithmSenderOption();
option.id = this.Support.ID;
option.enable_sendto_crop = this.Support.ViewConfig.IsSendToCrop;
option.target_bbox = target_bbox;
option.timecode = timeCode;
AlgorithmSender.AutoMode(manager, this.BuildPackage(AlgorithmAutoModeCmd.wrong_target, null, null), option);
}
/// <summary>
/// 手动校准 /// 手动校准
/// </summary> /// </summary>
/// <param name="info">手动校准信息</param> /// <param name="info">手动校准信息</param>
......
...@@ -121,6 +121,27 @@ namespace VIZ.H2V.Module ...@@ -121,6 +121,27 @@ namespace VIZ.H2V.Module
} }
/// <summary> /// <summary>
/// 错误标记
/// </summary>
/// <param name="target_bbox">目标框</param>
/// <param name="timeCode">时间码</param>
public override void ErrorTag(List<int> target_bbox, long timeCode)
{
if (target_bbox == null || target_bbox.Count != 4 || timeCode <= 0)
return;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSenderOption option = new AlgorithmSenderOption();
option.id = this.Support.ID;
option.enable_sendto_crop = this.Support.ViewConfig.IsSendToCrop;
option.target_bbox = target_bbox;
option.timecode = timeCode;
AlgorithmSender.AutoMode(manager, this.BuildPackage(AlgorithmAutoModeCmd.wrong_target, null, null), option);
}
/// <summary>
/// 手动校准 /// 手动校准
/// </summary> /// </summary>
/// <param name="info">手动校准信息</param> /// <param name="info">手动校准信息</param>
......
...@@ -299,7 +299,16 @@ ...@@ -299,7 +299,16 @@
<!-- AI功能区 --> <!-- AI功能区 -->
<StackPanel Orientation="Vertical" VerticalAlignment="Bottom" Grid.Row="1"> <StackPanel Orientation="Vertical" VerticalAlignment="Bottom" Grid.Row="1">
<Rectangle Height="2" Width="30" Fill="#AAFFFFFF" Margin="0,2,0,0"></Rectangle> <!-- 错误标记 -->
<!--<Border Margin="0,10,0,8">
<Button Width="32" Height="32"
Style="{StaticResource Button_Function}"
IsEnabled="{Binding Path=ViewStatus,Converter={StaticResource NDIViewStatus2IsEnabledConverter_SettingButton}}"
Command="{Binding AlgorithmErrorTagCommand}">
<Image Width="24" Height="24" Source="/VIZ.H2V.Module.Resource;component/Icons/ai_close_24x24.png"></Image>
</Button>
</Border>-->
<!-- 重启算法 -->
<Border Margin="0,10,0,0" ToolTip="重启算法" Background="Transparent"> <Border Margin="0,10,0,0" ToolTip="重启算法" Background="Transparent">
<Button Width="32" Height="32" <Button Width="32" Height="32"
Style="{StaticResource Button_Function}" Style="{StaticResource Button_Function}"
...@@ -308,6 +317,7 @@ ...@@ -308,6 +317,7 @@
<Image Width="24" Height="24" Source="/VIZ.H2V.Module.Resource;component/Icons/ai_refresh_24x24.png"></Image> <Image Width="24" Height="24" Source="/VIZ.H2V.Module.Resource;component/Icons/ai_refresh_24x24.png"></Image>
</Button> </Button>
</Border> </Border>
<!-- 关闭算法 -->
<Border Margin="0,10,0,0" ToolTip="关闭算法" Background="Transparent"> <Border Margin="0,10,0,0" ToolTip="关闭算法" Background="Transparent">
<Button Width="32" Height="32" <Button Width="32" Height="32"
Style="{StaticResource Button_Function}" Style="{StaticResource Button_Function}"
......
...@@ -487,5 +487,55 @@ namespace VIZ.H2V.Module ...@@ -487,5 +487,55 @@ namespace VIZ.H2V.Module
} }
#endregion #endregion
#region AlgorithmErrorTagCommand -- 算法错误标记命令
/// <summary>
/// 算法错误标记命令
/// </summary>
public VCommand AlgorithmErrorTagCommand { get; set; }
/// <summary>
/// 算法错误标记
/// </summary>
private void AlgorithmErrorTag()
{
// 只有在自动模式下可以标记
if (this.StrategyMode != AlgorithmStrategyMode.auto_mode)
return;
// 只有裁切状态下可以标记
if (this.ViewStatus != NDIViewStatus.CropRoi)
return;
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
VideoRenderInfo renderInfo = view.video.GetRenderInfo();
if (renderInfo == null)
return;
TrackingBoxPlugin trackingBoxPlugin = view.video.GetPlugin<TrackingBoxPlugin>(VideoControlPluginNames.TrackingBox);
if (trackingBoxPlugin == null)
return;
List<TrackingBoxInfo> trackingBoxInfos = trackingBoxPlugin.GetTrackingBoxInfos();
if (trackingBoxInfos == null || trackingBoxInfos.Count == 0)
return;
TrackingBoxInfo boxInfo = trackingBoxInfos[0];
// 标记错误
List<int> box = new List<int>();
box.Add((int)boxInfo.SrcRect.Left);
box.Add((int)boxInfo.SrcRect.Top);
box.Add((int)boxInfo.SrcRect.Right);
box.Add((int)boxInfo.SrcRect.Bottom);
this.AlgorithmControllerDic[this.StrategyType].ErrorTag(box, renderInfo.Frame.TimeStamp);
}
#endregion
} }
} }
...@@ -80,6 +80,7 @@ namespace VIZ.H2V.Module ...@@ -80,6 +80,7 @@ namespace VIZ.H2V.Module
this.IsAreaCorrectionEnabledChangedCommand = new VCommand(this.IsAreaCorrectionEnabledChanged); this.IsAreaCorrectionEnabledChangedCommand = new VCommand(this.IsAreaCorrectionEnabledChanged);
this.SaveAlgorithmConfigCommand = new VCommand(this.SaveAlgorithmConfig); this.SaveAlgorithmConfigCommand = new VCommand(this.SaveAlgorithmConfig);
this.SetActiveCommand = new VCommand(this.SetActive); this.SetActiveCommand = new VCommand(this.SetActive);
this.AlgorithmErrorTagCommand = new VCommand(this.AlgorithmErrorTag);
} }
/// <summary> /// <summary>
......
...@@ -192,26 +192,10 @@ ...@@ -192,26 +192,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="VideoMainView\View\VideoMainView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Generic.xaml"> <Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Page> </Page>
<Page Include="VideoView\View\VideoSettingView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="VideoView\View\VideoControlView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="VideoView\View\VideoView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="NDIMainView\Controller\Gpio\GpioController.cs" /> <Compile Include="NDIMainView\Controller\Gpio\GpioController.cs" />
...@@ -315,10 +299,6 @@ ...@@ -315,10 +299,6 @@
<Compile Include="SystemSetting\View\TallySettingPanelView.xaml.cs"> <Compile Include="SystemSetting\View\TallySettingPanelView.xaml.cs">
<DependentUpon>TallySettingPanelView.xaml</DependentUpon> <DependentUpon>TallySettingPanelView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="VideoMainView\View\VideoMainView.xaml.cs">
<DependentUpon>VideoMainView.xaml</DependentUpon>
</Compile>
<Compile Include="VideoMainView\ViewModel\VideoMainViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs"> <Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
...@@ -333,20 +313,6 @@ ...@@ -333,20 +313,6 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput> <DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile> </Compile>
<Compile Include="Setup\Provider\AppSetup_InitLiteDb.cs" /> <Compile Include="Setup\Provider\AppSetup_InitLiteDb.cs" />
<Compile Include="VideoView\Service\IVideoControlService.cs" />
<Compile Include="VideoView\ViewModel\VideoSettingViewModel.cs" />
<Compile Include="VideoView\View\VideoSettingView.xaml.cs">
<DependentUpon>VideoSettingView.xaml</DependentUpon>
</Compile>
<Compile Include="VideoView\View\VideoControlView.xaml.cs">
<DependentUpon>VideoControlView.xaml</DependentUpon>
</Compile>
<Compile Include="VideoView\Service\IVideoService.cs" />
<Compile Include="VideoView\ViewModel\VideoControlViewModel.cs" />
<Compile Include="VideoView\View\VideoView.xaml.cs">
<DependentUpon>VideoView.xaml</DependentUpon>
</Compile>
<Compile Include="VideoView\ViewModel\VideoViewModel.cs" />
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
......
<UserControl x:Class="VIZ.H2V.Module.VideoMainView"
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:local="clr-namespace:VIZ.H2V.Module"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/VIZ.Framework.Common.Resource;component/Style/Button/Button_WindowTop.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<!-- 头部 -->
<TextBlock Text="AI横转竖智能剪切系统" FontSize="20" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
<StackPanel Orientation="Horizontal" Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button Command="{Binding Path=MinCommand}" Style="{StaticResource Button_Min}"></Button>
<Button Command="{Binding Path=CloseCommand}" Style="{StaticResource Button_Close}"></Button>
</StackPanel>
<!-- 视频区域 -->
<Grid Grid.Row="1" Margin="20,0,20,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<local:VideoView Key="CAM1" Grid.Row="0" Grid.Column="0"></local:VideoView>
<local:VideoView Key="CAM2" Grid.Row="0" Grid.Column="1"></local:VideoView>
<local:VideoView Key="CAM3" Grid.Row="1" Grid.Column="0"></local:VideoView>
<local:VideoView Key="CAM4" Grid.Row="1" Grid.Column="1"></local:VideoView>
</Grid>
<!-- 状态区域 -->
<local:VideoControlView Grid.Row="2"></local:VideoControlView>
</Grid>
</UserControl>
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.Framework.Core;
namespace VIZ.H2V.Module
{
/// <summary>
/// VideoMainView.xaml 的交互逻辑
/// </summary>
public partial class VideoMainView : UserControl
{
public VideoMainView()
{
InitializeComponent();
WPFHelper.BindingViewModel(this, new VideoMainViewModel());
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
using VIZ.Framework.Common;
using System.Windows;
namespace VIZ.H2V.Module
{
/// <summary>
/// 主视图模型
/// </summary>
public class VideoMainViewModel : ViewModelBase
{
/// <summary>
/// 视频视图模型
/// </summary>
public VideoMainViewModel()
{
// 初始化命令
this.InitCommand();
// 初始化消息
this.InitMessage();
// 初始化属性
this.InitProperty();
}
/// <summary>
/// 初始化命令
/// </summary>
private void InitCommand()
{
this.LoadedCommand = new VCommand(this.Loaded);
this.MinCommand = new VCommand(this.Min);
this.CloseCommand = new VCommand(this.Close);
}
/// <summary>
/// 初始化消息
/// </summary>
private void InitMessage()
{
}
/// <summary>
/// 初始化属性
/// </summary>
private void InitProperty()
{
}
// ======================================================================================
// === Property ===
// ======================================================================================
// ======================================================================================
// === Command ===
// ======================================================================================
#region LoadedCommand -- 加载命令
/// <summary>
/// 加载命令
/// </summary>
public VCommand LoadedCommand { get; set; }
/// <summary>
///
/// </summary>
private void Loaded()
{
}
#endregion
#region CloseCommand -- 关闭命令
/// <summary>
/// 关闭命令
/// </summary>
public VCommand CloseCommand { get; set; }
/// <summary>
/// 关闭
/// </summary>
private void Close()
{
VideoMainView view = this.GetView<VideoMainView>();
if (view == null)
return;
MessageBoxExResult result = MessageBoxEx.ShowDialog("提示", "确定退出?", MessageBoxExButtons.YES_CANCEL);
if (result != MessageBoxExResult.YES)
return;
Window window = WPFHelper.GetAncestorByType<Window>(view);
if (window == null)
return;
window.Close();
}
#endregion
#region MinCommand -- 最小化窗口命令
/// <summary>
/// 最小化窗口命令
/// </summary>
public VCommand MinCommand { get; set; }
/// <summary>
/// 最小化
/// </summary>
private void Min()
{
VideoMainView view = this.GetView<VideoMainView>();
if (view == null)
return;
Window window = WPFHelper.GetAncestorByType<Window>(view);
if (window == null)
return;
window.WindowState = WindowState.Minimized;
}
#endregion
// ======================================================================================
// === Message ===
// ======================================================================================
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
namespace VIZ.H2V.Module
{
/// <summary>
/// 視頻控制服务
/// </summary>
public interface IVideoControlService : IService
{
/// <summary>
/// 播放是否可用
/// </summary>
bool IsPlayEnabled { get; set; }
/// <summary>
/// 暂停是否可用
/// </summary>
bool IsPauseEnabled { get; set; }
/// <summary>
/// 停止是否可用
/// </summary>
bool IsStopEnabled { get; set; }
/// <summary>
/// 时间滑块是否可用
/// </summary>
bool IsTimeBarEnabled { get; set; }
/// <summary>
/// 更新时间条信息
/// </summary>
void UpdateTimeBarInfo();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
using VIZ.H2V.Domain;
namespace VIZ.H2V.Module
{
/// <summary>
/// 视频服务
/// </summary>
public interface IVideoService : IService
{
/// <summary>
/// OpenCV键
/// </summary>
string OpenCVKey { get; set; }
/// <summary>
/// 视频模型
/// </summary>
VideoModel VideoModel { get; set; }
/// <summary>
/// 打开文件
/// </summary>
/// <param name="fileName">文件名</param>
void Open(string fileName);
/// <summary>
/// 播放
/// </summary>
void Play();
/// <summary>
/// 暂停
/// </summary>
void Pause();
/// <summary>
/// 停止
/// </summary>
void Stop();
/// <summary>
/// 设置位置
/// </summary>
/// <param name="position">帧位置</param>
void SetPosition(int position);
/// <summary>
/// 获取OpenCV属性信息
/// </summary>
/// <returns>OpenCV属性信息</returns>
OpenCVPropertyInfos GetOpenCVPropertyInfos();
}
}
<UserControl x:Class="VIZ.H2V.Module.VideoControlView"
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:fcommon="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
xmlns:local="clr-namespace:VIZ.H2V.Module"
xmlns:fcore="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
d:DataContext="{d:DesignInstance Type=local:VideoControlViewModel}"
mc:Ignorable="d"
d:DesignHeight="60" d:DesignWidth="1920">
<UserControl.Resources>
<ResourceDictionary>
<fcore:TimeSpan2DoubleConverter x:Key="TimeSpan2DoubleConverter" Type="Second"></fcore:TimeSpan2DoubleConverter>
<fcore:Double2TimeSpanConverter x:Key="Double2TimeSpanConverter" Type="Second"></fcore:Double2TimeSpanConverter>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140"></ColumnDefinition>
<ColumnDefinition Width="140"></ColumnDefinition>
<ColumnDefinition Width="140"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="140"></ColumnDefinition>
<ColumnDefinition Width="140"></ColumnDefinition>
<ColumnDefinition Width="350"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!-- 播放器控制 -->
<Button Content="播放" Width="120" Height="40" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0"
Command="{Binding Path=PlayCommand}"
IsEnabled="{Binding Path=IsPlayEnabled}"></Button>
<Button Content="暂停" Width="120" Height="40" Margin="10,0,10,0" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="1"
Command="{Binding Path=PauseCommand}"
IsEnabled="{Binding Path=IsPauseEnabled}"></Button>
<Button Content="停止" Width="120" Height="40" Margin="10,0,10,0" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="2"
Command="{Binding Path=StopCommmand}"
IsEnabled="{Binding Path=IsStopEnabled}"></Button>
<fcommon:VideoTimeBar Grid.Column="3" Foreground="White" FontSize="14"
Time="{Binding Path=PositionTime,Mode=OneWay}"
MaxTime="{Binding TotalTime,Mode=TwoWay}"
IsEnabled="{Binding Path=IsTimeBarEnabled}" >
<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="TimeBarManualValueChanged">
<behaviors:InvokeCommandAction Command="{Binding TimeBarManualValueChangedCommand}" PassEventArgsToCommand="True" />
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
</fcommon:VideoTimeBar>
<Button Content="倒退5秒" Width="120" Height="40" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="4"
Command="{Binding Path=BackCommand}"
IsEnabled="{Binding Path=IsStopEnabled}"></Button>
<Button Content="前进5秒" Width="120" Height="40" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="5"
Command="{Binding Path=ForwardCommand}"
IsEnabled="{Binding Path=IsStopEnabled}"></Button>
<Grid Grid.Column="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="跳转至:" FontSize="16" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
<TextBox Grid.Column="1" Padding="10,0,10,0" VerticalAlignment="Center"
Height="40" VerticalContentAlignment="Center" AcceptsReturn="False"
Text="{Binding Path=GotoString,Mode=TwoWay}"
ToolTip="时间格式:00:00:00"></TextBox>
<Button Grid.Column="2" Content="跳转" Width="120" Height="40"
Command="{Binding Path=GotoCommand}"
IsEnabled="{Binding Path=IsStopEnabled}"></Button>
</Grid>
<!-- 视频设置 -->
<Button Width="120" Height="40" HorizontalAlignment="Right" Margin="10,0,10,0" Content="视频设置" Grid.Column="7"
Command="{Binding Path=SettingCommand}"></Button>
</Grid>
</UserControl>
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.Framework.Core;
namespace VIZ.H2V.Module
{
/// <summary>
/// VideoControlView.xaml 的交互逻辑
/// </summary>
public partial class VideoControlView : UserControl
{
public VideoControlView()
{
InitializeComponent();
WPFHelper.BindingViewModel(this, new VideoControlViewModel());
}
}
}
<UserControl x:Class="VIZ.H2V.Module.VideoSettingView"
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:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:fcore="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
xmlns:fcommon="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
xmlns:local="clr-namespace:VIZ.H2V.Module"
d:DataContext="{d:DesignInstance Type=local:VideoSettingViewModel}"
mc:Ignorable="d" x:Name="uc"
d:DesignHeight="800" d:DesignWidth="1400">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/VIZ.Framework.Common.Resource;component/Style/ListBox/ListBox_None.xaml"></ResourceDictionary>
<ResourceDictionary Source="/VIZ.Framework.Common.Resource;component/Style/Button/Button_MessageBox.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
<fcore:Bool2VisibilityConverter x:Key="Bool2VisibilityConverter"></fcore:Bool2VisibilityConverter>
</ResourceDictionary>
</UserControl.Resources>
<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="Loaded">
<behaviors:InvokeCommandAction Command="{Binding LoadedCommand}" />
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
<Border Background="White" BorderBrush="#22000000" BorderThickness="1" CornerRadius="20">
<Border.Effect>
<DropShadowEffect Opacity="0.36"/>
</Border.Effect>
<Grid Margin="30,20,30,20">
<Grid.RowDefinitions>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="80"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="80"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<fcommon:DragWindowBar Grid.RowSpan="4" Grid.ColumnSpan="2" Background="Transparent"></fcommon:DragWindowBar>
<TextBlock Text="视频设置" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="16"></TextBlock>
<TextBlock Text="分组" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="24"></TextBlock>
<Border Grid.Row="2" BorderBrush="#44000000" BorderThickness="1" Margin="0,0,20,0">
<ListBox x:Name="lbGroup" Style="{StaticResource ListBox_None}" ItemContainerStyle="{StaticResource ListBoxItem_None_IsSelected}"
ItemsSource="{Binding Path=VideoGroups}" SelectedValue="{Binding Path=SelectedVideoGroup,Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="40">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Rectangle Width="10" Height="10" Fill="Green" VerticalAlignment="Center" HorizontalAlignment="Center"
Visibility="{Binding Path=IsCurrentGroup,Converter={StaticResource Bool2VisibilityConverter}}"></Rectangle>
<TextBlock Text="{Binding Path=Name}" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Column="1"
FontSize="18"></TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
<TextBlock Text="设置" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="24"></TextBlock>
<Border Grid.Row="2" Grid.Column="1" BorderBrush="#44000000" BorderThickness="1" Margin="20,0,0,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<!-- 名称 -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="名称:" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16"></TextBlock>
<TextBox Grid.Column="1" Height="40" VerticalContentAlignment="Center" AcceptsReturn="False"
Margin="0,0,20,0" Padding="10,0,10,0" FontSize="16"
Text="{Binding Path=SelectedVideoGroup.Name,Mode=TwoWay}"></TextBox>
</Grid>
<!-- 视频文件 -->
<ListBox Style="{StaticResource ListBox_None}" Grid.Row="1" Margin="10,0,10,10" ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ItemsSource="{Binding ElementName=lbGroup,Path=SelectedValue.VideoList}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="60">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"></ColumnDefinition>
<ColumnDefinition Width="400"></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Key}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16"></TextBlock>
<TextBox Text="{Binding Path=Path,Mode=OneWay}" VerticalAlignment="Center" Grid.Column="1"
ToolTip="{Binding Path=Path,Mode=OneWay}"
FontSize="16" Height="40" VerticalContentAlignment="Center" AcceptsReturn="False"
Padding="10,0,10,0" Margin="0,0,10,0" IsReadOnly="True"></TextBox>
<Button Content="..." Width="40" Height="40" Grid.Column="2"
Command="{Binding ElementName=uc,Path=DataContext.SelectVideoFileCommand}"
CommandParameter="{Binding .}"
VerticalAlignment="Center" HorizontalAlignment="Center"></Button>
<Button Content="清除" Width="40" Height="40" Grid.Column="3"
Command="{Binding ElementName=uc,Path=DataContext.ClearVideoFileCommand}"
CommandParameter="{Binding .}"
VerticalAlignment="Center" HorizontalAlignment="Center"></Button>
<TextBlock Text="时间偏移:" VerticalAlignment="Center" Grid.Column="4" FontSize="14"></TextBlock>
<TextBox Text="{Binding Path=OffsetSecString,Mode=TwoWay}"
VerticalAlignment="Center" Grid.Column="5"
FontSize="16" Height="40" VerticalContentAlignment="Center" AcceptsReturn="False"
Padding="10,0,10,0" Margin="0,0,10,0">
</TextBox>
<TextBlock Text="秒" VerticalAlignment="Center" Grid.Column="6" FontSize="14"></TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Border>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="3" Grid.Column="0">
<Button Grid.Row="2" Content="新建" Style="{StaticResource VMessageBox_Button_Yes}" Margin="10,0,10,0" Command="{Binding Path=NewGroupCommand}"></Button>
<Button Grid.Row="2" Content="删除" Style="{StaticResource VMessageBox_Button_Cancel}" Margin="10,0,10,0" Command="{Binding Path=DeleteGroupCommand}"></Button>
</StackPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="3" Grid.Column="1">
<Button Grid.Row="2" Content="关闭" Style="{StaticResource VMessageBox_Button_Cancel}" Margin="10,0,10,0" Command="{Binding Path=CloseCommand}"></Button>
<Button Grid.Row="2" Content="应用" Style="{StaticResource VMessageBox_Button_Yes}" Margin="10,0,10,0" Command="{Binding Path=ApplyCommand}"></Button>
</StackPanel>
</Grid>
</Border>
</UserControl>
\ 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.Framework.Core;
namespace VIZ.H2V.Module
{
/// <summary>
/// VideoSettingView.xaml 的交互逻辑
/// </summary>
public partial class VideoSettingView : UserControl
{
public VideoSettingView()
{
InitializeComponent();
WPFHelper.BindingViewModel(this, new VideoSettingViewModel());
}
}
}
<UserControl x:Class="VIZ.H2V.Module.VideoView"
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:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:VIZ.H2V.Module"
xmlns:fmodule="clr-namespace:VIZ.Framework.Common;assembly=VIZ.Framework.Common"
xmlns:fcore="clr-namespace:VIZ.Framework.Core;assembly=VIZ.Framework.Core"
d:DataContext="{d:DesignInstance Type=local:VideoViewModel}"
mc:Ignorable="d" x:Name="uc"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<fcore:Bool2VisibilityConverter x:Key="Bool2VisibilityConverter" TrueVisibility="Visible" FalseVisibility="Hidden"></fcore:Bool2VisibilityConverter>
</ResourceDictionary>
</UserControl.Resources>
<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="Loaded">
<behaviors:InvokeCommandAction Command="{Binding LoadedCommand}" />
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!-- 标题 -->
<TextBlock Text="{Binding ElementName=uc,Path=Key,Mode=OneWay}"
HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" Foreground="White"></TextBlock>
<!-- 视频区域 -->
<Border Grid.Row="1" BorderBrush="#ff4c4c4c" BorderThickness="1">
<fmodule:VideoControl x:Name="video" Visibility="{Binding Path=IsVideoShow,Converter={StaticResource Bool2VisibilityConverter}}"></fmodule:VideoControl>
</Border>
<!-- 其他 -->
<Grid Grid.Row="1" Grid.Column="1">
<CheckBox Content="显隐" Foreground="White" FontSize="16"
IsChecked="{Binding Path=IsVideoShow,Mode=TwoWay}"></CheckBox>
</Grid>
</Grid>
</UserControl>
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.Framework.Core;
using VIZ.Framework.Storage;
using VIZ.H2V.Domain;
namespace VIZ.H2V.Module
{
/// <summary>
/// VideoView.xaml 的交互逻辑
/// </summary>
public partial class VideoView : UserControl
{
public VideoView()
{
InitializeComponent();
WPFHelper.BindingViewModel(this, new VideoViewModel());
this.video.IsShowFPS = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, bool>(p => p.VIDEO_IS_SHOW_FPS);
}
#region Key --
/// <summary>
/// 键
/// </summary>
public string Key
{
get { return (string)GetValue(KeyProperty); }
set { SetValue(KeyProperty, value); }
}
/// <summary>
/// Using a DependencyProperty as the backing store for Key. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty KeyProperty =
DependencyProperty.Register("Key", typeof(string), typeof(VideoView), new PropertyMetadata(null));
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
using VIZ.Framework.Module;
using VIZ.Framework.Domain;
using VIZ.H2V.Domain;
using VIZ.Framework.Common;
using System.Windows;
using System.Diagnostics;
namespace VIZ.H2V.Module
{
/// <summary>
/// 视频控制视图模型
/// </summary>
public class VideoControlViewModel : ViewModelBase, IVideoControlService
{
/// <summary>
/// 视频控制视图模型
/// </summary>
public VideoControlViewModel()
{
// 注册视图模型服务
ApplicationDomainEx.ServiceManager.AddService(ServiceKeys.VideoControl, this);
// 初始化命令
this.InitCommand();
}
/// <summary>
/// 初始化命令
/// </summary>
private void InitCommand()
{
this.PlayCommand = new VCommand(this.Play);
this.PauseCommand = new VCommand(this.Pause);
this.StopCommmand = new VCommand(this.Stop);
this.SettingCommand = new VCommand(this.Setting);
this.BackCommand = new VCommand(this.Back);
this.ForwardCommand = new VCommand(this.Forward);
this.GotoCommand = new VCommand(this.Goto);
this.TimeBarManualValueChangedCommand = new VCommand<VideoTimeBarValueChangedEventArgs>(this.TimeBarManualValueChanged);
}
// ======================================================================================
// === Field ===
// ======================================================================================
/// <summary>
/// 当前监控的OpenCV流
/// </summary>
private OpenCVStream monitorStream;
// ======================================================================================
// === Property ===
// ======================================================================================
#region PositionTime -- 当前时间
private TimeSpan positionTime;
/// <summary>
/// 当前时间
/// </summary>
public TimeSpan PositionTime
{
get { return positionTime; }
set { positionTime = value; this.RaisePropertyChanged(nameof(PositionTime)); }
}
#endregion
#region TotalTime -- 总时间
private TimeSpan totalTime;
/// <summary>
/// 总时间
/// </summary>
public TimeSpan TotalTime
{
get { return totalTime; }
set { totalTime = value; this.RaisePropertyChanged(nameof(TotalTime)); }
}
#endregion
#region GotoString -- 跳转时间字符串
private string gotoString = "00:00:00";
/// <summary>
/// 跳转时间字符串
/// </summary>
public string GotoString
{
get { return gotoString; }
set { gotoString = value; this.RaisePropertyChanged(nameof(GotoString)); }
}
#endregion
#region IsPlayEnabled -- 播放是否可用
private bool isPlayEnabled;
/// <summary>
/// 播放是否可用
/// </summary>
public bool IsPlayEnabled
{
get { return isPlayEnabled; }
set { isPlayEnabled = value; this.RaisePropertyChanged(nameof(IsPlayEnabled)); }
}
#endregion
#region IsPauseEnabled -- 暂停是否可用
private bool isPauseEnabled;
/// <summary>
/// 暂停是否可用
/// </summary>
public bool IsPauseEnabled
{
get { return isPauseEnabled; }
set { isPauseEnabled = value; this.RaisePropertyChanged(nameof(IsPauseEnabled)); }
}
#endregion
#region IsStopEnabled -- 停止是否可用
private bool isStopEnabled;
/// <summary>
/// 停止是否可用
/// </summary>
public bool IsStopEnabled
{
get { return isStopEnabled; }
set { isStopEnabled = value; this.RaisePropertyChanged(nameof(IsStopEnabled)); }
}
#endregion
#region IsTimeBarEnabled -- 时间滑块是否可用
private bool isTimeBarEnabled;
/// <summary>
/// 时间滑块是否可用
/// </summary>
public bool IsTimeBarEnabled
{
get { return isTimeBarEnabled; }
set { isTimeBarEnabled = value; this.RaisePropertyChanged(nameof(IsTimeBarEnabled)); }
}
#endregion
// ======================================================================================
// === Command ===
// ======================================================================================
#region PlayCommand -- 播放命令
/// <summary>
/// 播放命令
/// </summary>
public VCommand PlayCommand { get; set; }
/// <summary>
/// 播放命令
/// </summary>
private void Play()
{
List<IVideoService> list = ApplicationDomain.ServiceManager.GetServiceList<IVideoService>();
list.ForEach(p => p.Play());
this.IsPauseEnabled = true;
this.IsStopEnabled = true;
this.IsTimeBarEnabled = true;
this.IsPlayEnabled = false;
}
#endregion
#region PauseCommand -- 暂停命令
/// <summary>
/// 暂停命令
/// </summary>
public VCommand PauseCommand { get; set; }
/// <summary>
/// 暂停
/// </summary>
private void Pause()
{
List<IVideoService> list = ApplicationDomain.ServiceManager.GetServiceList<IVideoService>();
list.ForEach(p => p.Pause());
this.IsPlayEnabled = true;
this.IsPauseEnabled = false;
}
#endregion
#region StopCommand -- 停止命令
/// <summary>
/// 停止命令
/// </summary>
public VCommand StopCommmand { get; set; }
/// <summary>
/// 停止
/// </summary>
private void Stop()
{
List<IVideoService> list = ApplicationDomain.ServiceManager.GetServiceList<IVideoService>();
list.ForEach(p => p.Stop());
this.IsPlayEnabled = true;
this.IsPauseEnabled = false;
this.IsStopEnabled = false;
this.PositionTime = TimeSpan.Zero;
}
#endregion
#region SettingCommand -- 视频设置命令
/// <summary>
/// 视频设置命令
/// </summary>
public VCommand SettingCommand { get; set; }
/// <summary>
/// 视频设置
/// </summary>
private void Setting()
{
VideoSettingView view = new VideoSettingView();
NoneWindow window = new NoneWindow(1400, 800, view);
window.ShowDialog();
}
#endregion
#region BackCommand -- 倒退命令
/// <summary>
/// 倒退命令
/// </summary>
public VCommand BackCommand { get; set; }
/// <summary>
/// 倒退
/// </summary>
private void Back()
{
TimeSpan time = TimeSpan.FromSeconds(this.PositionTime.TotalSeconds - 5);
this.GotoFrame(time);
}
#endregion
#region ForwardCommand -- 前进命令
/// <summary>
/// 前进命令
/// </summary>
public VCommand ForwardCommand { get; set; }
/// <summary>
/// 前进
/// </summary>
private void Forward()
{
TimeSpan time = TimeSpan.FromSeconds(this.PositionTime.TotalSeconds + 5);
this.GotoFrame(time);
}
#endregion
#region GotoCommand -- 跳转命令
/// <summary>
/// 跳转命令
/// </summary>
public VCommand GotoCommand { get; set; }
/// <summary>
/// 跳转
/// </summary>
private void Goto()
{
VideoControlView view = this.GetView<VideoControlView>();
Window window = WPFHelper.GetAncestorByType<Window>(view);
if (!TimeSpan.TryParse(this.GotoString, out TimeSpan time))
{
MessageBoxEx.ShowDialog("跳转时间格式不正确,格式:00:00:00", window);
return;
}
this.GotoFrame(time);
}
/// <summary>
/// 跳转帧
/// </summary>
/// <param name="time">跳转时间</param>
private void GotoFrame(TimeSpan time)
{
IVideoService service = this.GetFirstUsedService();
OpenCVPropertyInfos propertyInfos = service.GetOpenCVPropertyInfos();
int position = (int)(time.TotalSeconds * propertyInfos.Fps);
position = position > propertyInfos.FrameCount ? (int)propertyInfos.FrameCount : position;
position = position < 0 ? 0 : position;
List<IVideoService> list = ApplicationDomain.ServiceManager.GetServiceList<IVideoService>();
list.ForEach(p => p.SetPosition(position));
this.positionTime = time;
this.RaisePropertyChanged(nameof(PositionTime));
}
#endregion
#region TimeBarManualValueChangedCommand -- 进度条值手动改变时触发
/// <summary>
/// 进度条值手动改变时触发
/// </summary>
public VCommand<VideoTimeBarValueChangedEventArgs> TimeBarManualValueChangedCommand { get; set; }
/// <summary>
/// 进度条值手动改变
/// </summary>
/// <param name="args">事件参数</param>
private void TimeBarManualValueChanged(VideoTimeBarValueChangedEventArgs args)
{
List<IVideoService> list = ApplicationDomain.ServiceManager.GetServiceList<IVideoService>();
IVideoService service = this.GetFirstUsedService();
if (service == null)
return;
OpenCVPropertyInfos propertyInfos = service.GetOpenCVPropertyInfos();
if (propertyInfos == null)
return;
int position = (int)(propertyInfos.Fps * args.Time.TotalSeconds);
list.ForEach(p => p.SetPosition(position));
}
#endregion
// ======================================================================================
// === Public Function ===
// ======================================================================================
/// <summary>
/// 更新时间条信息
/// </summary>
public void UpdateTimeBarInfo()
{
IVideoService service = this.GetFirstUsedService();
if (service == null)
return;
OpenCVPropertyInfos propertyInfos = service.GetOpenCVPropertyInfos();
// 以获取到的第一个属性信息为主
this.TotalTime = TimeSpan.FromSeconds(propertyInfos.FrameCount / propertyInfos.Fps);
this.PositionTime = TimeSpan.Zero;
// 注册视频帧信息
if (this.monitorStream != null)
{
this.monitorStream.ExecuteVideoFrame -= OpenCVStream_ExecuteVideoFrame;
}
OpenCVStream stream = VideoStreamManager.Get<OpenCVStream>(service.OpenCVKey);
stream.ExecuteVideoFrame -= OpenCVStream_ExecuteVideoFrame;
stream.ExecuteVideoFrame += OpenCVStream_ExecuteVideoFrame;
this.monitorStream = stream;
}
// ======================================================================================
// === Private Function ===
// ======================================================================================
/// <summary>
/// 触发视频渲染
/// </summary>
private void OpenCVStream_ExecuteVideoFrame(object sender, VideoFrameEventArgs e)
{
WPFHelper.BeginInvoke(() =>
{
this.PositionTime = TimeSpan.FromTicks(e.Frame.TimeStamp);
if (e.Frame.IsEnd)
{
this.Stop();
}
});
}
/// <summary>
/// 获取第一根正在使用的视频服务
/// </summary>
/// <returns>视频服务</returns>
private IVideoService GetFirstUsedService()
{
var services = ApplicationDomainEx.ServiceManager.GetServiceList<IVideoService>();
foreach (IVideoService service in services)
{
OpenCVPropertyInfos propertyInfos = service.GetOpenCVPropertyInfos();
if (propertyInfos != null)
{
return service;
}
}
return null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Collections.ObjectModel;
using VIZ.Framework.Core;
using VIZ.H2V.Domain;
using VIZ.Framework.Common;
using VIZ.H2V.Storage;
using Microsoft.Win32;
namespace VIZ.H2V.Module
{
/// <summary>
/// 视频设置视图模型
/// </summary>
public class VideoSettingViewModel : ViewModelBase
{
/// <summary>
/// 视频设置视图模型
/// </summary>
public VideoSettingViewModel()
{
// 初始化命令
this.InitCommand();
}
/// <summary>
/// 初始化命令
/// </summary>
private void InitCommand()
{
this.LoadedCommand = new VCommand(this.Loaded);
this.ApplyCommand = new VCommand(this.Apply);
this.CloseCommand = new VCommand(this.Close);
this.SaveCommand = new VCommand(this.Save);
this.NewGroupCommand = new VCommand(this.NewGroup);
this.DeleteGroupCommand = new VCommand(this.DeleteGroup);
this.SelectVideoFileCommand = new VCommand<VideoModel>(this.SelectVideoFile);
this.ClearVideoFileCommand = new VCommand<VideoModel>(this.ClearVideoFile);
}
// ======================================================================================
// === Property ===
// ======================================================================================
#region VideoGroups -- 视频分组集合
private ObservableCollection<VideoGroupModel> videoGroups = new ObservableCollection<VideoGroupModel>();
/// <summary>
/// 视频分组集合
/// </summary>
public ObservableCollection<VideoGroupModel> VideoGroups
{
get { return videoGroups; }
set { videoGroups = value; this.RaisePropertyChanged(nameof(VideoGroups)); }
}
#endregion
#region SelectedVideoGroup -- 选中的视频分组
private VideoGroupModel selectedVideoGroup;
/// <summary>
/// 选中的视频分组
/// </summary>
public VideoGroupModel SelectedVideoGroup
{
get { return selectedVideoGroup; }
set
{
// 在切换完成之前保存一次
this.Save();
selectedVideoGroup = value;
this.RaisePropertyChanged(nameof(SelectedVideoGroup));
}
}
#endregion
// ======================================================================================
// === Command ===
// ======================================================================================
#region LoadedCommand -- 加载完成命令
/// <summary>
/// 加载完成命令
/// </summary>
public VCommand LoadedCommand { get; set; }
/// <summary>
/// 加载完成
/// </summary>
private void Loaded()
{
// 加载最后一次使用的视频分组信息
var logs = ApplicationDomainEx.LiteDbContext.VideoGroupLog.FindAll();
VideoGroupLogEntity log = logs.FirstOrDefault();
// 加载视频分组信息
var groups = ApplicationDomainEx.LiteDbContext.VideoGroup.Find(p => !p.IsDelete).ToList();
foreach (var group in groups)
{
VideoGroupModel groupModel = new VideoGroupModel();
groupModel.Id = group.Id;
groupModel.Name = group.Name;
groupModel.DateTime = group.DateTime;
groupModel.IsCurrentGroup = log != null && log.GroupId == group.Id;
if (group.VideoList != null)
{
foreach (var video in group.VideoList)
{
VideoModel videoModel = new VideoModel();
videoModel.Key = video.Key;
videoModel.Path = video.Path;
videoModel.OffsetSec = video.OffsetSec;
videoModel.OffsetSecString = video.OffsetSec.ToString();
groupModel.VideoList.Add(videoModel);
}
}
this.VideoGroups.Add(groupModel);
}
}
#endregion
#region ApplyCommand -- 应用流
/// <summary>
/// 应用流
/// </summary>
public VCommand ApplyCommand { get; set; }
/// <summary>
/// 应用流
/// </summary>
public void Apply()
{
VideoSettingView view = this.GetView<VideoSettingView>();
Window window = WPFHelper.GetAncestorByType<Window>(view);
if (this.SelectedVideoGroup == null)
{
MessageBoxEx.ShowDialog("请选择一个将要应用的视频分组", window);
return;
}
// 处理视频视图服务
var services = ApplicationDomainEx.ServiceManager.GetServiceList<IVideoService>();
foreach (IVideoService service in services)
{
VideoModel videoModel = this.SelectedVideoGroup.VideoList.FirstOrDefault(p => p.Key == service.OpenCVKey);
if (double.TryParse(string.IsNullOrWhiteSpace(videoModel.OffsetSecString) ? "0" : videoModel.OffsetSecString, out double value))
{
videoModel.OffsetSec = value;
}
service.VideoModel = videoModel;
service.Open(videoModel?.Path);
}
// 处理视频控制服务
var controlSrvice = ApplicationDomainEx.ServiceManager.GetService<IVideoControlService>(ServiceKeys.VideoControl);
if (controlSrvice == null)
return;
controlSrvice.IsPlayEnabled = true;
controlSrvice.IsPauseEnabled = false;
controlSrvice.IsStopEnabled = false;
controlSrvice.IsTimeBarEnabled = true;
controlSrvice.UpdateTimeBarInfo();
}
#endregion
#region CloseCommand -- 关闭按钮
/// <summary>
/// 关闭按钮
/// </summary>
public VCommand CloseCommand { get; set; }
/// <summary>
/// 关闭
/// </summary>
private void Close()
{
// 关闭之前保存一次
this.Save();
VideoSettingView view = this.GetView<VideoSettingView>();
if (view == null)
return;
Window window = WPFHelper.GetAncestorByType<Window>(view);
if (window == null)
return;
window.Close();
}
#endregion
#region SaveCommand -- 保存命令
/// <summary>
/// 保存命令
/// </summary>
public VCommand SaveCommand { get; set; }
/// <summary>
/// 保存
/// </summary>
private void Save()
{
if (this.SelectedVideoGroup == null)
return;
VideoGroupEntity group = ApplicationDomainEx.LiteDbContext.VideoGroup.FindById(this.SelectedVideoGroup.Id);
if (group == null)
{
group = new VideoGroupEntity();
}
group.DateTime = DateTime.Now;
group.Id = this.SelectedVideoGroup.Id;
group.Name = this.SelectedVideoGroup.Name;
group.VideoList = new List<VideoEntity>();
foreach (VideoModel videoModel in this.SelectedVideoGroup.VideoList)
{
VideoEntity video = new VideoEntity();
video.Key = videoModel.Key;
video.Path = videoModel.Path;
if (!double.TryParse(string.IsNullOrWhiteSpace(videoModel.OffsetSecString) ? "0" : videoModel.OffsetSecString, out double value))
{
MessageBoxEx.ShowDialog("输入的时间偏移格式不正确。", this.GetWindow());
return;
}
video.OffsetSec = value;
group.VideoList.Add(video);
}
ApplicationDomainEx.LiteDbContext.VideoGroup.Upsert(group);
}
#endregion
#region NewGroupCommand -- 新建视频分组命令
/// <summary>
/// 新建命令
/// </summary>
public VCommand NewGroupCommand { get; set; }
/// <summary>
/// 新建分组
/// </summary>
private void NewGroup()
{
VideoGroupModel groupModel = new VideoGroupModel();
groupModel.VideoList.Add(new VideoModel { Key = ServiceKeys.CAM_1 });
groupModel.VideoList.Add(new VideoModel { Key = ServiceKeys.CAM_2 });
groupModel.VideoList.Add(new VideoModel { Key = ServiceKeys.CAM_3 });
groupModel.VideoList.Add(new VideoModel { Key = ServiceKeys.CAM_4 });
VideoGroupEntity group = new VideoGroupEntity();
group.Name = "新建分组";
group.DateTime = DateTime.Now;
ApplicationDomainEx.LiteDbContext.VideoGroup.Insert(group);
groupModel.Id = group.Id;
groupModel.Name = group.Name;
this.VideoGroups.Add(groupModel);
}
#endregion
#region DeleteGroupCommand -- 删除分组命令
/// <summary>
/// 删除分组命令
/// </summary>
public VCommand DeleteGroupCommand { get; set; }
/// <summary>
/// 删除分组
/// </summary>
private void DeleteGroup()
{
VideoSettingView view = this.GetView<VideoSettingView>();
Window window = WPFHelper.GetAncestorByType<Window>(view);
if (this.SelectedVideoGroup == null)
{
MessageBoxEx.ShowDialog("请选择一个要删除的分组", window);
return;
}
MessageBoxExResult result = MessageBoxEx.ShowDialog("删除视频分组", $"是否删除视频分组:{this.SelectedVideoGroup.Name}", MessageBoxExButtons.YES_CANCEL, window);
if (result == MessageBoxExResult.CANCEL)
return;
VideoGroupEntity entity = ApplicationDomainEx.LiteDbContext.VideoGroup.FindById(this.SelectedVideoGroup.Id);
entity.IsDelete = true;
ApplicationDomainEx.LiteDbContext.VideoGroup.Update(entity);
this.VideoGroups.Remove(this.SelectedVideoGroup);
this.SelectedVideoGroup = null;
}
#endregion
#region SelectVideoFileCommand -- 选择视频文件命令
/// <summary>
/// 选择视频文件命令
/// </summary>
public VCommand<VideoModel> SelectVideoFileCommand { get; set; }
/// <summary>
/// 选择视频文件
/// </summary>
/// <param name="videoModel">视频模型</param>
private void SelectVideoFile(VideoModel videoModel)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = false;
ofd.Filter = "video files (.mp4)|*.mp4|All files (*.*)|*.*";
if (ofd.ShowDialog() != true)
return;
videoModel.Path = ofd.FileName;
}
#endregion
#region ClearVideoFileCommand -- 清理视频文件命令
/// <summary>
/// 清理视频文件命令
/// </summary>
public VCommand<VideoModel> ClearVideoFileCommand { get; set; }
/// <summary>
/// 清理视频文件命令
/// </summary>
/// <param name="videoModel"></param>
private void ClearVideoFile(VideoModel videoModel)
{
videoModel.Path = string.Empty;
videoModel.OffsetSec = 0;
videoModel.OffsetSecString = videoModel.OffsetSec.ToString();
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
using VIZ.Framework.Domain;
using VIZ.H2V.Domain;
namespace VIZ.H2V.Module
{
/// <summary>
/// 视频视图模型
/// </summary>
public class VideoViewModel : ViewModelBase, IVideoService
{
/// <summary>
/// 视频视图模型
/// </summary>
public VideoViewModel()
{
// 初始化命令
this.InitCommand();
}
/// <summary>
/// 初始化命令
/// </summary>
private void InitCommand()
{
this.LoadedCommand = new VCommand(this.Loaded);
}
// ======================================================================================
// === Property ===
// ======================================================================================
#region OpenCVKey -- 视频键
private string openCVKey;
/// <summary>
/// 视频键
/// </summary>
public string OpenCVKey
{
get { return openCVKey; }
set { openCVKey = value; this.RaisePropertyChanged(nameof(OpenCVKey)); }
}
#endregion
#region IsVideoShow -- 是否显示视频
private bool isVideoShow = true;
/// <summary>
/// 是否显示视频
/// </summary>
public bool IsVideoShow
{
get { return isVideoShow; }
set { isVideoShow = value; this.RaisePropertyChanged(nameof(IsVideoShow)); }
}
#endregion
#region VideoModel -- 视频模型
private VideoModel videoModel;
/// <summary>
/// 视频模型
/// </summary>
public VideoModel VideoModel
{
get { return videoModel; }
set { videoModel = value; this.RaisePropertyChanged(nameof(VideoModel)); }
}
#endregion
// ======================================================================================
// === Command ===
// ======================================================================================
#region LoadedCommand -- 加载命令
/// <summary>
/// 加载命令
/// </summary>
public VCommand LoadedCommand { get; set; }
/// <summary>
/// 加载
/// </summary>
private void Loaded()
{
if (!string.IsNullOrWhiteSpace(this.OpenCVKey))
return;
VideoView view = this.GetView<VideoView>();
if (view == null)
return;
this.OpenCVKey = view.Key;
// 注册服务
ApplicationDomain.ServiceManager.AddService(this.OpenCVKey, this);
// 添加视频流工具
OpenCVStreamOption option = new OpenCVStreamOption();
OpenCVStream stream = new OpenCVStream(option);
stream.ExecuteVideoFrame += Stream_ExecuteVideoFrame;
VideoStreamManager.Append(this.OpenCVKey, stream);
}
/// <summary>
/// 处理视频
/// </summary>
private void Stream_ExecuteVideoFrame(object sender, VideoFrameEventArgs e)
{
if (!this.IsVideoShow)
{
e.Frame.Dispose();
return;
}
VideoView view = this.GetView<VideoView>();
if (view == null)
{
e.Frame.Dispose();
return;
}
view.video.UpdateVideoFrame(e.Frame);
}
#endregion
// ======================================================================================
// === Private Field ===
// ======================================================================================
// ======================================================================================
// === IVideoViewModelService ===
// ======================================================================================
/// <summary>
/// 打开文件
/// </summary>
/// <param name="fileName">文件名</param>
public void Open(string fileName)
{
OpenCVStream stream = VideoStreamManager.Get<OpenCVStream>(this.OpenCVKey);
if (stream == null)
return;
stream.ChangeUri(fileName);
this.SetPosition(0);
}
/// <summary>
/// 播放
/// </summary>
public void Play()
{
OpenCVStream stream = VideoStreamManager.Get<OpenCVStream>(this.OpenCVKey);
if (stream == null)
return;
stream.Play();
}
/// <summary>
/// 暂停
/// </summary>
public void Pause()
{
OpenCVStream stream = VideoStreamManager.Get<OpenCVStream>(this.OpenCVKey);
if (stream == null)
return;
stream.Pause();
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
OpenCVStream stream = VideoStreamManager.Get<OpenCVStream>(this.OpenCVKey);
if (stream == null)
return;
stream.Stop();
this.SetPosition(0);
}
/// <summary>
/// 设置位置
/// </summary>
/// <param name="position">帧位置</param>
public void SetPosition(int position)
{
OpenCVStream stream = VideoStreamManager.Get<OpenCVStream>(this.OpenCVKey);
if (stream == null)
return;
if (this.VideoModel.OffsetSec != 0d)
{
OpenCVPropertyInfos propertyInfos = this.GetOpenCVPropertyInfos();
if (propertyInfos != null)
{
int offset = (int)(this.VideoModel.OffsetSec * propertyInfos.Fps);
position += offset;
position = position < 0 ? 0 : position;
}
}
stream.SetPosition(position);
stream.TriggerExecuteCurrentPosVideoFrame();
}
/// <summary>
/// 获取OpenCV属性信息
/// </summary>
/// <returns>OpenCV属性信息</returns>
public OpenCVPropertyInfos GetOpenCVPropertyInfos()
{
OpenCVStream stream = VideoStreamManager.Get<OpenCVStream>(this.OpenCVKey);
if (stream == null)
return null;
return stream.PropertyInfos;
}
}
}
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