当前位置:网站首页>Web technology sharing | webrtc recording video stream
Web technology sharing | webrtc recording video stream
2022-06-26 06:34:00 【anyRTC】
Listening start event
EventTarget.addEventListener() Method to register the specified listener to
EventTargetOn , When the object triggers the specified event , The specified callback function will be executed . The event target can be an element on a documentElement,DocumentandWindowOr any other object that supports Events ( such asXMLHttpRequest).addEventListener()The working principle of is to realizeEventListenerAdd a function or object to the function or object that calls itEventTargetIn the event listener list for the specified event type on .
document.querySelector('button#start').addEventListener('click', async () => {
document.querySelector('button#start').disabled = true;
const constraints = {
audio: {},
video: {
width: 1280, height: 720
}
};
await init(constraints);
});
Get audio and video tracks
MediaDevices.getUserMedia()The user will be prompted to give permission to use media input , Media input produces aMediaStream, It contains the track of the requested media type . This stream can contain a video track ( From hardware or virtual video sources , Like a camera 、 Video capture devices and screen sharing services, etc )、 An audio track ( Also from hardware or virtual audio sources , Like a microphone 、A/D Converters and so forth ), It could be another type of orbit .It returns a
Promiseobject , After successresolveCall back oneMediaStreamobject . If the user refuses permission , Or the required media source is not available ,promiseMeetingrejectCall back onePermissionDeniedErrorperhapsNotFoundError.
async function init(constraints) {
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
handleSuccess(stream);
} catch (e) {
console.error('navigator.getUserMedia error:', e);
}
}
HTMLMediaElementInterfacesrcObjectProperty sets or returns an object , This object provides a connection toHTMLMediaElementAssociated media source , This object is usuallyMediaStream, But according to the specification, it can beMediaSource,BlobperhapsFile.
function handleSuccess(stream) {
recordButton.disabled = false;
window.stream = stream;
const gumVideo = document.querySelector('video#gum');
gumVideo.srcObject = stream;
}
Recording media streams
MediaRecorder()The constructor creates aMediaStreamFor recordingMediaRecorderobjectMediaRecorder.ondataavailableEvent handler API Handledataavailableevent , Run the code in responseBlobData is provided for use .dataavailableWhen MediaRecorder When delivering media data to your application for use , The event is triggered . The data is in the... Containing the dataBlobObject . This happens in four cases :At the end of the media stream , All not yet passed to
ondataavailableThe media data of the handler will be stored in a single fileBlobIn the transfer .When calling
MediaRecorder.stop()(en-US) when , From the beginning of the record ordataavailableSince the last time the incident occurred All media data obtained will be transferred toBlobin ; thereafter , The capture is over .call
MediaRecorder.requestData()(en-US)dataavailablewhen , All media data captured since the beginning of recording or the last occurrence of the event will be delivered ; thenBlobCreate a new file , And continue media capture to this blob in .If you will
timesliceProperty is passed to the beginning of media captureMediaRecorder.start()(en-US) In the method ,dataavailableThen everytimesliceAn event is triggered in milliseconds . This means that every Blob Have a specific duration ( the last one Blob With the exception of , The latter may be shorter , Because it will be everything left since the last event ).
let mediaRecorder;
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
if (recordButton.textContent === ' Start recording ') {
startRecording();
} else {
stopRecording();
recordButton.textContent = ' Start recording ';
playButton.disabled = false;
}
});
function startRecording() {
recordedBlobs = [];
try {
mediaRecorder = new MediaRecorder(window.stream);
} catch (e) {
console.error(' establish MediaRecorder When abnormal :', e);
}
recordButton.textContent = ' Stop recording ';
playButton.disabled = true;
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start();
}
function stopRecording() {
mediaRecorder.stop();
}
function handleDataAvailable(event) {
if (event.data && event.data.size > 0) {
recordedBlobs.push(event.data);
}
}
Play media stream
URL.createObjectURL()Static methods create aDOMString, It contains a... That represents the object given in the parameter URL. This URL Life cycle and create it in the window ofdocumentbinding . This new URL Object represents the specifiedFileObject orBlobobject .
let recordedBlobs;
const recordedVideo = document.querySelector('video#recorded');
const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
const superBuffer = new Blob(recordedBlobs, { type: 'video/webm' });
recordedVideo.src = null;
recordedVideo.srcObject = null;
recordedVideo.src = window.URL.createObjectURL(superBuffer);
recordedVideo.controls = true;
recordedVideo.play();
});
HTML
<link rel="stylesheet" href="./index.css">
<video id="gum" autoplay></video>
<video id="recorded"></video>
<div>
<button id="start"> Start </button>
<button id="record" disabled> Start recording </button>
<button id="play" disabled>Play</button>
</div>
<script src="./index.js"></script>
CSS
button {
margin: 0 3px 10px 0;
padding-left: 2px;
padding-right: 2px;
width: 99px;
}
button:last-of-type {
margin: 0;
}
video {
vertical-align: top;
--width: 25vw;
width: var(--width);
height: calc(var(--width) * 0.5625);
}
video:last-of-type {
margin: 0 0 20px 0;
}
video#gumVideo {
margin: 0 20px 20px 0;
}
JavaScript
let mediaRecorder;
let recordedBlobs;
const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
if (recordButton.textContent === ' Start recording ') {
startRecording();
} else {
stopRecording();
recordButton.textContent = ' Start recording ';
playButton.disabled = false;
}
});
const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
const superBuffer = new Blob(recordedBlobs, { type: 'video/webm' });
recordedVideo.src = null;
recordedVideo.srcObject = null;
recordedVideo.src = window.URL.createObjectURL(superBuffer);
recordedVideo.controls = true;
recordedVideo.play();
});
function handleDataAvailable(event) {
if (event.data && event.data.size > 0) {
recordedBlobs.push(event.data);
}
}
function startRecording() {
recordedBlobs = [];
try {
mediaRecorder = new MediaRecorder(window.stream);
} catch (e) {
console.error(' establish MediaRecorder When abnormal :', e);
}
recordButton.textContent = ' Stop recording ';
playButton.disabled = true;
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start();
}
function stopRecording() {
mediaRecorder.stop();
}
function handleSuccess(stream) {
recordButton.disabled = false;
window.stream = stream;
const gumVideo = document.querySelector('video#gum');
gumVideo.srcObject = stream;
}
async function init(constraints) {
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
handleSuccess(stream);
} catch (e) {
console.error('navigator.getUserMedia error:', e);
}
}
document.querySelector('button#start').addEventListener('click', async () => {
document.querySelector('button#start').disabled = true;
const constraints = {
audio: {},
video: {
width: 1280, height: 720
}
};
await init(constraints);
});

