浏览器播放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);});}}}

下载

源码下载

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

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

相关文章

617. 合并二叉树

目录 一&#xff1a;题目&#xff1a; 二&#xff1a;代码&#xff1a; 三&#xff1a;结果&#xff1a; 一&#xff1a;题目&#xff1a; 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些…

捷达千里江山首发亮相,捷达品牌2024成都车展继续宠粉不停

2024年8月30日&#xff0c;捷达品牌携新车捷达千里江山惊艳亮相2024成都国际车展&#xff0c;并在五周年之际&#xff0c;发布幸福包油计划等宠粉福利&#xff0c;号召用户打卡千里江山&#xff0c;奔赴美好。与此同时&#xff0c;全新捷达VS5/VS7五周年纪念版车型进一步降低了…

H264码流结构讲解

所谓的码流结构就是指&#xff1a;视频经过编码之后所得到的数据是怎样排列的&#xff0c;换句话说&#xff0c;就是编码后的码流我们该如何将一帧一帧的数据分离开来&#xff0c;哪一块数据是一帧图像&#xff0c;哪一块是另外一帧图像&#xff0c;只要了解了这个&#xff0c;…

vue3是如何避免样式污染的?

众所周知&#xff0c;在vue中使用scoped可以避免父组件的样式渗透到子组件中。使用了scoped后会给html增加自定义属性data-v-x&#xff0c;同时会给组件内CSS选择器添加对应的属性选择器[data-v-x]。本文讲一下vue是如何给CSS选择器添加对应的属性选择器[data-v-x]。注&#xf…

JVM堆内存空间(heap)

在Java程序运行时&#xff0c;系统运行过程中产生的大部分实例对象以及数组对象都会被放到堆中存储。 默认情况下&#xff0c;如果不通过参数强制指定堆空间大小&#xff0c;那么JVM会根据当前所在的平台进行自适应调整&#xff0c;起始大小默认为当前物理机器内存的1/64&…

基于ssm+vue的汽车租赁管理系统

摘要 随着移动应用技术的发展&#xff0c;越来越多的用户借助于移动手机、电脑完成生活中的事务&#xff0c;许多的传统行业也更加重视与互联网的结合&#xff0c;以提高商家知名度和寻求更高的经济利益。针对传统汽车租赁系统&#xff0c;租赁信息、续租信息等问题&#xff0c…

【算法每日一练及解题思路】找出模式匹配字符串的异位词在原始字符串中出现的索引下标

【算法每日一练及解题思路】找出模式匹配字符串的异位词在原始字符串中出现的索引下标 一、题目&#xff1a;找出模式匹配字符串的异位词在原始字符串中出现的索引下标 二、举例&#xff1a; 两个字符串原始字符串initStr123sf3rtfb,模式匹配字符串regxf3s&#xff0c;找到模…

区域生长算法详解与Python实现

图像分割是计算机视觉中一个重要的任务&#xff0c;区域生长算法是其中的一种常见方法。本文将详细介绍区域生长算法的原理&#xff0c;并通过Python代码实现&#xff0c;带你一步步理解它的实际应用。 1. 区域生长算法简介 区域生长算法是一种基于像素相似性进行图像分割的方…

【方法论】读论文的三个层次,四个阶段,十个问题

学习资料 - 沈向洋十问 如何正确阅读一篇科研论文 阅读理解作者的意图&#xff0c;不同的阅读需求对应不同的阅读层次&#xff08;速读&#xff0c;精读&#xff0c;研读&#xff09; 速读&#xff1a;标题&#xff0c;引言&#xff0c;摘要&#xff0c;结论 文章要解决什么…

并发编程之定时任务定时线程池

并发编程之定时任务&定时线程池-CSDN博客

Upload-LABS通关攻略【1-20关】

