当前位置: 首页 > news >正文

浏览器播放RTSP流,支持H264、H265等格式,支持IE、Chrome等浏览器

目录

背景

解决方案

效果

代码

前端代码

后端代码

下载


背景

项目中需要在浏览器中播放RTSP流,实在是不想折腾ActiveX控件

1、麻烦(开发麻烦、使用时设置也麻烦)

2、非IE浏览器不兼容

解决方案

使用OpenCvSharp+Nancy写一个解码服务,提供http接口,返回解码后Mat对象的Base64字符串,前端页面循环调用并展示。

效果

浏览器播放RTSP流

代码

前端代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>rtsp播放测试</title>
    <link rel="stylesheet" href="bootstrap.min.css" />
    <script src="jquery-1.8.0.js" type="text/javascript"></script>
</head>
<body>
    <div class="container">
        <br />
        <div class="row">
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <span class="label label-primary">rtsp播放测试</span>
                    <br />
                </div>
                <div class="panel-body">
                    <input type="text" value="" id="txtRTSPURL" style="width: 500px;" /><br />
                    <br />
                    <input type="button" value="打开" id="btnOpen" />
                    <input type="button" value="播放" id="btnPlay" />
                    <input type="button" value="停止" id="btnStop" />
                    <input type="button" value="测试获取一帧" id="btnTest" />
                    </br> </br>
                    <img id="imgId" src="" style="width: 1024px" />
                </div>
            </div>
        </div>
    </div>
</body>
<script type="text/jscript">


    $(function () {

        $("#btnOpen").click(function () {
            var rtsp_url = $("#txtRTSPURL").val();
            $.ajax({
                type: "post",
                url: base_url + "/open",
                dataType: 'json',
                data: { "rtsp_url": rtsp_url },
                success: function (d) {
                    if (d.code == 1) {
                        alert("打开成功")
                    } else {
                        alert("打开失败:" + d.message)
                    }
                }
            })

        })


        $("#btnTest").click(function () {

            $.ajax({
                type: "post",
                url: base_url + "/getframe",
                dataType: 'json',
                data: "",
                success: function (d) {
                    if (d.code == 1) {
                        console.log(d.data);
                        $("#imgId").attr("src", "data:image/jpg;base64," + d.data);

                    } else {
                        alert("播放失败:" + d.message)
                    }
                }
            })

        })

        $("#btnPlay").click(function () {

            try {
                flag = true;
                showImage();
            } catch (e) {
            }

        })

        $("#btnStop").click(function () {
            flag = false;
            $.ajax({
                type: "post",
                url: base_url + "/close",
                dataType: 'json',
                data: "",
                success: function (d) {
                    if (d.code == 1) {

                    } else {
                        alert("关闭失败:" + d.message)
                    }
                }
            })
        })

    })

    var base_url = "http://127.0.0.1:8082";
    var flag = false;

    function showImage() {
        $.ajax({
            type: "post",
            url: base_url + "/getframe",
            dataType: 'json',
            data: "",
            success: function (d) {
                if (d.code == 1) {
                    $("#imgId").attr("src", "data:image/jpg;base64," + d.data);
                    if (flag) {
                        showImage();
                    }
                } else {
                    alert("播放失败:" + d.message)
                }
            }
        })

    }

</script>
</html>

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8" /><title>rtsp播放测试</title><link rel="stylesheet" href="bootstrap.min.css" /><script src="jquery-1.8.0.js" type="text/javascript"></script>
</head>
<body><div class="container"><br /><div class="row"><div class="panel panel-primary"><div class="panel-heading"><span class="label label-primary">rtsp播放测试</span><br /></div><div class="panel-body"><input type="text" value="" id="txtRTSPURL" style="width: 500px;" /><br /><br /><input type="button" value="打开" id="btnOpen" /><input type="button" value="播放" id="btnPlay" /><input type="button" value="停止" id="btnStop" /><input type="button" value="测试获取一帧" id="btnTest" /></br> </br><img id="imgId" src="" style="width: 1024px" /></div></div></div></div>
</body>
<script type="text/jscript">$(function () {$("#btnOpen").click(function () {var rtsp_url = $("#txtRTSPURL").val();$.ajax({type: "post",url: base_url + "/open",dataType: 'json',data: { "rtsp_url": rtsp_url },success: function (d) {if (d.code == 1) {alert("打开成功")} else {alert("打开失败:" + d.message)}}})})$("#btnTest").click(function () {$.ajax({type: "post",url: base_url + "/getframe",dataType: 'json',data: "",success: function (d) {if (d.code == 1) {console.log(d.data);$("#imgId").attr("src", "data:image/jpg;base64," + d.data);} else {alert("播放失败:" + d.message)}}})})$("#btnPlay").click(function () {try {flag = true;showImage();} catch (e) {}})$("#btnStop").click(function () {flag = false;$.ajax({type: "post",url: base_url + "/close",dataType: 'json',data: "",success: function (d) {if (d.code == 1) {} else {alert("关闭失败:" + d.message)}}})})})var base_url = "http://127.0.0.1:8082";var flag = false;function showImage() {$.ajax({type: "post",url: base_url + "/getframe",dataType: 'json',data: "",success: function (d) {if (d.code == 1) {$("#imgId").attr("src", "data:image/jpg;base64," + d.data);if (flag) {showImage();}} else {alert("播放失败:" + d.message)}}})}</script>
</html>

后端代码

