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

.NET MAUI Blazor混合应用本地大视频加载问题及方案探索

问题描述

为减少网络流量,视频文件仅从服务器下载一次并存储在缓存目录,播放时从本地读取。使用<video src="file:///path/to/video.mp4">会触发**"Not allowed to load local resource"**错误,但C#代码可正常读取本地文件。需实现将C#的FileStream对象传入HTML播放,且不能一次性加载大视频。

更新尝试:使用DotNetStreamReference传递流,但出现错误:Uncaught TypeError: Failed to execute 'appendBuffer' on 'SourceBuffer': Overload resolution failed.

错误原因

SourceBuffer.appendBuffer()仅接受ArrayBuffer或ArrayBufferView类型参数,而DotNetStreamReference返回的是JavaScript的ReadableStream,直接传入会导致类型不匹配,触发重载解析失败的错误。

解决方案

需将ReadableStream分块转换为Uint8Array(ArrayBufferView的子类)后写入SourceBuffer,同时利用updateend事件实现流式加载,避免一次性读取大文件:

  • 通过DotNetStreamReference将.NET端FileStream传递到JS
  • 在JS中用ReadableStream.getReader()分块读取流数据
  • 等待SourceBuffer完成当前写入后,再写入下一块数据
  • 所有块读取完成后标记媒体流结束并启动播放
修正后的完整代码
@page "/"
@inject IJSRuntime JS

<h1>视频流式播放测试</h1>

<p>缓存文件路径:@filepath</p>
<video controls style="width: 600px;" />

<script>
    async function streamToJavaScript(streamRef) {
        const video = document.querySelector("video");
        const mediaSource = new MediaSource();
        video.src = URL.createObjectURL(mediaSource);

        mediaSource.addEventListener("sourceopen", async () => {
            const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
            const readableStream = await streamRef.stream();
            const reader = readableStream.getReader();

            // 分块读取并写入SourceBuffer
            async function readChunk() {
                const { done, value } = await reader.read();
                if (done) {
                    if (mediaSource.readyState === 'open') {
                        mediaSource.endOfStream();
                        video.play();
                    }
                    return;
                }

                // 等待SourceBuffer可写入
                while (sourceBuffer.updating) {
                    await new Promise(resolve => sourceBuffer.addEventListener('updateend', resolve, { once: true }));
                }

                sourceBuffer.appendBuffer(value);
                readChunk();
            }

            readChunk();
        });
    }
</script>

@code {
    string filepath = Path.Combine(FileSystem.Current.CacheDirectory, "01_welcome.mp4");

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await base.OnAfterRenderAsync(firstRender);
            using var fileStream = File.OpenRead(filepath);
            using var streamRef = new DotNetStreamReference(fileStream, true);
            await JS.InvokeVoidAsync("streamToJavaScript", streamRef);
        }
    }
}
关键修改点
  • 增加firstRender判断,避免重复执行流传递逻辑
  • 用ReadableStream.getReader()实现分块读取,适配大文件场景
  • 等待sourceBuffer.updating状态结束后再写入下一块,防止并发写入冲突
  • 直接使用reader.read()返回的Uint8Array传入appendBuffer,匹配参数类型

内容的提问来源于stack exchange,提问作者Excosy S.P.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:46:17