转发 multipart/x-mixed-replace 直播 ASP.NET Core

问题描述 投票:0回答:1

我有一个 ASP.NET Core 服务器,根据客户端请求,开始从 AXIS 摄像机获取流并将其返回给客户端进行显示。如果浏览器直接通过 img src 属性向服务器发出 http 请求,则可以正常工作。但如果我使用 HttpClient (因为我需要 CancellationToken,所以我需要这样做),httpClient.GetStreamAsync 指令就会卡住,我无法解析返回的数据。

服务器端控制器(取自此处):

[ApiController]
[Route("[controller]")]
public class CameraSystemController : ControllerBase
{
    private string _contentTypeStreaming = "multipart/x-mixed-replace;boundary=myboundary";
    private HttpClient _httpClient = new HttpClient(new HttpClientHandler { Credentials = ...});

    [HttpGet("getStream")]
    public async Task<IActionResult> GetStream(CancellationToken token)
    {
        Stream stream = await _httpClient.GetStreamAsync("http://.../axis-cgi/mjpg/video.cgi?resolution=800x600&compression=50", token);
        if (stream != null) {
            FileStreamResult result = new FileStreamResult(stream, _contentTypeStreaming) {
                EnableRangeProcessing = true
            };
            return result;
        } else {
            return new StatusCodeResult((int)HttpStatusCode.ServiceUnavailable);
        }
    }
}

现在,正如我所说,我只要让浏览器通过

的方式执行http请求
// LiveCamera.razor
<img src="CameraSystem/getStream" onerror="@OnImgLoadingError" alt="">

相机在实时模式下获取的数据可以正确显示在浏览器中。 如果我以这种方式在客户端发出请求:

//LiveCamera.razor.cs
[Inject] public HttpClient Http { get; private set; }
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();

private async void StartStreamingRequest(object sender, ElapsedEventArgs e) {
    Console.WriteLine("I'm about to request live stream");
    Stream responseStream = await Http.GetStreamAsync("CameraSystem/getStream", _cancellationTokenSource.Token);
    Console.WriteLine("Header found!");
    string boundary = "myboundary";
    for (MultipartReader streamReader = new MultipartReader(boundary, responseStream); ;) {
        MultipartSection nextFrame = await streamReader.ReadNextSectionAsync(_cancellationTokenSource.Token);
        DisplayOneFrameCallback(nextFrame.Body);
    }
}

private void DisplayOneFrameCallback(Stream body)
{
    StreamReader reader = new StreamReader(body);
    string frameData = reader.ReadToEnd();
    _imgSrc = "data:image/jpeg;base64," + frameData;
    StateHasChanged();
}

在这一秒的情况下,请求正确执行(服务器端我可以看到执行的代码,从任务管理器我可以看到带宽使用量增加),但客户端卡在等待指令上,并且后续代码永远不会执行。现在,在Microsoft文档中的GetStreamAsync下可以阅读

此操作不会阻塞。返回的任务对象将在读取响应标头后完成。此方法不读取也不缓冲响应正文。

所以我希望它不会阻塞。因此,我认为我在服务器端生成的标头可能存在问题,即使浏览器请求工作得很好。

出于好奇,我用 Wireshark 捕获了摄像头和服务器之间的数据。 header 和 body 的初始部分是这样的:

..-...HTTP/1.0 200 OK..Cache-Control:无缓存..Pragma:无缓存..过期:1994 年 12 月 1 日星期四 16:00:00 GMT..连接:关闭..内容类型:multipart/x-mixed-replace;boundary=myboundary....--myboundary..内容类型:image/jpeg..内容长度:30146......

我已经使用浏览器开发人员工具进行了仔细检查,我可以确认从浏览器或从 httpClient 发送请求会产生完全相同的请求。此外,右键单击请求 URL 并发出“在新选项卡中打开”会打开一个选项卡,在这两种情况下我都可以在其中看到摄像头实时流。

你能帮我吗?

c# asp.net-core streaming blazor-webassembly ip-camera
1个回答
0
投票

我来到这个主题寻求帮助,我设法解决如下:

 [HttpGet("video4")]
 public async Task<IActionResult> Video4(HttpClient httpClient, CancellationToken cancellationToken)
 {
     try
     {
         var response = await httpClient.GetAsync("http://original.video.path/", HttpCompletionOption.ResponseHeadersRead, cancellationToken);
         Response.ContentType = response.Content.Headers.ContentType?.ToString();
         using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);

         await stream.CopyToAsync(Response.Body, 16 * 1024, cancellationToken);
         await Response.Body.FlushAsync(cancellationToken);
     }
     catch (OperationCanceledException){}
     return new EmptyResult();
 }

我使用的是net7。

我所有事情都是异步完成的。

HttpClient 已通过依赖注入提供。

从请求中重用CancellationToken。

© www.soinside.com 2019 - 2024. All rights reserved.