Video.js 是一个具有大量功能的流行的视频和音频 JavaScript 库,今天我们试试集成到 Blazor .

Blazor VideoPlayer 视频播放器 组件

示例

https://blazor.app1.es/videoPlayers

1. 新建工程b13video

dotnet new blazorserver -o b13video

2. 将项目添加到解决方案中:

dotnet sln add b13video/b13video.csproj

3. Pages\_Host.cshtml 引用 video-js.css

<link href="//vjs.zencdn.net/7.10.2/video-js.min.css" rel="stylesheet">

4. 接下来,Pages\_Host.cshtml 引用 Video.js, 添加以下脚本文件到Pages\_Host.cshtml

<script src="https://vjs.zencdn.net/7.10.2/video.js"></script>

<script src="https://unpkg.com/video.js/dist/video.min.js"></script>
<script src="https://unpkg.com/@@videojs/http-streaming/dist/videojs-http-streaming.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-youtube/2.6.1/Youtube.min.js"></script>

5. 添加 app.js 文件到 wwwroot文件夹

文件内容

function loadPlayer(id, options) {
videojs(id, options);
}

6. Pages\_Host.cshtml 引用 app.js

<script src="./app.js"></script>

完整文件看起来应该是这样

@page "/"
@using Microsoft.AspNetCore.Components.Web
@namespace b13video.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="b13video.styles.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
<link href="//vjs.zencdn.net/7.10.2/video-js.min.css" rel="stylesheet">
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
<component type="typeof(App)" render-mode="ServerPrerendered" /> <div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss"></a>
</div> <script src="_framework/blazor.server.js"></script> <script src="https://unpkg.com/video.js/dist/video.min.js"></script>
<script src="https://unpkg.com/@@videojs/http-streaming/dist/videojs-http-streaming.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-youtube/2.6.1/Youtube.min.js"></script>
<script src="./app.js"></script>
</body>
</html>

7. Razor 页面, 我们直接在 Index.razor 里添加

<video id="my-player"
class="video-js"
controls
preload="auto"
poster="//vjs.zencdn.net/v/oceans.png"
data-setup='{}'>
<source src="//vjs.zencdn.net/v/oceans.mp4" type="video/mp4" />
<source src="//vjs.zencdn.net/v/oceans.webm" type="video/webm" />
<source src="//vjs.zencdn.net/v/oceans.ogv" type="video/ogg" />
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank">
supports HTML5 video
</a>
</p>
</video>

跑一下

8. 封装

取消几行html组件设定,改为c#提供参数, 最终代码如下

<video id="my-player"
class="video-js"
muted >
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
@ -17,3 +14,27 @@
</a>
</p>
</video>
@inject IJSRuntime jsRuntime
@code{
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await jsRuntime.InvokeVoidAsync("loadPlayer", "my-player", new
{
width = 600,
height = 300,
controls = true,
autoplay = true,
preload = "auto",
poster = "//vjs.zencdn.net/v/oceans.png",
sources = new[] {
new { type = "application/x-mpegURL", src = "https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8"},
new { type = "video/mp4", src = "//vjs.zencdn.net/v/oceans.mp4"}
}
});
}
} }

调试一下,成功运行就进入下一步.

9. 组件化. {最终代码,请大家直接使用CV大法}

Pages\VideoPlayer.razor

@inject IJSRuntime jsRuntime
@namespace Blazor100.Components <div @ref="element">
<video id="video_@Id"
class="video-js"
muted
webkit-playsinline
playsinline
x-webkit-airplay="allow"
x5-video-player-type="h5"
x5-video-player-fullscreen="true"
x5-video-orientation="portraint">
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank">
supports HTML5 video
</a>
</p>
</video>
@if (Debug)
{
<pre>@info</pre>
}
</div>

Pages\VideoPlayer.razor.cs

