javascript Chrome扩展捕获流

xtfmy6hx  于 2022-11-20  发布在  Java
关注(0)|答案(1)|浏览(166)

我正在开发的chrome扩展,使以下:

  • 访问从chrome.tabCapture.capture获得的流(捕获视频时,我们暂时忽略音频捕获,因为它与我面临的问题无关)
  • 将此tabStream传递给URL.createObjectURL(tabStream)
  • 将生成的url用作DOM视频元素videoEl.src = URL.createObjectURL(tabStream)src
  • 调用videoEl.play(),当调用canplay事件时
  • videoEl作为参数传递给画布的上下文drawImage方法
  • 由于现在视频帧被渲染到画布元素中,因此可以对该帧执行许多有用的操作(裁剪、水印等)。

到目前为止,所有的工作都很完美。但是下面的最后两个步骤不起作用:

  • 使用canvasStream = canvasEl.captureStream(20)从画布元素创建流
  • 将此流传递到MediaRecorderrecorder = 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: http://stackoverflow.com/questions/39302814/mediastream-capture-canvas-and-audio-simultaneously#39302994
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+才能运行该示例

368yc8dk

368yc8dk1#

这很可能与我几个月前提交的Chromium错误有关:https://bugs.chromium.org/p/chromium/issues/detail?id=639105
以下是负责该API的Chrome工程师的回应:
画布不绘制/渲染新的帧时,背景,因此,画布捕捉不包含任何新的项目。AFAIK,有没有一种方法来绘制和捕捉画布时,标签是背景的权利,现在的方式,你期望在演示使用Chrome。
请将您的使用案例张贴在那里,并显示您对修复此问题的支持。

相关问题