using Nancy;
using Newtonsoft.Json;
using NLog;
using OpenCvSharp;
using OpenVINO.OCRService.Common;
using System;
using System.Threading;
using System.Threading.Tasks;namespace CaptureService
{public class CaptureModule : NancyModule{private Logger _log = NLog.LogManager.GetCurrentClassLogger();public static readonly object _locker = new object();public CaptureModule(){//跨域处理After.AddItemToEndOfPipeline((ctx) => ctx.Response.WithHeader("Access-Control-Allow-Origin", "*").WithHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS").WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type"));Get("/", p =>{return "Hello MediaCaptureService";});Post("/open", p =>{AjaxReturn ar = new AjaxReturn();if (Program.open){ar.code = 0;ar.message = "已开启,如需重新开启,请先关闭!";_log.Info(JsonConvert.SerializeObject(ar));return Response.AsJson<AjaxReturn>(ar);}string rtsp_url = Request.Form["rtsp_url"];if (string.IsNullOrEmpty(rtsp_url)){ar.code = 0;ar.message = "参数[rtsp_url]不能为空";_log.Info(JsonConvert.SerializeObject(ar));return Response.AsJson<AjaxReturn>(ar);}Program.rtsp_url = rtsp_url;Program.ctsCapture = new CancellationTokenSource();Program.open = true;try{Task.Factory.StartNew(() =>{Program.capture = new VideoCapture(Program.rtsp_url);if (Program.capture.IsOpened()){int index = 0;Mat frame = new Mat();while (true){if (Program.ctsCapture.IsCancellationRequested) break;Program.capture.Read(frame);if (Program.matQueue.Count >= 5){continue;}Program.matQueue.Enqueue(frame);//_log.Info(Program.matQueue.Count);//Cv2.ImWrite(index + ".jpg", frame);//index++;}if (Program.capture != null){Program.capture.Release();}}});ar.code = 1;ar.message = "success";}catch (Exception ex){ar.code = 0;ar.message = ex.Message;_log.Error(ex, "开启异常");}return Response.AsJson<AjaxReturn>(ar);});Post("/close", p =>{AjaxReturn ar = new AjaxReturn();try{Program.open = false;if (Program.ctsCapture != null){Program.ctsCapture.Cancel();}ar.code = 1;ar.message = "success";}catch (Exception ex){ar.code = 0;ar.message = ex.Message;_log.Error(ex, "关闭异常");}return Response.AsJson<AjaxReturn>(ar);});Post("/getframe", p =>{AjaxReturn ar = new AjaxReturn();if (!Program.open){ar.code = 0;ar.message = "网络流未打开,请先打开!";_log.Info(JsonConvert.SerializeObject(ar));return Response.AsJson<AjaxReturn>(ar);}if (Program.matQueue.Count == 0){ar.code = 1;ar.message = "图像队列为空";_log.Info(JsonConvert.SerializeObject(ar));return Response.AsJson<AjaxReturn>(ar);}try{Mat frame = new Mat();if (!Program.matQueue.TryDequeue(out frame)){ar.code = 0;ar.message = "获取图像失败";_log.Info(JsonConvert.SerializeObject(ar));return Response.AsJson<AjaxReturn>(ar);}ar.code = 1;ar.message = "success";var bytes = frame.ToBytes();ar.data = Convert.ToBase64String(bytes);}catch (Exception ex){ar.code = 0;ar.message = ex.Message;_log.Error(ex, "获取摄像头画面异常");}return Response.AsJson<AjaxReturn>(ar);});}}}

下载

源码下载

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 六、vue进阶知识点
  • 安防监控/软硬一体/视频汇聚网关EasyCVR硬件启动崩溃是什么原因?
  • Centos7.x安装grafana11
  • Spring框架;Spring中IOC简介及搭建;Spring中AOP简介;
  • Unity 3D学习资料集合
  • 英文缩写大全(IT领域和电子行业制造领域)
  • AI游戏革命!谷歌推出GameNGen,实时生成游戏画面,每秒20帧实时模拟
  • 浅谈通信协议设计
  • 线性约束最小方差准则(LCMV)波束形成算法及MATLAB深入仿真分析
  • 9.1写论文
  • JavaSE-递归法解决二分查找、快速排序
  • Qt:玩转QPainter后转之太极图
  • 蓝色炫酷碎粒子HTML5导航源码
  • go to + 名词 - go to the + 名词
  • shell了解和问答机制
  • 【Linux系统编程】快速查找errno错误码信息
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • Android组件 - 收藏集 - 掘金
  • chrome扩展demo1-小时钟
  • django开发-定时任务的使用
  • Quartz初级教程
  • Sass Day-01
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • Unix命令
  • Vue.js-Day01
  • 二维平面内的碰撞检测【一】
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 记录一下第一次使用npm
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 面试遇到的一些题
  • 前端设计模式
  • 嵌入式文件系统
  • 区块链分支循环
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 如何优雅地使用 Sublime Text
  • 小程序button引导用户授权
  • 一天一个设计模式之JS实现——适配器模式
  • 《天龙八部3D》Unity技术方案揭秘
  • 数据库巡检项
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (ISPRS,2021)具有遥感知识图谱的鲁棒深度对齐网络用于零样本和广义零样本遥感图像场景分类
  • (二)【Jmeter】专栏实战项目靶场drupal部署
  • (力扣题库)跳跃游戏II(c++)
  • (生成器)yield与(迭代器)generator
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • *2 echo、printf、mkdir命令的应用
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .NET Project Open Day(2011.11.13)
  • .NET牛人应该知道些什么(2):中级.NET开发人员
  • .pub是什么文件_Rust 模块和文件 - 「译」
  • .so文件(linux系统)
  • /usr/bin/env: node: No such file or directory
  • @ComponentScan比较
  • [ Python ]使用Charles对Python程序发出的Get与Post请求抓包-解决Python程序报错问题