HTML5 播放 RTSP/RTMP 方案
RTSP
RTSP(Real-Time Stream Protocol)协议是一个基于文本的多媒体播放控制协议,属于应用层。RTSP 以客户端方式工作,对流媒体提供播放、暂停、后退、前进等操作。该标准由 IETF 指定,对应的协议是 RFC2326。
RTSP 传输的一般是 TS、MP4 格式的流,其传输一般需要 2~3 个通道,命令和数据通道分离。使用 RTSP 协议传输流媒体数据需要有专门的媒体播放器和媒体服务器,也就是需要支持 RTSP 协议的客户端和服务器。
RTMP
RTMP 协议是 Real Time Message Protocol(实时信息传输协议)的缩写,它是由 Adobe 公司提出的一种应用层的协议,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题。
轻量方案,使用 NodeJS 和 ffmpeg 生成 HLS
服务端
js
const streamList = [
{
url: "rtmp://58.200.131.2:1935/livetv/gxtv",
name: "gxtv",
},
];
module.exports = streamList;
js
const express = require("express");
const path = require("path");
const os = require("os");
const { spawn } = require("child_process");
const cors = require("cors");
const makeDir = require("make-dir");
const streamList = require("./device/streamList");
const platform = os.platform(); // darwin,win32
const ffmpegPath = path.resolve(__dirname, `./ffmpeg/ffmpeg-${platform}`);
console.log("ffmpegPath:", ffmpegPath);
const app = express();
app.use(cors());
app.use(express.static(path.resolve(__dirname, "./media")));
function process(stream) {
// ffmpeg参数
let paramList = [
"-re",
"-r",
"25",
"-i",
stream.url,
"-strict",
"-2",
"-max_delay",
"500000",
"-fflags",
"flush_packets",
"-an", // 无音频
"-flags",
"-global_header",
"-hls_time",
"1",
"-hls_list_size",
"10",
"-hls_wrap",
"10",
"-vcodec",
"copy", // 不重新编码
"-hls_flags",
"delete_segments",
"-y", // 覆盖输出文件
path.resolve(__dirname, `./media/${stream.name}.m3u8`),
// "-loglevel",
// "quiet"
];
if (stream.url.indexOf("rtsp://") === 0) {
// RTSP私有参数
let rtspParamList = ["-stimeout", "60" + "000000", "-rtsp_transport", "tcp"];
paramList = rtspParamList.concat(paramList);
}
// 开启切片进程
let p = spawn(ffmpegPath, paramList, { encoding: "utf-8" });
// 监听进程输出
p.stderr.on("data", (data) => {
const d = data.toString();
console.log(d);
if (d.indexOf("unknown") !== -1 || d.indexOf("Operation not") !== -1 || d.indexOf("404 Not Found") !== -1) {
// 如果出现指定的异常,5s后重启进程
console.log("异常", stream.url);
p.kill();
setTimeout(() => {
p = process(stream);
}, 5000);
}
});
return p;
}
function start() {
makeDir(path.resolve(__dirname, `./media`)).then(() => {
streamList.forEach((stream) => {
console.log(stream.url);
process(stream);
});
});
}
start();
let port = 7000;
for (let i = 0; i < streamList.length; i++) {
// 按照视频数量启动多个端口,防止浏览器在同一域下只支持6个HTTP并发。
app.listen(port);
port++;
}
客户端
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<link rel="stylesheet" href="video-js.min.css" />
<script src="video.min.js"></script>
</head>
<body>
<video id="v" class="video-js vjs-default-skin" muted>
<source src="http://127.0.0.1:7000/gxtv.m3u8" type="application/x-mpegURL" />
</video>
<script>
var player = videojs(document.getElementById("v"), {}, function () {
player.play();
});
</script>
</body>
</html>
海康大华设备对接笔记
海康摄像机/硬盘录像机
老版本:
sh
rtsp://username:password@<ipaddress>/<videotype>/ch<number>/<streamtype>
DS-9016HF-ST 的 IP 通道 01 主码流:
sh
rtsp://admin:[email protected]:554/h264/ch33/main/av_stream
DS-9016HF-ST 的模拟通道 01 子码流:
sh
rtsp://admin:[email protected]:554/h264/ch1/sub/av_stream
老 URL,NVR(>=64 路的除外)的 IP 通道从 33 开始;新 URL,通道号全部按顺序从 1 开始。
新版本(硬盘录像机):
sh
rtsp://username:password@<address>:<port>/Streaming/channels/<id>(?parm1=value1&parm2-=value2…)
录像机 172.30.12.170
的通道 1 的子码流。
ID 命名规则:
通道 1 的主码流:101 通道 1 的子码流:102 通道 10 的主码流:1001 通道 10 的子码流:1002 通道 10 的第三码流:1003
sh
rtsp://admin:[email protected]:554/Streaming/channels/102
大华摄像机
sh
rtsp://admin:[email protected]:554/cam/realmonitor?channel=1&subtype=1
channel: 通道号,起始为 1。例如通道 2,则为 channel=2。 subtype: 码流类型,主码流为 0(即 subtype=0),辅码流为 1(即 subtype=1)。