首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Electron音视频录制

Electron音视频录制

作者头像
码客说
发布于 2019-10-21 09:14:43
发布于 2019-10-21 09:14:43
4.2K10
代码可运行
举报
文章被收录于专栏:码客码客
运行总次数:0
代码可运行

获取设备的支持情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var types = [
  "video/webm",
	"audio/webm",
	"video/webm\;codecs=vp8",
	"video/webm\;codecs=daala",
	"video/webm\;codecs=h264",
	"audio/webm\;codecs=opus",
	"video/mpeg"
];

for (var i in types) {
	console.log(types[i] + ":" + (MediaRecorder.isTypeSupported(types[i]) ? "支持" : "不支持"));
}

获取可用的视频源

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
desktopCapturer.getSources({
  types: ['screen']
}, (error, sources) => {
  if (error) throw error
  for (let source of sources) {
    console.info(source);
  }
});

定义全局变量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let audioStream;
let vedioStream;

let mediaRecorder;
let recordedChunks = [];

获取音频流

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getAudioStream() {
  navigator.mediaDevices.getUserMedia({audio: true, video: false})
      .then(function (stream) {
          audioStream = stream;
          getVedioStream()
          stream.onended = () => {
              console.log('Micro audio ended.')
          }
      })
      .catch(function (error) {
          console.log('getUserMedia() failed.')
      });
}

或者

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getAudioStream() {
  navigator.webkitGetUserMedia(
    {audio: true, video: false},
    function (stream) {
      console.log('Received audio stream.')
      audioStream = stream;
      getVedioStream()
      stream.onended = () => {
        console.log('Micro audio ended.')
      }
    },
    function () {
      console.log('getUserMedia() failed.')
    }
  );
}

获取视频流

sourceid可以通过获取可用的录制源返回source.id获取

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getVedioStream() {
  navigator.mediaDevices.getUserMedia({
    audio: false,
    video: {
      mandatory: {
        chromeMediaSource: 'desktop',
        // chromeMediaSourceId: sourceid,
        maxWidth: window.screen.width,
        maxHeight: window.screen.height
      }
    }
  }).then(function (stream) {
    vedioStream = stream;
    let liveVideo = document.querySelector("video");
    liveVideo.srcObject = stream;
    liveVideo.muted = true;
    liveVideo.play();

    startRecord();
  }).catch(function (err) {
    console.log('The following error occured: ' + err);
  })
}

或者

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getVedioStream() {
  navigator.webkitGetUserMedia({
    audio: false,
    video: {
      mandatory: {
        chromeMediaSource: 'desktop',
        // chromeMediaSourceId: sourceid,
        maxWidth: window.screen.width,
        maxHeight: window.screen.height
      }
    }
  }, function (stream) {
    vedioStream = stream;
    let liveVideo = document.querySelector("video");
    liveVideo.srcObject = stream;
    liveVideo.muted = true;
    liveVideo.play();
    startRecord();
  }, function () {

  })
}

录制带声音

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function startRecord() {
  if (audioStream) {
    let audioTracks = audioStream.getAudioTracks();
    vedioStream.addTrack(audioTracks[0]);
  }

  mediaRecorder = new MediaRecorder(vedioStream);

  mediaRecorder.ondataavailable = (event) => {
    if (event.data && event.data.size > 0) {
      recordedChunks.push(event.data)
    }
  };

  mediaRecorder.onstart = () => {
    console.log("开始录制")
  };
  mediaRecorder.onstop = () => {
    console.log("停止录制")
  };

  mediaRecorder.start();
}

停止录制

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 结束录制
function stopRecord() {
  if (mediaRecorder) {
    mediaRecorder.stop();
  } else {
    alert("还没有开始。");
  }
}

保存

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function formatLength(str, length) {
  str += '';
  if (str.length < length)
    return formatLength('0' + str, length)
  else
    return str
}

function getnowstr() {
  var now = new Date();
  var year = now.getFullYear(); //得到年份
  var month = formatLength(now.getMonth(), 2);//得到月份
  var date = formatLength(now.getDate(), 2);//得到日期
  var hour = formatLength(now.getHours(), 2);//得到小时
  var minu = formatLength(now.getMinutes(), 2);//得到分钟
  var all_time = year + "-" + month + "-" + date + "_" + hour + "-" + minu;
  return all_time;
}

// 保存视频
function saveRecord() {
  let blob = new Blob(recordedChunks, {type: "video/x-matroska;codecs=avc1,opus"});
  let url = URL.createObjectURL(blob);
  let a = document.createElement('a');
  var all_time = getnowstr();
  document.body.appendChild(a);
  a.style = 'display: none';
  a.href = url;
  a.download = all_time + 'video.webm';
  a.click()
  setTimeout(function () {
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url)
  }, 100)
}

