You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MediaSource加载Uint8Array无报错但视频无法播放问题排查

问题分析与解决方案

核心问题

你的代码存在几个关键问题,导致视频无法正常播放:

1. SourceBuffer MIME类型缺失编码参数

MediaSource API要求必须指定具体的音视频编码格式,只写video/mp4不足以让浏览器解析流数据。

2. 普通MP4不支持MediaSource流式拼接

单独能播放的MP4是非碎片化MP4,而MediaSource仅支持碎片化MP4(fMP4)——这种格式的文件结构是专为流式传输设计的。

3. 分片追加的异步逻辑错误

appendBuffer是异步操作,你直接递归调用get会导致多个分片同时写入,触发updating状态冲突,数据无法正确加载。

4. 分片索引范围错误

服务器有13个文件,索引应该是0到12,但原代码要等i===14才重置,会请求不存在的13.mp4和14.mp4。


修复后的完整代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Video</title>
</head>
<body>
    <div class="content">
        <h1>My Video</h1>
        <video id="video" width="640" height="480" autoplay muted controls></video>
        <script>
            'use strict';

            const video = document.querySelector('video');
            let currentIndex = 0;
            const totalChunks = 13; // 服务器上的分片总数
            const mediaSource = new MediaSource();
            let sourceBuffer;

            if (!window.MediaSource) {
                alert('当前平台不支持MediaSource API');
            }

            video.src = window.URL.createObjectURL(mediaSource);

            mediaSource.addEventListener('sourceopen', () => {
                // 替换为你的视频实际编码格式,示例为h.264视频+aac音频
                const mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
                sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
                
                // 监听分片追加完成事件,再加载下一个分片
                sourceBuffer.addEventListener('updateend', () => {
                    if (currentIndex < totalChunks) {
                        loadNextChunk();
                    } else {
                        // 所有分片加载完成,标记流结束
                        mediaSource.endOfStream();
                    }
                });

                // 启动第一个分片加载
                loadNextChunk();
            });

            function loadNextChunk() {
                const url = `${currentIndex}.mp4`;
                const xhr = new XMLHttpRequest();
                xhr.open('GET', url, true);
                xhr.responseType = 'arraybuffer';

                xhr.onload = () => {
                    if (xhr.status !== 200) {
                        alert(`请求${url}失败,状态码:${xhr.status}`);
                        return;
                    }
                    // 仅当sourceBuffer未在更新时,才追加数据
                    if (!sourceBuffer.updating) {
                        sourceBuffer.appendBuffer(new Uint8Array(xhr.response));
                        currentIndex++;
                    }
                };

                xhr.send();
            }
        </script>
    </div>
</body>
</html>

关键修复说明

  • 补全MIME编码参数:通过codecs明确视频(avc1开头对应h.264)和音频(mp4a开头对应AAC)的编码格式,可通过ffprobe 原视频文件查看实际编码。
  • 转换为碎片化MP4:用FFmpeg将每个普通MP4分片转为fMP4,命令示例:
    ffmpeg -i input.mp4 -movflags frag_keyframe+empty_moov+cmaf output_fmp4.mp4
    
  • 异步分片加载逻辑:通过updateend事件确保上一个分片写入完成后,再加载下一个,避免状态冲突。
  • 修正索引范围:根据13个文件设置totalChunks=13,索引从0到12,避免请求不存在的文件。

验证步骤

  1. 用FFmpeg将所有MP4分片转成碎片化格式。
  2. 替换代码中的mimeCodec为你视频的实际编码信息。
  3. 确保服务器上的分片文件名是0.mp4到12.mp4。
  4. 重新运行代码,视频即可正常播放。

内容的提问来源于stack exchange,提问作者Remi Demers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 17:05:09