当前位置: 首页 > article >正文

WebRtc07: 音视频录制实战

录制基础知识

MediaRecorder

// stream通过getUserMedia获取
var mediaRecorder = new MediaRecorder(stream[,option]);

option参数说明

在这里插入图片描述

API和事件

// API
// 开始录制媒体,timeslice是可选的,如果设置了会按时间切片存储数据
MediaRecorder.start(timeslice)
// 停止录制,此时会触发包括最终Blob数据的dataavailable事件
MediaRecorder.stop()
// 暂停录制
MediaRecorder.pause()
// 恢复录制
MediaRecorder.resume()
// 类型支持
MediaRecorder.isTypeSupported()

// 事件
// 数据有效时触发, 每次记录一定时间的数据时(如果没有指定时间切片,则记录整个数据)会定期触发
MediaRecorder.ondataavailable
// 当有错误发生时,录制会被停止
MediaRecorder.onerror

JavaScript几种数据存储方式

  • 字符串
  • Blob:类似一块搞笑的存储区域,方便将整个缓冲区写入文件
  • ArrayBuffer
  • ArrayBufferView

实战

录制音视频

实测使用firefox浏览器不支持webm
index.html

<html>
    <head>
            <title>WebRtc capture video and audio</title>
            <style>
                .none {
                        -webkit-filter: none;
                }
                .blur {
                        -webkit-filter: blur(3px);
                }
                .grayscale {
                        -webkit-filter:grayscale(1);
                }
                .invert {
                        -webkit-filter: invert(1);
                }
                .sepia {
                        -webkit-filter:sepia(1);
                }
            </style>
    </head>
    <body>
                <div>
                        <label>audioSource:</label>
                        <select id="audioSource"></select>
                </div>
                <div>
                        <label>audioOutput:</label>
                        <select id="audioOutput"></select>
                </div>
                <div>
                        <label>videoSource:</label>
                        <select id="videoSource"></select>
                </div>
                <div>
                        <label>filter:</label>
                        <select id="filter">
                                <option value="none"> None</option>
                                <option value="blur"> blur</option>
                                <option value="grayscale"> grayscale</option>
                                <option value="invert"> invert</option>
                                <option value="sepia"> sepia</option>

                        </select>
                </div>
                        <!-- controls用于显示控制按钮 -->
                        <!-- <audio autoplay controls id="audioplayer" ></audio> -->
                <table>
                        <tr>
                                <td><video autoplay playsinline id="player"></video></td>

                                <td><video playsinline id="recplayer"></video></td>

                                <!-- 显示视频约束 -->
                                <td><div id = 'constraints' class='output'></div></td>
                        </tr>
                        <tr>
                                <td><button id="record">Start Record</button></td>
                                <td><button id="recplay" disabled>Play</button></td>
                                <td><button id="download" disabled>Download</button></td>
                        </tr>
                </table>
                        
                <div>
                        <button id="snapshot">Take snapshot</button>
                </div>
                <div>
                        <canvas id="picture"></canvas>
                </div>

                <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
                <script src="./js/client.js"></script>
    </body>
</html>

client.js

'use strict'

// devices
var audioSource = document.querySelector('select#audioSource');
var audioOutput = document.querySelector('select#audioOutput');
var videoSource = document.querySelector('select#videoSource');

// filter
var filterSelect = document.querySelector('select#filter');

// picture
var snapshot = document.querySelector('button#snapshot');
var picture = document.querySelector('canvas#picture');
picture.width = 320;
picture.height = 240;

var videoplay = document.querySelector('video#player');
// 获取audioplayer
// var audioplay = document.querySelector('audio#audioplayer');

// div
var divConstraints = document.querySelector('div#constraints');

// record
var recVideo = document.querySelector('video#recplayer');
var btnRecord = document.querySelector('button#record');
var btnPlay = document.querySelector('button#recplay');
var btnDownload = document.querySelector('button#download');
var buffer;
var mediaRecorder;

function getDevice(deviceInfos) {
    deviceInfos.forEach(function(deviceInfos) {
        var option = document.createElement('option');
        option.text = deviceInfos.label;
        option.value = deviceInfos.deviceId;

        if (deviceInfos.kind == 'audioinput') {
            audioSource.appendChild(option);
        } else if (deviceInfos.kind == 'audiooutput') {
            audioOutput.appendChild(option);
        } else if (deviceInfos.kind == 'videoinput') {
            videoSource.appendChild(option);
        }
    });
}