播放

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function playRecord() {
  let video = document.querySelector('video')
  video.controls = true;
  video.muted = false;
  let blob = new Blob(recordedChunks, {type: "video/x-matroska;codecs=avc1,opus"})
  video.src = window.URL.createObjectURL(blob)
  video.play();
}

整体代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
    <title>Document</title>
</head>

<body>
<video id="live"></video>

<div class="toolbar">
    <span class="timer"></span>
    <button id="startOrStop">开始</button>
    <button id="save">保存</button>
    <button id="play">播放</button>
</div>

<style>
    body {
        margin: 0;
        padding: 0;
        overflow: hidden;
        width: 100vw;
        height: 100vh;
        display: flex;
        flex-direction: column;
    }

    #live {
        width: 100%;
        height: 0;
        flex-grow: 1;
    }

    .toolbar {
        width: 100%;
        height: 60px;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    .toolbar button {
        margin-left: 6px;
        margin-right: 6px;
        padding: 10px 16px;
        border-radius: 4px;
        background-color: blue;
        color: white;
    }

    .timer {
        width: 60px;
        text-align: center;
    }
</style>

<script>
    let n = 0;
    let timer;

    let audioStream;
    let vedioStream;

    let mediaRecorder;
    let recordedChunks = [];

    const startOrStopButton = document.getElementById("startOrStop");
    const saveButton = document.getElementById("save");
    const playButton = document.getElementById("play");
    startOrStopButton.addEventListener("click", startOrStopRecord);
    saveButton.addEventListener("click", saveRecord);
    playButton.addEventListener("click", playRecord);

    function getAudioStream() {
        navigator.mediaDevices.getUserMedia({audio: true, video: false})
            .then(function (stream) {
                audioStream = stream;
                getVedioStream()
                stream.onended = () => {
                    console.log('Micro audio ended.')
                }
            })
            .catch(function (error) {
                console.log('getUserMedia() failed.')
            });
    }

    function getVedioStream() {
        navigator.mediaDevices.getUserMedia({
            audio: false,
            video: {
                mandatory: {
                    chromeMediaSource: 'desktop',
                    maxWidth: window.screen.width,
                    maxHeight: window.screen.height
                }
            }
        }).then(function (stream) {
            vedioStream = stream;
            let liveVideo = document.querySelector("video");
            liveVideo.src = null;
            liveVideo.srcObject = vedioStream;
            liveVideo.controls = false;
            liveVideo.muted = true;
            liveVideo.play();

        }).catch(function (err) {
            console.log('The following error occured: ' + err);
        })
    }

    // 显示录制的秒数
    function startTimer() {
        const timerEl = document.querySelector(".timer");
        n = 0;
        timerEl.textContent = `${n}s`;
        timer = setInterval(() => {
            n += 1;
            timerEl.textContent = `${n}s`;
        }, 1000);
    }

    // 开始录制
    function startRecord() {
        if (audioStream) {
            let audioTracks = audioStream.getAudioTracks();
            vedioStream.addTrack(audioTracks[0]);
        }

        mediaRecorder = new MediaRecorder(vedioStream);
        mediaRecorder.ondataavailable = (event) => {
            if (event.data && event.data.size > 0) {
                recordedChunks.push(event.data)
            }
        };

        mediaRecorder.onstart = () => {
            console.log("开始录制")
        };
        mediaRecorder.onstop = () => {
            console.log("停止录制")
        };

        mediaRecorder.start();
    }

    // 结束录制
    function startOrStopRecord() {
        if (startOrStopButton.innerHTML === "开始") {
            recordedChunks = [];
            startTimer();
            startRecord();
            startOrStopButton.innerHTML = "停止"
        } else {
            clearInterval(timer);
            if (mediaRecorder) {
                mediaRecorder.stop();
                //停止视频音频流
                // vedioStream.getVideoTracks()[0].stop();
                // audioStream.getAudioTracks()[0].stop();
            }
            startOrStopButton.innerHTML = "开始"
        }
    }

    function formatLength(str, length) {
        str += '';
        if (str.length < length)
            return formatLength('0' + str, length);
        else
            return str
    }

    function getnowstr() {
        let now = new Date();
        let year = now.getFullYear(); //得到年份
        let month = formatLength(now.getMonth(), 2);//得到月份
        let date = formatLength(now.getDate(), 2);//得到日期
        let hour = formatLength(now.getHours(), 2);//得到小时
        let minu = formatLength(now.getMinutes(), 2);//得到分钟
        let time_all = year + "-" + month + "-" + date + "_" + hour + ":" + minu;
        return time_all;
    }

    // 保存视频
    function saveRecord() {
        let blob = new Blob(recordedChunks, {type: "video/x-matroska;codecs=avc1,opus"});
        let url = URL.createObjectURL(blob);
        let a = document.createElement('a');
        var all_time = getnowstr();
        document.body.appendChild(a);
        a.style = 'display: none';
        a.href = url;
        a.download = all_time + 'vedio.webm';
        a.click()
        setTimeout(function () {
            document.body.removeChild(a);
            window.URL.revokeObjectURL(url)
        }, 100)
    }

    function playRecord() {
        if (playButton.innerHTML === "播放") {
            let liveVideo = document.querySelector('video');
            liveVideo.controls = true;
            liveVideo.muted = false;
            let blob = new Blob(recordedChunks, {type: "video/x-matroska;codecs=avc1,opus"});
            liveVideo.srcObject = null;
            liveVideo.src = window.URL.createObjectURL(blob);
            liveVideo.play();
            playButton.innerHTML = "取消播放"
        } else {
            let liveVideo = document.querySelector("video");
            liveVideo.src = null;
            liveVideo.srcObject = vedioStream;
            liveVideo.controls = false;
            liveVideo.muted = true;
            liveVideo.play();
            playButton.innerHTML = "播放"
        }
    }

    getAudioStream();
</script>
</body>
</html>

工具类

为了方便使用封装成了工具类方便使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 *自动录屏模块*录制桌面
 *
 * @class Recorder
 */
class Recorder {
    constructor(path) {
        this.mediaOutputPath = path;
    }

    /**
     *开始录制
     *
     * @memberof Recorder
     */
    startRecord = () => {
        /* 要获取桌面音频必须设置audio约束如下 */
        this.getVedioStream().then(vedioStream => {
            this.getAudioStream().then((audioStream) => {
                vedioStream.addTrack(audioStream.getAudioTracks()[0])//注!此处添加麦克风音轨无效
                this.startRecorder(vedioStream);
            });
        }).catch(err => {
            this.getUserMediaError(err);
        });
    };

    /**
     *获取麦克风音频流
     *
     * @memberof Recorder
     */
    getAudioStream = () => {
        return navigator.mediaDevices.getUserMedia({audio: true, video: false})
    };


    /**
     *获取屏幕视频流
     *
     * @memberof Recorder
     */
    getVedioStream = () => {
        return navigator.mediaDevices.getUserMedia({
            audio: false,
            video: {
                mandatory: {
                    chromeMediaSource: 'desktop',
                    maxWidth: window.screen.width,
                    maxHeight: window.screen.height
                }
            }
        })
    };

    /**
     *获取媒体源失败
     *
     * @memberof Recorder
     */
    getUserMediaError = (err) => {
        console.log('mediaError', err);
    };


    getUserAudioError = (err) => {
        console.log('audioError', err);

    };

    /**
     *开始视频录制
     *
     * @memberof Recorder
     */
    startRecorder = (stream) => {
        this.recorder = new MediaRecorder(stream);
        this.recorder.start();
        this.recorder.ondataavailable = event => {
            let blob = new Blob([event.data], {
                type: 'video/webm'
            });
            this.saveMedia(blob);
        };
    };


    formatLength = (str, length) => {
        str += '';
        if (str.length < length)
            return this.formatLength('0' + str, length)
        else
            return str
    };


    getnowstr = () => {
        var now = new Date();
        var year = now.getFullYear(); //得到年份
        var month = this.formatLength(now.getMonth(), 2);//得到月份
        var date = this.formatLength(now.getDate(), 2);//得到日期
        var hour = this.formatLength(now.getHours(), 2);//得到小时
        var minu = this.formatLength(now.getMinutes(), 2);//得到分钟
        var all_time = year + "-" + month + "-" + date + "_" + hour + "-" + minu;
        return all_time;
    };

    /**
     *数据转换并保存成MP4
     *
     * @memberof Recorder
     */
    saveMedia = (blob) => {
        let reader = new FileReader();
        let _t = this;
        var filename = this.mediaOutputPath + this.getnowstr() + "_vedio.webm";
        reader.onload = function () {
            let buffer = Buffer.from(reader.result);
            const fs = require('fs')
            fs.writeFile(filename, buffer, {}, (err, res) => {
                if (err) {
                    console.error(err);
                    return
                }
            })
        };
        reader.readAsArrayBuffer(blob);
    };


    /**
     *停止录制视频
     *
     * @memberof Recorder
     */
    stopRecord = () => {
        this.recorder.stop();
    }


}

exports.Recorder = Recorder;

调用方式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const {Recorder} = require('./utils/Recorder');
let my_recorder = new Recorder("/Users/zhangjian/Downloads/");

// 开始录制
my_recorder.startRecord();
// 结束录制自动保存文件
if (my_recorder) {
  my_recorder.stopRecord();
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-08-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
强,不过。。。说好的MP4呢?结果输出的还是.webm啊
强,不过。。。说好的MP4呢?结果输出的还是.webm啊
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
Webrtc及WEB端音视频设备获取及流处理
注意本文和之前Electron获取设备的文章有重合,但是也不是一样的,因为在Electron中我们不但能用HTML的API,也能使用Electron的API,但是WEB中就有局限了,在WEB中就实现不了直接分享主屏幕,必须用户选择。
码客说
2022/09/23
2.8K0
Webrtc及WEB端音视频设备获取及流处理
使用h5新标准MediaRecorder API在web页面进行音视频录制
Media Recorder,顾名思义是控制媒体录制的api,在原生app开发中,是一个应用广泛的api,用于在app内录制音频和视频。
WendyGrandOrder
2018/11/26
23.1K11
使用h5新标准MediaRecorder API在web页面进行音视频录制
利用WebRTC录制采样的音视频
WebRTC录制音视频流之后,最终是通过Blob对象将数据保存成多媒体文件的,而Blob与ArrayBuffer和ArrayBufferView有着密切的关系。
码农帮派
2021/01/12
1.6K0
WebRTC网页打开摄像头并录制视频
前面我们能打开本地摄像头,并且在网页上看到摄像头的预览图像。 本文我们使用MediaRecorder来录制视频。在网页上播放录制好的视频,并能提供下载功能。
落寞的鱼丶
2022/02/26
1.8K0
50行代码搞定OneCode摄像头插件:快速定制实战指南
在工业监控、人脸识别等场景中,摄像头集成是常见需求。本文将以OneCode平台的xui.UI.Camera组件为例,展示如何用50行核心代码实现一个功能完备的摄像头插件,涵盖设备访问、视频流显示和拍照功能,并提炼OneCode插件开发的核心要素。
OneCode官方
2025/07/06
980
WebRTC 之 MediaRecorder_ 用你的浏览器录音和录像
既然现在的笔记本电脑,平板,手机都有摄像头和麦克风,那么录音和录像就是一件非常容易的事情了,但是如果不用别人写好的录音录像程序,让你自己来实现一个录音和录像应用,其实也没那么简单。
前端小tips
2021/11/30
2K0
WebRTC 之 MediaRecorder_ 用你的浏览器录音和录像
音视频通信加餐 —— WebRTC一肝到底
最近需要搭建一个在线课堂的直播平台,考虑到清晰度和延迟性,我们一致认为使用 WebRTC 最合适。
杨成功
2022/09/22
1.2K0
音视频通信加餐 —— WebRTC一肝到底
Web前端WebRTC攻略(二) 音视频设备及数据采集
2021年1月26日,W3C 和 IETF 同时宣布 WebRTC(Web Real-Time Communications,Web 实时通信)现发布为正式标准,标志着 WebRTC正式走进舞台。尽管如此,WebRTC 早已在视频会议和直播中得到了广泛的应用,成为了线上通信及协作服务的基石。IMWeb 团队是国内最早研究 WebRTC 的团队之一,在腾讯课堂、企鹅辅导等应用中都有实践。这是 WebRTC 系列的第二篇,希望可以帮助你更好的了解音视频。 一、音视频采集基本概念 在讲浏览器提供的用 JS 采集音
用户1097444
2022/06/29
3.9K0
Web前端WebRTC攻略(二) 音视频设备及数据采集
用JS轻松实现一个录音、录像、录屏工具库
最近项目遇到一个要在网页上录音的需求,在一波搜索后,发现了 react-media-recorder[1] 这个库。今天就跟大家一起研究一下这个库的源码吧,从 0 到 1 来实现一个 React 的录音、录像和录屏功能。
写代码的海怪
2022/03/29
1.4K0
用JS轻松实现一个录音、录像、录屏工具库
录屏工具开发
https://juejin.cn/post/6915287057795874824
@超人
2021/02/26
2.1K0
录屏工具开发
快速入门 WebRTC:屏幕和摄像头的录制、回放、下载
不知你是否用过 web 版的视频面试,或者 web 版在线会议,它们都支持分享屏幕、也能开启摄像头。这些都是浏览器上实现的,作为前端开发,是否好奇过这些功能的实现原理呢?
神说要有光zxg
2021/12/26
3.3K0
给测试小妹做了一个js版屏幕录制工具iREC,她用后竟说喜欢我
周末,公司里的测试小妹给我发消息说,她昨晚又加班到很晚,原因是研发要求提复杂bug时需要附上具体的操作流程以便详细了解操作过程和复现。最好能提供一个录制视频,这不是难为我们测试小妹嘛?随后她问我有没有好用,免费的录制屏幕的软件。我答应帮她找找。 看到这里你可能以为这是一篇软件推荐文章,但其实这是一篇造轮子的文章,经过一番搜索,我发现大多数的录屏软件,不是比较笨重,就是有些需要付费,或者无法跨平台使用。于是我想能不能自己开发一个录屏工具,这个想法一旦产生就无法停止,在造轮子之前我需要简单整理一下需求范围,以便挑选合适的工具来实现。
拿我格子衫来
2022/01/24
1.5K0
给测试小妹做了一个js版屏幕录制工具iREC,她用后竟说喜欢我
Electron / Chromium 屏幕录制 - 那些我踩过的坑
Web 屏幕录制也许对我们来说并不陌生,最常见的场景,例如:各种视频会议、远程桌面软件,远程会议软件的出现大大方便了人们的交流与沟通,在 WFH 期间对众多企业的线上运转起到关键的作用。除了屏幕的实时分享,录屏的应用还存在另一种应用场景,即“记录实时操作并保留现场,方便后续追溯与回放”,即是我们业务的主要场景。对于我们的业务,强依赖该功能的稳定性。以下是我们业务对该功能的一些硬性指标:
ConardLi
2021/09/29
4.6K1
Electron / Chromium 屏幕录制 - 那些我踩过的坑
探秘移动端网页调用摄像头的两种方式
PC 端网页调用摄像头的场景想必大家并不陌生,打开一个网址,开启摄像头开始笔试/视频聊天/直播等。
掘金安东尼
2022/09/22
4.8K0
探秘移动端网页调用摄像头的两种方式
通过 web 录制视频(摄像头)并上传
在用户通过提示允许的情况下,打开系统上的相机或屏幕共享和/或麦克风,并提供 MediaStream 包含视频轨道和/或音频轨道的输入。
张云飞Vir
2021/04/28
2.1K0
web H5摄像头-Media-Recorder-API-Demo
media-recorder-api <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>拍照2</title> </head> <body> <div style="display: block"> <button id="take" >拍照</button> <button onclick="upload()" >保存照片</button> <button
2021/11/08
5940
前端实现在浏览器网页中录音
页面中实现录音需要使用浏览器提供的MediaRecorder API,所以要实现页面录音就需要浏览器支持MediaStream Recording相关的功能,即浏览器能够获取浏览器的录音权限。
winty
2021/01/05
3.7K0
前端实现在浏览器网页中录音
【项目实战】基于 WebRTC 的音视频在线监考模块的设计与实现(下)
在上一篇博文 【复】基于 WebRTC 的音视频在线监考模块的设计与实现(上) 中,主要介绍了关于 WebRTC 的基本理论,那么这篇文章我们将进入实战阶段,通过 WebRTC 框架,去实现 P2P 通话,以及延伸到一对多的音视频通话,从而实现在线监考功能;
sidiot
2023/08/31
5390
【项目实战】基于 WebRTC 的音视频在线监考模块的设计与实现(下)
H5利用JS调用电脑摄像头实现拍照效果
今天学习了调用电脑摄像头,利用canvas画布将视频当前帧转换成图片的实例,其中用到了 mediaDevices.getUserMedia 方法。该方法提示用户允许使用媒体输入,产生包含所请求类型的媒体轨道。包括视频轨道(由诸如照相机,视频记录设备,屏幕共享服务等的硬件或虚拟视频源产生),音频轨道(类似地,由物理或虚拟音频源,如麦克风,A / D转换器等),以及其他可能的轨道类型。
德顺
2019/11/12
10K1
[javascript] 使用javascript实现webrtc视频聊天demo
自己的ID是自动获取的 ,然后输入对方的ID , 对方的ID可以这样获取 , 再打开新的浏览器或者手机也可以
唯一Chat
2021/02/04
2.2K0
[javascript] 使用javascript实现webrtc视频聊天demo
推荐阅读
相关推荐
Webrtc及WEB端音视频设备获取及流处理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档