边栏推荐
- 稀疏数组sparsearray
- When vs code uses prettier to format JS, there is a space between the name of the function definition and the parentheses, and ESLIt does not allow this space
- MySQL 索引底层原理
- Understanding of nil in go language
- 架构设计方法
- Distribution operation of D
- Reasons why MySQL indexes are not effective
- API and encapsulation of cookies
- Import export simple
- Thinking skills of technical leaders
猜你喜欢
![[golang] time related](/img/10/56c0031e11677a91a50cda7d8a952f.png)
[golang] time related

MYSQL索引不生效的原因

Several promotion routines of data governance

Phantom star VR equipment product details II: dark battlefield

【微服务系列】Protocol buffer动态解析

Logstash - logstash pushes data to redis

Marketing skills: compared with the advantages of the product, it is more effective to show the use effect to customers

MySQL 数据库的小白安装与登录

事务与消息语义

DS18B20 details
随机推荐
Temperature alarm
稀疏数组sparsearray
Research Report on pallet handling equipment industry - market status analysis and development prospect forecast
Zotero文献管理工具之Jasminum(茉莉花)插件
同步通信和异步通信的区别以及优缺点
个人博客系统需求分析
Five solutions across domains
New generation engineers teach you how to play with alluxio + ml (Part 1)
消息队列-全方位对比
Get the first and last days of the current month, and the first and last days of the previous month
Self attention and multi head self attention (MSA) in transformer
Mysql delete in 不走索引的
Architecture design method
数据治理工作的几种推进套路
MYSQL触发器要如何设置,简单教程新手一看就会
[spark] how to implement spark SQL field blood relationship
How can an enterprise successfully complete cloud migration?
EFK升级到ClickHouse的日志存储实战
Print bit information of numbers
Laravel 实现 groupBy 查询分组数量