浏览器可以插入 "mitm" 本地网络摄像头吗?
Can a browser plugin "mitm" the local webcam?
我想创建一个浏览器扩展,允许用户在任何使用 javascript 网络 API 的站点上向他们的 video/audio 流添加效果,而无需特殊插件。
Google 搜索并不是特别有用所以我开始怀疑这是否可能。
我有两个主要问题:
javascript+chrome可以吗?
非常感谢任何指向其他资源的链接。
我不是很喜欢 web-extensions,所以甚至可能有一个更简单的 API 可用,我不会详细介绍实现的细节,但理论上你确实可以做到。
所要做的就是重写您获取 MediaStream 的方法,将原始 MediaStream 绘制到 HTML canvas 您可以应用过滤器的地方,然后简单地 return 一个新的 MediaStream,它由 canvas 元素的 captureStream()
中的 MediaStream 的 VideoTrack 组成,可能还有来自原始 MediaStream 的其他音轨。
gUM 的一个非常基本的概念实施证明可能如下所示:
// overrides getUserMedia so it applies an invert filter on the videoTrack
{
const mediaDevices = navigator.mediaDevices;
const original_gUM = mediaDevices.getUserMedia.bind(mediaDevices);
mediaDevices.getUserMedia = async (...args) => {
const original_stream = await original_gUM(...args);
// no video track, no filter
if( !original_stream.getVideoTracks().length ) {
return original_stream;
}
// prepare our DOM elements
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const video = document.createElement('video');
// a flag to know if we should keep drawing on the canvas or not
let should_draw = true;
// no need for audio there
video.muted = true;
// gUM video tracks can change size
video.onresize = (evt) => {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
};
// in case users blocks the camera?
video.onpause = (evt) => {
should_draw = false;
};
video.onplaying = (evt) => {
should_draw = true;
drawVideoToCanvas();
};
video.srcObject = original_stream;
await video.play();
const canvas_track = canvas.captureStream().getVideoTracks()[0];
const originalStop = canvas_track.stop.bind(canvas_track);
// override the #stop method so we can revoke the camera stream
canvas_track.stop = () => {
originalStop();
should_draw = false;
original_stream.getVideoTracks()[0].stop();
};
// merge with audio tracks
return new MediaStream( original_stream.getAudioTracks().concat( canvas_track ) );
// the drawing loop
function drawVideoToCanvas() {
if(!should_draw) {
return;
}
ctx.filter = "none";
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.filter = "invert(100%)";
ctx.drawImage(video,0,0);
requestAnimationFrame( drawVideoToCanvas );
}
};
}
然后每个调用此方法的脚本都会收到过滤后的 videoTrack。
Outsourced example since gUM is not friend with StackSnippets.
现在我不确定如何覆盖 web-extensions 中的方法,您必须自己学习,并注意该脚本实际上只是一个概念验证,尚未准备好用于生产。除了演示案例,我什么也没做。
我想创建一个浏览器扩展,允许用户在任何使用 javascript 网络 API 的站点上向他们的 video/audio 流添加效果,而无需特殊插件。
Google 搜索并不是特别有用所以我开始怀疑这是否可能。
我有两个主要问题:
javascript+chrome可以吗?
非常感谢任何指向其他资源的链接。
我不是很喜欢 web-extensions,所以甚至可能有一个更简单的 API 可用,我不会详细介绍实现的细节,但理论上你确实可以做到。
所要做的就是重写您获取 MediaStream 的方法,将原始 MediaStream 绘制到 HTML canvas 您可以应用过滤器的地方,然后简单地 return 一个新的 MediaStream,它由 canvas 元素的 captureStream()
中的 MediaStream 的 VideoTrack 组成,可能还有来自原始 MediaStream 的其他音轨。
gUM 的一个非常基本的概念实施证明可能如下所示:
// overrides getUserMedia so it applies an invert filter on the videoTrack
{
const mediaDevices = navigator.mediaDevices;
const original_gUM = mediaDevices.getUserMedia.bind(mediaDevices);
mediaDevices.getUserMedia = async (...args) => {
const original_stream = await original_gUM(...args);
// no video track, no filter
if( !original_stream.getVideoTracks().length ) {
return original_stream;
}
// prepare our DOM elements
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const video = document.createElement('video');
// a flag to know if we should keep drawing on the canvas or not
let should_draw = true;
// no need for audio there
video.muted = true;
// gUM video tracks can change size
video.onresize = (evt) => {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
};
// in case users blocks the camera?
video.onpause = (evt) => {
should_draw = false;
};
video.onplaying = (evt) => {
should_draw = true;
drawVideoToCanvas();
};
video.srcObject = original_stream;
await video.play();
const canvas_track = canvas.captureStream().getVideoTracks()[0];
const originalStop = canvas_track.stop.bind(canvas_track);
// override the #stop method so we can revoke the camera stream
canvas_track.stop = () => {
originalStop();
should_draw = false;
original_stream.getVideoTracks()[0].stop();
};
// merge with audio tracks
return new MediaStream( original_stream.getAudioTracks().concat( canvas_track ) );
// the drawing loop
function drawVideoToCanvas() {
if(!should_draw) {
return;
}
ctx.filter = "none";
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.filter = "invert(100%)";
ctx.drawImage(video,0,0);
requestAnimationFrame( drawVideoToCanvas );
}
};
}
然后每个调用此方法的脚本都会收到过滤后的 videoTrack。
Outsourced example since gUM is not friend with StackSnippets.
现在我不确定如何覆盖 web-extensions 中的方法,您必须自己学习,并注意该脚本实际上只是一个概念验证,尚未准备好用于生产。除了演示案例,我什么也没做。