代码之家  ›  专栏  ›  技术社区  ›  Emanuela Colta

将blob转换为wav文件而不丢失数据或压缩

  •  4
  • Emanuela Colta  · 技术社区  · 6 年前

    我正在努力录制演讲并将其转换为可下载的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);  
    };     
    

    和MediaRecorder的设置 typings.d.ts 文件如下:

    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() 功能,以便在转换过程中保持录制质量。如果你能帮我,我会非常感激的。

    1 回复  |  直到 6 年前
        1
  •  2
  •   JSmith    6 年前

    正如我在文件的元数据中看到的那样 linked 在评论中。 您使用压缩文件的编解码器(这里是opus)。

    我看到两种解决方案:

    • 如果可以,请降低编解码器的压缩比。
    • 使用 WAV 具有未压缩配置的容器(例如,pcm)

    正如你在聊天中描述的那样,我认为这是第二个解决方案。 我自己不使用MediaRecorder,但我找到了这个方法来检查mime类型是否适用于它。

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

    那么我建议您在创建 Blob

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

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