using b13video.Pages;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Options;
using Microsoft.JSInterop;
using System.Text.Json.Serialization;
using static System.Runtime.InteropServices.JavaScript.JSType; namespace Blazor100.Components; public partial class VideoPlayer : IAsyncDisposable
{
[Inject] IJSRuntime? JS { get; set; }
private IJSObjectReference? module;
private DotNetObjectReference<VideoPlayer>? instance { get; set; }
protected ElementReference element { get; set; }
private bool init;
private string? info; private string Id { get; set; } = Guid.NewGuid().ToString(); /// <summary>
/// 资源类型
/// </summary>
[Parameter]
public string? SourcesType { get; set; } /// <summary>
/// 资源地址
/// </summary>
[Parameter]
public string? SourcesUrl { get; set; } [Parameter]
public int Width { get; set; } = 300; [Parameter]
public int Height { get; set; } = 200; [Parameter]
public bool Controls { get; set; } = true; [Parameter]
public bool Autoplay { get; set; } = true; [Parameter]
public string Preload { get; set; } = "auto"; /// <summary>
/// 设置封面
/// </summary>
[Parameter]
public string? Poster { get; set; } [Parameter]
public VideoPlayerOption? Option { get; set; } [Parameter]
public bool Debug { get; set; } protected override async Task OnAfterRenderAsync(bool firstRender)
{
try
{
if (firstRender)
{
module = await JS!.InvokeAsync<IJSObjectReference>("import", "./app.js");
instance = DotNetObjectReference.Create(this); Option = Option ?? new VideoPlayerOption()
{
Width = Width,
Height = Height,
Controls = Controls,
Autoplay = Autoplay,
Preload = Preload,
Poster = Poster,
//EnableSourceset= true,
//TechOrder= "['fakeYoutube', 'html5']"
};
Option.Sources.Add(new VideoSources(SourcesType, SourcesUrl)); try
{
await module.InvokeVoidAsync("loadPlayer", instance, "video_" + Id, Option);
}
catch (Exception e)
{
info = e.Message;
if (Debug) StateHasChanged();
Console.WriteLine(info);
if (OnError != null) await OnError.Invoke(info);
}
}
}
catch (Exception e)
{
if (OnError != null) await OnError.Invoke(e.Message);
}
} async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
await module.InvokeVoidAsync("destroy", Id);
await module.DisposeAsync();
}
} /// <summary>
/// 获得/设置 错误回调方法
/// </summary>
[Parameter]
public Func<string, Task>? OnError { get; set; } /// <summary>
/// JS回调方法
/// </summary>
/// <param name="init"></param>
/// <returns></returns>
[JSInvokable]
public void GetInit(bool init) => this.init = init; /// <summary>
/// JS回调方法
/// </summary>
/// <param name="error"></param>
/// <returns></returns>
[JSInvokable]
public async Task GetError(string error)
{
info = error;
if (Debug) StateHasChanged();
if (OnError != null) await OnError.Invoke(error);
} }

Pages\VideoPlayerOption.cs

using System.Text.Json.Serialization;

namespace b13video.Pages
{
public class VideoPlayerOption
{
[JsonPropertyName("width")]
public int Width { get; set; } = 300; [JsonPropertyName("height")]
public int Height { get; set; } = 200; [JsonPropertyName("controls")]
public bool Controls { get; set; } = true; [JsonPropertyName("autoplay")]
public bool Autoplay { get; set; } = true; [JsonPropertyName("preload")]
public string Preload { get; set; } = "auto"; /// <summary>
/// 播放资源
/// </summary>
[JsonPropertyName("sources")]
public List<VideoSources> Sources { get; set; } = new List<VideoSources>(); /// <summary>
/// 设置封面
/// </summary>
[JsonPropertyName("poster")]
public string? Poster { get; set; } //[JsonPropertyName("enableSourceset")]
//public bool EnableSourceset { get; set; } //[JsonPropertyName("techOrder")]
//public string? TechOrder { get; set; } = "['html5', 'flash']"; } /// <summary>
/// 播放资源
/// </summary>
public class VideoSources
{
public VideoSources() { } public VideoSources(string? type, string? src)
{
this.Type = type ?? throw new ArgumentNullException(nameof(type));
this.Src = src ?? throw new ArgumentNullException(nameof(src));
} /// <summary>
/// 资源类型<para></para>video/mp4<para></para>application/x-mpegURL<para></para>video/youtube
/// </summary>
[JsonPropertyName("type")]
public string Type { get; set; } = "application/x-mpegURL"; /// <summary>
/// 资源地址
/// </summary>
[JsonPropertyName("src")]
public string Src { get; set; } = "application/x-mpegURL";
}
}

wwwroot\app.js

var player = null;

export function loadPlayer(instance, id, options) {
console.log('player id', id);
player = videojs(id, options); player.ready(function () {
console.log('player.ready');
var promise = player.play(); if (promise !== undefined) {
promise.then(function () {
console.log('Autoplay started!');
}).catch(function (error) {
console.log('Autoplay was prevented.', error);
instance.invokeMethodAsync('GetError', 'Autoplay was prevented.'+ error);
});
}
instance.invokeMethodAsync('GetInit', true);
}); return false;
} export function destroy(id) {
if (undefined !== player && null !== player) {
player = null;
console.log('destroy');
}
}

10. 页面调用

<div class="row">

