1

我正在制作 Web 应用程序,它存储从大型视频文件中剪切下来的短音频文件。用户上传 .mp4 文件,选择声音长度,这里有一个小技巧。剪切音频只能在后端完成(如果我错了,请纠正我)并且发送 700MB 数据不是一个好的选择,所以我使用下面的代码从 .mp4 解码音频数据,然后使用 start 和 stop 参数发送它。后端(Node.js)使用 FFMPEG 剪切音频并保存。

这部分有效,但我意识到来自 60FPS 视频的解码音频听起来不太好(不可怕但在我的应用程序中完全没用)。我的目标是避免第三方,尤其是桌面应用程序(如 audacity),并允许用户从任何 mp4 视频中剪切相关的音频部分。有没有办法在浏览器中将 60FPS 视频转换为 30FPS 视频(ArrayBuffer)然后解码音频?

      fileInput.onchange = event => {
      this.file = event.target["files"][0];
      //.mp4 file
      this.fileURL = URL.createObjectURL(this.file)

      let baseAudioContext = new AudioContext();
      this.file.arrayBuffer().then(buff => {

        baseAudioContext.decodeAudioData(buff,
          success => {
            console.log(success)
            this.bufferToWave(success, 0, success.length);
          },
          err => console.log(err));
      })
    }

  bufferToWave(abuffer, offset, len) {

    var numOfChan = abuffer.numberOfChannels,
      length = len * numOfChan * 2 + 44,
      buffer = new ArrayBuffer(length),
      view = new DataView(buffer),
      channels = [], i, sample,
      pos = 0;

    // write WAVE header
    setUint32(0x46464952);                         // "RIFF"
    setUint32(length - 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 (hardcoded in this demo)

    setUint32(0x61746164);                         // "data" - chunk
    setUint32(length - pos - 4);                   // chunk length

    // write interleaved data
    for (i = 0; i < abuffer.numberOfChannels; i++)
      channels.push(abuffer.getChannelData(i));

    while (pos < length) {
      for (i = 0; i < numOfChan; i++) {             // interleave channels
        sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
        sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767) | 0; // scale to 16-bit signed int
        view.setInt16(pos, sample, true);          // update data chunk
        pos += 2;
      }
      offset++                                     // next source sample
    }

    // create Blob
    //return (URL || webkitURL).createObjectURL(new Blob([buffer], { type: "audio/wav" }));
    var u = (URL || webkitURL).createObjectURL(new Blob([buffer], { type: "audio/wav" }));

    //temporary part
    //downloading file to check quality
    //in this part sound is already broken, no need to show backend code
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = u;
    a.download = name;
    document.body.appendChild(a);
    a.click();



    function setUint16(data) {
      view.setUint16(pos, data, true);
      pos += 2;
    }

    function setUint32(data) {
      view.setUint32(pos, data, true);
      pos += 4;
    }
  }
4

0 回答 0