使用 SignalR 向前端推送图像

news/2025/9/27 20:46:44/文章来源:https://www.cnblogs.com/cchong005/p/19115645
我的早期方案
public class VideoService
{const string VideoFilePath = "D:\\Users\\xx\\Desktop\\";/// <summary>/// 运行中/// </summary>public bool IsRunning { get; private set; } = false;object locker = new();CancellationTokenSource cts = new();Memory<byte>? _memoryCache;/// <summary>/// 图片base64;/// </summary>public string ImageBase64 => _memoryCache == null ? "" : Convert.ToBase64String(_memoryCache.Value.Span);/// <summary>/// 启动/// </summary>public void Startup(){if (IsRunning) return;Monitor.Enter(locker);Task.Factory.StartNew(() =>{IsRunning = true;int index = 1;while (!cts.Token.IsCancellationRequested){// 长时间运行的逻辑string filePath = Path.Combine(VideoFilePath, $"{index}.jpg");if (index >= 2) index = 1; else index++;if (File.Exists(filePath)){var bytesRead = File.ReadAllBytes(filePath);_memoryCache = new Memory<byte>(bytesRead, 0, bytesRead.Length);}}}, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap().ContinueWith(t => {IsRunning = false;cts = new();Monitor.Exit(locker);});}/// <summary>/// 关闭/// </summary>public void Shutdown(){if (!IsRunning) return;cts.Cancel();}
}

然后从前端轮询 ImageBase64;这样的结果是图像非常不连贯

 

改造后使用  SignalR 向前端推送;

依赖 Microsoft.AspNetCore.SignalR 和 Microsoft.AspNetCore.SignalR.Client ; 在 nuget 下载

1 创建一个 Hub

/// <summary>
/// 主要用来映射连接端点
/// </summary>
public class VideoStreamHub : Hub
{// 可以在这里实现客户端连接管理
}

2 启用 SignalR 服务,并注册端点

image

3 改造 service

public class VideoService
{const string VideoFilePath = "D:\\Users\\xx\\Desktop\\";private readonly IHubContext<VideoStreamHub> _hubContext;public VideoService(IHubContext<VideoStreamHub> hubContext){_hubContext = hubContext;}/// <summary>/// 运行中/// </summary>public bool IsRunning { get; private set; } = false;object locker = new();CancellationTokenSource cts = new();Memory<byte>? _memoryCache;/// <summary>/// 图片base64;/// </summary>public string ImageBase64 => _memoryCache == null ? "" : Convert.ToBase64String(_memoryCache.Value.Span);/// <summary>/// 启动/// </summary>public void Startup(){if (IsRunning) return;Monitor.Enter(locker);cts = new();Task.Factory.StartNew(async () =>{IsRunning = true;int index = 1;while (!cts.Token.IsCancellationRequested){// 长时间运行的逻辑string filePath = Path.Combine(VideoFilePath, $"{index}.jpg");if (index >= 2) index = 1; else index++;if (File.Exists(filePath)){var bytesRead = File.ReadAllBytes(filePath);await _hubContext.Clients.All.SendAsync("ReceiveFrame", Convert.ToBase64String(bytesRead), cts.Token);  // 向前端的接收方法推送流}await Task.Delay(30, cts.Token);}cts.Token.ThrowIfCancellationRequested();}, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap().ContinueWith(t => {if (cts.Token.IsCancellationRequested){IsRunning = false;Monitor.Exit(locker);}});}/// <summary>/// 关闭/// </summary>public void Shutdown(){if (!IsRunning) return;cts.Cancel();}
}

 

4 前端注册接收方法

@page "/"
@using BlazorAppVideo.Services
@using Microsoft.AspNetCore.SignalR.Client
@inject VideoService _VideoService
@implements IDisposable
@inject NavigationManager NavManager<PageTitle>Home</PageTitle>
<img src="@currentFrame" alt="Blazor logo" />@code {string currentFrame { get; set; } = string.Empty;private HubConnection? hubConnection;CancellationTokenSource source = new();protected override async Task OnAfterRenderAsync(bool firstRender){await base.OnAfterRenderAsync(firstRender);if (firstRender){// 启动视频服务
            _VideoService.Startup();// 创建SignalR连接hubConnection = new HubConnectionBuilder().WithUrl(NavManager.ToAbsoluteUri("/videoStreamHub")).Build();// 注册接收帧的处理方法hubConnection.On<string>("ReceiveFrame", (frame) =>{currentFrame = $"data:image/jpeg;base64,{frame}";InvokeAsync(StateHasChanged);       // 接收到新帧后更新UI
            });await hubConnection.StartAsync();}}public void Dispose(){hubConnection?.DisposeAsync();}
}

 

 改造后图像非常连贯,可用于视觉项目,从服务端推送采集的图像到前端

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/919921.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

英文网站建设szjijie云溪网络建站宝盒

Playables 一、Playable Director&#xff1a;是一种用于控制和管理剧情、动画和音频的工具。它作为一个中央控制器&#xff0c;可以管理播放动画剧情、视频剧情和音频剧情&#xff0c;以及它们之间的时间、顺序和交互。 Playable Director组件具有以下作用&#xff1a; 剧情控…