    <div class="col-4">
<VideoPlayer SourcesType="application/x-mpegURL" SourcesUrl="https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8" Debug="true" />
</div>
<div class="col-4">
<VideoPlayer SourcesType="video/mp4" SourcesUrl="//vjs.zencdn.net/v/oceans.mp4" />
</div>
<div class="col-4">
<VideoPlayer SourcesType="application/x-mpegURL" SourcesUrl="https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8" />
</div>
</div>

项目源码

Github

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

AlexChow

今日头条 | 博客园 | 知乎 | Gitee | GitHub


Blazor 组件

条码扫描 ZXingBlazor



图片浏览器 Viewer

条码扫描 BarcodeScanner

手写签名 Handwritten

手写签名 SignaturePad

定位/持续定位 Geolocation

屏幕键盘 OnScreenKeyboard

百度地图 BaiduMap

谷歌地图 GoogleMap

蓝牙和打印 Bluetooth

PDF阅读器 PdfReader

文件系统访问 FileSystem

光学字符识别 OCR

电池信息/网络信息 WebAPI

Blazor组件自做十三: 使用 Video.js 在 Blazor 中播放视频的更多相关文章

  1. Blazor组件自做三 : 使用JS隔离封装ZXing扫码

    Blazor组件自做三 : 使用JS隔离封装ZXing扫码 本文基础步骤参考前两篇文章 Blazor组件自做一 : 使用JS隔离封装viewerjs库 Blazor组件自做二 : 使用JS隔离制作手写 ...

  2. Blazor组件自做八 : 使用JS隔离封装屏幕键盘kioskboard.js组件

    1. 运行截图 演示地址 2. 在文件夹wwwroot/lib,添加kioskboard子文件夹,添加kioskboards.js文件 2.1 常规操作,懒加载js库, export function ...

  3. Blazor组件自做一 : 使用JS隔离封装viewerjs库

    Viewer.js库是一个实用的js库,用于图片浏览,放大缩小翻转幻灯片播放等实用操作 本文相关参考链接 JavaScript 模块中的 JavaScript 隔离 Viewer.js工程 Blazo ...

  4. Blazor组件自做二 : 使用JS隔离制作手写签名组件

    Blazor组件自做二 : 使用JS隔离制作手写签名组件 本文相关参考链接 JavaScript 模块中的 JavaScript 隔离 Viewer.js工程 Blazor组件自做一 : 使用JS隔离 ...

  5. Blazor组件自做四 : 使用JS隔离封装signature_pad签名组件

    运行截图 演示地址 响应式演示 感谢szimek写的棒棒的signature_pad.js项目, 来源: https://github.com/szimek/signature_pad 正式开始 1. ...

  6. Blazor组件自做五 : 使用JS隔离封装Google地图

    Blazor组件自做五: 使用JS隔离封装Google地图 运行截图 演示地址 正式开始 1. 谷歌地图API 谷歌开发文档 开始学习 Maps JavaScript API 的最简单方法是查看一个简 ...

  7. Blazor组件自做六 : 使用JS隔离封装Baidu地图

