Posted in Javascript onFebruary 24, 2022
一、监听开始事件
- EventTarget.addEventListener() 方法将指定的监听器注册到
EventTarget
上,当该对象触发指定的事件时,指定的回调函数就会被执行。 事件目标可以是一个文档上的元素Element
,Document
和Window
或者任何其他支持事件的对象 (比如 XMLHttpRequest)。 addEventListener()
的工作原理是将实现EventListener的函数或对象添加到调用它的EventTarget上的指定事件类型的事件侦听器列表中。
document.querySelector('button#start').addEventListener('click', async () => {
document.querySelector('button#start').disabled = true;
const constraints = {
audio: {},
video: {
width: 1280, height: 720
}
};
await init(constraints);
});
二、获取音视频轨道
MediaDevices.getUserMedia()
会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器等等),也可能是其它轨道类型。- 它返回一个 Promise 对象,成功后会resolve回调一个
MediaStream
对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promise会reject回调一个 PermissionDeniedError 或者NotFoundError
。
async function init(constraints) {
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
handleSuccess(stream);
} catch (e) {
console.error('navigator.getUserMedia error:', e);
}
}
HTMLMediaElement
接口的 srcObject 属性设定或返回一个对象,这个对象提供了一个与HTMLMediaElement关联的媒体源,这个对象通常是 MediaStream ,但根据规范可以是 MediaSource, Blob 或者 File。
function handleSuccess(stream) {
recordButton.disabled = false;
window.stream = stream;
const gumVideo = document.querySelector('video#gum');
gumVideo.srcObject = stream;
}
三、录制媒体流
MediaRecorder()
构造函数会创建一个对指定的MediaStream
进行录制的MediaRecorder
对象MediaRecorder.ondataavailable
事件处理程序API处理dataavailable
事件,在响应运行代码Blob数据被提供使用。dataavailable
当MediaRecorder
将媒体数据传递到您的应用程序以供使用时,将触发该事件。数据在包含数据的Blob对象中提供。
这在四种情况下发生:
- 媒体流结束时,所有尚未传递到
ondataavailable
处理程序的媒体数据都将在单个Blob中传递。 - 当调用
MediaRecorder.stop() (en-US)
时,自记录开始或dataavailable事件最后一次发生以来已捕 获的所有媒体数据都将传递到Blob中;此后,捕获结束。 - 调用
MediaRecorder.requestData() (en-US) dataavailable
时,将传递自记录开始或事件最后一次发生以来捕获的所有媒体数据;然后Blob创建一个新文件,并将媒体捕获继续到该blob中。 - 如果将
timeslice
属性传递到开始媒体捕获的MediaRecorder.start() (en-US)
方法中,dataavailable则每timeslice毫秒触发一次事件。这意味着每个Blob都有特定的持续时间(最后一个Blob除外,后者可能更短,因为它将是自上次事件以来剩下的所有东西)。
let mediaRecorder;
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
if (recordButton.textContent === '开始记录') {
startRecording();
} else {
stopRecording();
recordButton.textContent = '开始记录';
playButton.disabled = false;
}
});
function startRecording() {
recordedBlobs = [];
try {
mediaRecorder = new MediaRecorder(window.stream);
} catch (e) {
console.error('创建MediaRecorder时异常:', e);
}
recordButton.textContent = '停止记录';
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);
}
}
四、播放媒体流
URL.createObjectURL()
静态方法会创建一个DOMString
,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。
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">开始</button>
<button id="record" disabled>开始记录</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 === '开始记录') {
startRecording();
} else {
stopRecording();
recordButton.textContent = '开始记录';
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('创建MediaRecorder时异常:', e);
}
recordButton.textContent = '停止记录';
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);
});
到此这篇关于WebRTC记录音视频流(web技术分享)的文章就介绍到这了,更多相关WebRTC记录音视频流内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章,希望大家以后多多支持三水点靠木!
WebRTC记录音视频流(web技术分享)
- Author -
anyRTC声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。
Reply on: @reply_date@
@reply_contents@