Pass-01 第一关是前端JS绕过 上传一个php文件显示只能上传特定后缀名的文件 这里将1.php改为1.jpg直接进行抓包&#xff0c;在数据包中将jpg改为php放行 文件上传成功&#xff0c;邮件图片新建页面打开 可以访问到1.php文件&#xff0c;则一句话密码上传成功 使用蚁剑 进行连接…

六、vue进阶知识点

一、scoped解决样式冲突 默认情况:写在组件中的样式会 全局生效→ 因此很容易造成多个组件之间的样式冲突问题。 1.全局样式:默认组件中的样式会作用到全局 2.局部样式:可以给组件加上 scoped 属性,可以让样式只作用于当前组件scoped原理? 1.当前组件内标签都被添加 data-v-…

智慧猪场实训中心解决方案

一、引言 随着科技的飞速发展&#xff0c;传统养猪业正经历着前所未有的变革。为了提高养猪效率、降低生产成本并保障猪只健康&#xff0c;智慧养猪场的概念应运而生。唯众特此推出《智慧猪场实训中心解决方案》&#xff0c;旨在通过先进的技术与管理手段&#xff0c;为养猪业培…

RTA-OS Port Guide学习(一)-基于S32K324 OS

文章目录 前言OS Port的安装Port CharacteristicsParameters of ImplementationConfiguration ParametersStack used for C-startup(SpPreStartOS)Stack used when idle (SpStartOS)Stack overheads for ISR activation (SpIDisp)Stack overheads for ECC tasks (SpECC)Stack o…

uniapp uni-popup底部弹框留白 底部颜色修改 滚动穿刺

做底部弹框的时候&#xff0c;可能出现以下场景需要处理。 一、出现底部留白不是白色&#xff0c;需要修改颜色的时候&#xff1a; 1、如果弹框不需要圆角效果&#xff0c;则在uni-popup加上背景色就行&#xff0c;弹框是个直角样式&#xff1a; 2、如果需要圆角效果&#xff0…

vue3本地运行错误集

1、解决报错ValidationError: Progress Plugin Invalid Options问题 ValidationError: Progress Plugin Invalid Optionsoptions should NOT have additional propertiesoptions should NOT have additional propertiesoptions should NOT have additional propertiesoptions …

「Claude3.5」全面超越「gpt-4o」,我用它做了个贪吃蛇,玩了一整天!

大家好&#xff0c;我是凡人。 就在昨天晚上Anthropic在X上连续发了4条动态来高调宣布他们的Claude 3.5 Sonnet中杯的版本已经全面向公众开放使用&#xff0c;大批的技术博主连夜测试&#xff0c;纷纷给出的不低的评价。 而这还仅仅是开胃小菜&#xff0c;官方宣称今年晚些时候…

苹果mac数据恢复概率大吗 mac数据恢复专业软件哪个好用

一般情况下&#xff0c;当我们把电脑中的数据删掉后&#xff0c;都会保存在回收站里面&#xff0c;但如果回收站被清空了或者数据在回收站中没有找到的话&#xff0c;那么&#xff0c;之前被删掉的数据还能恢复吗&#xff1f;恢复的概率有多大呢&#xff1f; 答案是可以的&…

【微服务】限流、熔断和降级(持续更新中~)

1、限流 1.1 什么是限流 限流&#xff08;Rate Limiting&#xff09;是一种常用的技术手段&#xff0c;用于控制系统对资源的访问速率&#xff0c;确保系统的稳定性和可靠性。在分布式系统、Web服务、API接口等场景中&#xff0c;限流尤为重要。通过限制请求的频率或数量&…

每天五分钟计算机视觉:人脸识别网络FaceNet

本文重点 在前面的课程中,为了解决人脸识别的问题,我们学习了Siamese神经网络。本文我们学习另外一种人脸识别网络模型FaceNet。 论文 FaceNet: A Unified Embedding for Face Recognition and Clustering FaceNet概述 FaceNet是谷歌在CVPR 2015上提出的一种深度学习模型,…