您当前的位置:首页 > 电脑百科 > 软件技术 > 音/视频编辑

WebRTC记录音视频流

时间:2022-02-17 14:19:42  来源:  作者:anyRTC云平台

监听开始事件

  • 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);
});
web技术分享|WebRTC记录音视频流

 



Tags:视频流   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
tiktok优质视频判断标准,tiktok怎么样发布视频流量高
课兴兴资源圈创始人分享过很多这类玩法,如果你看完不过瘾,欢迎关注课兴兴,后续为你分享更多干货!TikTok优质视频的判断标准主要包括以下几个方面:1.内容质量:视频内容需要有趣、有...【详细内容】
2024-04-09  Search: 视频流  点击:(7)  评论:(0)  加入收藏
实现浏览器播放rtsp视频流的解决方案
有同学问道:需要实时播放摄像头rtsp视频流,而浏览器不能直接播放,怎样解决?实现这个需求可以通过插件或者转码来实现。要实现这个目的,可以采用的方案非常得多,有商业的也有开源的...【详细内容】
2022-09-16  Search: 视频流  点击:(331)  评论:(0)  加入收藏
8款测试HLS m3u8视频流的免费在线播放器
翻译:Alex技术审校:纪永康本文来自OTTVerse,作者为Krishna Rao Vijayanagar。 ▲扫描图中二维码或点击阅读原文▲了解音视频技术大会更多信息 Easy-Tech#030# 通过m3u8播放器...【详细内容】
2022-06-06  Search: 视频流  点击:(372)  评论:(0)  加入收藏
音视频流媒体文件格式剖析:M3U8篇
M3U8背景介绍M3U8,用 UTF-8 编码。"M3U" 和 "M3U8" 文件都是苹果公司使用的 HTTP Live Streaming(HLS) 协议格式的基础;是 Unicode 版本的 M3U。M3U8文件是M3U文件的一种,只不过...【详细内容】
2022-05-09  Search: 视频流  点击:(1276)  评论:(0)  加入收藏
WebRTC记录音视频流
监听开始事件 EventTarget.addEventListener() 方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。 事件目标可以是一个文档上的...【详细内容】
2022-02-17  Search: 视频流  点击:(247)  评论:(0)  加入收藏
音视频流媒体开发WebRTC 基础知识 -- ICE 交互总结
【网络通信 -- WebRTC】WebRTC 基础知识 -- ICE 交互总结【1】ICE 的一般概念简介ICE 角色offer (主动发起)的一方为 controlling 角色answer (被动接受)的一方为 controlle...【详细内容】
2021-11-30  Search: 视频流  点击:(438)  评论:(0)  加入收藏
CDN视频流中的3个问题以及解决方法
由于CDN要求您通过其数据网导入所有的内容,因此一些流媒体提供商发现他们需要使用多个CDN来到达不同的地区。这意味着管理不同的系统、分散的流媒体以及添加更多的连接来传输...【详细内容】
2020-10-20  Search: 视频流  点击:(227)  评论:(0)  加入收藏
RTMP协议视频直播点播平台EasyDSS播放WS-FLV视频流报错,该如何解决?
TSINGSEE青犀视频团队研发在更新升级视频平台时,都增加了WS-FLV的播放格式,之前的博文解决过EasyGBS新版ws_flv视频流无法播放问题,EasyDSS视频直播点播平台更新后也支持ws_flv...【详细内容】
2020-08-19  Search: 视频流  点击:(593)  评论:(0)  加入收藏
如何用 OBS 和 WebSockets 播放视频流
用这些简化了 WebSockets 的开源支持工具来控制你的流媒体。 来源:https://linux.cn/article-12347-1.html 作者:Kevin Sonney 译者:Xingyu.Wang(本文字数:4340,阅读时长大约:6 分...【详细内容】
2020-06-25  Search: 视频流  点击:(442)  评论:(0)  加入收藏
为何视频流/网游大都使用UDP协议,而不用TCP协议?
TCP协议协议特点:面向连接的可靠传输,报头20字节,存在流量控制机制(超时重发,丢弃重复数据,检验数据,分段排序,拥塞处理,滑动窗口机制,保证数据能从一端传到另一端。) TCP要保证丢失的p...【详细内容】
2020-06-01  Search: 视频流  点击:(1894)  评论:(0)  加入收藏
▌简易百科推荐
视频杂音怎么消除只留人声?简单方法快来学
视频杂音怎么消除只留人声?在家看视频时,你是否经常被背景噪音所困扰,导致听不清人物对话?今天,我们就来介绍几个能帮我们消除视频中杂音的软件,让我们能享受清晰纯净的视听体验!一...【详细内容】
2024-01-31  译言工具集    Tags:视频杂音   点击:(56)  评论:(0)  加入收藏
如何将两个视频无缝拼接成一个视频?几种简单易行的方法推荐
怎么把两个视频拼接成一个视频?将两个视频拼接成一个视频是一种常见的视频编辑需求,特别是在需要制作长视频或合集时。拼接后的视频可以更加流畅自然,便于观看和分享。若是拼接...【详细内容】
2024-01-17  技术小蚂蚁    Tags:视频   点击:(72)  评论:(0)  加入收藏
初学者如何开始学习视频剪辑?新手如何利用剪辑技术赚钱?
想提升自身专业技术技能,我建议报名一个培训班去进行学习。今天我给亲们网罗了几家正规且口碑不错的职业教育学校,可以参考一下王氏教育开办多年几乎零负面,而且全国校区都是实...【详细内容】
2024-01-09  利娇少女    Tags:视频剪辑   点击:(85)  评论:(0)  加入收藏
剪辑师怎么学?剪辑师一个月收入多少?
剪辑师的月收入因地区、经验、技能水平等因素而异。一般来说,初级剪辑师的月收入在几千元左右,中级剪辑师的月收入在一万元左右,高级剪辑师的月收入则可能超过一万元。当然,这只...【详细内容】
2023-12-16  王氏动漫学习训练    Tags:剪辑师   点击:(105)  评论:(0)  加入收藏
ev剪辑如何消音?视频消音方法全都在这!
EV剪辑是一款视频制作软件,支持全格式精准剪辑,可以实现水印添加、配音、字幕、多轨道剪辑、转场等功能。ev剪辑支持消音操作,同时需要注意的地方还是很多的,在进行消音处理时,需...【详细内容】
2023-12-12  温暖如初的生活    Tags:剪辑   点击:(116)  评论:(0)  加入收藏
视频合并怎么制作?
听说你想了解一些视频合并方法?我能告诉你,这可是个有趣的活儿!你知道吗,合并视频不仅可以让你的作品更具创意,还能让你成为朋友圈里的视频剪辑高手!在这里,我将为大家介绍视频合并...【详细内容】
2023-12-12  王旭妍爱生活    Tags:视频合并   点击:(108)  评论:(0)  加入收藏
视频剪辑怎么剪?
在这个数字时代,我们对社交媒体上的视频编辑越来越感兴趣。你可能已经看到了各种专业水平的视频,从搞笑的猫咪视频到惊险刺激的极限运动镜头。而你可能也梦想着自己成为一个视...【详细内容】
2023-12-10  叮当猫的颜色    Tags:视频剪辑   点击:(109)  评论:(0)  加入收藏
新手做短视频用哪个软件好
新手做短视频用哪个软件好?随着短视频的兴起,越来越多的人开始接触短视频制作。对于新手来说,选择一个合适的短视频制作软件非常重要。本文将从以下5个步骤,教新手宝子快速制作...【详细内容】
2023-12-05  短视频    Tags:短视频   点击:(138)  评论:(0)  加入收藏
机器配音和真人配音有什么区别?
今天我要跟你聊聊机器配音和真人配音有什么区别。你知道吗,这个话题可不简单,因为这关乎到我们日常生活中的声音体验,听起来有点高大上,但实际上离我们并不遥远。首先,咱们得来说...【详细内容】
2023-11-30  叮当猫的颜色    Tags:配音   点击:(165)  评论:(0)  加入收藏
视频裁剪后清晰度下降用什么软件?
你是否曾经遇到过这样的场景&mdash;&mdash;想要裁剪一段视频,但却苦于没有合适的工具来实现?别着急!视频裁剪软件就是你的好帮手。这些软件充分利用了先进的视频处理技术,通过直...【详细内容】
2023-11-27  数码小风向    Tags:视频   点击:(163)  评论:(0)  加入收藏
站内最新
站内热门
站内头条