Vij*_*iya 4 javascript audio reactjs mediastream
我在 ReactJS 中使用 MediaRecorder 来录制来自麦克风的音频并以 MIME 类型“audio/mp3”存储到 blob 中。我想将此 blob 转换为 MP3 并将其上传到 S3 存储桶中。
我可以通过使用audioContext、decodeAudioData 和audioBufferToWav 函数将其转换为WAV,但是WAV 的大小非常大。由于 MP3 文件的大小相对非常小,所以我希望它将我的 blob 转换为 MP3。有什么帮助吗?
我用于录制和转换为 wav 的代码:
getUserMedia({ audio: true })
.then(stream => {
this.stream = stream;
const mimeType = 'audio/mp3';
this.mediaRecorder = new MediaRecorder(stream);
this.mediaRecorder.start();
const audioChunks = [];
this.mediaRecorder.addEventListener('dataavailable', event => {
audioChunks.push(event.data);
});
this.mediaRecorder.addEventListener('stop', () => {
const audioBlob = new Blob(audioChunks, {
type: mimeType});
});
}).catch(error => { });
Run Code Online (Sandbox Code Playgroud)
将上面创建的 blob 转换为 WAV:
const reader = new window.FileReader();
reader.readAsDataURL(audioBlob);
reader.onloadend = () => {
let base64 = reader.result + '';
base64 = base64.split(',')[1];
const ab = new ArrayBuffer(base64.length);
const buff = new Buffer.from(base64, 'base64');
const view = new Uint8Array(ab);
for (let i = 0; i < buff.length; ++i) {
view[i] = buff[i];
}
const context = new AudioContext();
context.decodeAudioData(ab, (buffer) => {
const wavFile = toWav(buffer);
}
Run Code Online (Sandbox Code Playgroud)
我正在存储wavFile到 S3 中。我想要MP3,请帮忙?
我没有使用 ReactJS MediaRecorder,也没有完全遵循您的具体示例中发生的事情,但是我有一个将 AudioBuffer 转换为 mp3 的解决方案。
第一个函数基于russellgood.com/how-to-convert-audiobuffer-to-audio-file。第二个基于lamejs。
function audioBufferToWav(aBuffer) {
let numOfChan = aBuffer.numberOfChannels,
btwLength = aBuffer.length * numOfChan * 2 + 44,
btwArrBuff = new ArrayBuffer(btwLength),
btwView = new DataView(btwArrBuff),
btwChnls = [],
btwIndex,
btwSample,
btwOffset = 0,
btwPos = 0;
setUint32(0x46464952); // "RIFF"
setUint32(btwLength - 8); // file length - 8
setUint32(0x45564157); // "WAVE"
setUint32(0x20746d66); // "fmt " chunk
setUint32(16); // length = 16
setUint16(1); // PCM (uncompressed)
setUint16(numOfChan);
setUint32(aBuffer.sampleRate);
setUint32(aBuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
setUint16(numOfChan * 2); // block-align
setUint16(16); // 16-bit
setUint32(0x61746164); // "data" - chunk
setUint32(btwLength - btwPos - 4); // chunk length
for (btwIndex = 0; btwIndex < aBuffer.numberOfChannels; btwIndex++)
btwChnls.push(aBuffer.getChannelData(btwIndex));
while (btwPos < btwLength) {
for (btwIndex = 0; btwIndex < numOfChan; btwIndex++) {
// interleave btwChnls
btwSample = Math.max(-1, Math.min(1, btwChnls[btwIndex][btwOffset])); // clamp
btwSample = (0.5 + btwSample < 0 ? btwSample * 32768 : btwSample * 32767) | 0; // scale to 16-bit signed int
btwView.setInt16(btwPos, btwSample, true); // write 16-bit sample
btwPos += 2;
}
btwOffset++; // next source sample
}
let wavHdr = lamejs.WavHeader.readHeader(new DataView(btwArrBuff));
let wavSamples = new Int16Array(btwArrBuff, wavHdr.dataOffset, wavHdr.dataLen / 2);
wavToMp3(wavHdr.channels, wavHdr.sampleRate, wavSamples);
function setUint16(data) {
btwView.setUint16(btwPos, data, true);
btwPos += 2;
}
function setUint32(data) {
btwView.setUint32(btwPos, data, true);
btwPos += 4;
}
}
Run Code Online (Sandbox Code Playgroud)
function wavToMp3(channels, sampleRate, samples) {
var buffer = [];
var mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
var remaining = samples.length;
var samplesPerFrame = 1152;
for (var i = 0; remaining >= samplesPerFrame; i += samplesPerFrame) {
var mono = samples.subarray(i, i + samplesPerFrame);
var mp3buf = mp3enc.encodeBuffer(mono);
if (mp3buf.length > 0) {
buffer.push(new Int8Array(mp3buf));
}
remaining -= samplesPerFrame;
}
var d = mp3enc.flush();
if(d.length > 0){
buffer.push(new Int8Array(d));
}
var mp3Blob = new Blob(buffer, {type: 'audio/mp3'});
var bUrl = window.URL.createObjectURL(mp3Blob);
// send the download link to the console
console.log('mp3 download:', bUrl);
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助!
这就是我MediaRecorder根据出色的 CuriousChad 答案组合和格式转换器的方式。只需要考虑 MP3 编码器作为立体声工作。
首先,将 AudioFormat 设置为 'WEBM' (Chrome)、'MP3' 或 'WAV':
this.mediaRecorder.onstop = e => {
if (AudioFormat === 'MP3' || AudioFormat === 'WAV')
{
var data = this.chunks[0];
var blob = new Blob(this.chunks, { type : 'video/webm' });
const audioContext = new AudioContext();
const fileReader = new FileReader();
// Set up file reader on loaded end event
fileReader.onloadend = () => {
const arrayBuffer = fileReader.result;// as ArrayBuffer;
// Convert array buffer into audio buffer
audioContext.decodeAudioData(arrayBuffer, (audioBuffer) => {
// Do something with audioBuffer
console.log(audioBuffer)
var MP3Blob = this.audioBufferToWav(audioBuffer);
onStop(MP3Blob,audioBuffer);
})
}
//Load blob
fileReader.readAsArrayBuffer(blob)
}
else {
var data = this.chunks[0];
var blob = new Blob(this.chunks, { type : 'audio/mpeg' });
onStop(blob,data)
}
this.chunks = [];
};
Run Code Online (Sandbox Code Playgroud)
二、将Buffer转Wav:
audioBufferToWav(aBuffer) {
let numOfChan = aBuffer.numberOfChannels,
btwLength = aBuffer.length * numOfChan * 2 + 44,
btwArrBuff = new ArrayBuffer(btwLength),
btwView = new DataView(btwArrBuff),
btwChnls = [],
btwIndex,
btwSample,
btwOffset = 0,
btwPos = 0;
setUint32(0x46464952); // "RIFF"
setUint32(btwLength - 8); // file length - 8
setUint32(0x45564157); // "WAVE"
setUint32(0x20746d66); // "fmt " chunk
setUint32(16); // length = 16
setUint16(1); // PCM (uncompressed)
setUint16(numOfChan);
setUint32(aBuffer.sampleRate);
setUint32(aBuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
setUint16(numOfChan * 2); // block-align
setUint16(16); // 16-bit
setUint32(0x61746164); // "data" - chunk
setUint32(btwLength - btwPos - 4); // chunk length
for (btwIndex = 0; btwIndex < aBuffer.numberOfChannels; btwIndex++)
btwChnls.push(aBuffer.getChannelData(btwIndex));
while (btwPos < btwLength) {
for (btwIndex = 0; btwIndex < numOfChan; btwIndex++) {
// interleave btwChnls
btwSample = Math.max(-1, Math.min(1, btwChnls[btwIndex][btwOffset])); // clamp
btwSample = (0.5 + btwSample < 0 ? btwSample * 32768 : btwSample * 32767) | 0; // scale to 16-bit signed int
btwView.setInt16(btwPos, btwSample, true); // write 16-bit sample
btwPos += 2;
}
btwOffset++; // next source sample
}
let wavHdr = lamejs.WavHeader.readHeader(new DataView(btwArrBuff));
//Stereo
let data = new Int16Array(btwArrBuff, wavHdr.dataOffset, wavHdr.dataLen / 2);
let leftData = [];
let rightData = [];
for (let i = 0; i < data.length; i += 2) {
leftData.push(data[i]);
rightData.push(data[i + 1]);
}
var left = new Int16Array(leftData);
var right = new Int16Array(rightData);
if (AudioFormat === 'MP3')
{
//STEREO
if (wavHdr.channels===2)
return this.wavToMp3Stereo(wavHdr.channels, wavHdr.sampleRate, left,right);
//MONO
else if (wavHdr.channels===1)
return this.wavToMp3Mono(wavHdr.channels, wavHdr.sampleRate, data);
}
else
return new Blob([btwArrBuff], {type: "audio/wav"});
function setUint16(data) {
btwView.setUint16(btwPos, data, true);
btwPos += 2;
}
function setUint32(data) {
btwView.setUint32(btwPos, data, true);
btwPos += 4;
}
}
Run Code Online (Sandbox Code Playgroud)
三、WAV转MP3:
我不得不切换到立体声,因为我有 2 个 MP3Encoder 左右声道。
wavToMp3(channels, sampleRate, left, right = null) {
var buffer = [];
var mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
var remaining = left.length;
var samplesPerFrame = 1152;
for (var i = 0; remaining >= samplesPerFrame; i += samplesPerFrame) {
if (!right)
{
var mono = left.subarray(i, i + samplesPerFrame);
var mp3buf = mp3enc.encodeBuffer(mono);
}
else {
var leftChunk = left.subarray(i, i + samplesPerFrame);
var rightChunk = right.subarray(i, i + samplesPerFrame);
var mp3buf = mp3enc.encodeBuffer(leftChunk,rightChunk);
}
if (mp3buf.length > 0) {
buffer.push(mp3buf);//new Int8Array(mp3buf));
}
remaining -= samplesPerFrame;
}
var d = mp3enc.flush();
if(d.length > 0){
buffer.push(new Int8Array(d));
}
var mp3Blob = new Blob(buffer, {type: 'audio/mp3'});
//var bUrl = window.URL.createObjectURL(mp3Blob);
// send the download link to the console
//console.log('mp3 download:', bUrl);
return mp3Blob;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4232 次 |
| 最近记录: |