高新西区网站建设网页设计作业保护动物

目录 90、简述一下你了解的设计模式。 91、用 Java 写一个单例类。 92、什么是 UML&#xff1f; 93、UML 中有哪些常用的图&#xff1f; 94、用 Java 写一个冒泡排序。 95、用 Java 写一个折半查找。 90、简述一下你了解的设计模式。 所谓设计模式&#xff0c;就是一套被…

C# WPF实现ComboBox实时搜索与数据绑定 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

隐私保护与联邦学习文献阅读

导读《Federated Machine Learning: Concept and Applications》《A Comprehensive Survey of Privacy-preserving Federated Learning》本文主要对上面两篇联邦学习(FL)综述文章进行了概括总结。 1、FL概念与分类FL的…

Java实习模拟面试|离散数学|概率论|金融英语|数据库实战|职业规划|期末冲刺|今日本科计科要闻速递:技术分享与学习指南 - 实践

Java实习模拟面试|离散数学|概率论|金融英语|数据库实战|职业规划|期末冲刺|今日本科计科要闻速递:技术分享与学习指南 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !…

飞扬动力网站建设wordpress管理主体

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件&#xff0c;仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数)&#xff1a;693 标注数量(xml文件个数)&#xff1a;693 标注类别数&#xff1a;6 标注类别名称:["missing_hole",…

2025.9.27

这场比赛还行吧...考的还不错,T1,T2没挂,T3不会,下面给个题解 显然按 \(b_i\) 从大到小选,因为这样减的最少,而因为我们认为他们是有用的,所以不用考虑 \(c_i\) 的限制。因为如果超了,我们不 如把它们扔出去。于…

深入解析:用 Spring Boot 打造 Docker 和 K8s 部署的硬核指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

9.27(课后作业

package com.itheima.arithmeticoperstor; public class Enum { //枚举 enum Size{SMALL,MEDIUM,LARGE}; //直接引用枚举值 Size s=Size.SMALL; //通过字符串获取枚举值 Size t=Size.valueOf("SMALL"); //定…

详细介绍:【序列晋升】45 Spring Data Elasticsearch 实战:3 个核心方案破解索引管理与复杂查询痛点,告别低效开发

详细介绍:【序列晋升】45 Spring Data Elasticsearch 实战:3 个核心方案破解索引管理与复杂查询痛点,告别低效开发pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important…

天津放心站内优化seops网页制作素材

转自 https://www.cnblogs.com/liuqiyun/p/8133904.html

做手机网站多少钱浏览器如何做购物网站

这是一个基于纯css实现的3D立体视觉效果鸡蛋动画特效&#xff0c;喜欢的朋友可以拿来使用演示动态效果 css实现的3D立体视觉效果鸡蛋动画特效

临沂做网站需要多少钱wordpress刷新才显示

乘着今天中午的时间 对以前项目的一个需求进行一定的处理 前天去了甲方公司 接到了了一个新的需求 就是可以把项目的一个富文本的编辑器可以设置为能够上传视频 于是乎 就要对vue里面的这个组件进行操作了 首先我们可以看一眼官网的文档 需要用到的就直接到官网文档进行查询即可…

jsp网站开发实现增删改查中国招聘网

在作图中&#xff0c;我们需要根据自己的业务来更改x轴y轴的标签。注意&#xff0c;坐标轴的修改已经不算做画图了&#xff0c;因为他不是图上的线条或轨迹(trace)了&#xff0c;所以用layout来设置。1>显示或者不显示坐标轴标签。fig.update_layout(xaxis dict(visible Fa…

个人网站备案电话访谈wordpress 字体类型

记一下第十二节课的内容。 一、PHP文件包含的四种方式 Include和Include_once 操作系统会读取包含的文件的内容&#xff0c;并将它插入主文件中&#xff0c;include方式的文件包含会在包含失败的情况下输出警告信息&#xff0c;而include_once方式会检查包含的文件是否已经被…

四则运算和验证码

四则运算的代码 package bb; import java.util.Random; public class Sizeyunsuan { public static void main(String[] args) { Random random=new Random(); for(int i=1;i<=30;i++) { int num1=random.nextInt(1…

博客写作者该何去何从

时代的改变 作为一个7年的博客创作者,随着AI时代的来临,我基本很少更新博客,一是用户对博客文章的需求减少了,二是我写的文章还不一定有AI写得好。而且现在各种新兴AI写作工具崛起,我觉得像之前那样码子好傻 好低…

第一次课动手动脑合集

1.EnumTest.java EnumTest.java中定义了枚举Size,该枚举包含SMALL、MEDIUM、LARGE三个常量。其运行结果体现了枚举的多项核心特性: 当用引用比较枚举变量s(Size.SMALL)与t(Size.LARGE)时,结果为false,这是因为…

JSON dump in Ruby

In Ruby, the json library’s API differs from Python’s json.dump. The equivalent in Ruby would be something like this:require jsondata = {name: "Christopher",message: "こんにちは世界&qu…