web前端录制canvas视频和video的声音,并合并成一个文件进行下载

news/2025/2/11 17:55:11/

 一、captureStream

captureStream‌是一个Web API方法,用于捕获指定元素的媒体流。该方法通常用于从<video>、<audio>或<canvas>元素中捕获实时视频流或音频流,以便进行进一步的处理,如直播、录制或分析‌。

captureStream()方法能够实时捕获视频流,适用于直播、实时监控等场景。

它返回一个MediaStream对象,该对象包含了捕获的视频流数据。相比其他视频捕获方法,captureStream()提供了较低的延迟和更好的灵活性‌。

1、captureStream() 返回的 MediaStream 对象为空

  • 视频元素尚未加载完成,导致无法捕获视频流。确保视频元素已经加载完成,可以通过监听 loadedmetadatacanplay 事件来确认。
  • 视频元素的源路径不正确或无法访问。检查视频元素的源路径是否正确,并确保视频文件可以正常访问。
javascript">const videoElement = document.createElement('video');
videoElement.src = 'video.mp4';videoElement.addEventListener('loadedmetadata', () => {const mediaStream = videoElement.captureStream();if (mediaStream) {// 处理捕获的视频流} else {console.error('Failed to capture stream');}
});

2、处理 captureStream() 返回的 MediaStream 对象

  • 使用 MediaRecorder 将 MediaStream 对象录制为视频文件。
  • 使用 RTCPeerConnectionMediaStream 对象推送到 WebRTC 服务器,实现实时通信。
javascript">const mediaRecorder = new MediaRecorder(mediaStream);mediaRecorder.ondataavailable = (event) => {if (event.data.size > 0) {// 处理录制的视频数据}
};
mediaRecorder.start();

3、AudioContext对象

如果浏览器不支持在video、audio对象上使用captureStream获取流数据,可以考虑使用AudioContext对象进行声音数据获取。

javascript">const audioContext = new (window.AudioContext || window.webkitAudioContext)()
const source = audioContext.createMediaElementSource(videoElement)
const destination = audioContext.createMediaStreamDestination()
source.connect(destination)
const audioStream = destination.stream

二、MediaStream()

构造函数**MediaStream()** 返回新建的 MediaStream 实例,该实例作为媒体流的内容的集合载体,其可能包含多个媒体数据轨,每个数据轨则由一个 MediaStreamTrack 对象表示。如果给出相应参数,在指定的数据轨则被添加到新的流中。否则,该流中不包含任何数据轨。

javascript">newStream = new MediaStream();
newStream = new MediaStream(stream);
newStream = new MediaStream(tracks[]);

参数:

stream:这是另一个 MediaStream 对象,其数据轨会被自动添加到新建的流中。且这些数据轨不会从原流中移除,即变成了两条流共享的数据。

tracks:这是 MediaStreamTrack 对象的 Array 类型的成员,代表了每一个添加到流中的数据轨。

返回值:

新建的 MediaStream 对象,会包含创建时已给的数据轨内容,若没有给定任何数据轨则内容为空。

合并录制的视频流和音频流

javascript">let canvas = document.getElementById('canvas')
let stream = canvas.captureStream(30)
let video = document.getElementById('video')
let audioStream = video.captureStream(30)// 创建一个新的MediaStream,将视频跟音频流合并进去
let combinedStream = new MediaStream([ ...stream.getTracks(), ...audioStream.getAudioTracks()
]);

 

 三、录制Demo

