목차
问题1:怎么上传
问题2:文件体积太大
继续缩小体积
最后就是这个采样率了
웹 프론트엔드 H5 튜토리얼 HTML5 웹페이지 녹화 및 압축 샘플 코드에 대한 자세한 설명

HTML5 웹페이지 녹화 및 압축 샘플 코드에 대한 자세한 설명

Mar 21, 2017 pm 03:26 PM

 最近公司需要用到web录音的功能

讲的都差不多

问题1:怎么上传

下载来的栗子也比较简单,可以直接运行

问题1:怎么上传

栗子中最后返回的是Blob数据

return new Blob([dataview], { type: type })
로그인 후 복사

因为对html5不熟,所以又查了一些数据

原来HTML5中使用FormData这个对象好方便

var fd = new FormData();
fd.append("audioData", blob);var xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.send(fd);
로그인 후 복사

C#服务器端 如下代码就可以接收了

public void ProcessRequest(HttpContext context)
{    if (context.Request.Files.Count > 0)
    {
        context.Request.Files[0].SaveAs("d:\\1.wav");
    }
}
로그인 후 복사

问题2:文件体积太大

是的,使用上面的栗子,直接录音保存后基本上2秒就需要400K,一段20秒的录音就达到了的4M

这样的数据根本无法使用,必须想办法压缩数据

我开始尝试读每一段代码

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;
}
로그인 후 복사

上面的代码,就是把字节数据格式化成wav的格式的过程

所以我又去查了wav的头文件

要压缩,就要从上面三个红圈的地方入手

最简单的就是把双声道改成单声道的,

在录音的时候只需要记录一个声道就可以了

// 创建声音的缓存节点,createJavaScriptNode方法的
    // 第二个和第三个参数指的是输入和输出都是双声道。
    //recorder = context.createJavaScriptNode(bufferSize, 2, 2);
    recorder = context.createJavaScriptNode(bufferSize, 1, 1);//这里改成1

    this.node.onaudioprocess = function(e){
      if (!recording) return;
      worker.postMessage({
        command: 'record',
        buffer: [
          e.inputBuffer.getChannelData(0)//,
          //e.inputBuffer.getChannelData(1)// 这里只需要保存一个
        ]
      });
    }

function exportWAV(type){
  var bufferL = mergeBuffers(recBuffersL, recLength);
  //var bufferR = mergeBuffers(recBuffersR, recLength);
  var interleaved = interleave(bufferL);//, bufferR); //合并数据的时候去到对右声道的处理
  var dataview = encodeWAV(interleaved);
  var audioBlob = new Blob([dataview], { type: type });
 
  this.postMessage(audioBlob);
}

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;
}
로그인 후 복사

然后修改一下注释,我不喜欢英文的....

