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

Blazor Server环境下服务器视频内存加载与循环自动播放方案咨询

Blazor Server实现视频循环自动播放方案

一、后端(ASP.NET Core)处理方案

1. 视频访问接口(非静态目录场景)

如果视频存储在非wwwroot目录,可通过Controller返回视频流或内存中的字节数据:

[ApiController]
[Route("api/videos")]
public class VideoController : ControllerBase
{
    private readonly YourDbContext _dbContext;
    private readonly IConfiguration _config;

    public VideoController(YourDbContext dbContext, IConfiguration config)
    {
        _dbContext = dbContext;
        _config = config;
    }

    // 获取所有视频ID列表
    [HttpGet("ids")]
    public async Task<IActionResult> GetVideoIds()
    {
        var videoIds = await _dbContext.Videos.Select(v => v.Id).ToListAsync();
        return Ok(videoIds);
    }

    // 按ID返回视频字节流
    [HttpGet("stream/{id}")]
    public async Task<IActionResult> GetVideoStream(int id)
    {
        var video = await _dbContext.Videos.FindAsync(id);
        if (video == null) return NotFound();

        var storagePath = _config["VideoStoragePath"];
        var fullPath = Path.Combine(storagePath, video.FileName);
        
        if (!System.IO.File.Exists(fullPath)) return NotFound();

        // 读取视频到内存
        var videoBytes = await System.IO.File.ReadAllBytesAsync(fullPath);
        return File(videoBytes, "video/mp4"); // 根据视频格式调整MIME类型
    }
}

2. 静态文件配置(推荐,高效直接)

如果视频存储在wwwroot/videos或其他目录,直接配置静态文件访问,无需额外接口:

// Program.cs
var builder = WebApplication.CreateBuilder(args);
// ...其他配置

var app = builder.Build();

// 默认静态文件访问(wwwroot目录)
app.UseStaticFiles();

// 额外目录的静态文件访问(比如D:\ServerVideos)
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(@"D:\ServerVideos"),
    RequestPath = "/server-videos"
});

// ...其他中间件配置

此时视频URL直接为/server-videos/xxx.mp4,数据库中存储文件名即可。


二、Blazor Server前端组件实现

方案1:流式播放(不缓存到内存,适合大视频)

直接通过视频URL播放,利用HTML5 video的onended事件切换下一个视频:

@page "/video-player"
@inject HttpClient Http
@implements IDisposable

<div class="video-container">
    <video @ref="_videoElement" width="800" autoplay controls @onended="PlayNext">
        <source src="@_currentVideoUrl" type="video/mp4">
        你的浏览器不支持HTML5视频播放。
    </video>
</div>

@code {
    private ElementReference _videoElement;
    private List<string> _videoUrls = new();
    private int _currentIdx = 0;
    private string _currentVideoUrl => _videoUrls.Count > 0 ? _videoUrls[_currentIdx] : string.Empty;

    protected override async Task OnInitializedAsync()
    {
        // 从后端获取视频URL列表(若用静态文件,可直接从数据库读取拼接)
        var videos = await Http.GetFromJsonAsync<List<dynamic>>("/api/videos/list");
        if (videos != null)
        {
            _videoUrls = videos.Select(v => v.Url.ToString()).ToList();
        }
    }

    private async Task PlayNext()
    {
        // 循环切换视频索引
        _currentIdx = (_currentIdx + 1) % _videoUrls.Count;
        // 等待DOM更新后触发播放
        await Task.Delay(100);
        await _videoElement.InvokeAsync("play");
    }

    public void Dispose()
    {
        // 页面销毁时停止播放
        _videoElement.InvokeAsync("pause").Wait();
    }
}

方案2:缓存到前端内存播放(适合小视频)

将视频下载到前端内存转为Blob URL,减少后端请求:

@page "/video-player-memory"
@inject HttpClient Http
@inject IJSRuntime JS
@implements IDisposable

<div class="video-container">
    <video @ref="_videoElement" width="800" autoplay controls @onended="PlayNext">
        <source src="@_currentBlobUrl" type="video/mp4">
        你的浏览器不支持HTML5视频播放。
    </video>
</div>

@code {
    private ElementReference _videoElement;
    private List<string> _blobUrls = new();
    private int _currentIdx = 0;
    private string _currentBlobUrl => _blobUrls.Count > 0 ? _blobUrls[_currentIdx] : string.Empty;

    protected override async Task OnInitializedAsync()
    {
        // 获取视频ID列表
        var videoIds = await Http.GetFromJsonAsync<List<int>>("/api/videos/ids");
        if (videoIds == null) return;

        foreach (var id in videoIds)
        {
            // 下载视频字节流
            var videoBytes = await Http.GetByteArrayAsync($"/api/videos/stream/{id}");
            // 通过JS转为Blob URL
            var blobUrl = await JS.InvokeAsync<string>("createBlobUrl", videoBytes, "video/mp4");
            _blobUrls.Add(blobUrl);
        }
    }

    private async Task PlayNext()
    {
        _currentIdx = (_currentIdx + 1) % _blobUrls.Count;
        await Task.Delay(100);
        await _videoElement.InvokeAsync("play");
    }

    public void Dispose()
    {
        // 释放Blob URL资源,避免内存泄漏
        foreach (var url in _blobUrls)
        {
            JS.InvokeVoidAsync("revokeObjectUrl", url).Wait();
        }
        _videoElement.InvokeAsync("pause").Wait();
    }
}

同时需要在_Host.cshtml(Blazor Server)中添加JS函数:

<script>
    // 创建Blob URL
    function createBlobUrl(byteArray, mimeType) {
        const blob = new Blob([new Uint8Array(byteArray)], { type: mimeType });
        return URL.createObjectURL(blob);
    }

    // 释放Blob URL
    function revokeObjectUrl(url) {
        URL.revokeObjectURL(url);
    }
</script>

三、注意事项

  • MIME类型匹配:确保返回的视频MIME类型与视频格式一致(如mp4对应video/mp4,webm对应video/webm),否则可能无法播放。
  • 内存占用:内存缓存方案仅适合小体积视频,大视频建议用流式播放,避免浏览器内存溢出。
  • 资源释放:Blazor组件销毁时务必停止视频播放并释放Blob URL(若使用),防止内存泄漏。
  • 权限控制:若视频需要权限验证,可在接口中添加身份验证逻辑,或使用ASP.NET Core的静态文件授权。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 06:10:33