javascript">// 判断是否是微信环境
export function isWeChatEnv() {const userAgent = navigator.userAgent.toLowerCase();return /micromessenger/.test(userAgent);
}
javascript">    let recorder = null; // 录制对象// 录制视频recordVideo(type) {console.error('录制视频')// 开始执行渲染canvas和播放video的代码逻辑、、、、、、this.recording = truelet canvas = document.getElementById('canvas')let stream = canvas.captureStream(30)// 获取音频上下文let audioStreamArr = []// let audioContextArr = []// let sourceArr = []for(let key in this.videoEles) {if(this.videoEles[key]?.captureStream) {const audioStream = this.videoEles[key].captureStream(30)audioStreamArr.push(audioStream)} else {const audioContext = new (window.AudioContext || window.webkitAudioContext)()const source = audioContext.createMediaElementSource(this.videoEles[key])const destination = audioContext.createMediaStreamDestination()source.connect(destination)const audioStream = destination.streamaudioStreamArr.push(audioStream)// const source = new MediaElementAudioSourceNode(audioContext, {//   mediaElement: this.videoEles[key]// })// const gainNode = new GainNode(audioContext)// source.connect(gainNode)// const destination = audioContext.createMediaStreamDestination()// gainNode.connect(destination)// const audioStream = destination.stream// audioContextArr.push(audioContext)// sourceArr.push(source)}}let audioChunks = []audioStreamArr.map(it => {audioChunks.push(...it.getAudioTracks())})// 创建一个新的MediaStream,将视频跟音频流合并进去let combinedStream = new MediaStream([ ...stream.getTracks(), ...audioChunks]);const userAgent = navigator.userAgent || navigator.vendorconsole.error('userAgent::', userAgent)let options = {}/*if ('MediaSource' in window && MediaSource.isTypeSupported('video/webm; codecs="vp9"')) {console.log('Your browser supports VP9 via MediaSource Extensions');} else {console.log('Your browser does NOT support VP9 via MediaSource Extensions');}*/// Androidif (userAgent.match(/Android/i)) {options = {audioBitsPerSecond: 128000,videoBitsPerSecond: 2500000,// mimeType: 'video/webm; codecs="vp8,opus"',mimeType: isWeChatEnv() ? 'video/webm; codecs="vp8,opus"' : 'video/mp4; codecs="avc1.64001e"',}} else if (/iPad|iPhone|iPod/.test(userAgent)) {options = {audioBitsPerSecond: 128000,videoBitsPerSecond: 2500000,mimeType: 'video/mp4; codecs="avc1"',}} else {options = {audioBitsPerSecond: 128000,videoBitsPerSecond: 2500000,// mimeType: 'video/webm; codecs="vp8"',mimeType: 'video/mp4; codecs="avc1"',}}// 初始化录制对象recorder = new MediaRecorder(combinedStream, options)let recordData = []// 收集录制数据recorder.ondataavailable = function(event) {if(event.data && event.data.size) {recordData.push(event.data)}}// 监听录制结束事件recorder.onstop = async () => {console.log('recorder onstop')let  blobType = 'video/mp4'let url = URL.createObjectURL(new Blob(recordData, {type: blobType}))console.log(url)// const a = document.createElement('a');// a.href = url;// a.download = 'recording.webm';// a.click();// URL.revokeObjectURL(url);const time = new Date().toJSON()if (window.navigator && window.navigator?.msSaveOrOpenBlob) {window.navigator.msSaveBlob(url, `${'recording'}_${time}.mp4`);console.log('IOS下载', url)} else {console.log('安卓下载', url)const link = document.createElement("a");link.style.display = "none";link.href = url;// link.target = '_blank';link.setAttribute("download", `${'recording'}_${time}.mp4`);document.body.appendChild(link);link.click();document.body.removeChild(link);}}recorder.start(10000)}// 结束录制recorder.stop()


http://www.ppmy.cn/news/1571212.html

相关文章

Elasticsearch 7 集群搭建问题排查:常见故障解决方案与优化技巧

引言 Elasticsearch 作为一种强大的分布式搜索引擎,已被广泛应用于各种场景,特别是在日志聚合、数据分析等领域中。然而,在实际部署中,尤其是集群搭建阶段,许多用户都会遇到配置问题,导致集群无法成功建立。在本文中,我们将通过一个实际的案例,详细分析和排查 Elastic…

collabora online+nextcloud+mariadb在线文档协助

1、环境 龙蜥os 8.9 docker 2、安装docker dnf -y install dnf-plugins-core dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sed -i shttps://download.docker.comhttps://mirrors.tuna.tsinghua.edu.cn/docker-ce /etc/yum.repos.…

国产化人工智能“产学 研用”一体化创新模式的智慧快消开源了

智慧快消视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。国产化人工智能“…

FFmpeg(一) 简介

FFmpeg 官网 FFmpeg 下载 ffmpeg-release-essentials.7z ffmpeg-release-full-shared.7z FFmpeg既是一款音视频编解码工具&#xff0c;同时也是一组音社频编解码开发套件 FFmpeg包含 多种音视频编码多种协议的流媒体多种色彩格式转换多种采样率转换多种码率转换多种丰富的…

deepseek API 调用-python

【1】创建 API keys 【2】安装openai SDK pip3 install openai 【3】代码&#xff1a; https://download.csdn.net/download/notfindjob/90343352

c语言:取绝对值

假设我们有一个 long 类型的变量 l&#xff0c;我们希望恢复其绝对值。以下是两种方法的对比&#xff1a; 方法1&#xff1a;使用条件语句 这个很好理解&#xff0c;负数时取负运算 &#xff0c;用于数值的符号反转。 long abs_value(long l) {if (l < 0) {return -l;} e…

仿 RabbitMQ 实现的简易消息队列

文章目录 项目介绍开放环境第三⽅库介绍ProtobufMuduo库 需求分析核⼼概念实现内容 消息队列系统整体框架服务端模块数据管理模块虚拟机数据管理模块交换路由模块消费者管理模块信道&#xff08;通信通道&#xff09;管理模块连接管理模块 客户端模块 公共模块日志类其他工具类…

储能系统-系统架构

已更新系列文章包括104、61850、modbus 、单片机等&#xff0c;欢迎关注 IEC61850实现方案和测试-1-CSDN博客 快速了解104协议-CSDN博客 104调试工具2_104协议调试工具-CSDN博客 1 电池储能系统&#xff08;BESS&#xff09; 架构 电池储能系统主要包括、电池、pcs、本地控制…