function encodeWAV(samples) {
    var dataLength = samples.length * 2;
    var buffer = new ArrayBuffer(44 + dataLength);
    var view = new DataView(buffer);

    var sampleRateTmp = sampleRate;
    var sampleBits = 16;
    var channelCount = 1;
    var offset = 0;
    /* 资源交换文件标识符 */
    writeString(view, offset, &#39;RIFF&#39;); offset += 4;
    /* 下个地址开始到文件尾总字节数,即文件大小-8 */
    view.setUint32(offset, /*32这里地方栗子中的值错了,但是不知道为什么依然可以运行成功*/ 36 + dataLength, true); offset += 4;
    /* WAV文件标志 */
    writeString(view, offset, &#39;WAVE&#39;); offset += 4;
    /* 波形格式标志 */
    writeString(view, offset, &#39;fmt &#39;); offset += 4;
    /* 过滤字节,一般为 0x10 = 16 */
    view.setUint32(offset, 16, true); offset += 4;
    /* 格式类别 (PCM形式采样数据) */
    view.setUint16(offset, 1, true); offset += 2;
    /* 通道数 */
    view.setUint16(offset, channelCount, true); offset += 2;
    /* 采样率,每秒样本数,表示每个通道的播放速度 */
    view.setUint32(offset, sampleRateTmp, true); offset += 4;
    /* 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 */
    view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset += 4;
    /* 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 */
    view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
    /* 每样本数据位数 */
    view.setUint16(offset, sampleBits, true); offset += 2;
    /* 数据标识符 */
    writeString(view, offset, &#39;data&#39;); offset += 4;
    /* 采样数据总数,即数据总大小-44 */
    view.setUint32(offset, dataLength, true); offset += 4;
    /* 采样数据 */
    floatTo16BitPCM(view, 44, samples);

    return view;
}
로그인 후 복사

一旦把双声道变为单声道,数据直接缩小一半了

但是还不够

继续缩小体积

除了声道以外,还有一个可以缩减的地方就是采样位数 默认是16位的,我们改成8位 又可以减少一半了

function encodeWAV(samples) {
    var sampleBits = 8;//16;//这里改成8位
    var dataLength = samples.length * (sampleBits / 8);
    var buffer = new ArrayBuffer(44 + dataLength);
    var view = new DataView(buffer);

    var sampleRateTmp = sampleRate;

    var channelCount = 1;
    var offset = 0;
    /* 资源交换文件标识符 */
    writeString(view, offset, &#39;RIFF&#39;); offset += 4;
    /* 下个地址开始到文件尾总字节数,即文件大小-8 */
    view.setUint32(offset, /*32这里地方栗子中的值错了,但是不知道为什么依然可以运行成功*/ 36 + dataLength, true); offset += 4;
    /* WAV文件标志 */
    writeString(view, offset, &#39;WAVE&#39;); offset += 4;
    /* 波形格式标志 */
    writeString(view, offset, &#39;fmt &#39;); offset += 4;
    /* 过滤字节,一般为 0x10 = 16 */
    view.setUint32(offset, 16, true); offset += 4;
    /* 格式类别 (PCM形式采样数据) */
    view.setUint16(offset, 1, true); offset += 2;
    /* 通道数 */
    view.setUint16(offset, channelCount, true); offset += 2;
    /* 采样率,每秒样本数,表示每个通道的播放速度 */
    view.setUint32(offset, sampleRateTmp, true); offset += 4;
    /* 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 */
    view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset += 4;
    /* 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 */
    view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
    /* 每样本数据位数 */
    view.setUint16(offset, sampleBits, true); offset += 2;
    /* 数据标识符 */
    writeString(view, offset, &#39;data&#39;); offset += 4;
    /* 采样数据总数,即数据总大小-44 */
    view.setUint32(offset, dataLength, true); offset += 4;
    /* 采样数据 */
    //floatTo16BitPCM(view, 44, samples);
    floatTo8BitPCM(view, 44, samples);//这里改为写入8位的数据
    return view;
}
로그인 후 복사

8和16的取值范围不一样

对比一下To8和To16的方法

这里方法是我自己猜的,如果不对还望指出~~~

function floatTo16BitPCM(output, offset, input) {
    for (var i = 0; i < input.length; i++, offset += 2) {   
    //因为是int16所以占2个字节,所以偏移量是+2
        var s = Math.max(-1, Math.min(1, input[i]));
        output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
    }
}


function floatTo8BitPCM(output, offset, input) {
    for (var i = 0; i < input.length; i++, offset++) {    
    //这里只能加1了
        var s = Math.max(-1, Math.min(1, input[i]));
        var val = s < 0 ? s * 0x8000 : s * 0x7FFF;         
        val = parseInt(255 / (65535 / (val + 32768)));     
        //这里有一个转换的代码,这个是我个人猜测的,就是按比例转换
        output.setInt8(offset, val, true);
    }
}
로그인 후 복사

怀着忐忑的心情,启动网页...居然听的到声音~居然成功了!!!

经过这样之后又减少了一半大小

最后就是这个采样率了

网页中录音组件的采样率是44100 不知道在哪里改,查询了一些资料,未果...

所以又自己猜测了,是不是我把已经缓存的时候按照比例抛弃一些就可以模拟减少采样率的操作呢?

比如现在已经缓存的数据大小是40960 是不是我直接间隔一位抛弃一次数据,将数据大小变成20480 就可以算是采样率变成22050了呢?

同理,要编程11025只要再抛弃一半的数据?

所以我又做了如下修改

function interleave(inputL, inputR) {
    var compression = 44100 / 11025;    //计算压缩率 
    var length = inputL.length / compression;
    var result = new Float32Array(length);

    var index = 0,
      inputIndex = 0;

    while (index < length) {
        result[index] = inputL[inputIndex];
        inputIndex += compression;//每次都跳过3个数据
        index++;
    }
    return result;
}


function encodeWAV(samples) {
    var dataLength = samples.length;
    var buffer = new ArrayBuffer(44 + dataLength);
    var view = new DataView(buffer);

    var sampleRateTmp = 11025 ;//sampleRate;//写入新的采样率 
    var sampleBits = 8;
    var channelCount = 1;
    var offset = 0;
    /* 资源交换文件标识符 */
    writeString(view, offset, &#39;RIFF&#39;); offset += 4;
    /* 下个地址开始到文件尾总字节数,即文件大小-8 */
    view.setUint32(offset, /*32*/ 36 + dataLength, true); offset += 4;
    /* WAV文件标志 */
    writeString(view, offset, &#39;WAVE&#39;); offset += 4;
    /* 波形格式标志 */
    writeString(view, offset, &#39;fmt &#39;); offset += 4;
    /* 过滤字节,一般为 0x10 = 16 */
    view.setUint32(offset, 16, true); offset += 4;
    /* 格式类别 (PCM形式采样数据) */
    view.setUint16(offset, 1, true); offset += 2;
    /* 通道数 */
    view.setUint16(offset, channelCount, true); offset += 2;
    /* 采样率,每秒样本数,表示每个通道的播放速度 */
    view.setUint32(offset, sampleRateTmp, true); offset += 4;
    /* 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 */
    view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset += 4;
    /* 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 */
    view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
    /* 每样本数据位数 */
    view.setUint16(offset, sampleBits, true); offset += 2;
    /* 数据标识符 */
    writeString(view, offset, &#39;data&#39;); offset += 4;
    /* 采样数据总数,即数据总大小-44 */
    view.setUint32(offset, dataLength, true); offset += 4;
    /* 采样数据 */
    floatTo16BitPCM(view, 44, samples);

    return view;
}
로그인 후 복사

再次怀着忐忑的心情,启动网页...居然听的到声音~居然又成功了

最后把之前的代码整理封装一下

js

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body>
    <div>
        <audio controls autoplay></audio>
        <input onclick="startRecording()" type="button" value="录音" />
        <input onclick="stopRecording()" type="button" value="停止" />
        <input onclick="playRecording()" type="button" value="播放" />
        <input onclick="uploadAudio()" type="button" value="提交" />
    </div>

    <script type="text/javascript" src="HZRecorder.js"></script>


    <script>

        var recorder;

        var audio = document.querySelector(&#39;audio&#39;);

        function startRecording() {
            HZRecorder.get(function (rec) {
                recorder = rec;
                recorder.start();
            });
        }

        function stopRecording() {
            recorder.stop();
        }

        function playRecording() {
            recorder.play(audio);
        }

        function uploadAudio() {
            recorder.upload("Handler1.ashx", function (state, e) {
                switch (state) {
                    case &#39;uploading&#39;:
                        //var percentComplete = Math.round(e.loaded * 100 / e.total) + &#39;%&#39;;
                        break;
                    case &#39;ok&#39;:
                        //alert(e.target.responseText);
                        alert("上传成功");
                        break;
                    case &#39;error&#39;:
                        alert("上传失败");
                        break;
                    case &#39;cancel&#39;:
                        alert("上传被取消");
                        break;
                }
            });
        }

    </script>

</body>
</html>
로그인 후 복사

위 내용은 HTML5 웹페이지 녹화 및 압축 샘플 코드에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 채팅 명령 및 사용 방법
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

HTML의 테이블 테두리 HTML의 테이블 테두리 Sep 04, 2024 pm 04:49 PM

HTML의 테이블 테두리 안내. 여기에서는 HTML의 테이블 테두리 예제를 사용하여 테이블 테두리를 정의하는 여러 가지 방법을 논의합니다.

HTML 여백-왼쪽 HTML 여백-왼쪽 Sep 04, 2024 pm 04:48 PM

HTML 여백-왼쪽 안내. 여기에서는 HTML margin-left에 대한 간략한 개요와 코드 구현과 함께 예제를 논의합니다.

HTML의 중첩 테이블 HTML의 중첩 테이블 Sep 04, 2024 pm 04:49 PM

HTML의 Nested Table에 대한 안내입니다. 여기에서는 각 예와 함께 테이블 내에 테이블을 만드는 방법을 설명합니다.

HTML 테이블 레이아웃 HTML 테이블 레이아웃 Sep 04, 2024 pm 04:54 PM

HTML 테이블 레이아웃 안내. 여기에서는 HTML 테이블 레이아웃의 값에 대해 예제 및 출력 n 세부 사항과 함께 논의합니다.

HTML 입력 자리 표시자 HTML 입력 자리 표시자 Sep 04, 2024 pm 04:54 PM

HTML 입력 자리 표시자 안내. 여기서는 코드 및 출력과 함께 HTML 입력 자리 표시자의 예를 논의합니다.

HTML 정렬 목록 HTML 정렬 목록 Sep 04, 2024 pm 04:43 PM

HTML 순서 목록에 대한 안내입니다. 여기서는 HTML Ordered 목록 및 유형에 대한 소개와 각각의 예에 대해서도 설명합니다.

HTML에서 텍스트 이동 HTML에서 텍스트 이동 Sep 04, 2024 pm 04:45 PM

HTML에서 텍스트 이동 안내. 여기서는 Marquee 태그가 구문과 함께 작동하는 방식과 구현할 예제에 대해 소개합니다.

HTML 온클릭 버튼 HTML 온클릭 버튼 Sep 04, 2024 pm 04:49 PM

HTML onclick 버튼에 대한 안내입니다. 여기에서는 각각의 소개, 작업, 예제 및 다양한 이벤트의 onclick 이벤트에 대해 설명합니다.

See all articles