Chrome扩展程序CaptureStream

姆索布恰克

我正在开发chrome扩展程序,它可以实现以下功能:

  • 可以访问从中获取的流chrome.tabCapture.capture(在捕获视频时,由于音频捕获与我面临的问题无关,因此现在暂时忽略音频捕获)

  • 传递tabStreamURL.createObjectURL(tabStream)

  • 使用结果网址作为srcDOM Video ElementvideoEl.src = URL.createObjectURL(tabStream)

  • 调用videoEl.play()以及何时调用canplay事件

  • videoElas作为参数传递给canvas的contextdrawImage方法

  • 由于现在将视频帧渲染到canvas元素中,因此可以在该帧上执行很多有用的操作(裁剪,加水印等)

直到这一点的所有作品完美。但是,下面的两个最后的步骤不起作用:

  • 使用以下元素从canvas元素创建流 canvasStream = canvasEl.captureStream(20)

  • 将此流传递到MediaRecorderrecorder = new MediaRecorder(canvasStream))并开始记录:recorder.start()

本质上,如果这种方法在chrome扩展程序的背景之外使用(例如:https//jsfiddle.net/williamwallacebrave/2rgv7pgj/7/),那么所有方法都可以完美地工作。但是当在chrome扩展程序背景中使用时,我可以清楚地检测到视频帧是在canvas元素中发送和渲染的,但是不知何故,要么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+才能运行该示例

马克斯·斯托勒

这很可能与此有关铬的bug我提交了几个月前:https://bugs.chromium.org/p/chromium/issues/detail?id=639105

下面是负责该API的Chrome浏览器工程师的回应:

画布在背景时不会绘制/渲染新框架,因此,画布捕获不包含任何新项目。AFAIK,当按Tab键将背景设置为背景时,无法使用您在使用Chrome的演示中所期望的方式来绘制和捕获画布。

请在那里发表您的使用情况,并显示您获得此固定支撑。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章