簡體   English   中英

在不丟失數據或壓縮的情況下將 blob 轉換為 WAV 文件

[英]Convert blob to WAV file without loosing data or compressing

我正在錄制演講並將其轉換為可下載的 WAV 文件。 我正在使用 Angular6 和 MediaRecorder。 首先,我獲取 blob,然后從 blob 中獲取 .wav 文件。 問題是 WAV 文件(可以播放並且聽起來不錯)在此過程中丟失了大部分屬性,並且不是有效的 WAV。 它一直是一個 WebM 文件。 為了進一步處理,我需要真正有效和高質量的 WAV 文件。 最后,我得到了 ~20KB 的文件,而不是 ~300KB 的更大文件。

我的代碼如下所示:

//convert Blob to File. Pass the blob and the file title as arguments
var blobToFile = (theBlob: Blob, fileName:string): File => {
  var b: any = theBlob;
  //Add properties to the blob
  b.lastModifiedDate = new Date();
  b.name = fileName;
  return <File>theBlob;
}

var browser = <any>navigator;  
var headers = new Headers();  
var audioCtx = new AudioContext();
var chunks =[];
var constraints = { audio: true, video: false }; 

var promisifiedOldGUM = function(constraints, successCallback, errorCallback) {
  var getUserMedia = (browser.getUserMedia || browser.webkitGetUserMedia || browser.mozGetUserMedia || browser.msGetUserMedia);

  // Some browsers just don't implement it - return a rejected promise with an error to keep a consistent interface
  if(!getUserMedia) {
    return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
  }

  // Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
  return new Promise(function(successCallback, errorCallback) {
    getUserMedia.call(browser, constraints, successCallback, errorCallback);
  });

}
if (browser.mediaDevices.getUserMedia) {
  browser.mediaDevices.getUserMedia(constraints).then((stream) => { 
  this.mediaRecorder = new MediaRecorder(stream);        

this.mediaRecorder.onstop  = function(){
        var last_bit= chunks[chunks.length-1];
        var blob = new Blob([last_bit], { 'type' : 'audio/wav' });
        var audioURL = window.URL.createObjectURL(blob);
        //convert Blob to file 
        var file = blobToFile(blob, "my-recording.wav"); 

        var link = document.createElement("a");
        link.href = audioURL;
        link.download = 'audio_recording_' + new Date().getTime() + '.wav';
        link.innerHTML = "download file";
        document.body.appendChild(link);  
};     

typings.d.ts文件中的 MediaRecorder 設置如下所示:

declare class MediaRecorder extends EventTarget {

// readonly mimeType: string;
readonly MimeType: 'audio/x-wav';  // 'audio/vnd.wav';
readonly state: 'inactive' | 'recording' | 'paused';
readonly stream: MediaStream;
ignoreMutedMedia: boolean;
videoBitsPerSecond: number;
audioBitsPerSecond: 16000//number;

ondataavailable: (event : MediaRecorderDataAvailableEvent) => void;
onerror: (event: MediaRecorderErrorEvent) => void;
onpause: () => void;
onresume: () => void;
onstart: () => void;
onstop: () => void;

constructor(stream: MediaStream);

start();

stop();

resume();

pause();

isTypeSupported(type: string): boolean;

requestData();


addEventListener<K extends keyof MediaRecorderEventMap>(type: K, listener: (this: MediaStream, ev: MediaRecorderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;

addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;

removeEventListener<K extends keyof MediaRecorderEventMap>(type: K, listener: (this: MediaStream, ev: MediaRecorderEventMap[K]) => any, options?: boolean | EventListenerOptions): void;

removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;

} 

我不知道如何更改blobToFile()函數以在轉換過程中保持錄制質量。 如果你能幫我解決這個問題,我將不勝感激。

正如我在您在評論中鏈接的文件的元數據中看到的那樣。 您使用壓縮文件的編解碼器(此處為Opus)。

我看到兩個解決方案:

  • 如果可以的話,降低編解碼器的壓縮率。
  • 使用具有未壓縮配置的WAV容器(例如PCM)

正如你在聊天中描述我的問題,我認為這更像是第二種解決方案。 我自己不使用mediarecorder但是我發現這個方法來檢查mime類型是否適用它。

MediaRecorder.isTypeSupported("audio/wav;codecs=MS_PCM")

那么你建議你在創建Blob時改變mime類型

new Blob(chunks, { 'type' : 'audio/wav; codecs=MS_PCM' });

要么

new Blob(chunks, { 'type' : 'audio/wav; codecs=0' });

您可以通過創建新的BlobmediaRecorder實例的結果轉換為wav 簡單但不那么明顯,僅適用於 Chrome(我用 v77.0.3865.90 測試過)。

即使MediaRecorder.isTypeSupported('audio/wav')在瀏覽器的控制台上返回false ,您也可以執行以下操作:

    navigator.mediaDevices.getUserMedia({ audio: true })
      .then(stream => {
          const mediaRecorder = new MediaRecorder(stream);
            this.mediaRecorder.ondataavailable = (e) => {
                const blobDataInWebaFormat = e.data; // .weba = webaudio; subset of webm
                const blobDataInWavFormat: Blob = new Blob([blobDataInWebaFormat], { type : 'audio/wav; codecs=0' });
                const dataUrl = URL.createObjectURL(blobDataInWavFormat);
                console.log(dataUrl); // There you can listen to your recording in a wav format
            });
            };
      });

希望它對某人有用,即使是一年后!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM