.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.
相关产品推荐
相关产品推荐

