音视频的录制音视频的分为服务端录制和客户端录制,下面主要讲的是利用webrtc进行客户端录制的方式。
因为WebRTC 录制音视频流之后,最终是通过 Blob 对象将数据保存成多媒体文件的,
-
Blob
对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成ReadableStream
来用于数据操作。 -
Blob 表示的不一定是JavaScript原生格式的数据。
File
接口基于Blob
,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。 -
要从其他非blob对象和数据构造一个
Blob
,请使用Blob()
构造函数。要创建一个 blob 数据的子集 blob,请使用slice()
方法。要获取用户文件系统上的文件对应的Blob
对象。 - 接受
Blob
对象的API也被列在File
文档中。
了解完Blob的特性之后呢, 我们进入正题。
获取元素声明变量
let mediaRecorder;
let recordedBlobs;
const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
const playButton = document.querySelector('button#play');
const downloadButton = document.querySelector('button#download');
绑定点击事件
-
URL.createObjectURL()
静态方法会创建一个DOMString
,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的document
绑定。这个新的URL 对象表示指定的File
对象或Blob
对象。 URL.revokeObjectURL()
静态方法用来释放一个之前已经存在的、通过调用URL.createObjectURL()
创建的 URL 对象。当你结束使用某个 URL 对象之后,应该通过调用这个方法来让浏览器知道不用在内存中继续保留对这个文件的引用了。你可以在sourceopen
被处理之后的任何时候调用revokeObjectURL()
。这是因为createObjectURL()
仅仅意味着将一个媒体元素的src
属性关联到一个MediaSource
对象上去。调用revokeObjectURL()
使这个潜在的对象回到原来的地方,允许平台在合适的时机进行垃圾收集。
recordButton.addEventListener('click', () => {
if (recordButton.textContent === 'Start Recording') {
startRecording();
} else {
stopRecording();
recordButton.textContent = 'Start Recording';
playButton.disabled = false;
downloadButton.disabled = false;
}
});
playButton.addEventListener('click', () => {
const superBuffer = new Blob(recordedBlobs);
recordedVideo.src = null;
recordedVideo.srcObject = null;
recordedVideo.src = window.URL.createObjectURL(superBuffer);
recordedVideo.controls = true;
recordedVideo.play();
});
downloadButton.addEventListener('click', () => {
const blob = new Blob(recordedBlobs, {
type: 'video/webm'
});
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'test.webm';
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 100);
});
document.querySelector('button#start').addEventListener('click', async () => {
const constraints = {
audio: {},
video: {
width: 1280,
height: 720
}
};
console.log('Using media constraints:', constraints);
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);
}
}
function handleSuccess(stream) {
recordButton.disabled = false;
console.log('getUserMedia() got stream:', stream);
window.stream = stream;
const gumVideo = document.querySelector('video#gum');
gumVideo.srcObject = stream;
}
开始记录方法
function startRecording() {
recordedBlobs = [];
try {
mediaRecorder = new MediaRecorder(window.stream);
} catch (e) {
console.error('Exception while creating MediaRecorder:', e);
return;
}
recordButton.textContent = 'Stop Recording';
playButton.disabled = true;
downloadButton.disabled = true;
mediaRecorder.onstop = (event) => {
console.log('Recorder stopped: ', event);
console.log('Recorded Blobs: ', recordedBlobs);
};
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start();
}
function handleDataAvailable(event) {
if (event.data && event.data.size > 0) {
recordedBlobs.push(event.data);
}
}
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta id="theme-color" name="theme-color" content="#ffffff">
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div id="container">
<video id="gum" playsinline autoplay muted></video>
<video id="recorded" playsinline loop></video>
<div>
<button id="start">Start camera</button>
<button id="record" disabled>Start Recording</button>
<button id="play" disabled>Play</button>
<button id="download" disabled>Download</button>
</div>
</div>
<script src="./main.js" async></script>
</body>
</html>
CSS
button {
background-color: #d84a38;
border: none;
border-radius: 2px;
color: white;
font-family: 'Roboto', sans-serif;
font-size: 0.8em;
margin: 0 0 1em 0;
padding: 0.5em 0.7em 0.6em 0.7em;
}
button:active {
background-color: #cf402f;
}
button:hover {
background-color: #cf402f;
}
button[disabled] {
color: #ccc;
}
button[disabled]:hover {
background-color: #d84a38;
}
div#container {
margin: 0 auto 0 auto;
max-width: 60em;
padding: 1em 1.5em 1.3em 1.5em;
}
video {
background: #222;
margin: 0 0 20px 0;
--width: 100%;
width: var(--width);
height: calc(var(--width) * 0.75);
}
webRTC功能是非常强大的,关于webrtc和直播还有很多技术需要我们去研究,上续呢是DEMO的示例代码,感兴趣的小伙伴可以亲自试一试。
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/148599.html