在HTML5场景下播放RTSP流并添加滤镜美化画面,核心思路是先通过WebRTC技术拉取RTSP流并渲染到video元素,再将video的画面实时绘制到Canvas上,最后通过Canvas的像素操作或者CSS滤镜属性实现滤镜效果。

前期准备:拉取RTSP流并渲染到video
HTML5原生不支持直接播放RTSP协议,需要借助后端转流服务将RTSP转为WebRTC支持的格式,前端通过WebRTC API拉取流并绑定到video元素。以下是基础拉流代码:
// 创建video元素用于接收流
const videoElement = document.createElement('video');
videoElement.autoplay = true;
videoElement.muted = true;
// WebRTC拉流逻辑,假设后端已经提供转流服务
async function pullRTSPStream() {
const peerConnection = new RTCPeerConnection();
// 假设信令服务返回SDP offer,这里简化逻辑
const offer = await fetch('/get_rtsp_offer').then(res => res.json());
await peerConnection.setRemoteDescription(offer);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
// 将流绑定到video元素
peerConnection.ontrack = (event) => {
videoElement.srcObject = event.streams[0];
};
}
pullRTSPStream();
核心实现:通过Canvas添加滤镜
video元素本身无法直接添加复杂滤镜,需要将video的实时画面绘制到Canvas画布上,再对Canvas的内容做滤镜处理。首先创建Canvas元素并关联video:
// 创建Canvas元素
const canvasElement = document.createElement('canvas');
const ctx = canvasElement.getContext('2d');
// 设置Canvas尺寸和video一致
videoElement.onloadedmetadata = () => {
canvasElement.width = videoElement.videoWidth;
canvasElement.height = videoElement.videoHeight;
};
// 将Canvas添加到页面显示
document.body.appendChild(canvasElement);
实时绘制video画面到Canvas
使用requestAnimationFrame循环将video的当前帧绘制到Canvas上,保证画面实时更新:
function drawVideoToCanvas() {
if (videoElement.readyState === videoElement.HAVE_ENOUGH_DATA) {
// 将video当前帧绘制到Canvas
ctx.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
// 调用滤镜处理函数
applyFilter();
}
requestAnimationFrame(drawVideoToCanvas);
}
drawVideoToCanvas();
常见滤镜实现代码
以下是几种常用的画面滤镜实现,通过操作Canvas的像素数据或者CSS属性完成:
1. 灰度滤镜
通过修改Canvas像素的RGB值,将每个像素的RGB转为相同的灰度值:
function applyGrayFilter() {
// 获取Canvas像素数据
const imageData = ctx.getImageData(0, 0, canvasElement.width, canvasElement.height);
const data = imageData.data;
// 遍历所有像素
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// 灰度计算公式:0.299*R + 0.587*G + 0.114*B
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
data[i] = gray;
data[i + 1] = gray;
data[i + 2] = gray;
}
// 将处理后的像素数据放回Canvas
ctx.putImageData(imageData, 0, 0);
}
2. 暖色调滤镜
增加红色和绿色通道的数值,降低蓝色通道数值,实现暖色效果:
function applyWarmFilter() {
const imageData = ctx.getImageData(0, 0, canvasElement.width, canvasElement.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
// 红色通道增加30,绿色通道增加15,蓝色通道减少20,超出255则取255
data[i] = Math.min(255, data[i] + 30);
data[i + 1] = Math.min(255, data[i + 1] + 15);
data[i + 2] = Math.max(0, data[i + 2] - 20);
}
ctx.putImageData(imageData, 0, 0);
}
3. 模糊滤镜(CSS实现)
如果不想操作像素数据,也可以直接给Canvas添加CSS滤镜属性,实现模糊效果:
// 给Canvas添加5px的高斯模糊 canvasElement.style.filter = 'blur(5px)';
滤镜切换与性能优化
可以通过函数调用的方式切换不同滤镜,同时需要注意性能优化:
- 像素操作类滤镜(如灰度、暖色调)计算量较大,高分辨率视频建议降低Canvas绘制频率,比如每2帧处理一次
- CSS滤镜性能优于像素操作,优先使用CSS滤镜实现简单效果
- 不需要滤镜时可以直接停止Canvas绘制循环,直接显示video元素减少性能消耗
以下是滤镜切换的示例代码:
let currentFilter = 'none';
// 切换滤镜函数
function switchFilter(filterType) {
currentFilter = filterType;
}
function applyFilter() {
switch(currentFilter) {
case 'gray':
applyGrayFilter();
break;
case 'warm':
applyWarmFilter();
break;
case 'blur':
canvasElement.style.filter = 'blur(5px)';
break;
default:
// 无滤镜,不需要额外处理
break;
}
}
注意事项
如果RTSP流是后端通过HTTP转发到前端的,也可以直接将流转为video支持的MP4格式,但是实时性会低于WebRTC方案。另外操作Canvas像素时需要注意跨域问题,如果video的流来源和页面不同域,需要后端配置CORS允许跨域访问,否则getImageData会报错。
通过以上步骤,就可以在HTML5播放RTSP流的同时,灵活添加各种滤镜实现画面美化,开发者可以根据需求调整滤镜参数,实现自定义的画面效果。