UNPKG

@kwai-video-team/kwai-player-web

Version:

<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*

1,500 lines (1,154 loc) 54.9 kB
<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [简介](#%E7%AE%80%E4%BB%8B) - [功能列表](#%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A8) - [音视频格式支持](#%E9%9F%B3%E8%A7%86%E9%A2%91%E6%A0%BC%E5%BC%8F%E6%94%AF%E6%8C%81) - [浏览器适配](#%E6%B5%8F%E8%A7%88%E5%99%A8%E9%80%82%E9%85%8D) - [桌面端浏览器](#%E6%A1%8C%E9%9D%A2%E7%AB%AF%E6%B5%8F%E8%A7%88%E5%99%A8) - [Android端浏览器](#android%E7%AB%AF%E6%B5%8F%E8%A7%88%E5%99%A8) - [iOS端浏览器](#ios%E7%AB%AF%E6%B5%8F%E8%A7%88%E5%99%A8) - [H5 功能说明](#h5-%E5%8A%9F%E8%83%BD%E8%AF%B4%E6%98%8E) - [快速开始](#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B) - [如何使用](#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8) - [NPM方式接入](#npm%E6%96%B9%E5%BC%8F%E6%8E%A5%E5%85%A5) - [导出包类型](#%E5%AF%BC%E5%87%BA%E5%8C%85%E7%B1%BB%E5%9E%8B) - [组件示例](#%E7%BB%84%E4%BB%B6%E7%A4%BA%E4%BE%8B) - [原生库](#%E5%8E%9F%E7%94%9F%E5%BA%93) - [React](#react) - [Vue2](#vue2) - [Vue3](#vue3) - [需要参考的文档:](#%E9%9C%80%E8%A6%81%E5%8F%82%E8%80%83%E7%9A%84%E6%96%87%E6%A1%A3) - [Server-side-rendering (SSR)](#server-side-rendering-ssr) - [CORS](#cors) - [播放H.265/KVC/VVC说明](#%E6%92%AD%E6%94%BEh265kvcvvc%E8%AF%B4%E6%98%8E) - [wasm解码器兼容性:](#wasm%E8%A7%A3%E7%A0%81%E5%99%A8%E5%85%BC%E5%AE%B9%E6%80%A7) - [wasm解码器性能优化](#wasm%E8%A7%A3%E7%A0%81%E5%99%A8%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96) - [插件](#%E6%8F%92%E4%BB%B6) - [插件使用](#%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8) - [向插件传入配置](#%E5%90%91%E6%8F%92%E4%BB%B6%E4%BC%A0%E5%85%A5%E9%85%8D%E7%BD%AE) - [获取插件实例](#%E8%8E%B7%E5%8F%96%E6%8F%92%E4%BB%B6%E5%AE%9E%E4%BE%8B) - [获取所有插件实例](#%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E6%8F%92%E4%BB%B6%E5%AE%9E%E4%BE%8B) - [内置插件说明](#%E5%86%85%E7%BD%AE%E6%8F%92%E4%BB%B6%E8%AF%B4%E6%98%8E) - [I18nPlugin](#i18nplugin) - [LoggerPlugin](#loggerplugin) - [WaterMarkPlugin(水印)](#watermarkplugin%E6%B0%B4%E5%8D%B0) - [原生库 示例](#%E5%8E%9F%E7%94%9F%E5%BA%93-%E7%A4%BA%E4%BE%8B) - [Vue 示例](#vue-%E7%A4%BA%E4%BE%8B) - [React 示例](#react-%E7%A4%BA%E4%BE%8B) - [ControlsPlugin](#controlsplugin) - [PlayInfoPlugin](#playinfoplugin) - [PrefetchPlugin](#prefetchplugin) - [PreviewPlugin](#previewplugin) - [HotkeyPlugin](#hotkeyplugin) - [RotatePlugin](#rotateplugin) - [AlphaVideoPlugin](#alphavideoplugin) - [API](#api) - [active](#active) - [type](#type) - [自定义插件](#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8F%92%E4%BB%B6) - [利用钩子](#%E5%88%A9%E7%94%A8%E9%92%A9%E5%AD%90) - [注册销毁插件](#%E6%B3%A8%E5%86%8C%E9%94%80%E6%AF%81%E6%8F%92%E4%BB%B6) - [插件实现示例](#%E6%8F%92%E4%BB%B6%E5%AE%9E%E7%8E%B0%E7%A4%BA%E4%BE%8B) - [API](#api-1) - [原生库属性](#%E5%8E%9F%E7%94%9F%E5%BA%93%E5%B1%9E%E6%80%A7) - [src](#src) - [controls](#controls) - [showInfoPanel](#showinfopanel) - [productName](#productname) - [bizData](#bizdata) - [disableHotkey](#disablehotkey) - [disableDownload](#disabledownload) - [disableAdaptive](#disableadaptive) - [currentLevel](#currentlevel) - [nextLevel](#nextlevel) - [audioTrack](#audiotrack) - [totalVideoFrames](#totalvideoframes) - [currentVideoFrame](#currentvideoframe) - [showProgress](#showprogress) - [API](#api-2) - [constructor(id: string, data?: Partial<KwaiPlayer.KwaiPlayerData>)](#constructorid-string-data-partialkwaiplayerkwaiplayerdata) - [destroy(): void](#destroy-void) - [isFullscreen(): boolean;](#isfullscreen-boolean) - [requestFullscreen: (type?: "window" | "system" | undefined) => void;](#requestfullscreen-type-window--system--undefined--void) - [exitFullscreen: (type?: "window" | "system" | undefined) => void;](#exitfullscreen-type-window--system--undefined--void) - [requestPictureInPicture(): Promise<PictureInPictureWindow> | undefined;](#requestpictureinpicture-promisepictureinpicturewindow--undefined) - [screenshot(): Promise<ImageData | void>](#screenshot-promiseimagedata--void) - [refresh(): void;](#refresh-void) - [getPluginInstance<pluginLabel extends keyof PluginMap>(label: string | pluginLabel): PluginMap[pluginLabel] | undefined;](#getplugininstancepluginlabel-extends-keyof-pluginmaplabel-string--pluginlabel-pluginmappluginlabel--undefined) - [KwaiPlayer.register(plugin: typeof PluginModule, method: RegisterMethod = 'append');](#kwaiplayerregisterplugin-typeof-pluginmodule-method-registermethod--append) - [KwaiPlayer.deregister(plugin: typeof PluginModule | string);](#kwaiplayerderegisterplugin-typeof-pluginmodule--string) - [createSubContainer(layer = KwaiPlayerLayer.DEFAULT): HTMLDivElement](#createsubcontainerlayer--kwaiplayerlayerdefault-htmldivelement) - [原生js组件事件](#%E5%8E%9F%E7%94%9Fjs%E7%BB%84%E4%BB%B6%E4%BA%8B%E4%BB%B6) - [manifestparsed](#manifestparsed) - [levelswitching](#levelswitching) - [levelswitched](#levelswitched) - [levelswitchplaying](#levelswitchplaying) - [levelswitchfailed](#levelswitchfailed) - [audiotrackswitching](#audiotrackswitching) - [audiotrackswitched](#audiotrackswitched) - [React组件与原生js组件差异](#react%E7%BB%84%E4%BB%B6%E4%B8%8E%E5%8E%9F%E7%94%9Fjs%E7%BB%84%E4%BB%B6%E5%B7%AE%E5%BC%82) - [React事件对应表](#react%E4%BA%8B%E4%BB%B6%E5%AF%B9%E5%BA%94%E8%A1%A8) - [Vue组件与原生js组件差异](#vue%E7%BB%84%E4%BB%B6%E4%B8%8E%E5%8E%9F%E7%94%9Fjs%E7%BB%84%E4%BB%B6%E5%B7%AE%E5%BC%82) - [在页面中引入](#%E5%9C%A8%E9%A1%B5%E9%9D%A2%E4%B8%AD%E5%BC%95%E5%85%A5) - [错误码](#%E9%94%99%E8%AF%AF%E7%A0%81) <!-- END doctoc generated TOC please keep comment here to allow auto update --> # 简介 快手Web播放组件基于HTML5的[HTMLVideoElement(\<video \/>)](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLVideoElement)。 提供适配Vue2/Vue3/React/原生JS的多个版本接入。 同时支持桌面端和移动端浏览器环境。 npm:https://www.npmjs.com/package/@kwai-video-team/kwai-player-web Demo和文档:https://s2-10895.kwimgs.com/kos/nlav10895/kwaiplayer-web/index.html ## 功能列表 | 功能点 | 功能说明 | | :-------------- | :--------------------------------------------------------------------------- | | 支持协议 | 支持 FLV、HLS、MP4、WebRTC、裸流 等丰富的音视频格式 | | 播放-URL | 支持网络视频的 URL 方式播放 | | 播放-Manifest | 支持快手协议,更多咨询问题请联系我们。 | | 播放-本地文件 | 本地文件方式播放 | | 播放-videoID | 支持vid播放(开发中) | | 基本功能 | 支持开始、结束、暂停、自动播放、循环播放、断点续播、重播、倍速等播放控制功能 | | 清晰度切换-手动 | 支持开始、结束、暂停、自动播放、循环播放、断点续播、重播、倍速等播放控制功能 | | 清晰度切换-平滑 | 配合GOP对齐HLS/快手协议,支持无停顿平滑切换 | | 清晰度切换-自动 | 配合GOP对齐HLS/快手协议,支持根据网速自动切换清晰度 | | 预览图 | 支持预览图功能 | | 弹幕防挡 | 支持弹幕防挡 | | 水印 | 支持在播放组件中添加自定义水印 | | H.265支持 | 快手web端265解决方案 | | 自定义启播时间 | 支持自定义视频开启播放的时间 | | 多实例 | 支持在一个界面添加多个播放器同时播放 | | 边下边播 | 支持视频播放的同时缓存下载后面的内容 | | HLS标准加密 | 支持基于 HLS 提供的 AES encryption 方案,使用密钥对视频数据加密 | | DRM | widevine | | 逐帧播放 | MP4支持上下帧逐帧播放 | ## 音视频格式支持 | 协议 | H.264 | H.265 | H.266 | AV1 | KVC | AAC | MP3 | Opus | | ------------- | :---- | :---------------: | :---: | :--------: | :---: | :---: | :---: | :---: | | flv + flv切片 | 支持 | 依赖浏览器 + wasm | x | 依赖浏览器 | x | x | 支持 | x | | mp4 | 支持 | 依赖浏览器 + wasm | wasm | 依赖浏览器 | wasm | wasm | 支持 | 支持 | | HLS | 支持 | 依赖浏览器 + wasm | x | x | wasm | x | 支持 | - | | 裸流 | 支持 | 依赖浏览器 + wasm | x | 依赖浏览器 | wasm | x | - | - | | webRTC直播 | 支持 | - | x | - | - | - | - | - | YUV支持: 8bit/10bit yuv420p/yuv422p/yuv444p。YUV文件命名需要符合模板:name_WxH_FPS_BITDEPTH_CHROMA.yuv。 > 面向普通用户的场景不推荐使用wasm解码器。如果要使用H.265/AV1编码,推荐采用快手web端H.265整体解决方案,更多咨询问题请联系我们。 ## 浏览器适配 ### 桌面端浏览器 | 浏览器 | MP4 | FLV | HLS | | ----------- | :--- | :---: | :---: | | Chrome 39+ | 支持 | 支持 | 支持 | | Edge win10 | 支持 | 支持 | 支持 | | IE11+ | 支持 | 支持 | 支持 | | Firefox 42+ | 支持 | 支持 | 支持 | | Safari 8+ | 支持 | 支持 | 支持 | ### Android端浏览器 | 浏览器 | MP4 | FLV | HLS | | ---------- | :--- | :---: | :---: | | Chrome 39+ | 支持 | 支持 | 支持 | | 微信 | 支持 | 支持 | 支持 | | Edge | 支持 | 支持 | 支持 | ### iOS端浏览器 | 浏览器 | MP4 | FLV | HLS | | ------ | :--- | :----: | :---: | | Chrome | 支持 | 不支持 | 支持 | | 微信 | 支持 | 不支持 | 支持 | | Safari | 支持 | 不支持 | 支持 | | Edge | 支持 | 不支持 | 支持 | ## H5 功能说明 | 功能 | 桌面端 | Android | iOS | | -------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------- | :---------------------------------------------------------------------------- | | 全屏 | 支持 | 不支持 | 1. iOS 10以下版本的Safari浏览器无法禁止视频自动全屏播放;<br>2. 仅支持网页全屏 | | 自动播放 | 播放组件会按照以下规则尝试自动播放:有声音自动播放,失败后尝试静音自动播放,失败后不自动播放。<br>1. Chrome遵循以下播放规则:https://developer.chrome.com/blog/autoplay/<br>2. Safari依赖浏览器设置 | 策略同桌面端 | 策略同桌面端 | | 音量 | 支持 | 依赖设备音量 | 依赖设备音量 | | 倍速 | 支持 | 部分移动端浏览器不支持设置倍速 | 不支持 | # 快速开始 播放组件提供原生js组件,React组件,Vue2/Vue3组件。可以通过NPM使用或者在页面引入的方式引入。 ## 如何使用 ### NPM方式接入 ```js npm i @ks-video/kwai-player-web import KwaiPlayer from '@ks-video/kwai-player-web'; player = new KwaiPlayer('#player', { src: 'http://xxxx.mp4', autoplay: true, productName: 'KPN', // 用于区分上报 }); // 上报数据如果不是国内生产环境,需要设置上报插件环境,查看LoggerPlugin插件的说明 ``` ### 导出包类型 **推荐使用** 默认导出(full)或各框架对应的导出包含了大部分常用插件, 基础导出(basic)减少了基本控件以外的插件,对于不需要使用过多功能的情况使用 | 类型 | npm引用 | 备注 | ES5 UMD | ES6 UMD | ES6 Module | | ---------------- | ------------------------------------ | ----------------------------------- | ------- | ------- | ---------- | | 完整版-原生库 | @ks-video/kwai-player-web | 包含完整功能,原生库 | ✓ | ✕ | ✓ | | 完整版-Vue2版本 | @ks-video/kwai-player-web/vue2 | 包含完整功能,vue2版本 | ✓ | ✕ | ✓ | | 完整版-Vue3版本 | @ks-video/kwai-player-web/vue3 | 包含完整功能,vue3版本 | ✕ | ✓ | ✓ | | 完整版-React版本 | @ks-video/kwai-player-web/react | react | ✓ | ✕ | ✓ | | 小包版-原生库 | @ks-video/kwai-player-web/mini | 不包含控制条的最小功能包,原生库 | ✓ | ✕ | ✓ | | 小包版-vue2 | @ks-video/kwai-player-web/vue2-mini | 不包含控制条的最小功能包,vue2版本 | ✓ | ✕ | ✓ | | 小包版-vue3 | @ks-video/kwai-player-web/vue3-mini | 不包含控制条的最小功能包 vue3版本 | ✕ | ✓ | ✓ | | 小包版-react | @ks-video/kwai-player-web/react-mini | 不包含控制条的最小功能包,react版本 | ✓ | ✕ | ✓ | | 基础版-原生库 | @ks-video/kwai-player-web/basic | 包含控制条的最小功能包,原生库 | ✓ | ✕ | ✓ | > 各包包含插件情况、详见插件文档 ## 组件示例 ### 原生库 ```js import KwaiPlayer from '@ks-video/kwai-player-web'; player = new KwaiPlayer('#player', { src: 'http://xxxx.mp4', autoplay: true, }); ``` ```html <body> <div id="player"></div> </body> ``` ### React ```js import KwaiPlayerReact from '@ks-video/kwai-player-web/react'; function App() { const videoRef = useRef(null); useEffect(() => { if (videoRef.current) { videoRef.current.play(); } }, [videoRef]); function onLoadedMetadata(){ const duration = videoRef?.current?.duration//总时长 const videoheight = videoRef?.current?.videoHeight//视频资源的高度 const videowidth = videoRef?.current?.videoWidth//视频资源的宽度 console.log(duration, videoheight, videowidth) } function onerror(val){ console.log(val) } function onTimeUpdate() { console.log(videoRef?.current?.currentTime);//打印当前时间 } return ( <div className="App"> <KwaiPlayerReact className="kwai-player-react" ref={videoRef} src={'http://xxxx.mp4'} autoPlay={true} controls={true} onTimeUpdate={onTimeUpdate} preload="auto" onError={onerror} onLoadedMetadata={onLoadedMetadata} ></KwaiPlayerReact> </div> ); } ``` ### Vue2 ```js import KwaiPlayerVue2 from '@ks-video/kwai-player-web/vue2'; import poster from '../xxxx@2x.png' export default { name: 'App', data() { return { src: 'http://xxxx.mp4', autoplay: true, controls:true, loop:true, poster:poster }; }, components: { 'kwai-player-vue2': KwaiPlayerVue2, }, methods:{ error(val){ console.log(val) }, loadedmetadata(){ let duration = this.$refs['videoRef'].getDuration() let videoheight = this.$refs['videoRef'].getVideoHeight() let videowidth = this.$refs['videoRef'].getVideoWidth() }, timeupdate(){ console.log(this.$refs['videoRef'].getCurrentTime())//当前时间 } } }; ``` ```html <kwai-player-vue2 class="player" :src="src" :controls="controls" :autoplay="autoplay" :loop="loop" :poster="poster" @error="error" @loadedmetadata="loadedmetadata" @timeupdate="timeupdate" > </kwai-player-vue2> ``` ### Vue3 ```js import KwaiPlayerVue3 from '@ks-video/kwai-player-web/vue3'; import poster from '../xxxx@2x.png' import {ref} from'vue' export default { name: "demo", components: { 'kwai-player-vue3': KwaiPlayerVue3, }, setup(){ const src = ref('https://playurl') const autoplay = ref(true) const controls = ref(true) const loop = ref(true) const videoRef = ref(null) const timeupdate = ()=>{ console.log(videoRef._value.getCurrentTime())//当前时间 } const loadedmetadata = ()=>{ const duration = videoRef._value.getDuration() const videoheight = videoRef._value.getVideoHeight() const videowidth = videoRef._value.getVideoWidth() } const error = (val)=>{ console.log(val) } return { videoRef, src, autoplay, controls, poster, timeupdate, loadedmetadata, error } } } ``` ```html <kwai-player-vue3 class="player" :src="src" :controls="controls" :autoplay="autoplay" :loop="loop" :poster="poster" @error="error" @loadedmetadata="loadedmetadata" @timeupdate="timeupdate" /> ``` ### 需要参考的文档: 播放组件的属性、API及事件参考了HTMLVideoElement的实现。 1. [HTMLVideoElement](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLVideoElement) 2. [HTMLMediaElement](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLMediaElement) ## Server-side-rendering (SSR) 可以安全地在Node中require此库 ## CORS 视频资源必须允许GET请求,且包含[CORS](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS)响应头。 ## 播放H.265/KVC/VVC说明 > 面向普通用户的场景不推荐使用wasm解码器。如果要使用H.265/AV1编码,推荐采用快手web端H.265整体解决方案,更多咨询问题请联系我们。 浏览器不支持H.265/KVC/VVC解码时,会采用wasm解码器。 采用wasm解码器时,上层业务是无感知的。 ### wasm解码器兼容性: chrome 67+ ### wasm解码器性能优化 播放组件在使用wasm解码器器时支持多线程解码及SIMD,且会根据浏览器能力开启对应的加速解码功能。 多线程解码用到了SharedArrayBuffer,chrome 92+需要对播放页增加两个响应头,推荐添加 ``` Cross-Origin-Embedder-Policy: require-corp Cross-Origin-Opener-Policy: same-origin ``` [chrome 92相关说明](https://developer.chrome.com/blog/enabling-shared-array-buffer/) [Cross-Origin-Opener-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy) [Cross-Origin-Embedder-Policy](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy) 播放页中的部分标签可能需要添加[crossorigin](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Attributes/crossorigin)属性 > 页面增加这两个头会导致无法加载跨域资源。以下是以图片为例的解决方案。 > > 1. 解决方案A:在图片的响应头中添加:Cross-Origin-Resource-Policy: cross-origin; > 2. 解决方案B:img标签中增加crossorigin属性 # 插件 播放组件实现了插件系统,用与解耦功能,增加各功能之间的组合能力。 播放组件已内置了很多插件,如**控制条****水印****信息面板**等插件。 > 播放组件中已经生成了多个版本的插件组合产物 | 插件名称 | 功能 | 完整版 | 小包版 | 基础版 | | ----------------- | ------------ | ------ | ------ | ------ | | I18nPlugin | 国际化 | ✓ | ✓ | ✕ | | PlayInfoPlugin | 信息面板 | ✓ | ✓ | ✓ | | ControlsPlugin | 控制条 | ✓ | ✕ | ✓ | | LoggerPlugin | 日志上报 | ✓ | ✓ | ✓ | | WaterMarkPlugin | 水印 | ✓ | ✕ | ✕ | | PrefetchPlugin | 预热 | ✓ | ✕ | ✕ | | PreviewPlugin | 进度条预览图 | ✓ | ✕ | ✕ | | HotkeyPlugin | 快捷键 | ✓ | ✕ | ✕ | | RotatePlugin | 旋转画面 | ✓ | ✕ | ✕ | | AlphaVideoPlugin | 透明视频 | ✓ | ✕ | ✕ | ## 插件使用 ### 向插件传入配置 通过player的plugins参数传入配置 数据格式: ``` { '插件名称': Record<string, any> } ``` 示例: ``` import { KwaiPlayer } from '@ks-video/kwai-player-web'; // 示例,设置语言插件为英文 new KwaiPlayer('#player-1', { plugins: { I18nPlugin: { lang: 'en', } } } ``` ### 获取插件实例 ```ts const plugin = player.getPluginInstance('I18nPlugin'); ``` ### 获取所有插件实例 ```ts const plugin = player.getAllPlugins(); ``` ## 内置插件说明 ### I18nPlugin 多语言功能,默认包含中英,根据浏览器语言自动切换 参数: plugins: { I18nPlugin: { lang?: string // 选择语言名 langDict?: { // 多语言字典 lang: string, // 语言名 map: Record<string, Record<string, string>> // 字典内容,区分插件 Record<插件名, Record<字典key, 字典value>> }[], } } ```ts import { KwaiPlayer } from '@ks-video/kwai-player-web; new KwaiPlayer('#player-1', { plugins: { I18nPlugin: { lang: 'en' } } } ``` 通过传入插件配置的方式新增语言 ```ts import { ControlsPluginLabel, LangDict, ControlsLangDictKey } from '@ks-video/kwai-player-web; const langDict:LangDict = { { lang: 'en', // 指定语言 map: { [ControlsPluginLabel]: { // 用于控制条插件 [ControlsLangDictKey.PLAY]: 'Play', // 指定对应key显示的文字 [ControlsLangDictKey.PAUSE]: 'Pause', } } } }; new KwaiPlayer('#player-1', { plugins: { I18nPlugin: { langDict, } } } ``` ### LoggerPlugin 播放组件数据上报 ### WaterMarkPlugin(水印) 可以通过在播放器容器中增加子元素的方式添加水印 > 水印<div>必须包含属性 kwai-player-watermark #### 原生库 示例 ```html <style> .wm { background-repeat: repeat; background-image: url(data:image/svg+xml;base64,.......); } </style> <div id="player"> <div class="wm" kwai-player-watermark></div> </div> ``` #### Vue 示例 ```js <style> .wm { background-repeat: repeat; background-image: url(data:image/svg+xml;base64,.......) } </style> <kwai-player-vue2 class="player" :src="src" :autoplay="autoplay" > <div className="wm" kwai-player-watermark></div> </kwai-player-vue2> ``` #### React 示例 ```js <style> .wm { background-repeat: repeat; background-image: url(data:image/svg+xml;base64,.......) } </style> <KwaiPlayerReact className="kwai-player-react" src={src} autoPlay={true} > <div className="wm" kwai-player-watermark="true"></div> </KwaiPlayerReact> ``` ### ControlsPlugin 实现了默认控制条 UI 交互 参数: ``` plugins: { ControlsPlugin: { danmakuControls?: DanmakuControlsPos, // 弹幕插件在非全屏时显示的位置 / 依赖弹幕插件 danmakuControlsFull?: DanmakuControlsPos, // 弹幕插件在全屏时的显示位置 / 依赖弹幕插件 showBottomButtonBar?: boolean, // 是否按时下方播放按钮 showProgress?: boolean, // 是否显示进度条 showTime?: boolean, // 是否显示播放时间 showWindowFullScreen?: boolean, // 是否显示窗口全屏按钮 seekMode?: 'onDragChange' | 'onDragEnd', // seek 模式,拖动进度条实时seek/拖动进度条完成时seek showProgressTime?: boolean, // 是否在进度条上显示时间,默认不显示 showPlaybackRate?: boolean, // 是否展示倍速功能 showContextMenu?: boolean, // 是否展示右键菜单功能 stateChange?: (data: StateChangeData) => void, // UI状态回调 } } type StateChangeData = { type: 'controlsVisibility', value: boolean }; // 控制条显示隐藏状态变化 ``` ### PlayInfoPlugin 提供播放信息面板 ### PrefetchPlugin 提供播放地址链接预热功能,用于不自动播放且不预加载情况下的起播速度 ### PreviewPlugin 增加控制条上的预览画面,需要指定预览图地址;需要配合streamlake服务使用 ```ts import { KwaiPlayer } from '@ks-video/kwai-player-web; const player = new KwaiPlayer('#player-1' { src: 'xxx', previewUrl: 'xxxx', // 设置预览图url }); ``` ### HotkeyPlugin 可利用键盘快进快退、暂停播放、音量高低调节 | 键位 | 单击 | 长按 | | ---------- | ------------------------------------------------------------- | ----------------------------------- | | ArrowRight | 前进 10s | 3 倍速 | | ArrowLeft | 回退进度的两百分之 1 秒(若大于 10s 则为 10s、小于 5s 则为 5s) | 每 100ms 出发一次回退(时长如单击) | | ArrowUp | 增加音量的 5% | 每 100ms 增加音量的 5% | | ArrowDown | 减少音量的 5% | 每 100ms 减少音量的 5% | | Space | 播放/暂停 | -- | ### RotatePlugin 画面旋转插件 参数: ``` // 配置类型 type OptionType = 'mirror' | 'counterClockwise' | 'clockwise'; type OptionValue = 'pc' | 'mobile' | 'always'; type OptionShow = OptionValue | Record<OptionType, OptionValue>; type RotatePluginOption = { showInPlayBar?: OptionShow, showInContextMenu?: OptionShow, svgRaw?: { mirror?: string, counterClockwise?: string, clockwise?: string, } } // 配置传入 plugins: { AlphaVideoPlugin: RotatePluginOption, } ``` ### AlphaVideoPlugin 透明视频插件,支持透明视频的播放 参数: ``` plugins: { AlphaVideoPlugin: { active?: boolean, // 是否启动。默认:undefined,自动识别 type?: undefined | "2:1" | "1:1", // 透明视频类型。默认:undefined,自动识别 } } ``` #### API ##### active set: 是否启动。默认:undefined,自动识别 #### type set: 透明视频类型。默认:undefined,自动识别 可选值:undefined | "2:1" | "1:1" ## 自定义插件 可以自定义插件 + 插件名唯一,注册同名插件仅最后一次注册生效,故可采用这种方法替换已有插件。 + 例如:自定义名称为ControlsPlugin的插件,注册在完整包中,会替换默认的播控UI + 自定义插件实现需要继承PluginModule或其他基础插件的抽象类 + 自定义插件需要在实例化之前完成注册 + 注册方法仅需要执行一次 + 注销方法和销毁播放器无关,正常情况不需要调用 播放组件中的DOM分为以下三层,添加子容器需要指定一个层级,从下向上依次为VIDEO/VIDEO_INTERACTIVE/DEFAULT ### 利用钩子 - 挂载前 ```ts beforeInstall(player: IKwaiPlayer, options?: any): void ``` 数据准备完成,还未开始实例化播放内核前触发 - 挂载后 ```ts afterInstall(player: IKwaiPlayer, options?: any): void ``` 实例化播放内核后触发 - 销毁前 ```ts beforeUninstall(player: IKwaiPlayer): void ``` 销毁播放内核前触发 - 销毁后 ```ts afterUninstall(player: IKwaiPlayer): void ``` 销毁播放内核后触发 ### 注册销毁插件 实现一个插件后需要在**KwaiPlayer**对象上注册 1. 注册插件方法只用调用一次 2. 销毁播放器不需要调用注销 ```ts KwaiPlayer.register(WaterMarkPlugin); //注册 KwaiPlayer.deregister(WaterMarkPlugin); //注销 ``` ### 插件实现示例 ```ts import { IKwaiPlayer, KwaiPlayerEvent, PluginModule } from '@ks-video/kwai-player-web'; // 新插件替换已有的logger插件 // export default class ExamplePlugin extends LoggerPluginModule { // 新插件与已有插件共存 export default class ExamplePlugin extends PluginModule { private _player: IKwaiPlayer | undefined; /** * 播放器实例化前钩子 * @param player 播放器实例 * @param options 实例化播放器时指定的当前插件的参数 */ public beforeInstall(player: IKwaiPlayer, options?: any | undefined): void { this._player = player; console.log('beforeInstall', options); // 播放事件处理 this._player.on(KwaiPlayerEvent.REPORT, this._onReport); // 切换视频事件处理 this._player.on(KwaiPlayerEvent.ATTRIBUTE_CHANGE_SRC, this._onSrcChange); } /** * 播放器实例化后钩子 * @param player 播放器实例 * @param options 实例化播放器时指定的当前插件的参数 */ public afterInstall(_player: IKwaiPlayer, _options?: any): void { console.log('afterInstall'); } /** * 播放器销毁前钩子 * @param player 播放器实例 */ public beforeUninstall(_player: IKwaiPlayer): void { console.log('beforeUninstall'); } /** * 播放器销毁后钩子 * @param player 播放器实例 */ public afterUninstall(_player: IKwaiPlayer): void { console.log('afterUninstall'); this._player?.off(KwaiPlayerEvent.REPORT, this._onReport); this._player?.off(KwaiPlayerEvent.ATTRIBUTE_CHANGE_SRC, this._onSrcChange); } /** * 插件id,获取插件,传入参数等操作的标识 * 同名插件只会同时存在一个 */ public getLabel(): string { // LoggerPluginLabel return 'ExamplePlugin'; } private _onReport = (e: { type: string, value: any }): void => { } private _onSrcChange = (): void => { } } ``` # API 播放组件提供原生js方式接入,React组件方式接入,Vue2/Vue3组件方式接入。原生js、React、Vue的API和事件名称有差异,需要注意。 播放器的属性、API及事件参考了HTMLVideoElement的实现。 需要参考的文档: 1. [HTMLVideoElement](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLVideoElement) 2. [HTMLMediaElement](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLMediaElement) ## 原生库属性 **以下属性同HTMLVideoElement** | 属性 | 定义 | 备注 | | :---------------------- | :------------------- | ---- | | crossOrigin | 跨域设置 | | | preload | 当前视频预加载设置 | | | defaultPlaybackRate | 默认播放速度 | | | playbackRate | 播放速度 | | | autoplay | 自动播放 | | | loop | 循环播放开关 | | | controls | 播放控件显示开关 | | | volume | 音量 | | | muted | 静音 | | | defaultMuted | 默认静音 | | | poster | 封面图 | | | disablePictureInPicture | 画中画是否可用开关 | | | playsinline | 手机H5小窗播放开关 | | | buffered | 缓存范围 | 只读 | | duration | 视频时长 | 只读 | | ended | 是否播放结束 | 只读 | | error | 错误信息 | 只读 | | played | 已播放范围 | 只读 | | readyState | 视频状态 | 只读 | | seekable | 可seek范围 | 只读 | | seeking | 是否处于seek状态中 | 只读 | | networkState | 当前视频加载网络状态 | 只读 | | paused | 是否暂停状态 | 只读 | | videoWidth | 视频源宽 | 只读 | | videoHeight | 视频源高 | 只读 | **暂未实现的属性** + audioTracks + currentSrc 只读 + initialTime 只读 + mediaGroup + mediaKeys + moz* + sinkId + textTracks + videoTracks + width + height > width/height暂不支持,需要使用样式控制 **与HTMLVideoElement有差异的属性** ### src 可传入视频URL、manifest JSON、File。可传入空字符串进入停止状态 ### controls 依赖插件: ControlsPlugin 定义同HTMLVideoElement,用于控制播放控件,可选值有不同 + controls可选值说明 + false:关闭播放控件,如果需要自定义播放控件请使用该选项 + true:使用默认播放控件 + 'default':使用默认播放控件 ### showInfoPanel 依赖插件: PlayInfoPlugin get: 返回是否显示信息面板 set: 设置是否显示信息面板 ### productName 依赖插件: LoggerPlugin 业务名,用于从上报数据中区分业务 ### bizData 依赖插件: LoggerPlugin 业务数据,会加入到上报中 ```ts type BizData = { resourceId?: string | number, // 资源ID userId?: string | number, // 用户id photoId?: string, // yoda上报 activityTag?: string, // yoda上报 // eslint-disable-next-line @typescript-eslint/no-explicit-any request?: { header: Record<string, any> }, secretId?: string, // 不会加入上报 secretKey?: string, // 不会加入上报 isVip?: boolean | number, } & Record<string, unknown>; ``` ### disableHotkey 依赖插件: HotkeyPlugin get: 返回当前热键功能是否开启 set: 设置当前热键功能是否开启 ### disableDownload 依赖插件: ControlsPlugin controls===‘origin’时是否使下载功能可用 ### disableAdaptive 自适应码率是否可用,默认:true > 以上已实现的可写属性均可在构造函数中传入 ### currentLevel get: 返回当前正在加载的流index set: 立即切换至指定的流index 设置为-1,切换至自动码率 ### nextLevel get: 返回下一个加载的流index set: 下一个切换的视频流index 设置为-1,切换至自动码率 ### audioTrack get: 返回当前的音频轨index set: 立即切换至指定的音频轨index ### totalVideoFrames get: 返回当前播视频总帧数 ### currentVideoFrame get: 返回当前播放位置对应的帧index set: seek至指定帧 ### showProgress get: 设置是否显示进度条 set: 获取当前是否显示进度条 > totalVideoFrames>0时可用 ## API **以下API同HTMLVideoElement** + load() + play() + pause() + requestPictureInPicture(); **以下API暂未实现** + ms* + canPlayType() + captureStream() + fastSeek() + setMediaKeys() + setSinkId() **与HTMLVideoElement有差异的API** ### constructor(id: string, data?: Partial<KwaiPlayer.KwaiPlayerData>) 构造函数 参数说明: + id: 播放器容器id + data: 播放器参数,与HTMLVideoElement相同的API定义也可同data传入 ```js type KwaiPlayerData = { src: any; crossOrigin?: string; preload?: string; defaultPlaybackRate?: number; playbackRate?: number; autoplay?: boolean; loop?: boolean; controls?: boolean | string; volume?: number; muted?: boolean; defaultMuted?: boolean; poster?: string; disablePictureInPicture?: boolean; disableDownload?: boolean; disableAdaptive?: boolean; playsinline?: boolean; plugins: { [key in string]: object }; // 参见插件说明 }; ``` ### destroy(): void 销毁 ### isFullscreen(): boolean; 是否全屏 ### requestFullscreen: (type?: "window" | "system" | undefined) => void; 请求全屏 ```type?: "window" | "system"``` 窗口全屏 | 系统全屏 ### exitFullscreen: (type?: "window" | "system" | undefined) => void; 退出全屏 ```type?: "window" | "system" | undefined``` 窗口全屏 | 系统全屏 | 自动 ### requestPictureInPicture(): Promise<PictureInPictureWindow> | undefined; 进入画中画 ### screenshot(): Promise<ImageData | void> 截图 ### refresh(): void; 刷新,重新加载视频 ### getPluginInstance<pluginLabel extends keyof PluginMap>(label: string | pluginLabel): PluginMap[pluginLabel] | undefined; 获取插件实例 *** > 以下API用于自定义插件 ### KwaiPlayer.register(plugin: typeof PluginModule, method: RegisterMethod = 'append'); 注册插件 使用场景: + 替换现有包中的组件,例如更换UI,使用其他播控UI插件 + 自定义插件,更多查看自定义插件说明 参数: plugin: 插件 method: 添加位置,放在最前或者最后,prepend/append,插件注册的顺序会影响到钩子调用的顺序 更多查看插件自定义组件部分内容 ### KwaiPlayer.deregister(plugin: typeof PluginModule | string); 注销插件 更多查看插件自定义组件说明 ### createSubContainer(layer = KwaiPlayerLayer.DEFAULT): HTMLDivElement 创建一个子容器,用于在播放器中添加DOM 参数: layer 添加层级 ```ts enum KwaiPlayerLayer { VIDEO = 'video', // 视频内容层,例如视频画面,水印,全景视频渲染画面 VIDEO_INTERACTIVE = 'videoInteractive', // 视频交互层,如弹幕 DEFAULT = 'default', // 播控层,如播放组件,视频信息面板 } ``` ## 原生js组件事件 **以下事件同HTMLVideoElement** | 属性 | 定义 | 备注 | | -------------- | :----------------------------- | ---- | | abort | 资源未完全加载时触发,非错误 | | | canplay | 可播时 | | | canplaythrough | 可播时,估计已加载足够数据 | | | durationchange | 视频总时长变更 | | | emptied | 媒体源设置为空时 | | | ended | 播放结束 | | | error | 发生错误 | | | loadeddata | 当前播放位置视频帧加载完成 | | | loadedmetadata | metadata加载完成 | | | loadstart | 开始加载 | | | pause | 进入暂停状态 puased转为true时 | | | play | 进入播放状态 puased转为false时 | | | playing | 播放准备开始时 | | | progress | 加载资源 | | | ratechange | 播放速度变更 | | | resize | 视频源尺寸变更 | | | seeked | seek完成 | | | seeking | seek开始 | | | stalled | 尝试获取数据但是为取到时触发 | | | suspend | 加载数据被挂起 | | | timeupdate | 播放时间变更 | | | volumechange | 音量变更 | | | waiting | 缺少数据导致播放暂停 | | **与HTMLVideoElement有差异的事件** > 以下事件与多清晰度相关 ### manifestparsed + 定义:manifest解析成功事件 + 数据: ```js { levels: { width: 640, // 宽,可选 height: 360, // 高,可选 qualityType: "360" qualityLabel: "标清" }[], // 可用流列表 currentLevel: 3, // 当前流index, audioTracks?: { lang: 'en', // 语言 qualityLabel: '', qualityType: '', }[], // 可用音频轨 audioTrack?: 0, // 当前音频轨index } ``` ### levelswitching + 定义:开始进行码率切换 + 数据: ```js { bitrate: 460560, // 码率 smooth: true, // 是否平滑切换 auto: false, // 是否自动 level: 1, // level下标 id: 1, // 切换操作id } ``` ### levelswitched + 定义:码率切换成功事件 + 数据: ```js { bitrate: 460560, // 码率 smooth: true, // 是否平滑切换 auto: false, // 是否自动 level: 1, // level下标 id: 1, // 切换操作id } ``` ### levelswitchplaying + 定义:码率切换开始播放,切换至自动码率时无此事件 + 数据: ```js { bitrate: 460560, // 码率 smooth: true, // 是否平滑切换 auto: false, // 是否自动 level: 1, // level下标 id: 1, // 切换操作id } ``` ### levelswitchfailed + 定义:切换清晰度失败 ### audiotrackswitching + 定义:音频轨开始切换 + 数据: ```js { level: 0, // 音频轨id smooth: false, // 是否平滑切换 auto: false, // 是否自动切换 id: 1 // 切换操作id } ``` ### audiotrackswitched + 定义:音频轨切换完成 + 数据: ```js { level: 0, // 音频轨id smooth: false, // 是否平滑切换 auto: false, // 是否自动切换 id: 1 // 切换操作id } ``` ## React组件与原生js组件差异 API相同 ### React事件对应表 | React组件事件 | 对应事件 | | --------------------- | :------------------ | | onAbout | abort | | onCanplay | canplay | | onCanplayThrough | canplaythrough | | onDurationChange | durationchange | | onEmptied | emptied | | onEnded | ended | | onError | error | | onLoadedData | loadeddata | | onLoadedMetadata | loadedmetadata | | onLoadStart | loadstart | | onPause | pause | | onPlay | play | | onPlaying | playing | | onProgress | progress | | onRateChange | ratechange | | onResize | resize | | onSeeked | seeked | | onSeeking | seeking | | onStalled | stalled | | onSuspend | suspend | | onTimeUpdate | timeupdate | | onVolumeChange | volumechange | | onWaiting | waiting | | onManifestParsed | manifestparsed | | onLevelSwitching | levelswitching | | onLevelSwitched | levelswitched | | onLevelSwitchPlaying | levelswitchplaying | | onLevelSwitchFailed | levelswitchfailed | | onAudioTrackSwitching | audiotrackswitching | | onAudioTrackSwitched | audiotrackswitched | ## Vue组件与原生js组件差异 事件相同 **以下props同HTMLVideoElement** + crossOrigin //是否设置跨域 + preload //是否预加载 + defaultPlaybackRate //设置默认播放倍速 + playbackRate //修改播放倍速 + autoplay //是否设置视频播自动播放 + loop //是否在视频播放结束的时候,自动返回视频开始的地方,继续播放 + controls //是否在视频底部使用默认面板 包括控制音量,跨帧,暂停/播放等 + volume //设置音量 + muted //设置音量是否静音 + defaultMuted //设置音量是否默认静音 + poster //视频播放之前,作为海报展示的图片 + disablePictureInPicture //是否禁用画中画选项 + playsinline //指明视频将内联(inline)播放,即在元素的播放区域内 + src //播放URL或者manifest内容 **Vue组件属性对照表** | Vue组件 API | 原生js组件属性 | | ------------------------------------------------------- | :------------------------------------------------ | | getError | error | | getNetworkState | networkState | | getBuffered | buffered | | getReadyState | readyState | | getSeeking | seeking | | getDuration | duration | | getPaused | paused | | getSeekable | seekable | | getEnded | ended | | getVideoWidth | videoWidth | | getVideoHeight | videoHeight | | getSrc / setSrc | src | | getCrossOrigin / setCrossOrigin | crossOrigin | | getPreload / setPreload | preload | | getCurrentTime / setCurrentTime | currentTime | | getDefaultPlaybackRate / setDefaultPlaybackRate | defaultPlaybackRate | | getPlaybackRate / setPlaybackRate | playbackRate | | getAutoplay / setAutoplay | autoplay | | getLoop / setLoop | loop | | getControls / setControls | controls | | getVolume / setVolume | volume | | getMuted / setMuted | muted | | getDefaultMuted / setDefaultMuted | defaultMuted | | getPoster / setPoster | poster | | getDisablePictureInPicture / setDisablePictureInPicture | disablePictureInPicture | | getPlaysinline / setPlaysinline | playsinline + webkit-playsinline + x5-playsinline | ### 在页面中引入 + 引入js ```html <script src="https://cdn.jsdelivr.net/npm/@kwai-video-team/kwai-player-web/full/kwai-player-web-full.js"></script> ``` + 提供挂载元素 ```html <body> <div id="player"></div> </body> ``` + 实例化 ```html <script> player = new KwaiPlayer.default('#player', { src: 'http://xxxx.mp4', autoplay: true, }); </script> ``` 可以根据需要引入不同包 ```html <script src="https://cdn.jsdelivr.net/npm/@kwai-video-team/kwai-player-web/full/kwai-player-web-full.js"></script> <script src="https://cdn.jsdelivr.net/npm/@kwai-video-team/kwai-player-web/vue2/kwai-player-web-vue2.js"></script> <script src="https://cdn.jsdelivr.net/npm/@kwai-video-team/kwai-player-web/vue3/kwai-player-web-vue3.js"></script> <script src="https://cdn.jsdelivr.net/npm/@kwai-video-team/kwai-player-web/react/kwai-player-web-react.js"></script> ``` # 错误码 播放组件错误说明 | code | 定义 | | | :-------- | :------------------------------------------------------ | :------------- | | 10xx | 流加载错误 | 网络错误 | | 1000 | 流加载错误且无http status code,加载资源的跨域头不正确 | 网络错误 | | 1001 | 流加载错误400 | 网络错误 | | 1002 | 流加载错误401 | 网络错误 | | 1003 | 流加载错误403 | 网络错误 | | 1004 | 流加载错误404 | 网络错误 | | 1005 | 流加载错误4xx | 网络错误 | | 1006 | 流加载错误5xx | 网络错误 | | 1007 | 流加载错误,连接超时 | 网络错误 | | 1008 | 流加载错误,数据超时 | 网络错误 | | 1009 | 流加载出错,传输过程中失败 | 网络错误 | | 11xx | hlsManifestLoadError HLS manifest加载错误 | 网络错误 | | 12xx | hlsLevelLoadError HLS level加载错误 | 网络错误 | | 13xx | hls音频track playlist加载失败 | 网络错误 | | 14xx | hls key加载失败 网络错误 | 网络错误 | | 15xx | drm license加载失败 | 网络错误 | | 16xx | 解码库加载失败 | 网络错误 | | 100 | canNotSeek无法seek | | | 101 | video触发错误 且未取到MediaError.code | | | 102 | 不支持的协议 | | | 103 | 传入配置错误 | | | 106 | seek至指定帧失败 | | | 107 | 传入Src为空 | | | 111 | video触发错误 对应MediaError.code 1 | 参考MediaError | | 112 | video触发错误 对应MediaError.code 2 | 参考MediaError | | 113 | video触发错误 对应MediaError.code 3 | 参考MediaError | | 114 | video触发错误 对应MediaError.code 4 | 参考MediaError | | 200 | mediaSourceError 初始化MSE错误,MediaSource未定义时触发 | | | 201 | addSourceBufferError MSE增加SourceBuffer失败 | | | 202 | sourceBufferError MSE的SourceBuffer触发错误 | | | 203 | endOfStreamError MSE结束流错误 | | | 204 | appendBufferError MSE填充buffer错误 | | | 205 | SourceBuffer changeType 错误 | | | 301 | 解封装错误 | | | 302 | 重新封装错误 | | | 303 | remuxAllocError 重新封装alloc mdat存储错误 | | | 304 | remux worker报错 | | | 305 | 未找到解封装器 | | | 400 | manifestParsingError manifest解析错误 | | | 401 | levelSwitchError HLS level切换错误 | | | 500~506 | 加密视频解密错误 | | | 600 | wasm解码库加载失败 | | | 601 | wasm解码库启动失败 | | | 602 | wasm解码库渲染失败 | | | 603 | wasm解码时WebGL发生错误 | | | 604 | wasm解码不支持 | | | 1011~1019 | webRTC直播错误 | | 错误码111~114 参考[MediaError code说明](https://developer.mozilla.org/en-US/docs/Web/API/MediaError/code),