一、问题描述
我用Aforge类库打开了本地的摄像头,可以在PC看到实时画面。但是,我想把该实时画面通过局域网络,传输给另一台PC。Aforge类库或Socket的Demo,请参考我的博客。
Aforge类库 Demo(建议你用Aforge类库,因为它是功能最强大的,包含了人工智能算法、图像处理算法等等功能):
(六)WPF/C# 使用Aforge类库打开USB摄像头:实现拍照/重拍功能。
Socket Demo:
https://blog.csdn.net/xpj8888/article/category/8321616等系列。
二、别人的实时视频监控画面方案
1、OpenCV结合socket进行实时视频传输(OpenCV + TCP协议 + Socket + C++实现)
https://blog.csdn.net/neal1991/article/details/45009229
https://blog.csdn.net/u012736685/article/details/77131633(实时图片传输、再现)
https://www.cnblogs.com/ryhan/p/4470107.html
https://blog.csdn.net/pengz0807/article/details/52204134
2、android 手机采集摄像头视频 socket 视频传输 实时传播
以下两个参考方法都是传输视频画面(图片帧的方式),没有传输语音。
https://blog.csdn.net/a289973483/article/details/52790217
https://www.cnblogs.com/lijiongquan/p/4729445.html
3、Socket+视频流
(重点)https://blog.csdn.net/ilipan/article/details/44982807(图片帧的形式)
https://blog.csdn.net/u011426247/article/details/80551749
https://blog.csdn.net/theArcticOcean/article/details/52658748
https://download.csdn.net/download/xmcy001122/4914401(图片帧)
基于superSocket——AForge的UDP摄像并传输视频案例-CSDN下载
MyCamMonitorServer AForge 摄像头监控,开启Socket监听发送 到的...(联合开发网)
三、我的实现方法
1、技术点
1.1、肉眼分辨率
所谓的帧就是一幅完整的图象,一般人眼看视频时有24帧/秒就是流畅的了;所以,我们在一秒内,传输24章图像即可,然后在接收端把图片重现即可。
https://bbs.csdn.net/topics/392357720?list=lz
1.2、视频压缩
当然,你可以把图片编码后解码(即压缩),从而满足在一定的宽度速率下传输。请参考:https://zhidao.baidu.com/question/473219109.html
2、发送端(是在Aforge类库上修改的,该类库已经存放到GitHub上)
MainWindow.xaml:
<Window x:Class="AForge.Wpf.MainWindow"
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:local="clr-namespace:AForge.Wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="422.669"
Height="350"
mc:Ignorable="d">
<Grid>
<Image x:Name="videoPlayer" Margin="10,0,10,70" />
<ComboBox x:Name="comboBox"
Width="167"
Height="21"
Margin="10,0,0,25"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
DisplayMemberPath="Name"
ItemsSource="{Binding VideoDevices}"
SelectedItem="{Binding CurrentDevice}" />
<Label Width="167"
Height="24"
Margin="10,0,0,46"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Content="Select video source" />
<Button Width="67"
Height="21"
Margin="213,0,0,25"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Click="btnStart_Click"
Content="Start" Background="Red" />
<Button Width="67"
Height="21"
Margin="296,0,0,25"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Click="btnStop_Click"
Content="Stop" />
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
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 AForge.Video;
using AForge.Video.DirectShow;
using System.Net.Sockets;
using System.Net;
using System.IO;
namespace AForge.Wpf
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
#region Public properties
public ObservableCollection<FilterInfo> VideoDevices { get; set; }
public FilterInfo CurrentDevice
{
get { return _currentDevice; }
set { _currentDevice = value; this.OnPropertyChanged("CurrentDevice"); }
}
private FilterInfo _currentDevice;
#endregion
#region Private fields
private IVideoSource _videoSource;
#endregion
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket socketWatch2;
public MainWindow()
{
string strSocketStartFlag = "1";
string strSocketIP = "192.168.xxx.xx";//无线网
int point = 50000;
if (strSocketStartFlag == "1")
{
IPAddress ip = IPAddress.Parse(strSocketIP);
IPEndPoint iPEndPoint = new IPEndPoint(ip, point);
socketWatch.Bind(iPEndPoint);
socketWatch.Listen(10);
MessageBox.Show("监听成功");
//开启线程监听
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}
//InitializeComponent();
this.DataContext = this;
GetVideoDevices();
this.Closing += MainWindow_Closing;
}
Socket Server;
//将远程连接的客户端的IP地址和Socket存入集合中
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
string Receive_IPandPort = null;
void Listen(object o)
{
socketWatch2 = o as Socket;
//等待客户端的连接,并且创建一个负责通信的Socket
while (true)
{
try
{
//负责跟客户端通信的Socket
Server = socketWatch2.Accept();
//将远程连接的客户端的IP地址和Socket存入集合中
dicSocket.Add(Server.RemoteEndPoint.ToString(), Server);
//将远程连接的客户端的IP地址和端口号存储下拉框中
//cboUsers.Items.Add(Server.RemoteEndPoint.ToString());
//Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate2(cboUsers.Items.Add), Server.RemoteEndPoint.ToString());
Receive_IPandPort = Server.RemoteEndPoint.ToString();
//192.168.0.100:连接成功
//Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), Server.RemoteEndPoint.ToString() + ":" + "连接成功");
//开启一个新的线程,不停地接收客户端发送过来的消息
//Thread th = new Thread(Receive);
//th.IsBackground = true;
//th.Start(Server);
}
catch { }
}
}
public void receiveFunc(object obj)
{
Socket Server = obj as Socket;
int ithread1 = Thread.CurrentThread.ManagedThreadId;
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024 * 3];
//实际接收到的有效字节数
//int r = mainWindow.Server.Receive(buffer);
int r = Server.Receive(buffer);
if (r == 0)//未收到任何东西
{
break;
}
//第一个字节表示接收的是文字消息
else
{
}
}
catch
{
//MessageBox.Show("你接收的是非法文件或非法消息");
}
}
//return server1;
}
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
StopCamera();
}
/// <summary>
/// 打开摄像头
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStart_Click(object sender, RoutedEventArgs e)
{
StartCamera();
}
private void video_NewFrame(object sender, Video.NewFrameEventArgs eventArgs)
{
try
{
BitmapImage bi;
using (var bitmap = (Bitmap)eventArgs.Frame.Clone())
{
bi = bitmap.ToBitmapImage();
//将BitmapImage转成字节
Stream stream = bi.StreamSource;
if (stream != null && stream.Length > 0)
{
stream.Position = 0;//必须要。
BinaryReader br = new BinaryReader(stream);
//内容
byte[] bytVideoContext = br.ReadBytes((int)stream.Length);
//标志位
byte[] bytVideoSurveillanceSendFlag = new byte[2] { 0x03, 0 };
byte[] bytSum = new byte[2 + 921654];
Array.ConstrainedCopy(bytVideoSurveillanceSendFlag, 0, bytSum, 0, bytVideoSurveillanceSendFlag.Length);
Array.ConstrainedCopy(bytVideoContext, 0, bytSum, bytVideoSurveillanceSendFlag.Length, bytVideoContext.Length);
dicSocket[Receive_IPandPort].Send(bytSum);
}
}
bi.Freeze(); // avoid cross thread operations and prevents leaks
Dispatcher.BeginInvoke(new ThreadStart(delegate { videoPlayer.Source = bi; }));
}
catch (Exception exc)
{
MessageBox.Show("Error on _videoSource_NewFrame:\n" + exc.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
StopCamera();
}
}
/// <summary>
/// 关闭摄像头
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStop_Click(object sender, RoutedEventArgs e)
{
StopCamera();
}
private void GetVideoDevices()
{
VideoDevices = new ObservableCollection<FilterInfo>();
foreach (FilterInfo filterInfo in new FilterInfoCollection(FilterCategory.VideoInputDevice))
{
VideoDevices.Add(filterInfo);
}
if (VideoDevices.Any())
{
CurrentDevice = VideoDevices[0];
}
else
{
MessageBox.Show("No video sources found", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void StartCamera()
{
if (CurrentDevice != null)
{
_videoSource = new VideoCaptureDevice(CurrentDevice.MonikerString);
_videoSource.NewFrame += video_NewFrame;
_videoSource.Start();
}
}
private void StopCamera()
{
if (_videoSource != null && _videoSource.IsRunning)
{
_videoSource.SignalToStop();
_videoSource.NewFrame -= new NewFrameEventHandler(video_NewFrame);
}
}
#region INotifyPropertyChanged members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
#endregion
}
}
BitmapHelpers.cs:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace AForge.Wpf
{
static class BitmapHelpers
{
public static BitmapImage ToBitmapImage(this Bitmap bitmap)
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
MemoryStream ms = new MemoryStream();
bitmap.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
bi.StreamSource = ms;
bi.EndInit();
return bi;
}
}
}
3、接收端(解决了粘包和拆包问题)
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 Microsoft.Win32;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Threading;
using KeenRayLargePC.Views;
using KeenRayLargePC.PublicFunc;
using System.Windows.Interop;
using System.Xml.Linq;
using System.Drawing.Imaging;
using System.Drawing;
using KeenRayLargePC.Common;
namespace KeenRayLargePC
{
public partial class MainWindow : Window
{
#region 标志位
//标志位长度
const int FLAG_LENGTH = 2;
//加载页面标志
string pageTypeFlag = null;
//启动页面标志
static byte[] btStudyPageRecFlag = new byte[FLAG_LENGTH] { 0x00, 0 };
static byte[] btReviewPageRecFlag = new byte[FLAG_LENGTH] { 0x01, 0 };
static byte[] btHistoryPageRecFlag = new byte[FLAG_LENGTH] { 0x02, 0 };
//启动图片接收、字符接收标志
static byte[] btImageRecFlag = new byte[FLAG_LENGTH] { 0x04, 0 };
static byte[] btStringRecFlag = new byte[FLAG_LENGTH] { 0x00, 0 };
//启动用户、列表、曝光标志
static byte[] btUserRecFlag = new byte[FLAG_LENGTH] { 0x00, 0 };//这里出现的0x00标志与前面的0x00没有联系。
static byte[] btListViewRecFlag = new byte[FLAG_LENGTH] { 0x08, 0 };
static byte[] btExposeRecFlag = new byte[FLAG_LENGTH] { 0x10, 0 };
//启动KV、mA、ms、mAs标志
static byte[] btExposeKVRecFlag = new byte[FLAG_LENGTH] { 0x00, 0 };
static byte[] btExposemARecFlag = new byte[FLAG_LENGTH] { 0x20, 0 };
static byte[] btExposemsRecFlag = new byte[FLAG_LENGTH] { 0x40, 0 };
static byte[] btExposemAsRecFlag = new byte[FLAG_LENGTH] { 0x60, 0 };
//启动 Plus/Reduce标志
static byte[] btExposePlusRecFlag = new byte[FLAG_LENGTH] { 0x00, 0 };
static byte[] btExposeReduceRecFlag = new byte[FLAG_LENGTH] { 0x80, 0 };
//将字节转整数
Int16 iStudyPageRecFlag = System.BitConverter.ToInt16(btStudyPageRecFlag, 0);
Int16 iReviewPageRecFlag = System.BitConverter.ToInt16(btReviewPageRecFlag, 0);
Int16 iHistoryPageRecFlag = System.BitConverter.ToInt16(btHistoryPageRecFlag, 0);
Int16 iStringRecFlag = System.BitConverter.ToInt16(btStringRecFlag, 0);
Int16 iImageRecFlag = System.BitConverter.ToInt16(btImageRecFlag, 0);
Int16 iUserRecFlag = System.BitConverter.ToInt16(btUserRecFlag, 0);
Int16 iListViewRecFlag = System.BitConverter.ToInt16(btListViewRecFlag, 0);
Int16 iExposeRecFlag = System.BitConverter.ToInt16(btExposeRecFlag, 0);
Int16 iExposeKVRecFlag = System.BitConverter.ToInt16(btExposeKVRecFlag, 0);
Int16 iExposemARecFlag = System.BitConverter.ToInt16(btExposemARecFlag, 0);
Int16 iExposemsRecFlag = System.BitConverter.ToInt16(btExposemsRecFlag, 0);
Int16 iExposemAsRecFlag = System.BitConverter.ToInt16(btExposemAsRecFlag, 0);
Int16 iExposePlusRecFlag = System.BitConverter.ToInt16(btExposePlusRecFlag, 0);
Int16 iExposeReduceRecFlag = System.BitConverter.ToInt16(btExposeReduceRecFlag, 0);
#endregion
#region 字段
StudyPage studyPage = new StudyPage();
ReviewPage reviewPage = new ReviewPage();
HistoryPage historyPage = new HistoryPage();
ExposeValueMsgFunc exposeValueMsgFunc = new ExposeValueMsgFunc();
ImageFunc imageFunc = new ImageFunc();
ListViewMsgFunc listViewMsgFunc = new ListViewMsgFunc();
UserMsgFunc userMsgFunc = new UserMsgFunc();
Log log = new Log();//日志类
Config config = new Config();
#endregion
#region 视频监控
int iCameraFlag = 1; //视频监控开关状态。0:关闭。1:打开。
List<byte> VideoList = new List<byte>(); //存放视频帧
const int BITMAP_IMAGE_LENGTH = 921654; //帧字节长度
byte[] btCurrentBitmapImage = new byte[BITMAP_IMAGE_LENGTH];//当前帧
byte[] btLastBitmapImage = new byte[BITMAP_IMAGE_LENGTH];//上一帧
#endregion
#region socket 初始化
byte[] btRecBuffer = new byte[1000 * 1001];//socket接收缓存区
int iRecBuffeActualByteCount = 0; //socket实际接收到的有效字节数
Socket Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public Socket ClientVar
{
get { return Client; }
}
#endregion
/// <summary>
/// 默认构造函数
/// </summary>
public MainWindow()
{
InitializeComponent();
//清空日志
log.ClearLogFunc();
//配置IP
string strIPconfigFilePath = Environment.CurrentDirectory + "\\IPconfig.xml";
IPAddress serverIP = IPAddress.Parse(config.IpConfigFunc(strIPconfigFilePath));
IPEndPoint serverIPEndPoint = new IPEndPoint(serverIP, 50000);
获得要连接的远程服务器应用程序的IP地址和端口号
//Client.Connect(serverIPEndPoint);
//MessageBox.Show("连接服务器状态:成功");
//Thread threadReceive = new Thread(Receive);
将threadReceive设置为后台线程
//threadReceive.IsBackground = true;
启动线程
//threadReceive.Start();
}
/// <summary>
/// 接收函数
/// </summary>
private void Receive()
{
while (true)
{
try
{
iRecBuffeActualByteCount = Client.Receive(btRecBuffer);
if (iRecBuffeActualByteCount == 0)//未收到任何东西
{
break;
}
else //有收到信息
{
//拷贝,找出butter的标志位。
byte[] btRecFlag = new byte[2];
Array.ConstrainedCopy(btRecBuffer, 0, btRecFlag, 0, btRecFlag.Length);
//转成整数,以便进行与操作。
Int16 iRecFlag = System.BitConverter.ToInt16(btRecFlag, 0);
//因为视频监控是不连续的帧,所以每次接收的btRecBuffer数据不一定有标志位。因此,不能根据每组btRecBuffer数据来判断是否启动视频监控
if (iCameraFlag == 1)
{
//默认打开视频监控画面
App.Current.Dispatcher.Invoke((Action)delegate ()
{
Panel.SetZIndex(imgVideoSurveillance, 2);
});
LoadVideoSurveillanceFunc(iRecBuffeActualByteCount, btRecBuffer);
}
//关闭视频监控,打开其他页面。
else if (iCameraFlag == 0)
{
//前两位为00,则启动StudyPage。iRecFlag & 0x03,表示提取字节的前两位。
if ((iRecFlag & 0x03) == iStudyPageRecFlag)
{
LoadStudyPageFunc(iRecFlag);
}
//前两位为01,则启动ReviewPage
else if ((iRecFlag & 0x03) == iReviewPageRecFlag)
{
LoadReviewPageFunc(iRecFlag);
}
//前两位为10,则启动HistoryPage
else if ((iRecFlag & 0x03) == iHistoryPageRecFlag)
{
LoadHistoryPageFunc(iRecFlag);
}
}
}
}
catch(Exception ex)
{
MessageBox.Show("连接不上");
log.WriteErrorLogFunc(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "MainWindow.xaml.cs::Receive()——" + "Socket接收发送错误:" + ex.ToString() + "\n\n");
}
}
}
/// <summary>
/// 加载检查页
/// </summary>
/// <param name="iRecFlag"></param>
private void LoadStudyPageFunc(int iRecFlag)
{
try
{
pageTypeFlag = "studyPage";
//加载页面
App.Current.Dispatcher.Invoke((Action)delegate ()
{
Frame.Content = studyPage;
});
#region 加载非图片
//iRecFlag & 0x04,表示提取字节的第三位。
if ((iRecFlag & 0x04) == iStringRecFlag)//启动文字信息。
{
if ((iRecFlag & 0x18) == iUserRecFlag)//启动用户信息
{
userMsgFunc.GetUserMsgFunc(iRecBuffeActualByteCount, btRecBuffer, studyPage, reviewPage, pageTypeFlag);
}
else if ((iRecFlag & 0x18) == iListViewRecFlag)//启动列表信息
{
listViewMsgFunc.GetListViewMsgFunc(iRecBuffeActualByteCount, btRecBuffer, studyPage, historyPage, pageTypeFlag);
}
else if ((iRecFlag & 0x18) == iExposeRecFlag)//启动曝光信息
{
string strVar = exposeValueMsgFunc.GetExposeValueMsgFunc(iRecBuffeActualByteCount, btRecBuffer);
if ((iRecFlag & 0x60) == iExposeKVRecFlag)//启动KV
{
if ((iRecFlag & 0x80) == iExposePlusRecFlag)//加
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_KVValue.Content = strVar;
});
}
else if ((iRecFlag & 0x80) == iExposeReduceRecFlag)//减
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_KVValue.Content = strVar;
});
}
}
else if ((iRecFlag & 0x60) == iExposemARecFlag)//启动mA
{
if ((iRecFlag & 0x80) == iExposePlusRecFlag)//加
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
//studyPage.lbl_mAValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(iRecBuffeActualByteCount, btRecBuffer);
studyPage.lbl_mAValue.Content = strVar;
});
}
else if ((iRecFlag & 0x80) == iExposeReduceRecFlag)//减
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
//studyPage.lbl_mAValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(iRecBuffeActualByteCount, btRecBuffer);
studyPage.lbl_mAValue.Content = strVar;
});
}
}
else if ((iRecFlag & 0x60) == iExposemsRecFlag)//启动ms
{
if ((iRecFlag & 0x80) == iExposePlusRecFlag)//加
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
//studyPage.lbl_msValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(iRecBuffeActualByteCount, btRecBuffer);
studyPage.lbl_msValue.Content = strVar;
});
}
else if ((iRecFlag & 0x80) == iExposeReduceRecFlag)//减
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
//studyPage.lbl_msValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(iRecBuffeActualByteCount, btRecBuffer);
studyPage.lbl_msValue.Content = strVar;
});
}
}
else if ((iRecFlag & 0x60) == iExposemAsRecFlag)//启动mAs
{
if ((iRecFlag & 0x80) == iExposePlusRecFlag)//加
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
//studyPage.lbl_mAsValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(iRecBuffeActualByteCount, btRecBuffer);
studyPage.lbl_mAsValue.Content = strVar;
});
}
else if ((iRecFlag & 0x80) == iExposeReduceRecFlag)//减
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
//studyPage.lbl_mAsValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(iRecBuffeActualByteCount, btRecBuffer);
studyPage.lbl_mAsValue.Content = strVar;
});
}
}
}
}
#endregion
#region 加载图片
else if ((iRecFlag & 0x04) == iImageRecFlag)//启动图片信息
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
imageFunc.GetImageFunc(iRecBuffeActualByteCount, btRecBuffer, studyPage, reviewPage, pageTypeFlag);
});
}
#endregion
}
catch (Exception ex)
{
log.WriteErrorLogFunc(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "MainWindow.xaml.cs::LoadStudyPageFunc()——" + "加载检查页发送错误:" + ex.ToString() + "\n\n");
}
}
/// <summary>
/// 加载阅片页
/// </summary>
/// <param name="iRecFlag"></param>
private void LoadReviewPageFunc(int iRecFlag)
{
try
{
pageTypeFlag = "reviewPage";
App.Current.Dispatcher.Invoke((Action)delegate ()
{
Frame.Content = reviewPage;
});
//iRecFlag & 0x04,表示提取字节的第三位。
if ((iRecFlag & 0x04) == iStringRecFlag)//启动文字-用户信息。
{
userMsgFunc.GetUserMsgFunc(iRecBuffeActualByteCount, btRecBuffer, studyPage, reviewPage, pageTypeFlag);
}
else if ((iRecFlag & 0x04) == iImageRecFlag)//启动图片信息
{
imageFunc.GetImageFunc(iRecBuffeActualByteCount, btRecBuffer, studyPage, reviewPage, pageTypeFlag);
}
}
catch (Exception ex)
{
log.WriteErrorLogFunc(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "MainWindow.xaml.cs::LoadReviewPageFunc()——" + "加载阅片页发送错误:" + ex.ToString() + "\n\n");
}
}
/// <summary>
/// 加载历史页
/// </summary>
/// <param name="iRecFlag"></param>
private void LoadHistoryPageFunc(int iRecFlag)
{
try
{
pageTypeFlag = "HistoryPage";
App.Current.Dispatcher.Invoke((Action)delegate ()
{
Frame.Content = historyPage;
});
//iRecFlag & 0x04,表示提取字节的第三位。
if ((iRecFlag & 0x04) == iStringRecFlag)//启动文字信息。
{
if ((iRecFlag & 0x18) == iListViewRecFlag)//启动列表信息
{
//listViewMsgFunc.GetListViewMsgFunc(iRecBuffeActualByteCount, btRecBuffer, studyPage, historyPage, pageTypeFlag);
}
}
}
catch (Exception ex)
{
log.WriteErrorLogFunc(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "MainWindow.xaml.cs::LoadHistoryPageFunc()——" + "加载历史页发送错误:" + ex.ToString() + "\n\n");
}
}
/// <summary>
/// 加载视频监控画面
/// </summary>
/// <param name="iRecFlag"></param>
private void LoadVideoSurveillanceFunc(int iRecBuffeActualByteCount, byte[] btRecBuffer)
{
try
{
//将缓存器的有效字节拿出来
byte[] btRecBufferVideoContent = new byte[iRecBuffeActualByteCount];
Array.ConstrainedCopy(btRecBuffer, 0, btRecBufferVideoContent, 0, iRecBuffeActualByteCount);
VideoQueneFunc(btRecBufferVideoContent);
//log.WriteErrorLogFunc(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "MainWindow.xaml.cs::LoadVideoSurveillanceFunc——" + "帧长度 = " + iRecBuffeActualByteCount.ToString() + "\n\n");
}
catch (Exception ex)
{
log.WriteErrorLogFunc(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "MainWindow.xaml.cs::LoadVideoSurveillanceFunc——" + "视频监控发送错误:"+ ex.ToString() + "\n\n");
}
}
/// <summary>
/// 视频缓存队列
/// </summary>
/// <param name="btVedioRecByte"></param>
/// <returns></returns>
private void VideoQueneFunc(byte[] btVedioRecByte)
{
try
{
//插入:将字节数组插入到末尾
VideoList.AddRange(btVedioRecByte);
//网络慢状态:收到少于1帧,画面停留在上一时刻。同时解决拆包问题。
if (VideoList.Count < (BITMAP_IMAGE_LENGTH + FLAG_LENGTH))
{
btCurrentBitmapImage = btLastBitmapImage;
return;
}
//正常网络状态下:来一帧,则处理一帧
else if ((BITMAP_IMAGE_LENGTH + FLAG_LENGTH) * FLAG_LENGTH > VideoList.Count && VideoList.Count >= (BITMAP_IMAGE_LENGTH + FLAG_LENGTH))
{
//拷贝
Array.ConstrainedCopy(VideoList.ToArray(), FLAG_LENGTH, btCurrentBitmapImage, 0, BITMAP_IMAGE_LENGTH);
btLastBitmapImage = btCurrentBitmapImage;
//删除
VideoList.RemoveRange(0, (BITMAP_IMAGE_LENGTH + FLAG_LENGTH));
}
//网络较好,接收端未能及时处理所有帧:解决粘包问题,并将画面更新到最新帧。
else if (VideoList.Count >= (BITMAP_IMAGE_LENGTH + FLAG_LENGTH) * FLAG_LENGTH)
{
int iCurrentImageFrameCount;
iCurrentImageFrameCount = VideoList.Count / (BITMAP_IMAGE_LENGTH + FLAG_LENGTH);
//删除多余帧
VideoList.RemoveRange(0, (BITMAP_IMAGE_LENGTH + FLAG_LENGTH) * (iCurrentImageFrameCount - 1));
//拷贝当前帧
Array.ConstrainedCopy(VideoList.ToArray(), FLAG_LENGTH, btCurrentBitmapImage, 0, BITMAP_IMAGE_LENGTH);
btLastBitmapImage = btCurrentBitmapImage;
//删除当前帧
VideoList.RemoveRange(0, (BITMAP_IMAGE_LENGTH + FLAG_LENGTH));
}
//字节转BitmapImage
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnDemand;
MemoryStream ms = new MemoryStream(btCurrentBitmapImage);
bitmapImage.StreamSource = ms;
bitmapImage.EndInit();
bitmapImage.Freeze();
//更新UI
App.Current.Dispatcher.Invoke((Action)delegate ()
{
imgVideoSurveillance.Source = bitmapImage;
});
}
catch (Exception ex)
{
log.WriteErrorLogFunc(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "MainWindow.xaml.cs::VideoQueneFunc()——" + "视频缓存队列发送错误:" + ex.ToString() + "\n\n");
}
}
/// <summary>
/// 关闭系统
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnSysShutDown_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
/// <summary>
/// 视频监控开关状态
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Camera_Click(object sender, RoutedEventArgs e)
{
try
{
if (iCameraFlag == 0)//如果在关闭状态下,那就打开它。
{
iCameraFlag = 1;
//显示窗口
Panel.SetZIndex(imgVideoSurveillance, 2);//imgVideoSurveillance是图片控件的名字;
//Socket给主程序,启动USB视频监控,并将监控画面传输到当前窗口。
}
else if (iCameraFlag == 1)// 如果在打开状态下,那就关闭它。
{
iCameraFlag = 0;
//关闭窗口
Panel.SetZIndex(imgVideoSurveillance, 0);
//Socket给主程序,关闭USB视频监控
}
}
catch(Exception ex)
{
log.WriteErrorLogFunc(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\n" + "MainWindow.xaml.cs::Camera_Click()——" + "视频监控开关状态发送错误:" + ex.ToString() + "\n\n");
}
}
}
}