如何单独播放由MediaRecorder创建的WEBM文件

问题描述 投票:3回答:2

为了录制音频和视频,我正在MediaRecorder API的ondataavailable下创建webm文件。我必须分别播放每个创建的webm文件。

Mediarecorder api仅将标头信息插入第一个块(webm文件),因此,其余的块在没有标头信息的情况下不会单独播放。

如建议的link 1link 2,我从第一个块中提取了标题信息,

// for the most regular webm files, the header information exists
// between 0 to 189 Uint8 array elements

const headerIinformation = arrayBufferFirstChunk.slice(0, 189); 

并且将此标头信息附加到第二块中,仍然不能播放第二块,但是这次浏览器正在显示视频的海报(单帧)和两个块的总和持续时间,例如:10秒;每个块的持续时间为5秒。

我使用十六进制编辑器执行的同一标头信息。我在编辑器中打开了webm文件,并将第一个webm文件中的前190个元素复制到了第二个文件中,如下图所示,即使这次,第二个webm文件也无法播放,结果与前面的示例相同。

红色显示标题信息:

webm hex

这次,我从第一个webm文件复制了标头和群集信息,将其放置到第二个文件中,如下图所示,但没有成功,

webm hex

问题

我在这里做错了什么?

我们有什么方法可以分别播放webm文件/块吗?

注意:我无法使用MediaSource播放这些块。

编辑1

正如@Brad所建议的,我想将所有内容插入第一个群集之前的内容,再插入到后面的群集中。我有几个webm文件,每个文件的持续时间为5秒。深入研究文件后,我知道几乎每个备用文件都没有聚类点(没有0x1F43B675)。

这里我很困惑,我必须在每个文件的开头或每个第一个群集的开头插入标头信息(初始化数据)?如果我选择一个更高的选项,那么如何播放没有群集的webm文件?

或者,首先,我需要使每个webm文件在开始时就具有聚类的方式,因此我可以在这些文件中的聚类之前添加标头信息?

javascript webm web-mediarecorder ebml
2个回答
3
投票

//对于最常规的webm文件,标头信息存在

//在0到189个Uint8数组元素之间

没有看到实际的文件数据,这很难说,但这可能是错误的。 “标题信息”必须是直到第一个Cluster element为止的所有内容。也就是说,您希望保留从文件开头到看到0x1F43B675之前的所有数据,并将其视为初始化数据。每个文件可能/将会有所不同。在我的测试文件中,这种情况发生在1 KB英寸之后。

并且将此标头信息附加到第二块中,仍然不能播放第二块,但是这次浏览器正在显示视频的海报(单帧)和两个块的总和持续时间,例如:10秒;每个块的持续时间为5秒。

MediaRecorder输出的块与分段无关,并且可以在不同的时间发生。您实际上可能想在Cluster元素上进行拆分。这意味着您需要解析此WebM文件,至少要等到它们的标识符0x1F43B675出现时才将它们拆分出来。

我们有什么方法可以分别播放webm文件/块吗?

您走在正确的道路上,只需将第一个群集之前的所有内容放在后面的群集中。

一旦您完成了这项工作,您可能会遇到的下一个问题是,您将无法仅使用任何集群来做到这一点。第一个Cluster must以关键帧开头,否则浏览器不会对其进行解码。 Chrome一定程度上会跳到下一个群集,但这并不可靠。不幸的是,无法使用MediaRecorder配置关键帧放置。如果您有幸能够处理此视频服务器端,请按照以下方法使用FFmpeg:https://stackoverflow.com/a/45172617/362536


0
投票

好吧,这看起来并不像您必须遍历Blob来查找魔术值那样简单。

let offset = -1;
let value = 0;
const magicNumber = parseInt("0x1F43B675".match(/[a-fA-F0-9]{2}/g).reverse().join(''), 16)

while(value !== magicNumber) {
  offset = offset + 1;

  try {
    const arr = await firstChunk.slice(offset, offset + 4).arrayBuffer().then(buffer => new Int32Array(buffer));
    value = arr[0];
  }
  catch(error) {
    return;
  }
}

offset = offset + 4;

答案是193 199

const header = firstChunk.slice(0, offset);
const blobType = firstChunk.type;
const blob = new Blob([header, chunk], { type: blobType });

然后就可以了。现在的问题是我怎么得到这个号码?为什么不是42的倍数?

蛮力] >>

逻辑很简单,录制视频,收集块,切片第一个块,计算新的blob,然后尝试用HTMLVideoElement播放。如果失败,则增加偏移量。

(async() => {

    const microphoneAudioStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });

    const mediaRecorder = new MediaRecorder(microphoneAudioStream);
    let chunks = [];

    mediaRecorder.addEventListener('dataavailable', (event) => {
        const blob = event.data;
        chunks = [...chunks, blob];
    });

    mediaRecorder.addEventListener("stop", async () => {
        const [firstChunk, ...restofChunks] = chunks;
        const [secondBlob] = restofChunks;
        const blobType = firstChunk.type;

        let index = 0;
        const video = document.createElement("video");

        while(index < 1000) {
            const header = firstChunk.slice(0, index);
            const blob = new Blob([header, secondBlob], { type: blobType });
            const url = window.URL.createObjectURL(blob);

            try {
                video.setAttribute("src", url);
                await video.play();
                console.log(index);
                break;
            }
            catch(error) {

            }

            window.URL.revokeObjectURL(url);

            index++;
        }
    })

    mediaRecorder.start(200);

    const stop = () => {
        mediaRecorder.stop();
    }

    setTimeout(stop, 400)

})();

我注意到,对于timeslice中较小的MediaRecorder.start参数和setTimeout中的超时参数,标头偏移变为1。可悲的是,它仍然不是42。

© www.soinside.com 2019 - 2024. All rights reserved.