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

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:视频流   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
监听开始事件 EventTarget.addEventListener() 方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。 事件目标可以是一个文档上的...【详细内容】
2022-02-17  Tags: 视频流  点击:(0)  评论:(0)  加入收藏
【网络通信 -- WebRTC】WebRTC 基础知识 -- ICE 交互总结【1】ICE 的一般概念简介ICE 角色offer (主动发起)的一方为 controlling 角色answer (被动接受)的一方为 controlle...【详细内容】
2021-11-30  Tags: 视频流  点击:(57)  评论:(0)  加入收藏
由于CDN要求您通过其数据网导入所有的内容,因此一些流媒体提供商发现他们需要使用多个CDN来到达不同的地区。这意味着管理不同的系统、分散的流媒体以及添加更多的连接来传输...【详细内容】
2020-10-20  Tags: 视频流  点击:(86)  评论:(0)  加入收藏
TSINGSEE青犀视频团队研发在更新升级视频平台时,都增加了WS-FLV的播放格式,之前的博文解决过EasyGBS新版ws_flv视频流无法播放问题,EasyDSS视频直播点播平台更新后也支持ws_flv...【详细内容】
2020-08-19  Tags: 视频流  点击:(165)  评论:(0)  加入收藏
用这些简化了 WebSockets 的开源支持工具来控制你的流媒体。 来源:https://linux.cn/article-12347-1.html 作者:Kevin Sonney 译者:Xingyu.Wang(本文字数:4340,阅读时长大约:6 分...【详细内容】
2020-06-25  Tags: 视频流  点击:(101)  评论:(0)  加入收藏
TCP协议协议特点:面向连接的可靠传输,报头20字节,存在流量控制机制(超时重发,丢弃重复数据,检验数据,分段排序,拥塞处理,滑动窗口机制,保证数据能从一端传到另一端。) TCP要保证丢失的p...【详细内容】
2020-06-01  Tags: 视频流  点击:(376)  评论:(0)  加入收藏
每一个行业做久了,都会有些小小的私心,就是把这个东西完善到更好,甚至到创造一个新东西的地步,我做视频行业也是这样的(我相信一定不是我一个人这么想的),所以如果有开发者提出什么...【详细内容】
2020-03-09  Tags: 视频流  点击:(93)  评论:(0)  加入收藏
本文来自即构科技技术副总裁冼牛在LiveVideoStackCon 2019上海大会的演讲,详细介绍了即构科技在实时流媒体传输协议选择,抖动处理,拥塞控制等多方面的实践。文 / 冼牛整理 / L...【详细内容】
2019-08-28  Tags: 视频流  点击:(211)  评论:(0)  加入收藏
很多人可能不了解直播APP,特别是音视频流内容分发和转发的方面的内容,我们作为前端用户是很难了解到直播APP实现的技术,具体整个直播实现的流程是什么样?实现技术是什么样?现在小...【详细内容】
2019-06-17  Tags: 视频流  点击:(413)  评论:(0)  加入收藏
▌简易百科推荐
监听开始事件 EventTarget.addEventListener() 方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。 事件目标可以是一个文档上的...【详细内容】
2022-02-17  anyRTC云平台    Tags:视频流   点击:(0)  评论:(0)  加入收藏
前言FFMpeg读做“FF Mpeg”,“FF”指的是“Fast Forward”,而“Mpeg”指的是Moving Picture Experts Group(动态图像专家组)。根据官方介绍,FFMpeg是一个完整的、跨平台的音频和...【详细内容】
2022-02-11  Java云海    Tags:FFMpeg   点击:(10)  评论:(0)  加入收藏
目前短视频行业的快速兴起,越来越多的人开始从事短视频行业,同时也有许多人在为视频后期的配音而焦虑,自己的原声配音,要么不是音色不够好要么就是音色太单一,今天小编就教给大家...【详细内容】
2022-01-26  哆啦A梦的静香    Tags:视频配音   点击:(24)  评论:(0)  加入收藏
mp3文件太大怎么压缩变小?大家都知道mp3是一种常见的音频文件格式,我们平常的录音文件都是这种格式的,也是使用最广泛的音频格式。有时候mp3文件很大会给我们的使用造成很大的...【详细内容】
2022-01-18  西部理工男    Tags:mp3文件   点击:(25)  评论:(0)  加入收藏
首先开始的时候我们插入一张雷神大大的图帮助大家理解一下我们今天的操作究竟属于那一步。 从上图可以看出我们要做的,就是将像素层的 YUV 格式,编码出编码层的 h264数据。首...【详细内容】
2022-01-14  海哥科技宅    Tags:FFmpeg   点击:(45)  评论:(0)  加入收藏
剪映可以剪辑音频,具体操作方法如下:1、打开剪映后,点击“开始创作”。2、在“照片视频”或“素材库”中随便选择一个媒体文件,然后点击添加。建议选择图片,可省去步骤3和步骤4中...【详细内容】
2022-01-10  玩手机的张先生    Tags:剪映   点击:(120)  评论:(0)  加入收藏
m4a和mp3一样,都是一种音频格式,m4a是一种专属于苹果的音频格式,比如iphone手机的录音文件就是m4a格式的,对于苹果手机用户来说并不陌生。而mp3则是一种常见的通用的音频格式,大...【详细内容】
2022-01-10  优速办公软件    Tags:m4a   点击:(34)  评论:(0)  加入收藏
电脑如何mp4转mp3?mp4和mp3分别是常见的视频和音频文件。当我们从网上获取视频或音频时经常能够接触到它们。简单地从网上获取mp4视频和mp3音频,我们都会,但是用电脑如何将mp4...【详细内容】
2022-01-10  娱乐乐小女警    Tags:视频文件   点击:(65)  评论:(0)  加入收藏
很多人想在Windows11电脑上录制电脑上播放的声音或音乐,却不知道如何操作。Win11系统是微软推出的最新系统,很多人购买的电脑上都预装了正版Win11系统,小编购买的联想笔记本电...【详细内容】
2022-01-10  手机技术达人    Tags:录制   点击:(111)  评论:(0)  加入收藏
嗨喽,亲爱的小伙伴们,小编我又来啦!每每收到私信我都很想把我之前分享过的文章转发给这些需要的小伙伴。不过呢,重新换个角度去分享也挺好的,让更多的小伙伴看到小编的分享也不错...【详细内容】
2022-01-10  酷酷的西部牛仔    Tags:视频   点击:(32)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条