JS基于页面实现音视频的录制(一)

本文介绍了HTML5中实现音视频录制的三种方法,重点讲解了使用MediaRecorder类和AudioContext接口的实现方式,详细阐述了MediaRecorder的使用流程、主要方法,并给出了实例代码。
摘要由CSDN通过智能技术生成

前言
音频与视频信息的捕捉一直是Web开发中的一个难点。许多年来,我们一直依赖浏览器插件来实现这个需求,随着HTML 5推出,这种情况有所改变。因为,HTML5提供了许多可以访问硬件设备的API,例如:访问GPS设备的Geolocation API、访问accelerometer设备的Orientation API、访问GPU设备的WebGL API、访问音频播放设备的Web Audio API等等。这些API功能非常强大,使用这些API,开发者可以直接通过编写JavaSccript脚本代码来访问底层硬件设备,这也使得通过网页实现音视频的录制变成现实。

1.1 H5网页实现音视频录制的方法

H5网页实现录音(像)的方法有以下几种:

第一种方法:依赖于浏览器插件(Flash 或 Silverlight)实现。

第二种方法:通过Web Api中的MediaRecorder接口实现。MediaRecorder API由w3c制定并致力推进,但ios和微软反应冷淡,所以目前的兼容性都不理想。目前,主要的试验田在chrome和firefox,移动端兼容安卓内置的chrome内核浏览器,Safari/Edge等浏览器一直没有实现。

第三种方法:通过Web Api中的MediaDevices接口提供的getUserMedia方法,并结合AudioContext接口有关方法实现。这个方法涉及到WebRTC的一系列Web API,从采集、编码到通信层面都有,相对要复杂得多,但兼容性好,已经得到了所有主流浏览器的支持。

1.2 使用MediaRecorder类实现前端音视频录制

1.2.1 MediaRecorder类能够录制哪些数据源?
任何媒体形式的标签,对应的数据源都可以录制成音视频。包括 <audio>, <video>,<canvas>, 其中 <audio>, <video>可以来自网络媒体文件,也可以来自本机设备采集。而<canvas>的内容则更加自由,任何绘制在画布上的用户操作,2d或3d图像,都可以进行录制。它为web提供了更多可能性,我们甚至可以把一个h5游戏流程录成视频,保存落地或进行实况传输。

1.2.2 MediaRecorder类录制出来是什么格式的数据?
是经过标准编码后的媒体流数据,可以注入video标签,也可以打包生成文件,还可以进一步做流级别的数据处理,比如画面识别、动态插入内容、播放跳转控制等等。

1.2.3 MediaRecorder类常用的方法
使用MediaRecorder录音录像时,需要严格遵守API说明中的函数调用先后顺序,否则不能成功执行。MediaRecorder类的常用方法:

· MediaRecorder() 构造方法

· getMaxAmplitude() 得到目前为止最大的幅度

· prepare() 准备录音机

· release() 释放MediaRecorder对象

· reset() 重置MediaRecorder对象,使其为空闲状态

· setAudioEncoder() 设置音频编码

· setAudioSource() 设置音频源

· setCamera() 设置摄像机

· setMaxDuration() 设置最大期限

· setMaxFileSize() 设置文件的最大尺寸

· setOnErrorListener() 错误监听

· setOutputFile() 设置输出文件

· setOutputFormat() 设置输出文件的格式

· setPreviewDisplay() 设置预览

· setVideoEncoder() 设置视频编码

· setVideoFrameRate() 设置视频帧的频率

· setVideoSize() 设置视频的宽度和高度(分辨率)

· setVideoSource() 设置视频源

· start() 开始录制

· stop() 停止录制

1.2.4 MediaRecorder录制音视频的主要流程和代码
在这里插入图片描述

① 打开摄像头

HTML5的getUserMedia API为用户提供访问硬件设备媒体(摄像头、视频、音频、地理位置等)的接口,基于该接口,开发者可以在不依赖任何浏览器插件的条件下访问硬件媒体设备。

语法:navigator.mediaDevices.getUserMedia(constraints,onSuccess,onError);

