ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

使用 SignalR 向前端推送图像

使用 SignalR 向前端推送图像
我的早期方案
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();}
}

 

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

 

返回列表