With the rise of live broadcasts and short videos, video has become a very mainstream method of outputting operational/product information because it carries a greater amount of information. However, due to the interests of various domestic browser manufacturers, they have placed many restrictions on the video capabilities of HTML5, which are not limited to:
For specific questions, please refer to "Mobile Terminal Video Mining Implementation of Complex Frame Animation" written by Tencent's IMWeb team.
In order to solve these problems, we implemented WXInlinePlayer by soft decoding FLV. The third-party technology and platform API used are as follows:
At the same time, we also wrote the WebAssembly version of FLV Demuxer. You can find the relevant code in lib/codec.
The compatibility test uses the relevant models provided by the BrowserStack service, for reference only:
https://eroszy.github.io/WXInlinePlayer/example/index.html
Please make sure you have installed parcel/emscripten 1.38.45/cmake and make, then execute the following command:
npm install # 初始化工程
npm update # 更新工程有关的插件。如果网络错误,改用 cnpm update
bash build.sh
The final product will be in the example folder.
Please note:
- Please build in a *nix environment. Compilation of OpenH264 under Windows is not guaranteed.
- Please make sure emscripten is in version 1.38.45, otherwise wasm32 errors will occur.
- cmake version needs to be 3.16+
<!DOCTYPE html >
< html >
< head >
< meta charset =" UTF-8 " />
< title > WXInlinePlayer </ title >
< style >
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
</ style >
</ head >
< body >
< canvas id =" container " width =" 800 " height =" 450 " > </ canvas >
< script src =" ./index.js " > </ script >
< script >
if ( WXInlinePlayer . isSupport ( ) ) {
WXInlinePlayer . init ( {
asmUrl : './prod.baseline.asm.combine.js' ,
wasmUrl : './prod.baseline.wasm.combine.js'
} ) ;
WXInlinePlayer . ready ( ) . then ( ( ) => {
const player = new WXInlinePlayer ( {
url : 'https://static.petera.cn/mm.flv' ,
$container : document . getElementById ( 'container' ) ,
hasVideo : true ,
hasAudio : true ,
volume : 1.0 ,
muted : false ,
autoplay : true ,
loop : true ,
isLive : false ,
chunkSize : 128 * 1024 ,
preloadTime : 5e2 ,
bufferingTime : 1e3 ,
cacheSegmentCount : 64 ,
customLoader : null
} ) ;
const { userAgent } = navigator ;
const isWeChat = / MicroMessenger / i . test ( userAgent ) ;
if ( ! isWeChat ) {
alert ( 'click to play!' ) ;
document . body . addEventListener ( 'click' , ( ) => {
player . play ( ) ;
} ) ;
}
} ) ;
}
</ script >
</ body >
</ html >
In the project root directory, enter the command to start the server:
npm run serve
Then enter the URL to access the demo:
http://localhost:8888/example/index.html
Whether the current execution environment supports WXInlinePlayer.
if ( WXInlinePlayer . isSupport ( ) ) {
console . log ( 'WXInlinePlayer support' ) ;
}
To initialize WXInlinePlayer, you need to pass in the specific address of the loaded H264 decoding library. For the selection of decoding library, please refer to: How to choose decoding dependencies.
if ( WXInlinePlayer . isSupport ( ) ) {
WXInlinePlayer . init ( {
asmUrl : './prod.baseline.asm.combine.js' ,
wasmUrl : './prod.baseline.wasm.combine.js'
} ) . catch ( e => {
console . log ( `WXInlinePlayer init error: ${ e } ` ) ;
} ) ;
}
WXInlinePlayer is ready and can be initialized safely.
if ( WXInlinePlayer . isSupport ( ) ) {
WXInlinePlayer . init ( { /*.....*/ } ) ;
WXInlinePlayer . ready ( ) . then ( ( ) => {
console . log ( 'WXInlinePlayer ready' ) ;
} ) ;
}
WXInlinePlayer constructor, please refer to: Initialization parameters for related initialization parameters.
WXInlinePlayer . ready ( ) . then ( ( ) => {
const player = new WXInlinePlayer ( { /*...*/ } ) ;
} ) ;
for video playback. It should be noted that due to browser limitations (excluding WeChat and Chrome versions below 66), higher versions have disabled audio automatic playback, so calling this method directly may not be effective. Please click/touchstart/touchend/touchmove, etc. Let users actively trigger events.
document . body . addEventListener ( 'click' , ( ) => {
player . play ( ) ;
} ) ;
Stops the entire player and cannot be resumed.
player . stop ( ) ;
Pause current playback.
player . pause ( ) ;
Resumes a paused operation caused by pause.
player . resume ( ) ;
Get/set the current volume.
const volume = player . volume ( ) ; // get volume
player . volume ( volume ) ; // set volume
Get/set mute status.
const muted = player . mute ( ) ; // get mute
player . mute ( muted ) ; // set mute
Destroy the player and release all memory for recycling.
player . destroy ( ) ;
Get the current playback time. Please note that there may be negative values, so please handle them carefully.
player . on ( 'timeUpdate' , ( ) => {
let currentTime = player . getCurrentTime ( ) ;
currentTime = currentTime <= 0 ? 0 : currentTime ;
} ) ;
The playable duration can be understood as the buffering duration.
player . on ( 'timeUpdate' , ( ) => {
const duration = player . getAvaiableDuration ( ) ;
} ) ;
There are currently 3 sets of decoding libraries, namely:
The difference is:
We recommend using baseline.asm/baseline.wasm when you play advertising videos/marketing videos/small animation videos that are sensitive to the size of the dependent library, and use it when playing on-demand videos/live videos that are not sensitive to the size of the dependent library. all.asm/all.wasm.
On the development machine, for the same video, WXInlinePlayer and FFMpeg implementations such as Taobao and Huajiao have similar memory usage and CPU usage. The overall performance of WXInlinePlayer is about 5-10% better than the FFMpeg solution, while H265 has reduced deblocking. Its performance is about 30% better than the FFMpeg solution. The following is a comparison of H265 playback performance:
WXInlinePlayer's lags and delays mainly come from three places:
Generally speaking, if the user's network environment is good, it is difficult to cause a bottleneck due to the use of WebGL in rendering (the operation is very simple), which generally causes constant lags and delays due to insufficient soft decoding performance.
To optimize the delay caused by insufficient soft decoding performance, we generally start from several places:
Currently, WXInlinePlayer can decode 1280x720, code rate 1024, and frame rate 24fps videos on mid-to-high-end machines relatively smoothly.
Regarding the video parameters mentioned above, you can view them through FFmpeg:
ffmpeg -i " your.flv "
Here we give the profile/frame rate/code rate/resolution of mainstream platforms for reference:
platform | type | clarity | profile | Frame rate | Code rate | resolution |
---|---|---|---|---|---|---|
Tiger teeth | Horizontal screen | SD | High | twenty four | 500k | 800x450 |
Tiger teeth | Horizontal screen | HD | High | twenty four | 1200k | 1280x720 |
Tiger teeth | Vertical screen | HD | Main | 16 | 1280k | 540x960 |
Qixiu | Vertical screen | SD | High | 15 | 307k | 204x360 |
Qixiu | Vertical screen | HD | High | 15 | 512k | 304x540 |
Qixiu | Vertical screen | ultra clear | Baseline | 15 | 1440k | 720x1280 |
Tik Tok | Vertical screen | default | High | 30 | 1600k (more changes, for reference only) | 720x1280 |
quick worker | Vertical screen | default | High | 25 | 2880k (more changes, for reference only) | 720x1280 |
We recommend you:
Our commonly used low-latency configuration parameters of WXInlinePlayer are as follows, for reference only. Please adjust them according to your live stream/on-demand file configuration:
{
chunkSize : 128 * 1024 ,
preloadTime : 5e2 ,
bufferingTime : 1e3 ,
cacheSegmentCount : 64 ,
}
At the same time, you can use the performance event to determine the current decoding performance, then prompt the user and downgrade to your backup solution (such as direct video playback/static images/sequence frames, etc.):
player . on ( 'performance' , ( { averageDecodeCost , averageUnitDuration } ) => {
const prop = averageUnitDuration / averageDecodeCost ;
if ( prop >= 2.0 ) {
console . log ( 'good performance' ) ;
} else if ( prop < 2.0 && prop >= 1.0 ) {
console . log ( 'ok, thats fine' ) ;
} else {
console . log ( 'bad performance' ) ;
}
} ) ;
The FFmpeg solution currently has several major problems. The first is the size of the decoding library. After reduction, it is about 2M, and gzip is about 600k. This is unacceptable for products that care about the size of the dependent library. Secondly, FFmpeg's solution is difficult to optimize by yourself. For example, WXInlinePlayer will do multiple worker decoding in 2.0, which is very costly to modify such a solution.
The reasons for lags and delays are complicated. For WXInlinePlayer, the decoding speed generally cannot keep up with the playback speed. Please refer to how to reduce lags and delays for optimization.
Both iOS and Android UC have castrated WebAssembly/ASM.js, so they simply do not support it.
Please use FFmpeg or other similar tools. Here is a simple command example:
ffmpeg -i " your.mp4 " -vcodec libx264 -acodec aac out.flv
The FLV specification of WXInlinePlayer follows Kingsoft's FLV expansion specification. If you need to perform related encoding, you can refer to its related FFmpeg patch or the encoder written by Kingsoft.