rtsp+rtmp多路流媒体播放
一、前言
之前博主有写过 一篇博文,讲的是使用videojs在谷歌浏览器网页上播放rtmp流媒体,具体可参考我之前的博客:https://www.cnblogs.com/FHC1994/p/9981440.html
最近又开始研究了一下网页播放流媒体,在这里我主要补充一些播放rtmp、rtsp流媒体的其他方法
二、rtsp和rtmp流媒体
2.1 视频传输原理
从网络上接收视频时首先需要要解协议(RTSP/RTMP/HTTP),然后是解格式(MKV,RMVB),之后才是将视频(H264)和音频(AAC)格式数据分别解码为图像(RGB/YUV)和声音(PCM),再根据时间戳同步播放
2.2 RTSP和RTMP介绍

RTSP(Real Time Streaming Protocol),RFC2326,实时流传输协议,是TCP/IP协议体系中的一个应用层协议,由哥伦比亚大学、网景和RealNetworks公司提交的IETF RFC标准。该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP在体系结构上位于RTP和RTCP之上,它使用TCP或UDP完成数据传输。目前多数网络摄像机支持RTSP、ONVIF等通用的协议,而支持RTMP比较少
RTMP是Real Time Messaging Protocol(实时消息传输协议)的首字母缩写。该协议基于TCP,是一个协议族,包括RTMP基本协议及RTMPT/RTMPS/RTMPE等多种变种。RTMP是一种设计用来进行实时数据通信的网络协议,主要用来在Flash/AIR平台和支持RTMP协议的流媒体/交互服务器之间进行音视频和数据通信。支持该协议的软件包括Adobe Media Server/Ultrant Media Server/red5等。使用RTMP技术的流媒体系统有一个非常明显的特点:使用 Flash Player 作为播放器客户端,而Flash Player 现在已经安装在了全世界将近99%的PC上,因此一般情况下收看RTMP流媒体系统的视音频是不需要安装插件的。用户只需要打开网页,就可以直接收看流媒体,十分方便。直播服务普遍采用了RTMP作为流媒体协议,FLV作为封装格式,H.264作为视频编码格式,AAC作为音频编码格式。FLV是RTMP使用的封装格式,H.264是当今实际应用中编码效率最高的视频编码标准,AAC则是当今实际应用中编码效率最高的音频编码标准。
RTSP和RTMP是2种不同的网络传输协议,RTSP(Real Time Streaming Protocol)是实时流传输协议,而RTMP是Real Time Messaging Protocol(实时消息传输协议)。RTSP主要用于IPTV,原因是传输数据使用的是UDP,在网络环境比较稳定的情况下,传输效率是比较高的。RTMP主要用于互联网音视频传输,它使用的是TCP传输,因为互联网环境相对较差,采用RTMP保证了视频的传输质量,但是其传输延迟相对较高,传输效率相对较低
参考:https://blog.csdn.net/liujiayu2/article/details/80658395
https://blog.csdn.net/leixiaohua1020/article/details/18893769 (视音频编解码技术,推荐)
2.3 补充
RTSP直播源地址:
rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov
三、rtsp、rtmp播放方法
3.1 videojs播放rtmp流媒体——videojs不支持rtsp——仅支持在Hbuilder等自带服务器环境下打开才可以播放rtmp
代码如下:
<!-- 播放rtmp网络视频 -->
<!DOCTYPE html>
<html>
<head>
<title>播放器</title>
<link href="./videolib/css/video-js.min.css" rel="stylesheet" type="text/css">
<style>
html,body{
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<div>
<video id="myvideo1" width="350" height="250" class="video-js vjs-default-skin" muted controls>
<!-- rtmp视频流 -->
<source src="rtmp://202.69.69.180:443/webcast/bshdlive-pc" type="rtmp/flv">
</video>
<br />
<video id="myvideo2" width="350" height="250" class="video-js vjs-default-skin" muted controls>
<!-- rtmp视频流 -->
<source src="rtmp://media3.sinovision.net:1935/live/livestream" type="rtmp/flv">
</video>
</div>
<script src="./videolib/js/video.min.js"></script>
<script src="./videolib/videojs-flash.min.js"> </script>
<script>
var player1 = videojs("myvideo1", {}, function() {
console.log("videojs播放器初始化成功")
})
player1.play()
var player2 = videojs("myvideo2", {}, function() {
console.log("videojs播放器初始化成功")
})
player2.play()
</script>
</body>
</html>
效果:

3.2 flowplayerjs播放rtmp流媒体——flowplayerjs不支持rtsp——支持在本地直接打开播放rtmp
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>rtmp直播</title>
<link rel="stylesheet" href="./css/video-js.css">
<link rel="stylesheet" href="./css/h5splayer.css">
<script src="./js/flowplayer-3.2.13.min.js"></script>
</head>
<body>
<div class="h5video" id="playerDiv1" style="float: left;"></div>
<div class="h5video" id="playerDiv2" style="float: left;"></div>
<div class="h5video" id="playerDiv3" style="float: left;"></div>
<script> // 播放地址
var url_1 = 'rtmp://202.69.69.180:443/webcast/bshdlive-pc';
var url_2 = 'rtmp://media3.sinovision.net:1935/live/livestream';
var url_3 = 'rtmp://58.200.131.2:1935/livetv/hunantv'; var oPlayerDiv1 = document.getElementById('playerDiv1');
var oPlayerDiv2 = document.getElementById('playerDiv2');
var oPlayerDiv3 = document.getElementById('playerDiv3'); oPlayerDiv1.setAttribute("data-rtmp", url_1);
oPlayerDiv1.setAttribute("href", url_1); oPlayerDiv2.setAttribute("data-rtmp", url_2);
oPlayerDiv2.setAttribute("href", url_2); oPlayerDiv3.setAttribute("data-rtmp", url_3);
oPlayerDiv3.setAttribute("href", url_3); var swfStr = "./swf/flowplayer-3.2.18.swf"
var obj_1 = {
clip: {
provider: 'rtmp',
bufferLength: 0,
bufferTime: 0,
autoPlay: true,
live: true
},
plugins: {
rtmp: {
url: "flowplayer.rtmp-3.2.13.swf",
netConnectionUrl: url_1
}
}
}; const obj_2 = JSON.parse(JSON.stringify(obj_1)) //js对象的深拷贝 // JSON.stringify() 方法将 JavaScript 对象转换为字符串 JSON.parse() 方法将数据转换为 JavaScript 对象
obj_2.plugins.rtmp.netConnectionUrl = url_2;
const obj_3 = JSON.parse(JSON.stringify(obj_1))
obj_3.plugins.rtmp.netConnectionUrl = url_3; flowplayer('playerDiv1', swfStr, obj_1);
flowplayer('playerDiv2', swfStr, obj_2);
flowplayer('playerDiv3', swfStr, obj_3);
</script>
</body>
</html>
效果:

注意!!!
1. 由于RTMP协议是在 Flash 播放器上播放的,所以对于H5的video播放器是不能直接播放的,必须要让所用浏览器支持flash,才可以播放rtmp流媒体。目前来说,谷歌浏览器是支持Flash的,但是在2020年12月后谷歌浏览器将不再支持Flash,所以以上两种方法只能暂时使用,并不是长久之计!

2. flowplayerjs不支持rtsp流媒体,浏览器原生js只支持http,基于flash的播放器也只能支持到rtmp,如果要支持rtsp需要使用c/c++插件(npapi或者activex)。videojs同样如此,不支持rtsp流媒体
3.3 python搭建flask服务器播放rtsp、rtmp流媒体
python代码如下:
from flask import Flask, render_template, Response
import cv2 class VideoCamera():
def __init__(self,vurl):
# 通过opencv获取实时视频流
self.video = cv2.VideoCapture(vurl) def __del__(self):
self.video.release() def get_frame(self):
success, image = self.video.read()
ret, jpeg = cv2.imencode('.jpg', image)
#转化为字节流
return jpeg.tobytes() # app是Flask的实例,它接收包或者模块的名字作为参数,但一般都是传递__name__
app = Flask(__name__)
@app.route('/') # 主页
def index():
return render_template('index.html') @app.route('/video1_feed') # 这个地址返回rtsp视频流响应
def video1_feed():
return Response(gen1(VideoCamera("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov")), mimetype='multipart/x-mixed-replace; boundary=frame') @app.route('/video2_feed') # 这个地址返回rtmp视频流响应
def video2_feed():
return Response(gen2(VideoCamera("rtmp://202.69.69.180:443/webcast/bshdlive-pc")), mimetype='multipart/x-mixed-replace; boundary=frame')\ @app.route('/video3_feed') # 这个地址返回rtmp视频流响应
def video3_feed():
return Response(gen3(VideoCamera("rtmp://media3.sinovision.net:1935/live/livestream")), mimetype='multipart/x-mixed-replace; boundary=frame') @app.route('/video4_feed') # 这个地址返回rtmp视频流响应
def video4_feed():
return Response(gen4(VideoCamera("rtmp://58.200.131.2:1935/livetv/hunantv")), mimetype='multipart/x-mixed-replace; boundary=frame') def gen1(camera):
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
def gen2(camera):
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
def gen3(camera):
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
def gen4(camera):
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n') if __name__ == '__main__':
app.run(host='127.0.0.1', debug=True, port = 5000)
html代码如下:
<html>
<head>
<title>多路视频直播</title>
<style>
html, body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
.divbg{
width:300px;
height:200px;
}
.videostyle{
min-height: 100%;
min-width: 100%;
max-height: 100%;
max-width: 100%;
}
</style>
</head>
<body>
<h2>rtsp流媒体</h2>
<!-- 第一个rtsp视频流 -->
<div class="divbg">
<img class="videostyle" src="{{ url_for('video1_feed') }}">
</div>
<br>
<h2>rtmp流媒体</h2>
<!-- 第一个rtmp视频流 -->
<div class="divbg" style="float: left; margin-right: 5px;">
<img class="videostyle" src="{{ url_for('video2_feed') }}">
</div>
<!-- 第二个rtmp视频流 -->
<div class="divbg" style="float: left; margin-right: 5px;">
<img class="videostyle" src="{{ url_for('video3_feed') }}">
</div>
<!-- 第三个rtmp视频流 -->
<div class="divbg" style="float: left;">
<img class="videostyle" src="{{ url_for('video4_feed') }}">
</div>
</body>
</html>
效果:
python控制台:

网页效果:

注意!!!
python搭建一个flask服务器后,就可以播放任何格式的流媒体协议,因为flask后端直接将视频流转换为一帧一帧的图片,然后推送到网页上显示即可!但是,python搭建flask服务器播放rtsp、rtmp流媒体的缺点就是没办法播放声音,只有图片!
源程序可到博主github上下载:https://github.com/HuerFu/h5_rtmp_play
rtsp+rtmp多路流媒体播放的更多相关文章
- [转]流媒体协议介绍(rtp/rtcp/rtsp/rtmp/mms/hls)
[转]流媒体协议介绍(rtp/rtcp/rtsp/rtmp/mms/hls) http://blog.csdn.net/tttyd/article/details/12032357 RTP ...
- 网络流媒体协议的联系与区别(RTP RTCP RTSP RTMP HLS)
目录 网络流媒体协议的联系与区别(RTP RTCP RTSP RTMP HLS) 简结 RTP RTCP RTSP 区别与联系 RTSP.RTMP.HLS 区别与联系 关于直播 流媒体各协议层次图 基 ...
- 几款优秀的点播、RTSP/RTMP直播播放器介绍
1.ijkplayer 项目地址: https://github.com/Bilibili/ijkplayer 介绍:Ijkplayer 是Bilibili发布的基于 FFplay 的轻量级 Andr ...
- javaCV开发详解之4:转流器实现(也可作为本地收流器、推流器,新增添加图片及文字水印,视频图像帧保存),实现rtsp/rtmp/本地文件转发到rtmp流媒体服务器(基于javaCV-FFMPEG)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- javaCV开发详解之3:收流器实现,录制流媒体服务器的rtsp/rtmp视频文件(基于javaCV-FFMPEG)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- 监控系统的多协议直播(RTSP RTMP HTTP Live Streaming)
监控系统的多协议直播(RTSP RTMP HTTP Live Streaming)
- rtsp/rtmp/hls/onvif测试源以及ffmpeg在流媒体方面的应用
一.rtsp/rtmp/hls/onvif测试源 1. rtsp rtsp://184.72.239.149/vod/mp4:BigBuckBunny_175k.mov 2.rtmp rtmp://l ...
- EasyPlayer Android基于ffmpeg实现播放(RTSP/RTMP/HTTP/HLS)同步录像功能
之前有博客专门介绍了EasyPlayer的本地录像的功能,简单来说,EasyPlayer是一款RTSP播放器,它将RTSP流里的音视频媒体帧解析出来,并用安卓系统提供的MediaMuxer类进行录像. ...
- 推荐:实现RTSP/RTMP/HLS/HTTP协议的轻量级流媒体框架,支持大并发连接请求
推荐一个比较好用的流媒体服务开源代码: ZLMediaKit: 实现RTSP/RTMP/HLS/HTTP协议的轻量级流媒体框架,支持大并发连接请求 https://gitee.com/xiahcu/Z ...
随机推荐
- 【前端控件】JQuery datepicker 日期控件设置
datepicker控件可通过参数设置进行语言切换,以下可实现,系统所有日期控件默认为中文,在特定页面或者特定条件下可切换成英语!~ HTML: <!DOCTYPE html> <h ...
- BZOJ 2460 & 洛谷 P4570 [BJWC2011]元素 (线性基 贪心)
题目链接: 洛谷 BZOJ 题意 给定 \(n\) 个矿石,每个矿石有编号和魔力值两种属性,选择一些矿石,使得魔力值最大且编号的异或和不为 0. 思路 线性基 贪心 根据矿石的魔力值从大到小排序. 线 ...
- JUC源码分析-线程池篇(三)Timer
JUC源码分析-线程池篇(三)Timer Timer 是 java.util 包提供的一个定时任务调度器,在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次. 1. Ti ...
- Linux apache httpd virtual配置
必须要关闭 selinux,否则无法访问目录
- leetcode.数组.287寻找重复数-Java
1. 具体题目 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找出这个重复的数. 示例 1: ...
- <随便写>软件设计遵循的基本原则
1.高内聚,低耦合 所谓高内聚,是指一个软件模块内各个元素彼此结合的紧密程度要高,即一个软件模块是由相关性很强的代码组成,只负责一项任务,也就是常说的单一责任原则. 所谓低耦合,是指一个软件系统内不同 ...
- 「CSP-S 2019」树的重心
题目 考场上送\(75pts\)真实良心,正解不难:考虑直接对于每一个点算割掉多少条边能使得这个点成为重心,不难发现对于一个不是重心的点,我们要割掉的那条边一定在那个大于\(\lfloor \frac ...
- jetson更换源
参考链接:https://blog.csdn.net/qq_36396941/article/details/88903094 Nano的镜像默认是国外的源,速度很慢,国内的源有的上不去,有的包无法安 ...
- Windows进程调度相关
结构体所在环境: Windows XP Version 2600 (Service Pack 3) UP Free x86 compatible EPROCESS: ntdll!_EPROCESS + ...
- to meet you 常用类库与技巧
1.Java的异常体系 2.从概念角度解析Java的异常处理机制 3.从责任角度看Java的异常体系 checked exception 必须try catch 或者继续向上抛出异常,否则编译不能通过 ...