媒体事件过滤器
用于从 a 对重播事件生成一个正常的默认解释的可依赖性自由而微小的套件 HTML 介质。 。 。 .
为什么
HTML5 视频元素不产生符合跟踪器和用户界面要求的更新的一致事件集,比如 loaded, (中文(简体) ), buffering 或者说 seeking。 。 。 .
在"媒体源扩展"上方所搭建的不同玩家引擎都有自己的执行功能来收听事件.
这个过滤器旨在提供一个单一的真理源,可以跨玩家引擎和浏览器本土回放使用.
坚持 Eyvinn 玩家分析规格。 。 。 .
概览
/** Loading of stream is complete, playback is ready to start */
/** It is now safe to let the user press a play button */
"loaded";
/** A seek has started */
"seeking";
/** A seek has ended */
"seeked";
/** Buffering has started */
/** Does not trigger during seek, cancelled by a seek */
"buffering";
/** Buffering has ended */
/** Does not trigger during seek */
"buffered";
/** A request to start playing again has been made */
"play";
/** The stream has started playing after loading completed
* OR the stream has started playing after the stream was previously paused */
"playing";
/** The stream has been paused */
"pause";
/** The end of the stream was reached */
"ended";
/** A timeupdate event */
"timeupdate";
限制
不支持本地 HTML5 MSE 控件( N)<video controls>) (中文(简体) ). 它有效,但事件序列不会在所有浏览器中严格遵循EPAS.
使用量
npm install @eyevinn/media-event-filter
yarn add @eyevinn/media-event-filter
创建和监听事件过滤器的示例 .
import {
getMediaEventFilter,
FilteredMediaEvent,
} from "@eyevinn/media-event-filter";
const videoElement = document.createElement("video");
// Using a switch statement
const mediaEventFilter = getMediaEventFilter({
mediaElement: videoElement,
callback: (event: FilteredMediaEvent) => {
switch (event) {
case FilteredMediaEvent.LOADED:
// handle loaded
break;
case FilteredMediaEvent.BUFFERING:
// handle buffering
break;
case FilteredMediaEvent.BUFFERED:
// handle buffered
// ...
default:
break;
}
},
});
// Call when done
mediaEventFilter.teardown();
// Object notation can also be used
const handlers = {
[FilteredMediaEvent.LOADED]: () => {
/* handle loaded */
},
[FilteredMediaEvent.BUFFERING]: () => {
/* handle buffering */
},
[FilteredMediaEvent.BUFFERED]: () => {
/* handle buffered */
},
// ...
};
const mediaEventFilter = getMediaEventFilter({
mediaElement: videoElement,
callback: (event: FilteredMediaEvent) => handlers[event]?.(),
});
// It is safe to use destructuring
const { teardown } = getMediaEventFilter({
/* ... */
});
teardown();
样本 Shaka + 反应组件
滤波器可以方便地在Shaka上方建立反应UI.
裸骨样本集成(参见 代码:
import { useCallback, useEffect, useMemo, useRef, useState } from "React";
import shaka from "shaka-player";
import {
FilteredMediaEvent,
getMediaEventFilter,
} from "@eyevinn/media-event-filter";
const PlayerComponent = ({ videoUrl }) => {
const videoRef = useRef(null);
const [playing, setPlaying] = useState(false);
const [loading, setLoading] = useState(true);
const [blocked, setBlocked] = useState(false);
useEffect(() => {
if (!videoUrl || !videoRef.current) return () => {};
const eventFilter = getMediaEventFilter({
mediaElement: videoRef.current,
// add your state handlers here
callback: (event) => {
switch (event) {
case FilteredMediaEvent.LOADED:
setLoading(false);
// attempt autoplay
videoRef.current.play().catch((e) => {
// catch autoplay block
if (e.name.indexOf("NotAllowedError") > -1) {
setBlocked(true);
}
});
break;
case FilteredMediaEvent.PLAYING:
// reset autplay blocked
setBlocked(false);
// we're playing!
setPlaying(true);
break;
case FilteredMediaEvent.ENDED:
case FilteredMediaEvent.PAUSE:
setPlaying(false);
break;
default:
break;
}
},
});
const player = new shaka.Player(videoRef.current);
// Add configuration if needed
// player.configure()
player
// start loading the stream
.load(videoUrl)
// catch errors during load
.catch(console.error);
// Kill player when unmounted
return () => {
player.destroy();
eventFilter.teardown();
};
}, [videoUrl, videoRef]);
const play = useCallback(() => {
if (!videoRef.current) return;
videoRef.current.play();
}, [videoRef]);
const pause = useCallback(() => {
if (!videoRef.current) return;
videoRef.current.pause();
}, [videoRef]);
return (
<div style={{ width: "720px", margin: "20px auto" }}>
{loading && <p>Video is Loading</p>}
{!loading &&
(playing ? (
<button type="button" onClick={pause}>
Pause
</button>
) : (
<button type="button" onClick={play}>
Play
</button>
))}
{blocked && <p>Autoplay blocked, please start playback manually</p>}
<video ref={videoRef} style={{ width: "100%", height: "auto" }} />
</div>
);
};
// Use it:
<PlayerComponent videoUrl="https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd" />
福利
无论引擎(Shaka, Hls.js, DashJS, 原生)或浏览器(Chrome, Firefox, Safari),为回放事件获取单一的真相来源.
将事件直接插入您的 UI 状态管理中, 以获取重播状态更新的可靠真相源 .
事件序列映射直接通向受欢迎的跟踪提供者并回放SDK而不进行进一步过滤,比如Youbora,Comscore,Yosspace,或Nielsen. 如果你们也得到支持,我们欢迎公关更新这个名单!
兼容 电子考绩制度。 。 。 .
活动
事件描述及其顺序.
示例顺序
LOADED; // playback is ready to start
PLAYING; // playback started
SEEKING; // seek requested
PAUSED; // manual pause
PLAY; // manual play
SEEKED; // seek finished
PLAYING; // video is rolling again
BUFFERING; // unable to continue playing due to missing buffer
BUFFERED; // buffer ended by incoming seek request
SEEKING; // seek requested
SEEKED; // seek finished
PAUSED; // manual pause
PLAY; // manual play
PLAYING; // video is rolling again
ENDED; // video reached the end
已装入
视频的初始负载已经完成,准备开始播放.
装入前没有其它事件可以触发 .
请求
寻已起.
如果正在缓冲,则在寻求之前会被触发.
缓冲事件无法在搜索中触发 .
装入前不能触发 .
已寻求
寻觅已后.
装入前不能触发 .
没有先前的寻找事件就无法触发.
缓冲
缓起已起.
无法在搜索中触发 .
装入前不能触发 .
缓冲
缓冲已经结束,或因寻求而中断.
无法在搜索中触发 .
没有先前的缓冲事件就无法触发 .
播放
已请求播放 .
装入前不能触发 .
如果视频之前没有暂停, 则无法触发 .
播放
播放已经开始 .
装入前不能触发 .
寻找时不能触发 .
缓冲时不能触发 .
如果视频之前没有暂停, 则无法触发 .
求取或缓冲时请求的玩法会在求取或缓冲完成后触发玩法.
暂停
播放已暂停 .
寻求或缓冲并不算作穷困.
装入前不能触发 .
时间更新日期
时间更新事件
装入前不能触发 .
结束
玩家已到达一流的尽头.
允许在流尾到达后重新启动流 allowResumeAfterEnded 改为 true。 。 。 .
捐款
欢迎为改进不同引擎的兼容性或增加支持,跟踪解决方案,浏览器做出贡献.
Git 工作方法
项目使用特色分支,a 重组合并策略。 。 。 .
确保你有 git pull 设置为再基准模式 :
git config pull.rebase true
可以选择添加 --global 标记为上方命令.
要开始研究一个新的功能: git checkout <feature branch name>。 。 。 .
由于该项目使用语义释放到 自动生成释放注释 基于承诺,在作出承诺时必须遵守一些规则.
这个项目使用 常规承诺。 。 。 .
读取 使用有纪律的 Git。 。 。 .
读取 如何撰写提交信件。 。 。 .
承诺应:
- 包含一个单一的更改集( 较小的承诺更好)
- 通过测试、打字和打字检查
- 无法被打破
它与能够节省时间的自动化同时,也能够通过 双节使捕虫成为几分钟而不是几天的事 外有多篇关于"分形"魔法的文章.
承诺信息的基本结构:
<type>[optional scope]: <title starting with verb in infinitive>
[optional body]
[optional footer]
自动放出注释要效果好,尝试描述被添加或被更改的内容,而不是描述代码的作用. 示例
fix(seek): rewrite calculation in seek module // bad, the consumer does not know what issue this fixes
fix(seek): stop player from freezing after seek // good, the consumer understands what is now working again
开发
要启动 Dev 服务器 : pnpm dev检查 demo 财务报告和审定财务报表 public/index.html 详细情况.
熟悉 HTML5 视频标准、 shaka、hlsjs 或其他引擎 建议在发言前先发言.
https://www.w3.org/TR/2011/WD-html5-20110113/video.html 互联网档案馆的存檔,存档日期2013-12-21
https://html.spec.whywg.org/multipage/media.html 互联网档案馆的存檔,存档日期2013-12-22
https://html.spec.whywg.org/multipage/media.html#mediaevents (中文(简体) )
试验用 Shaka 2.5.X - 4.X.X
在Safari接受本地视频测试
用hls.js测试
在Safari 13.1+、Firefox、Chrome、Edge试验过
在OSX、Windows、Linux上测试
释放
释放是通过github动作被触发的,该动作将自动递增版本并基于承诺写入更动日志.
可以通过运行进行手动发布 pnpm release。 。 。 .
支助
加入我们 slack 社区 您可以在其中张贴任何关于我们开放源代码项目的问题。 Eyevin的咨询业务也可以提供:
- 本构成部分的进一步发展
- 此组件定制并整合到您的平台
- 支助和维持协定
联系人 销售量@ eyevin.se 如果你有兴趣.
关于 Eyevinn 技术
目光技术 一家独立咨询公司,专门从事录像和流媒体制作。 独立的方式,我们不与任何平台或技术供应商进行商业联系。 作为我们创新和推动工业前进的途径,我们开发了概念证明和工具。 我们学到的东西和我们写的代码 与行业分享 博客 并且通过公开提供我们写的代码.
想知道更多关于"Eyevin" 和如何工作在这里。 联系我们 工作@ eyevin.se来啊!