function getMediaStream(stream) {
    videoplay.srcObject = stream;

    var videoTrack = stream.getVideoTracks()[0];
    var videoConstraints = videoTrack.getSettings();
    divConstraints.textContent = JSON.stringify(videoConstraints, null, 2);

    // 将流放到全局对象中
    window.stream = stream;
    // audioplay.srcObject = stream;
    return navigator.mediaDevices.enumerateDevices();
}
function handleError(err) {
    console.log('getUserMedia error: ', err);
}

function start() {
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
        console.log('getUserMedia is not supported');
    } else {
        var deviceId = videoSource.value;
        var constraints = {
            video : {
                width: 640,
                height: 480,
                frameRate: 30,
                deviceId : deviceId ? deviceId : undefined
            },
            // video : false,
            audio : true
        }
        navigator.mediaDevices.getUserMedia(constraints).then(getMediaStream).then(getDevice).catch(handleError);
    }
}
start();

videoSource.onchange = start;

filterSelect.onchange = function() {
    videoplay.className = filterSelect.value;
}

snapshot.onclick = function() {
    picture.className = filterSelect.value;
    picture.getContext('2d').drawImage(videoplay, 0, 0, picture.width, picture.height);
}
function handleDataAvilable(e) {
    if (e && e.data && e.data.size > 0) {
        buffer.push(e.data);
    }
}
function startRecord() {
    buffer = [];
    var options = {
        mimeType: 'video/webm;codecs=vp8'
    }

    
    if (MediaRecorder.isTypeSupported(options.mimeType)) {
        console.error(`${options.mimeType} is not supported`);
        return;
    }

    try {
        mediaRecorder = new MediaRecorder(window.stream, options);
    } catch (error) {
        console.error('failed to create mediaRecorder');
        return;
    }
    mediaRecorder.ondataavilable = handleDataAvilable;
    mediaRecorder.start(10);
}
function stopRecord() {
    mediaRecorder.stop();
    console.log(`媒体类型:${mediaRecorder.mimeType}`);
}
btnRecord.onclick = ()=>{
    if (btnRecord.textContent == 'Start Record') {
        startRecord();
        btnRecord.textContent = 'Stop Record';
        btnPlay.disabled = true;
        btnDownload.disabled = true;
    } else {
        stopRecord();
        btnRecord.textContent = 'Start Record';
        btnPlay.disabled = false;
        btnDownload.disabled = false;
    }
}

btnPlay.onclick = ()=>{
    // 这里的mimeType必须和录制的一致
    var blob = new Blob(buffer, {type: 'video/webm'});
    recVideo.src = window.URL.createObjectURL(blob);
    recVideo.srcObject = null;
    recVideo.controls = true;
    recVideo.play();
}

btnDownload.onclick = ()=> {
    // 这里的mimeType必须和录制的一致
    var blob = new Blob(buffer, {type: 'video/webm'});
    var url = window.URL.createObjectURL(blob);
    var a = document.createElement('a');

    a.href = url;
    a.style.display = 'none';
    a.download = 'aaa.webm';
    a.click();
}

捕获桌面

getDisplayMedia

在这里插入图片描述
只需要把getUserMedia改成getDisplayMedia即可实现捕获桌面的功能


http://www.kler.cn/a/540325.html

相关文章:

  • vscode卡住---回退版本解决
  • 【大数据技术】搭建完全分布式高可用大数据集群(ZooKeeper)
  • idea Ai工具通义灵码,Copilot我的使用方法以及比较
  • 如何在Vscode中接入Deepseek
  • 测试中的第一性原理:回归本质的质量思维革命
  • 通过Demo案例的形式弄懂Java中的设计模式
  • 人岗匹配为核,打造精确高效招聘 “高速路”
  • 多模态识别和自然语言处理有什么区别
  • Tomcat添加到Windows系统服务中,服务名称带空格
  • 81页精品PPT | 华为流程与信息化实践与架构规划分享
  • 多头自注意力中的多头作用及相关思考
  • 《我在技术交流群算命》(三):QML的Button为什么有个蓝框去不掉啊(QtQuick.Controls由Qt5升级到Qt6的异常)
  • 深入理解QT的View-Model-Delegate机制和用法
  • 开发指南098-logback-spring.xml说明
  • C# 学习目录
  • 海外直播场景下的AWS技术架构设计与实践
  • 【医院管理会计专题】2.管理会计:医院运营管理的隐形引擎
  • AutoMQ 如何实现没有写性能劣化的极致冷读效率
  • 11g ADG主备切换步骤
  • 【JAVA使用Aes加密报错:Illegal key size or default parameters,如何解决?】
  • FFmpeg 学习路径
  • VeryReport和FineReport两款报表软件深度分析对比
  • 只需三步!5分钟本地部署deep seek——MAC环境
  • MongoDB 的使用场景
  • Transformers as SVM(2023 NIPS)
  • react概览webpack基础