关山初度尘未洗,策马扬鞭再奋蹄!这篇文章主要讲述web技术分享| WebRTC记录音视频流相关的知识,希望能为你提供帮助。
监听开始事件
- 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 = https://www.songbingjia.com/android/null;
recordedVideo.srcObject = null;
recordedVideo.src = window.URL.createObjectURL(superBuffer);
recordedVideo.controls = true;
recordedVideo.play();
);
HTML
<
link rel="stylesheet" href="https://www.songbingjia.com/android/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="https://www.songbingjia.com/android/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 = https://www.songbingjia.com/android/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);
);
【web技术分享| WebRTC记录音视频流】
文章图片
推荐阅读
- 数据库之MySQL主从复制与读写分离
- #yyds干货盘点# executor包(执行器功能)
- Ant Design Vue子表格展开只展开一行,其他行折叠#yyds干货盘点#
- JAVA SE—— 文件IO流 (经常忘记的知识点总结)
- #yyds干货盘点# ==,equals,hashcode三者之间的区别
- Java架构进阶笔记(一不小心就死锁了,怎么办())
- Python print()中的sep参数用法介绍
- Python Django的会话框架用法
- Python数据结构S3(字符串、列表、元组、迭代)