containers:指定请求的媒体类型,主要包含video和audio,至少要有一个类型被指定。

onSuccess:onSuccess是一个自定义的函数。当正确打开摄像头或麦克风,并捕获到视(音)频流时,回调此函数。视频流会作为默认参数传递给onSuccess。

onError:onError是一个自定义函数。如果浏览器无法找到指定的媒体类型或者无法满足相对应的参数要求,回调此函数。错误信息会作为默认参数传递给onError。

下面一段代码展现了getUserMedia接口与相关参数具体使用方法。

//不同的浏览器访问硬件设备的方法不同,首先要找到与浏览器匹配的方法
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

let constrains = {
        //用来定义音视频格式、状态
    audio:true,
    video:true
}

if (navigator.getUserMedia) {
     //判断是否找到与浏览器匹配的方法
    navigator.getUserMedia(constrains, onSuccess, onError);   //打开摄像头或麦克风,并获取视频流
} 
  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Html5网页纯JavaScript录制MP3音频 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Html5网页JavaScript录制MP3音频</title> <meta charset="utf-8" /> </head> <body> Html5网页JavaScript录制MP3音频 录制 停止 上传 调试信息: [removed][removed] [removed] var recorder = new MP3Recorder({ debug:true, funOk: function () { btnStart.disabled = false; log('初始化成功'); }, funCancel: function (msg) { log(msg); recorder = null; } }); var mp3Blob; function funStart(button) { btnStart.disabled = true; btnStop.disabled = false; btnUpload.disabled = true; log('录音开始...'); recorder.start(); } function funStop(button) { recorder.stop(); btnStart.disabled = false; btnStop.disabled = true; btnUpload.disabled = false; log('录音结束,MP3导出中...'); recorder.getMp3Blob(function (blob) { log('MP3导出成功'); mp3Blob = blob; var url = URL.createObjectURL(mp3Blob); var div = document.createElement('div'); var au = document.createElement('audio'); var hf = document.createElement('a'); au.controls = true; au.src = url; hf.href = url; hf.download = new Date().toISOString() + '.mp3'; hf[removed] = hf.download; div.appendChild(au); div.appendChild(hf); recordingslist.appendChild(div); }); } function log(str) { recordingslist[removed] += str + ''; } function funUpload() { var fd = new FormData(); var mp3Name = encodeURIComponent('audio_recording_' + new Date().getTime() + '.mp3'); fd.append('mp3Name', mp3Name); fd.append('file', mp3Blob); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { recordingslist[removed] += '上传成功:' + mp3Name + ''; } }; xhr.open('POST', 'upload.ashx'); xhr.send(fd); } [removed] </body> </html> [javascript] view plain copy 在CODE上查看代码片派生到我的代码片 (function (exports) { var MP3Recorder = function (config) { var recorder = this; config = config || {}; config.sampleRate = config.sampleRate || 44100; config.bitRate = config.bitRate || 128; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; if (navigator.getUserMedia) { navigator.getUserMedia({ audio: true }, function (stream) { var context = new AudioContext(), microphone = context.createMediaStreamSource(stream), processor = context.createScriptProcessor(16384, 1, 1),//bufferSize大小,输入channel数,输出channel数 mp3ReceiveSuccess, currentErrorCallback; config.sampleRate = context.sampleRate; processor.onaudioprocess = function (event) { //边录音边转换 var array = event.inputBuffer.getChannelData(0); realTimeWorker.postMessage({ cmd: 'encode', buf: array }); }; var realTimeWorker = new Worker('js/worker-realtime.js'); realTimeWorker.onmessage = function (e) { switch (e.data.cmd) { case 'init': log('初始化成功'); if (config.funOk) { config.funOk(); } break; case 'end': log('MP3大小:', e.data.buf.length); if (mp3ReceiveSuccess) { mp3ReceiveSuccess(new Blob(e.data.buf, { type: 'audio/mp3' })); } break; case 'error': log('错误信息:' + e.data.error); if (currentErrorCallback) { currentErrorCallback(e.data.error); } break; default: log('未知信息:', e.data); } }; recorder.getMp3Blob = function (onSuccess, onError) { currentErrorCallback = onError; mp3ReceiveSuccess = onSuccess; realTimeWorker.postMessage({ cmd: 'finish' }); }; recorder.start = function () { if (processor && microphone) { microphone.connect(processor); processor.connect(context.destination); log('开始录音'); } } recorder.stop = function () { if (processor && microphone) { microphone.disconnect(); processor.disconnect(); log('录音结束'); } } realTimeWorker.postMessage({ cmd: 'init', config: { sampleRate: config.sampleRate, bitRate: config.bitRate } }); }, function (error) { var msg; switch (error.code || error.name) { case 'PERMISSION_DENIED': case 'PermissionDeniedError': msg = '用户拒绝访问麦客风'; break; case 'NOT_SUPPORTED_ERROR': case 'NotSupportedError': msg = '浏览器不支持麦客风'; break; case 'MANDATORY_UNSATISFIED_ERROR': case 'MandatoryUnsatisfiedError': msg = '找不到麦客风设备'; break; default: msg = '无法打开麦克风,异常信息:' + (error.code || error.name); break; } if (config.funCancel) { config.funCancel(msg); } }); } else { if (config.funCancel) { config.funCancel('当前浏览器不支持录音功能'); } } function log(str) { if (config.debug) { console.log(str); } } } exports.MP3Recorder = MP3Recorder; })(window);
Record sounds / noises around you and turn them into music. It’s a work in progress, at the moment it enables you to record live audio straight from your browser, edit it and save these sounds as a WAV file. There's also a sequencer part where you can create small loops using these sounds with a drone synth overlaid on them. See it working: http://daaain.github.com/JSSoundRecorder Technology ---------- No servers involved, only Web Audio API with binary sound Blobs passed around! ### Web Audio API #### GetUserMedia audio for live recording Experimental API to record any system audio input (including USB soundcards, musical instruments, etc). ```javascript // shim and create AudioContext window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext; var audio_context = new AudioContext(); // shim and start GetUserMedia audio stream navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; navigator.getUserMedia({audio: true}, startUserMedia, function(e) { console.log('No live audio input: ' + e); }); ``` #### Audio nodes for routing You can route audio stream around, with input nodes (microphone, synths, etc), filters (volume / gain, equaliser, low pass, etc) and outputs (speakers, binary streams, etc). ```javascript function startUserMedia(stream) { // create MediaStreamSource and GainNode var input = audio_context.createMediaStreamSource(stream); var volume = audio_context.createGain(); volume.gain.value = 0.7; // connect them and pipe output input.connect(volume); volume.connect(audio_context.destination); // connect recorder as well - see below var recorder = new Recorder(input); } ``` ### WebWorker Processing (interleaving) record buffer is done in the background to not block the main thread and the UI. Also WAV conversion for export is also quite heavy for longer recordings, so best left to run in the background. ```javascript this.context = input.context; this.node = this.context.createScriptProcessor(4096, 2, 2); this.node.onaudioprocess = function(e){ worker.postMessage({ command: 'record', buffer: [ e.inputBuffer.getChannelData(0), e.inputBuffer.getChannelData(1) ] }); } ``` ```javascript function record(inputBuffer){ var bufferL = inputBuffer[0]; var bufferR = inputBuffer[1]; var interleaved = interleave(bufferL, bufferR); recBuffers.push(interleaved); recLength += interleaved.length; } function interleave(inputL, inputR){ var length = inputL.length + inputR.length; var result = new Float32Array(length); var index = 0, inputIndex = 0; while (index < length){ result[index++] = inputL[inputIndex]; result[index++] = inputR[inputIndex]; inputIndex++; } return result; } ``` ```javascript function encodeWAV(samples){ var buffer = new ArrayBuffer(44 + samples.length * 2); var view = new DataView(buffer); /* RIFF identifier */ writeString(view, 0, 'RIFF'); /* file length */ view.setUint32(4, 32 + samples.length * 2, true); /* RIFF type */ writeString(view, 8, 'WAVE'); /* format chunk identifier */ writeString(view, 12, 'fmt '); /* format chunk length */ view.setUint32(16, 16, true); /* sample format (raw) */ view.setUint16(20, 1, true); /* channel count */ view.setUint16(22, 2, true); /* sample rate */ view.setUint32(24, sampleRate, true); /* byte rate (sample rate * block align) */ view.setUint32(28, sampleRate * 4, true); /* block align (channel count * bytes per sample) */ view.setUint16(32, 4, true); /* bits per sample */ view.setUint16(34, 16, true); /* data chunk identifier */ writeString(view, 36, 'data'); /* data chunk length */ view.setUint32(40, samples.length * 2, true); floatTo16BitPCM(view, 44, samples); return view; } ``` ### Binary Blob Instead of file drag and drop interface this binary blob is passed to editor. Note: BlobBuilder deprecated (but a lot of examples use it), you should use Blob constructor instead! ```javascript var f = new FileReader(); f. { audio_context.decodeAudioData(e.target.result, function(buffer) { $('#audioLayerControl')[0].handleAudio(buffer); }, function(e) { console.warn(e); }); }; f.readAsArrayBuffer(blob); ``` ```javascript function exportWAV(type){ var buffer = mergeBuffers(recBuffers, recLength); var dataview = encodeWAV(buffer); var audioBlob = new Blob([dataview], { type: type }); this.postMessage(audioBlob); } ``` ### Virtual File – URL.createObjectURL You can create file download link pointing to WAV blob, but also set it as the source of an Audio element. ```javascript var url = URL.createObjectURL(blob); var audioElement = document.createElement('audio'); var downloadAnchor = document.createElement('a'); audioElement.controls = true; audioElement.src = url; downloadAnchor.href = url; ``` TODO ---- * Sequencer top / status row should be radio buttons :) * Code cleanup / restructuring * Enable open / drag and drop files for editing * Visual feedback (levels) for live recording * Sequencer UI (and separation to a different module) Credits / license ----------------- Live recording code adapted from: http://www.phpied.com/files/webaudio/record.html Editor code adapted from: https://github.com/plucked/html5-audio-editor Copyright (c) 2012 Daniel Demmel MIT License
要在 HTML 页面实现按住按钮录制声音,松开结束录制,需要使用 Web Audio API 和 getUserMedia() 方法。 具体步骤如下: 1. 首先需要在 HTML 文件中添加一个按钮和一个音频元素,用于录制和播放录制的声音。 ```html <button id="record">录制</button> <audio id="player" controls></audio> ``` 2. 然后在 JavaScript 文件中获取按钮和音频元素,并添加事件监听器,用于开始和停止录制。 ```javascript const recordButton = document.getElementById('record'); const player = document.getElementById('player'); let mediaRecorder; let chunks = []; recordButton.addEventListener('mousedown', startRecording); recordButton.addEventListener('mouseup', stopRecording); function startRecording() { navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { mediaRecorder = new MediaRecorder(stream); mediaRecorder.start(); chunks = []; mediaRecorder.addEventListener('dataavailable', e => chunks.push(e.data)); mediaRecorder.addEventListener('stop', () => { const blob = new Blob(chunks); player.src = URL.createObjectURL(blob); }); }); } function stopRecording() { mediaRecorder.stop(); } ``` 3. 在 startRecording() 函数中,首先使用 getUserMedia() 方法获取音频流。然后创建一个 MediaRecorder 实例并开始录制音频。每次录制到新的数据块时,将它们添加到 chunks 数组中。当录制结束时,将所有数据块组合成一个 Blob 对象,然后使用 URL.createObjectURL() 方法创建一个 URL,将其分配给音频元素的 src 属性,以便可以播放录制的声音。 4. 在 stopRecording() 函数中,调用 MediaRecorder 的 stop() 方法,停止录制音频。 这样,当用户按下按钮时,将开始录制声音,松开按钮时录制将停止,并可以播放录制的声音。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

画虎成鳖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值