首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在ASP.NET核中将RTSP流从IP摄像机转发到浏览器

在ASP.NET核中将RTSP流从IP摄像机转发到浏览器
EN

Stack Overflow用户
提问于 2021-11-09 14:15:12
回答 1查看 4.9K关注 0票数 4

我有一个Blazor托管的应用程序,在这个应用程序中,我需要根据客户请求从轴摄像机(通过RTSP命令)获取一个h264记录,并以浏览器可以再现视频的方式返回它。如果在轴相机上查询录音列表,答案包括这个,我想在浏览器上播放的那个。

代码语言:javascript
运行
复制
    <recording diskid="SD_DISK" recordingid="20211109_122753_1AB3_B8A44F2D0300" starttime="2021-11-09T11:27:53.060281Z" starttimelocal="2021-11-09T12:27:53.060281+01:00" stoptime="2021-11-09T11:43:01.125987Z" stoptimelocal="2021-11-09T12:43:01.125987+01:00" recordingtype="continuous" eventid="continuous" eventtrigger="continuous" recordingstatus="completed" source="1" locked="No">
        <video mimetype="video/x-h264" width="800" height="600" framerate="15:1" resolution="800x600"/>
    </recording>

通过“开放网络流.”,我可以用VLC成功地再现录音。和打字

代码语言:javascript
运行
复制
rtsp://192.168.0.125/axis-media/media.amp?recordingid=20211109_140710_E1A3_B8A44F2D0300

然后提供用户名和密码,所以我确信命令是正确的。通过在url中嵌入用户名和密码,还可以使用项目播放录音,其中使用了我下面使用过的更简单的语法w.r.t,所以我的示例可能有点过于复杂。

服务器端--多亏了RtspClientSharp,我可以成功地检索流,但是我无法以正确的方式返回它。到目前为止我有这样的想法:

代码语言:javascript
运行
复制
[HttpGet("RecordingsDemo")]
    public async Task<IActionResult> RecordingsDemo() {
        string deviceIp = "rtsp://192.168.0.125";
        string recordingUri = "rtsp://192.168.0.125/axis-media/media.amp?recordingid=20211109_140710_E1A3_B8A44F2D0300";
        Uri playRequestUri = new Uri(recordingUri);

        CancellationTokenSource cts = new CancellationTokenSource();
        NetworkCredential networkCredential = new NetworkCredential("user", "password");
        ConnectionParameters connectionParameters = new ConnectionParameters(new Uri(deviceIp), networkCredential);
        RtspTcpTransportClient RtspTcpClient = new RtspTcpTransportClient(connectionParameters);
        await RtspTcpClient.ConnectAsync(cts.Token);

        RtspRequestMessage message = new RtspRequestMessage(RtspMethod.SETUP, playRequestUri);
        message.AddHeader("Transport", "RTP/AVP/TCP;unicast");
        RtspResponseMessage response = await RtspTcpClient.EnsureExecuteRequest(message, cts.Token);
        System.Collections.Specialized.NameValueCollection headers = response.Headers;
        string sessionId = headers["SESSION"];
        if (sessionId == null) { throw new Exception("RTSP initialization failed: no session id returned from SETUP command"); }
        message = new RtspRequestMessage(RtspMethod.PLAY, playRequestUri, sessionId);
        response = await RtspTcpClient.EnsureExecuteRequest(message, cts.Token);
        Stream stream = RtspTcpClient.GetStream();
        if (stream != null) {
            Response.Headers.Add("Cache-Control", "no-cache");
            FileStreamResult result = new FileStreamResult(stream, "video/x-h264") {
                EnableRangeProcessing = true
            };
            return result;
        } else {
            return new StatusCodeResult((int)HttpStatusCode.ServiceUnavailable);
        }
        return new StatusCodeResult((int)HttpStatusCode.OK);
    }

请注意,在上面的代码中,为了更快地构建构造函数,我向RtspRequestMessage添加了一个构造函数。特别是,我添加了以下代码:

代码语言:javascript
运行
复制
    public uint _lastCSeqUsed { get; private set; }

    /// <param name="method">SETUP, PLAY etc</param>
    /// <param name="connectionUri">rtsp://<servername>/axis-media/media.amp?recordingid=...</param>
    /// <param name="cSeq">Method that generate the sequence number. The receiver will reply with the same sequence number</param>
    /// <param name="protocolVersion">Default to 1.0 if omitted or null</param>
    /// <param name="userAgent">Doesn't matter really</param>
    /// <param name="session">This parameter has to be initialized with the value returned by the SETUP method</param>
    public RtspRequestMessage(RtspMethod method, Uri connectionUri, string session = "", Func<uint> cSeqProvider = null, 
        Version protocolVersion = null, string userAgent = "client")
        : base((protocolVersion != null) ? protocolVersion : new Version("1.0"))
    {
        Method = method;
        ConnectionUri = connectionUri;
        UserAgent = userAgent;

        _cSeqProvider = (cSeqProvider != null) ? cSeqProvider : myfun;
        CSeq = (cSeqProvider != null) ? _cSeqProvider() : 0;

        if (!string.IsNullOrEmpty(session))
            Headers.Add("Session", session);
    }

    public void AddHeader(string name, string value)
    {
        Headers.Add(name, value);
    }

    private uint myfun()
    {
        return ++CSeq;
    }

当客户端通过GET方法调用此方法时,我非常确定记录是正确检索的,查看频闪和Wireshark。您可以在下一张图片中看到Wireshark的输出,其中192.168.0.125是照相机,192.168.0.120是服务器。

但是,服务器返回的文件似乎不可播放。即使使用VLC,我也不能播放返回的文件或流。下一张图片显示了客户机-服务器通信,其中192.168.0.16是客户机,192.168.0.51是服务器。

我需要能够返回html5视频元素可以播放的流。

请你指出正确的方向好吗?谢谢

编辑::,如你所见,我找到了一种方法,贴在下面。但是,我希望有一个更好的解决方案,不需要在磁盘上写入,也不需要生成of.ts文件所增加的延迟。因此,如果有人愿意作出贡献,我就不提这个问题。

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69899709

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档