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

1cosmwyk  于 2023-06-20  发布在  Java
关注(0)|答案(2)|浏览(241)

为了录制音频和视频,我在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文件放在第二个文件,类似下面的图片,但没有成功,

问题

我做错了什么?
有没有什么方法可以单独播放webm文件/块?
注意:我不能使用MediaSource播放这些块。

编辑1

正如@布拉德建议的那样,我想将第一个集群之前的所有内容插入到后面的集群中。我有几个webm文件,每个文件的持续时间为5秒。在深入挖掘文件之后,我才知道,几乎每个备用文件都没有集群点(没有0x 1F 43 B675)。
这里我很困惑,我必须在每个文件的开头或每个第一个簇的开头插入头信息(初始化数据)?如果我选择后面的选项,那么如何播放没有任何集群的webm文件?
或者,首先我需要使每个webm文件的方式,它有集群在一开始,所以我可以prepend头信息之前,集群在这些文件?

编辑2

经过一些挖掘和阅读this,我得出的结论是,每个webm文件需要头信息,集群和实际数据。

ux6nzvsh

ux6nzvsh1#

//对于最常规的webm文件,头信息是存在的
//0到189个Uint 8数组元素
在没有看到实际文件数据的情况下,很难说,但这可能是错误的。“头信息”需要是直到第一个Cluster element的所有信息。也就是说,您希望保留从文件开始到看到0x1F43B675之前的所有数据,并将其视为初始化数据。这可以/将因文件而异。在我的测试文件中,这发生在中的1 KB之后。
并将该头信息挂入第二块中,第二块仍然不能播放,但此时浏览器显示的是视频海报(单帧)和两块之和的时长,例如:10秒;每个块持续时间为5秒。
从MediaRecorder输出的块与分段无关,并且可以在不同的时间出现。您实际上希望在Cluster元素上进行拆分。这意味着您需要解析这个WebM文件,至少要解析到当集群的标识符0x1F43B675出现时拆分集群的程度。
有没有什么方法可以单独播放webm文件/块?
你走在正确的道路上,只要把第一个集群之前的所有东西都前置到后面的集群。
一旦你得到了工作,你可能会遇到的下一个问题是,你将无法做到这一点与任何集群。第一个群集 * 必须 * 以关键帧开始,否则浏览器不会对其进行解码。Chrome会跳到下一个集群,但这并不可靠。不幸的是,没有办法配置关键帧的位置与MediaRecorder。如果你足够幸运,能够处理这个视频服务器端,这里是如何用FFmpeg做到这一点:https://stackoverflow.com/a/45172617/362536

njthzxwz

njthzxwz2#

**好吧,看起来这并不像你必须扫描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)

})();
  • 我注意到,对于MediaRecorder.start中较小的timeslice参数和setTimeout中的超时参数,头偏移量变为1。可惜不是42。

相关问题