    1. 运行截图 演示地址 2. 在文件夹wwwroot/lib,添加baidu子文件夹,添加baidumap.js文件 2.1 跟上一篇类似,用代码方式异步加载API,脚本生成新的 body > ...

  8. Blazor组件自做九: 用20行代码实现文件上传,浏览目录功能 (3)

    接上篇 Blazor组件自做九: 用20行代码实现文件上传,浏览目录功能 (2) 7. 使用配置文件指定监听地址 打开 appsettings.json 文件,加入一行 "UseUrls&q ...

  9. video.js 一个页面同时播放多个视频

    $(data).each(function(i, item) { // innerHTML += '<li type-id="'+item.id+'">'+ // '& ...

  10. video.js分段自动加载视频【html5视频播放器】

    突发奇想的需求,要在官网上放一个一个半小时的视频教程…… 然而,加载成了问题,页面是cshtml的.net混合网站,不知道哪儿的限制,导致视频加不出来. 没有办法,只能前端想办法了. 于是将视频切割成 ...

随机推荐

  1. 案例分享 生产环境逐步迁移至k8s集群 - pod注册到consul

    #案例分享 生产环境逐步迁移至k8s集群 - pod注册到consul #项目背景 多套业务系统, 所有节点注册到consul集群,方便统一管理 使用consul的dns功能, 所有节点hostnam ...

  2. NSIS隐藏桌面

    下午在网上闲逛发现了一段代码, 刷新桌面用的,当时觉得可以利用nsis现有命令再结合API来实现,翻了些资料,终于搞定,同时结合查找到的桌面句柄,写了一个隐藏桌面的小玩意娱乐下. 完整脚本: !inc ...

  3. SpringBoot(三) - Slf4j+logback 日志,异步请求,定时任务

    1.Slf4j+logback 日志 SpringBoot框架的默认日志实现:slf4j + logback: 默认日志级别:info,对应了实际生产环境日志级别: 1.1 日志级别 # 常见的日志框 ...

  4. linux 安装/卸载go环境

    linux 安装/卸载go环境(基于centos8) 安装 下载go的安装包 Golang官网下载地址:https://golang.org/dl/ 将安装包解压放到到usr/local中,并解压 c ...

  5. 《吐血整理》高级系列教程-吃透Fiddler抓包教程(28)-Fiddler如何抓取Android7.0以上的Https包-下篇

    1.简介 虽然依旧能抓到大部分Android APP的HTTP/HTTPS包,但是别高兴的太早,有的APP为了防抓包,还做了很多操作:① 二次加密有的APP,在涉及到关键数据通信时,会将正文二次加密后 ...

  6. 【一】ERNIE:飞桨开源开发套件,入门学习,看看行业顶尖持续学习语义理解框架,如何取得世界多个实战的SOTA效果?

    ​ 参考文章: 深度剖析知识增强语义表示模型--ERNIE_财神Childe的博客-CSDN博客_ernie模型 ERNIE_ERNIE开源开发套件_飞桨 https://github.com/Pad ...

  7. 浅谈消息队列 Message Queue

    消息队列:在消息传递的过程中暂时保存消息的容器,充当发送者和接受者的中间人 消息队列的基本操作 using System; using System.Messaging; namespace MQ { ...

  8. 【笔记】入门DP

    复习一下近期练习的入门 \(DP\) .巨佬勿喷.\(qwq\) 重新写一遍练手,加深理解. 代码已经处理,虽然很明显,但请勿未理解就贺 \(qwq\) 0X00 P1057 [NOIP2008 普及 ...

  9. jmeter分布式压测对master、slave防火墙配置

    首先要了解jmeter分布式压测的基础概念:master为统计结果的服务器,slave为各台压力机,如下图所示 一.结论 针对master 1.修改jmeter.properties的client.r ...

  10. ironic组件硬件自检服务——ironic-inspector

    介绍 ironic-inspector是一个用于硬件自检的辅助型服务,它可以对被ironic组件管理的裸金属节点进行硬件自检,通过在裸金属节点上运行内存系统,发现裸金属节点的硬件信息,例如CPU数量和 ...