获取从
chrome.tabCapture.capture
获得的流(暂时忽略音频捕捉,因为它与我面临的问题无关)将此
tabStream
传递给URL.createObjectURL(tabStream)
使用生成的URL作为DOM视频元素
videoEl.src = URL.createObjectURL(tabStream)
的src
调用
videoEl.play()
并在调用canplay
事件时将
videoEl
作为参数传递给画布的上下文drawImage
方法由于现在视频帧被渲染到画布元素中,因此可以对这些帧执行许多有用的操作(裁剪、加水印等)
到目前为止,所有工作都进行得很完美。但是接下来的两个步骤不起作用:
使用
canvasStream = canvasEl.captureStream(20)
从画布元素创建一个流将此流传递给
MediaRecorder
(recorder = new MediaRecorder(canvasStream)
)并开始录制:recorder.start()
本质上,如果在Chrome扩展程序的背景之外使用此方法(例如在这里:https://jsfiddle.net/williamwallacebrave/2rgv7pgj/7/),所有工作都进行得很完美。但是当在Chrome扩展程序的后台中使用时,我可以清楚地检测到视频帧被发送并渲染在画布元素中,但某种方式要么canvasEl.captureStream()
没有推送数据,要么记录器无法捕获它们。同样,如果在内容脚本中使用该方法,一切都进行得很完美。但是在内容脚本中,我无法访问tabCapture
流。
这是我的清单文件:
{
"name": "super app",
"manifest_version": 2,
"description": "...",
"version": "0.0.1",
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"page_action": {
"default_title": "app",
"default_icon": "static/images/logo.png"
},
"icons": {
"128": "static/images/logo.png"
},
"background": {
"page": "background.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"exclude_matches": ["http://localhost:3000/*"],
"css": [
"static/css/style.css"
],
"js": [
"vendor/system.js",
"vendor/jquery.min.js",
"content/config.js",
"content/index.js"
]
}
],
"web_accessible_resources": [
"background/*",
"vendor/*",
"content/*",
"common/*.js",
"capturer.html",
"static/*",
"*"
],
"externally_connectable": {
"matches": [
"http://localhost:3000/*"
]
},
"permissions": [
"tabs",
"activeTab",
"<all_urls>",
"clipboardRead",
"clipboardWrite",
"tabCapture",
"notifications",
"tts"
]
}
以下是模拟代码,作为内容脚本运行正常,但作为后台脚本则无法正常工作:
// SOURCE: https://dev59.com/hlkS5IYBdhLWcg3w6qMz
var cStream,
aStream,
recorder,
chunks = [],
canvasEl = document.createElement('canvas');
canvasEl.width = 400;
canvasEl.height = 400;
document.body.appendChild(canvasEl);
/*
create and run external video
*/
var videoEl = document.createElement('video');
videoEl.crossOrigin = 'anonymous';
videoEl.src = 'https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4';
videoEl.play();
videoEl.addEventListener('play', function(){
var audioCtx = new AudioContext();
var dest = audioCtx.createMediaStreamDestination();
aStream = dest.stream;
var sourceNode = audioCtx.createMediaElementSource(this);
console.log('connected audio');
sourceNode.connect(dest);
// output to our headphones
sourceNode.connect(audioCtx.destination)
var canvasCtx = canvasEl.getContext('2d');
console.log('play video in canvas');
draw(this, canvasCtx);
startRecording();
setTimeout(() => {
stopRecording();
}, 10000)
}, false);
function exportStream(e) {
console.log('exportStream', chunks.length);
if (chunks.length) {
var blob = new Blob(chunks),
videoURL = URL.createObjectURL(blob),
resultVideoEl = document.createElement('video');
resultVideoEl.controls = true;
resultVideoEl.src = videoURL;
resultVideoEl.onend = function() {
URL.revokeObjectURL(videoURL);
}
document.body.insertBefore(resultVideoEl, canvasEl);
} else {
document.body.insertBefore(
document.createTextNode('no data saved'), canvasEl);
}
}
function saveChunks(e) {
console.log('save chunks', e.data.size);
e.data.size && chunks.push(e.data);
}
function stopRecording() {
console.log('STOP RECORDING');
videoEl.pause();
recorder.stop();
}
function startRecording() {
console.log('START RECORDING');
cStream = canvasEl.captureStream(30);
cStream.addTrack(aStream.getAudioTracks()[0]);
recorder = new MediaRecorder(cStream);
recorder.start();
// =============================================
// THIS PART IS NOT FIRED WHEN RUN IN BACKGROUND
// and final chunks is always an empty array.
// =============================================
recorder.ondataavailable = saveChunks;
recorder.onstop = exportStream;
}
function draw(v,ctx) {
if(videoEl.paused || videoEl.ended) return false;
// here I'm cropping the video frames and taking only 400 by 400
// square shifted by 100, 100 vector
ctx.drawImage(v, 100, 100, 400, 400, 0, 0, 400,400);
setTimeout(draw,20,v,ctx);
}
请注意,此captureStream和MediaRecorder相对较新,因此您需要Chrome 51+才能运行该示例。
manifest.json
吗?在document.body.insertBefore(document.createTextNode('no data saved'), canvas);
中出现了Uncaught ReferenceError: canvas is not defined
错误;在play()
请求被pause()
调用打断时,出现了Uncaught (in promise) DOMException
。 - guest271314javascript
是否返回预期结果? - guest271314