目录
效果
项目
代码
下载
效果
C#VideoCapture多路视频播放
项目
代码
using OpenCvSharp;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MultiVideoDemo
{
public partial class Form4 : Form
{
public Form4()
{
InitializeComponent();
}
CancellationTokenSource ctsShow;
CancellationTokenSource[] taskCTS = new CancellationTokenSource[6];
ConcurrentQueue<Mat>[] matQueue = new ConcurrentQueue<Mat>[6];
int fps = 25;
string[] rtsp_url = new string[40];
List<RTSPURLInfo> play_rtsp_url = new List<RTSPURLInfo>();
/// <summary>
/// 停止
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
ctsShow.Cancel();
for (int i = 0; i < 6; i++)
{
taskCTS[i].Cancel();
}
}
private void Form1_Load(object sender, EventArgs e)
{
//初始化
for (int i = 0; i < 6; i++)
{
taskCTS[i] = new CancellationTokenSource();
matQueue[i] = new ConcurrentQueue<Mat>();
}
for (int i = 0; i < 40; i++)
{
rtsp_url[i] = "1.dav";
}
//play_rtsp_url
for (int i = 0; i < 6; i++)
{
play_rtsp_url.Add(new RTSPURLInfo((i + 1).ToString(), rtsp_url[i]));
}
}
/// <summary>
/// 播放
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
ctsShow = new CancellationTokenSource();
for (int i = 0; i < 6; i++)
{
taskCTS[i] = new CancellationTokenSource();
matQueue[i] = new ConcurrentQueue<Mat>();
}
play_rtsp_url.Clear();
for (int i = 0; i < 6; i++)
{
play_rtsp_url.Add(new RTSPURLInfo((i + 1).ToString(), rtsp_url[i]));
}
for (int i = 0; i < play_rtsp_url.Count; i++)
{
Task.Run(() => DecodeRTSP(play_rtsp_url[i].index, matQueue[i], play_rtsp_url[i].url, taskCTS[i].Token));
System.Threading.Thread.Sleep(100);
}
//显示线程
Task.Run(() =>
{
Mat mat = new Mat();
string winName = "video";
Cv2.NamedWindow(winName, WindowFlags.Normal);
Cv2.ResizeWindow(winName, fullSize);
int delay = (int)(1000 / fps);
Stopwatch stopwatch = new Stopwatch();
while (true)
{
stopwatch.Restart();
delay = (int)(1000 / fps);
if (ctsShow.IsCancellationRequested) break;
Mat frame = CombiningImages();
Cv2.ImShow(winName, frame);
delay = (int)(delay - stopwatch.ElapsedMilliseconds);
if (delay <= 0)
{
delay = 1;
}
Console.WriteLine("delay:" + delay.ToString());
Cv2.WaitKey(delay);
frame.Dispose();
}
Cv2.DestroyAllWindows();
});
}
OpenCvSharp.Size fullSize = new OpenCvSharp.Size(1008, 570);
OpenCvSharp.Size mainSize = new OpenCvSharp.Size(672, 380);
OpenCvSharp.Size subSize = new OpenCvSharp.Size(336, 190);
Mat CombiningImages()
{
Console.WriteLine(string.Format("matQueue0:{0},matQueue1:{1},matQueue2:{2},matQueue3:{3},matQueue4:{4},matQueue5:{5}"
, matQueue[0].Count
, matQueue[1].Count
, matQueue[2].Count
, matQueue[3].Count
, matQueue[4].Count
, matQueue[5].Count
));
Mat mat = Mat.Zeros(fullSize, MatType.CV_8UC3);
Mat mat0 = new Mat();
matQueue[0].TryDequeue(out mat0);
if (mat0 == null || mat0.Empty())
{
mat0 = Mat.Zeros(mainSize, MatType.CV_8UC3);
}
Cv2.Resize(mat0, mat0, mainSize);
Mat mat1 = new Mat();
matQueue[1].TryDequeue(out mat1);
if (mat1 == null || mat1.Empty())
{
mat1 = Mat.Zeros(subSize, MatType.CV_8UC3);
}
Cv2.Resize(mat1, mat1, subSize);
Mat mat2 = new Mat();
matQueue[2].TryDequeue(out mat2);
if (mat2 == null || mat2.Empty())
{
mat2 = Mat.Zeros(subSize, MatType.CV_8UC3);
}
Cv2.Resize(mat2, mat2, subSize);
Mat mat3 = new Mat();
matQueue[3].TryDequeue(out mat3);
if (mat3 == null || mat3.Empty())
{
mat3 = Mat.Zeros(subSize, MatType.CV_8UC3);
}
Cv2.Resize(mat3, mat3, subSize);
Mat mat4 = new Mat();
matQueue[4].TryDequeue(out mat4);
if (mat4 == null || mat4.Empty())
{
mat4 = Mat.Zeros(subSize, MatType.CV_8UC3);
}
Cv2.Resize(mat4, mat4, subSize);
Mat mat5 = new Mat();
matQueue[5].TryDequeue(out mat5);
if (mat5 == null || mat5.Empty())
{
mat5 = Mat.Zeros(subSize, MatType.CV_8UC3);
}
Cv2.Resize(mat5, mat5, subSize);
//第一张主图
Rect roi0 = new Rect(0, 0, 672, 380);
Mat position0 = new Mat(mat, roi0);
mat0.CopyTo(position0);
//第二张图
Rect roi1 = new Rect(672, 0, 336, 190);
Mat position1 = new Mat(mat, roi1);
mat1.CopyTo(position1);
//第三张图
Rect roi2 = new Rect(672, 190, 336, 190);
Mat position2 = new Mat(mat, roi2);
mat2.CopyTo(position2);
//第4张图
Rect roi3 = new Rect(672, 380, 336, 190);
Mat position3 = new Mat(mat, roi3);
mat3.CopyTo(position3);
//第5张图
Rect roi4 = new Rect(336, 380, 336, 190);
Mat position4 = new Mat(mat, roi4);
mat4.CopyTo(position4);
//第6张图
Rect roi5 = new Rect(0, 380, 336, 190);
Mat position5 = new Mat(mat, roi5);
mat5.CopyTo(position5);
mat0.Dispose();
mat1.Dispose();
mat2.Dispose();
mat3.Dispose();
mat4.Dispose();
mat5.Dispose();
position0.Dispose();
position1.Dispose();
position2.Dispose();
position3.Dispose();
position4.Dispose();
position5.Dispose();
return mat;
}
void DecodeRTSP(string index, ConcurrentQueue<Mat> matQueue, string url, CancellationToken cancellationToken = default)
{
VideoCapture vcapture = new VideoCapture(url);
if (!vcapture.IsOpened())
{
Console.WriteLine("打开视频文件失败");
return;
}
// 计算等待时间(毫秒)
int taskDelay = (int)(1000 / fps);
Stopwatch stopwatch = new Stopwatch();
while (true)
{
if (cancellationToken.IsCancellationRequested) break;
stopwatch.Restart();
Mat frame = new Mat();
if (!vcapture.Read(frame))
{
Console.WriteLine("读取失败");
break;
}
taskDelay = (int)(1000 / fps);
//中间标注数字,模拟路数
Cv2.PutText(frame, index.ToString(), new OpenCvSharp.Point(frame.Width / 2, frame.Height / 2), HersheyFonts.HersheySimplex, 20, Scalar.Red, 20);
matQueue.Enqueue(frame);
taskDelay = (int)(taskDelay - stopwatch.ElapsedMilliseconds);
if (matQueue.Count > 100)
{
Console.WriteLine("index:" + index + ",后续处理能力不足……");
}
if (matQueue.Count < 10)
{
taskDelay = taskDelay - 5;
}
if (taskDelay <= 0)
{
taskDelay = 0;
}
Console.WriteLine("index:" + index + ",taskDelay:" + taskDelay);
Task.Delay(taskDelay).Wait();
}
vcapture.Release();
}
/// <summary>
/// 取消第一路
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
taskCTS[0].Cancel();
}
/// <summary>
/// 记载第7路
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
for (int i = 0; i < 6; i++)
{
taskCTS[i].Cancel();
}
for (int i = 0; i < 6; i++)
{
taskCTS[i] = new CancellationTokenSource();
}
//删除最后一个元素
play_rtsp_url.RemoveAt(play_rtsp_url.Count - 1);
//把第7路的地址 放到第一的位置
play_rtsp_url.Insert(0, new RTSPURLInfo("7", rtsp_url[6]));
for (int i = 0; i < play_rtsp_url.Count; i++)
{
Task.Run(() => DecodeRTSP(play_rtsp_url[i].index, matQueue[i], play_rtsp_url[i].url, taskCTS[i].Token));
System.Threading.Thread.Sleep(10);
}
}
/// <summary>
/// 加载第8路
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_Click(object sender, EventArgs e)
{
for (int i = 0; i < 6; i++)
{
taskCTS[i].Cancel();
}
for (int i = 0; i < 6; i++)
{
taskCTS[i] = new CancellationTokenSource();
}
//删除最后一个元素
play_rtsp_url.RemoveAt(play_rtsp_url.Count - 1);
//把第8路的地址 放到第一的位置
play_rtsp_url.Insert(0, new RTSPURLInfo("8", rtsp_url[7]));
for (int i = 0; i < play_rtsp_url.Count; i++)
{
Task.Run(() => DecodeRTSP(play_rtsp_url[i].index, matQueue[i], play_rtsp_url[i].url, taskCTS[i].Token));
System.Threading.Thread.Sleep(10);
}
}
}
public class RTSPURLInfo
{
public string index;
public string url;
public RTSPURLInfo(string index, string url)
{
this.index = index;
this.url = url;
}
}
}
using OpenCvSharp;using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.Diagnostics;using System.Threading;using System.Threading.Tasks;using System.Windows.Forms;namespace MultiVideoDemo{ public partial class Form4 : Form { public Form4() { InitializeComponent(); } CancellationTokenSource ctsShow; CancellationTokenSource[] taskCTS = new CancellationTokenSource[6]; ConcurrentQueue<Mat>[] matQueue = new ConcurrentQueue<Mat>[6]; int fps = 25; string[] rtsp_url = new string[40]; List<RTSPURLInfo> play_rtsp_url = new List<RTSPURLInfo>(); /// <summary> /// 停止 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, EventArgs e) { ctsShow.Cancel(); for (int i = 0; i < 6; i++) { taskCTS[i].Cancel(); } } private void Form1_Load(object sender, EventArgs e) { //初始化 for (int i = 0; i < 6; i++) { taskCTS[i] = new CancellationTokenSource(); matQueue[i] = new ConcurrentQueue<Mat>(); } for (int i = 0; i < 40; i++) { rtsp_url[i] = "1.dav"; } //play_rtsp_url for (int i = 0; i < 6; i++) { play_rtsp_url.Add(new RTSPURLInfo((i + 1).ToString(), rtsp_url[i])); } } /// <summary> /// 播放 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { ctsShow = new CancellationTokenSource(); for (int i = 0; i < 6; i++) { taskCTS[i] = new CancellationTokenSource(); matQueue[i] = new ConcurrentQueue<Mat>(); } play_rtsp_url.Clear(); for (int i = 0; i < 6; i++) { play_rtsp_url.Add(new RTSPURLInfo((i + 1).ToString(), rtsp_url[i])); } for (int i = 0; i < play_rtsp_url.Count; i++) { Task.Run(() => DecodeRTSP(play_rtsp_url[i].index, matQueue[i], play_rtsp_url[i].url, taskCTS[i].Token)); System.Threading.Thread.Sleep(100); } //显示线程 Task.Run(() => { Mat mat = new Mat(); string winName = "video"; Cv2.NamedWindow(winName, WindowFlags.Normal); Cv2.ResizeWindow(winName, fullSize); int delay = (int)(1000 / fps); Stopwatch stopwatch = new Stopwatch(); while (true) { stopwatch.Restart(); delay = (int)(1000 / fps); if (ctsShow.IsCancellationRequested) break; Mat frame = CombiningImages(); Cv2.ImShow(winName, frame); delay = (int)(delay - stopwatch.ElapsedMilliseconds); if (delay <= 0) { delay = 1; } Console.WriteLine("delay:" + delay.ToString()); Cv2.WaitKey(delay); frame.Dispose(); } Cv2.DestroyAllWindows(); }); } OpenCvSharp.Size fullSize = new OpenCvSharp.Size(1008, 570); OpenCvSharp.Size mainSize = new OpenCvSharp.Size(672, 380); OpenCvSharp.Size subSize = new OpenCvSharp.Size(336, 190); Mat CombiningImages() { Console.WriteLine(string.Format("matQueue0:{0},matQueue1:{1},matQueue2:{2},matQueue3:{3},matQueue4:{4},matQueue5:{5}" , matQueue[0].Count , matQueue[1].Count , matQueue[2].Count , matQueue[3].Count , matQueue[4].Count , matQueue[5].Count )); Mat mat = Mat.Zeros(fullSize, MatType.CV_8UC3); Mat mat0 = new Mat(); matQueue[0].TryDequeue(out mat0); if (mat0 == null || mat0.Empty()) { mat0 = Mat.Zeros(mainSize, MatType.CV_8UC3); } Cv2.Resize(mat0, mat0, mainSize); Mat mat1 = new Mat(); matQueue[1].TryDequeue(out mat1); if (mat1 == null || mat1.Empty()) { mat1 = Mat.Zeros(subSize, MatType.CV_8UC3); } Cv2.Resize(mat1, mat1, subSize); Mat mat2 = new Mat(); matQueue[2].TryDequeue(out mat2); if (mat2 == null || mat2.Empty()) { mat2 = Mat.Zeros(subSize, MatType.CV_8UC3); } Cv2.Resize(mat2, mat2, subSize); Mat mat3 = new Mat(); matQueue[3].TryDequeue(out mat3); if (mat3 == null || mat3.Empty()) { mat3 = Mat.Zeros(subSize, MatType.CV_8UC3); } Cv2.Resize(mat3, mat3, subSize); Mat mat4 = new Mat(); matQueue[4].TryDequeue(out mat4); if (mat4 == null || mat4.Empty()) { mat4 = Mat.Zeros(subSize, MatType.CV_8UC3); } Cv2.Resize(mat4, mat4, subSize); Mat mat5 = new Mat(); matQueue[5].TryDequeue(out mat5); if (mat5 == null || mat5.Empty()) { mat5 = Mat.Zeros(subSize, MatType.CV_8UC3); } Cv2.Resize(mat5, mat5, subSize); //第一张主图 Rect roi0 = new Rect(0, 0, 672, 380); Mat position0 = new Mat(mat, roi0); mat0.CopyTo(position0); //第二张图 Rect roi1 = new Rect(672, 0, 336, 190); Mat position1 = new Mat(mat, roi1); mat1.CopyTo(position1); //第三张图 Rect roi2 = new Rect(672, 190, 336, 190); Mat position2 = new Mat(mat, roi2); mat2.CopyTo(position2); //第4张图 Rect roi3 = new Rect(672, 380, 336, 190); Mat position3 = new Mat(mat, roi3); mat3.CopyTo(position3); //第5张图 Rect roi4 = new Rect(336, 380, 336, 190); Mat position4 = new Mat(mat, roi4); mat4.CopyTo(position4); //第6张图 Rect roi5 = new Rect(0, 380, 336, 190); Mat position5 = new Mat(mat, roi5); mat5.CopyTo(position5); mat0.Dispose(); mat1.Dispose(); mat2.Dispose(); mat3.Dispose(); mat4.Dispose(); mat5.Dispose(); position0.Dispose(); position1.Dispose(); position2.Dispose(); position3.Dispose(); position4.Dispose(); position5.Dispose(); return mat; } void DecodeRTSP(string index, ConcurrentQueue<Mat> matQueue, string url, CancellationToken cancellationToken = default) { VideoCapture vcapture = new VideoCapture(url); if (!vcapture.IsOpened()) { Console.WriteLine("打开视频文件失败"); return; } // 计算等待时间(毫秒) int taskDelay = (int)(1000 / fps); Stopwatch stopwatch = new Stopwatch(); while (true) { if (cancellationToken.IsCancellationRequested) break; stopwatch.Restart(); Mat frame = new Mat(); if (!vcapture.Read(frame)) { Console.WriteLine("读取失败"); break; } taskDelay = (int)(1000 / fps); //中间标注数字,模拟路数 Cv2.PutText(frame, index.ToString(), new OpenCvSharp.Point(frame.Width / 2, frame.Height / 2), HersheyFonts.HersheySimplex, 20, Scalar.Red, 20); matQueue.Enqueue(frame); taskDelay = (int)(taskDelay - stopwatch.ElapsedMilliseconds); if (matQueue.Count > 100) { Console.WriteLine("index:" + index + ",后续处理能力不足……"); } if (matQueue.Count < 10) { taskDelay = taskDelay - 5; } if (taskDelay <= 0) { taskDelay = 0; } Console.WriteLine("index:" + index + ",taskDelay:" + taskDelay); Task.Delay(taskDelay).Wait(); } vcapture.Release(); } /// <summary> /// 取消第一路 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button4_Click(object sender, EventArgs e) { taskCTS[0].Cancel(); } /// <summary> /// 记载第7路 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button3_Click(object sender, EventArgs e) { for (int i = 0; i < 6; i++) { taskCTS[i].Cancel(); } for (int i = 0; i < 6; i++) { taskCTS[i] = new CancellationTokenSource(); } //删除最后一个元素 play_rtsp_url.RemoveAt(play_rtsp_url.Count - 1); //把第7路的地址 放到第一的位置 play_rtsp_url.Insert(0, new RTSPURLInfo("7", rtsp_url[6])); for (int i = 0; i < play_rtsp_url.Count; i++) { Task.Run(() => DecodeRTSP(play_rtsp_url[i].index, matQueue[i], play_rtsp_url[i].url, taskCTS[i].Token)); System.Threading.Thread.Sleep(10); } } /// <summary> /// 加载第8路 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button5_Click(object sender, EventArgs e) { for (int i = 0; i < 6; i++) { taskCTS[i].Cancel(); } for (int i = 0; i < 6; i++) { taskCTS[i] = new CancellationTokenSource(); } //删除最后一个元素 play_rtsp_url.RemoveAt(play_rtsp_url.Count - 1); //把第8路的地址 放到第一的位置 play_rtsp_url.Insert(0, new RTSPURLInfo("8", rtsp_url[7])); for (int i = 0; i < play_rtsp_url.Count; i++) { Task.Run(() => DecodeRTSP(play_rtsp_url[i].index, matQueue[i], play_rtsp_url[i].url, taskCTS[i].Token)); System.Threading.Thread.Sleep(10); } } } public class RTSPURLInfo { public string index; public string url; public RTSPURLInfo(string index, string url) { this.index = index; this.url = url; } }}
下载
源码下载