一个可支持HEVC/H.265编码播放720P、1080P的播放器
~^_^~
作者用爱发电 如果 h265web.js 帮助到了你,请点击右上角的star!
h265web.js | mpeg.js (解析ts) |
h265web.js 底层265解码器SDK |
---|---|---|
h265web.js | MPEG-Demuxer.js | h265web.js-wasm-decoder |
License GPL-3.0 https://www.gnu.org/licenses/gpl-3.0.md
更新日志 | 内容 |
---|---|
时间 | 2021/04/27 |
- | 1.修复部分视频播放中马赛克问题 |
- | 2.修复部分视频第一个GOP马赛克问题 |
时间 | 2021/04/22 |
- | 1.新测试播放内核 增加Seek功能 |
- | 2.新测试播放内核 兼容yuvj420p |
- | 3.一些其他细节的完善 |
时间 | 2021/04/12 |
- | 1.修复了默认内核播放 hev错误的问题 |
- | 2.修复了默认内核播放 部分nalu错误的问题 |
- | 3.修复了默认内核播放 部分花屏问题 |
时间 | 2021/04/07 |
- | 1.时长错误问题 |
时间 | 2021/03/28 |
- | 1.增加缓冲进度条 |
- | 2.解决了一些Bug,优化了一些性能 |
- | 3.移出HLS播放的无用日志 |
- | 4.增加去音频播放选项(新内核) |
时间 | 2021/03/14 |
- | 1.新播放内核:字节对齐渲染问题解决 |
时间 | 2021/03/12 |
- | 1.很抱歉,这几天事情交织在一起,有些累,因为我的个人疏忽,导致HLS/M3u8能力不可用,今天已紧急修复. |
时间 | 2021/03/06 |
- | 1.新播放内核类型,解决多路窗口播放加载失败问题 |
时间 | 2021/02/28 |
- | 1.开放给H.265解码器喂完整的265nalu帧函数 append265NaluFrame(nalBuf); |
- | 2.开放新库,解析h265流为帧数据的工具 raw-parser.js |
时间 | 2021/02/21 |
- | 1.更新底层265解码器SDK项目 - https://github.com/numberwolf/h265web.js-wasm-decoder |
时间 | 2021/02/18 |
- | 1.新播放内核,增加音频播放能力 |
时间 | 2021/02/08 |
- | 1.增加播放内核类型:新播放内核,可兼容多种解码Badcase(测试阶段, 输入媒资Mp4Box需要前置Moov,当前还不支持音频、Seek) |
时间 | 2021/01/04 |
- | 1.支持H.265的流式接入,可直接以265的URI进行播放、也可以流式字节填充播放(可应用于直播) |
- | 2.取消了播放器自带的播放view蒙板(用于点击播放画面触发暂停/播放能力),开放给用户自行实现 |
- | 3.支持 如果播放器配置的长宽与视频纵横比不匹配,自动裁剪黑边区域 |
- | 4.增加onPlayFinish 事件回调,播放结束调用 |
@TODO | 内容 |
---|---|
播放能力 | 增加http-flv直播能力 |
- 协议
协议 | 模式 | 是否支持 | 说明 |
---|---|---|---|
mp4 | 点播 | 是 | ---- |
mpeg-ts | 点播 | 是 | ---- |
m3u8 | 点播 | 是 | ---- |
hls | 直播 | 是 | ---- |
H.265 | 点播 | 是 | ---- |
H.265 | 直播 | 是 | ---- |
http-flv | 直播 | 否 | 待支持 |
flv | 点播 | 否 | 待支持 |
- 能力
能力 | 是否支持 | 其他 |
---|---|---|
直播 | 是 | ---- |
点播 | 是 | ---- |
Seek跳转 | 是 | core=1 时的新内核不支持 |
精准Seek | 是 | ---- |
封面图 | 是 | ---- |
边下边播 | 是 | ---- |
音量调节 | 是 | ---- |
播放 | 是 | ---- |
暂停 | 是 | ---- |
重新播放 | 是 | ---- |
暂停截图 | 是 | ---- |
1080p播放 | 是 | ---- |
720p播放 | 是 | ---- |
多路播放 | 是 | ---- |
去音频播放 | 是 | ---- |
缓冲进度 | 是 | ---- |
token = "base64:QXV0aG9yOmNoYW5neWFubG9uZ3xudW1iZXJ3b2xmLEdpdGh1YjpodHRwczovL2dpdGh1Yi5jb20vbnVtYmVyd29sZixFbWFpbDpwb3JzY2hlZ3QyM0Bmb3htYWlsLmNvbSxRUTo1MzEzNjU4NzIsSG9tZVBhZ2U6aHR0cDovL3h2aWRlby52aWRlbyxEaXNjb3JkOm51bWJlcndvbGYjODY5NCx3ZWNoYXI6bnVtYmVyd29sZjExLEJlaWppbmcsV29ya0luOkJhaWR1";
- Github: https://github.com/numberwolf/h265web.js
- Email([email protected])
- QQ: 531365872
- QQ技术支持群: 925466059
- Discord:numberwolf#8694
- 微信:numberwolf11
类型 | 点播 | 直播 |
---|---|---|
点击 放大 |
-
使用流程也可以直接看
play.js
和index.html
的Demo使用 -
本项目可以直接放在你的
web服务器
目录下访问index.html
———————— API以及事件能力
如果想使用底层的265解码器能力 可以看 h265web.js-wasm-decoder
- 方式1.1:引入Github的本地文件
require
形式
// 引入Github的本地文件
require('./dist/h265webjs');
- 方式1.2:引入Github的本地文件
import xxx from xxx
形式 (推荐)
// 引入Github的本地文件
import H265webjsModule from './dist/index';
- 从Github下载dist。
-
本地引入(从Github h265web.js)
- 1)require形式
require('./dist/h265webjs');
- 2)
import xxx from xxx
形式 (推荐)
// 引入Github的本地文件 import H265webjsModule from './dist/index';
- 创建代码如下
const PLAYER_CORE_TYPE_DEFAULT = 0; // 默认播放器内核
const PLAYER_CORE_TYPE_CNATIVE = 1; // 实验播放器内核
var config = {
type: "mp4",
player: "glplayer",
width: 960,
height: 540,
accurateSeek : true,
token : token,
extInfo : {
moovStartFlag : true,
readyShow : true,
rawFps : 30,
autoCrop : false,
core : PLAYER_CORE_TYPE_DEFAULT
}
};
- 配置详解
配置项 | 类型 | 可选值 | 必填 | 说明 |
---|---|---|---|---|
type | String | mp4/hls/ts/raw265 | 是 | 播放文件的类型 |
player | String | - | 是 | 播放窗口的dom的id值 |
width | Int | - | 是 | 播放窗口的宽度 |
height | Int | - | 是 | 播放窗口的高度 |
accurateSeek | Bool | true/false | 是 | 精准Seek(暂时固定为true) |
token | String | - | 是 | 播放器token值 |
extInfo | Object | - | 否 | 播放器额外配置 |
+ moovStartFlag | Bool | true/false | 否:默认false | Mp4的moov box是否前置 关联到动态加载 |
+ readyShow | Bool | true/false | 否:默认false | 是否需要封面图展示 |
+ rawFps | Float32 | 例如:30 | 否:默认24 | HEVC/AVC裸流播放时候的帧率设定 |
+ autoCrop | Bool | - | 否:默认false | 如果播放器配置的长宽与视频纵横比不匹配,自动裁剪黑边区域 |
+ core | Int | - | 否:默认0 | 0:默认播放内核 1:测试阶段的高成功率播放内核 |
+ coreProbePart | Float32 | - | 否:默认1.0 | 探测Mp4媒体的属性,百分比 0.0~1.0 ,正常moov前置的文件都用0.1(10%)可以(只适用于测试阶段的高成功率播放内核) |
+ ignoreAudio | Int | - | 否:默认0 | 0:带音频播放 1:忽略音频播放 |
- 创建方法(全局方法)
new265webjs(
播放地址
,播放器配置
)
参数 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
播放地址 | String | - | 是 | 播放视频地址 |
播放器配置 | Object | - | 是 | 播放器配置信息 |
-
创建示例Demo
-
1)路径 + 配置
- 例子1 创建
mp4/hls/ts
类型播放器
let videoURL = "h265_test.mp4"; let config = { type: "mp4", player: "glplayer", width: 960, height: 540, accurateSeek : true, token : token, extInfo : { moovStartFlag : true, readyShow : true } };
- 例子2 创建
raw265
类型 播放h265裸流 播放器(包括直播)
let config = { type: "raw265", player: "glplayer", width: 960, height: 540, accurateSeek : true, token : token, extInfo : { readyShow : true, rawFps : 30 // 播放帧率 } };
- 例子1 创建
-
2)创建播放器
-
- 以
require('./src/h265webjs');
引入为前提
- 以
示例:
let player = new265webjs(videoURL, config); // 全局方法
-
- 以
import H265webjsModule from './dist/index';
引入为前提 (推荐)
- 以
示例:
let player = H265webjsModule.createPlayer(videoURL, config);
-
- 如果创建的是
raw265
类型的裸流数据播放 请注意
这部分fetch请求网络数据以及异步喂数据的过程 请自行改写,下面给出的仅仅是一个demo,网络IO和解析265流为帧数据会非常耗时。
如果你可以通过websocket直接一帧一帧传输的话,那么只需要调用喂265数据的函数即可。
raw265
类型下,喂一帧一帧H.265播放
调用函数
函数 返回 说明 append265NaluFrame NULL 喂一帧265数据 参数
参数 类型 默认值 必填 说明 frame Uint8Array - 是 一帧265数据 例子 - 这里直接将265文件通过网络串流传输
// // fetch 265 // you can use your code to fetch vod stream // only need `h265webjs.append265NaluFrame(nalBuf);` to append 265 frame // let rawParser = new RawParserModule(); let fetchFinished = false; let startFetch = false; let networkInterval = window.setInterval(() => { if (!startFetch) { startFetch = true; fetch(url265).then(function(response) { let pump = function(reader) { return reader.read().then(function(result) { if (result.done) { // console.log("========== RESULT DONE ==========="); fetchFinished = true; window.clearInterval(networkInterval); networkInterval = null; return; } let chunk = result.value; rawParser.appendStreamRet(chunk); return pump(reader); }); } return pump(response.body.getReader()); }) .catch(function(error) { console.log(error); }); } }, 1); // fps>=30 play else cache let naluParseInterval = window.setInterval(() => { if (nalBuf != false) { // require h265webjs.append265NaluFrame(nalBuf); } else if (fetchFinished) { window.clearInterval(naluParseInterval); naluParseInterval = null; } }, 1);
- 如果创建的是
-
-
主要用于SEEK完成做一些操作
- 示例
player.onSeekFinish = () => {
// todo
};
回调参数 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
width | int | - | - | YUV宽度 |
height | int | - | - | YUV高度 |
imageBufferY | Uint8Array | - | - | Y分量 |
imageBufferB | Uint8Array | - | - | ChromaB分量 |
imageBufferR | Uint8Array | - | - | ChromaR分量 |
可以利用事件回调的YUV做全屏播放
需要调用
setRenderScreen
函数开启才可以收到事件回调数据, 下方1.5 API
会说明
- 示例
player.onRender = (width, height, imageBufferY, imageBufferB, imageBufferR) => {
// todo
};
媒体文件当前加载成功,可以进行播放
- 示例
player.onLoadFinish = () => {
// todo
};
回调参数 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
videoPTS | float64 | - | - | 当前播放时间 |
- 示例
player.onPlayTime = (videoPTS) => {
// todo
console.log(videoPTS)
};
- 示例
player.onPlayFinish = () => {
// finished
};
回调参数 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
cPts | float64 | - | - | 当前缓冲进度时间 |
- 示例
player.onCacheProcess = (cPts) => {
// console.log("onCacheProcess => ", cPts);
};
一般在配置完成【播放器配置】和【事件】之后进行播放器加载
- 示例
player.do();
调用函数 | 返回 | 说明 |
---|---|---|
isPlaying() | bool | 是否正在播放中 |
- 示例
if (player.isPlaying()) {
// 正在播放中
} else {
// 当前是暂停状态
}
调用函数 | 返回 | 说明 |
---|---|---|
play() | - | 开始播放 |
- 示例
player.play();
调用函数 | 返回 | 说明 |
---|---|---|
pause() | - | 暂停播放 |
- 示例
player.pause();
开启之后,
onRender
事件才可以收到数据
调用函数 | 返回 | 说明 |
---|---|---|
setRenderScreen({param1} ) |
- | 开启/关闭渲染过程中 回调YUV帧数据 |
- 参数
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
param1 | bool | false | 开启/关闭渲染过程中 回调YUV帧数据 |
- 示例
// 开启
player.setRenderScreen(true);
// 关闭
player.setRenderScreen(false);
调用函数 | 返回 | 说明 |
---|---|---|
seek({pts} ) |
- | Seek到某一个时刻 |
- 参数
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
pts | float64 | - | Seek到某一个时刻的时间点 |
- 示例
// Seek到10.01秒
player.seek(10.01);
调整视频的播放音量
调用函数 | 返回 | 说明 |
---|---|---|
setVoice({volume} ) |
- | 调整音量 |
- 参数
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
volume | float64 | - | 范围区间是[0, 1.0] , 0为mute,1.0为全开音量 |
- 示例
// 音量开启一半
player.setVoice(0.5);
获取当前播放的视频文件的信息数据
调用函数 | 返回 | 说明 |
---|---|---|
mediaInfo() | Object | 媒资详情 |
- 返回值示例
meta:
audioNone: false // 是否不包含音频轨
durationMs: 600000 // 时长 毫秒级
fps: 25 // 帧率
sampleRate: 44100 // 音频采样率
size: // 视频分辨率
height: 720
width: 1280
videoCodec: 0
videoType: "vod" // 点播vod 直播live
- 示例
let mediaInfo = player.mediaInfo();
微信 | 支付宝 | PayPal |
---|---|---|
TODO |
- mp4
ffmpeg -i input.mp4 \
-vcodec libx265 -pix_fmt \
-acodec aac -ac 2 -ar 44100 \
-preset medium -maxrate 1000k -bufsize 1000k \
-vtag hev1 \
-movflags faststart \
-y video.mp4
- hls/m3u8 录屏
ffmpeg -f avfoundation -i 1:0 \
-q 4 -r 10 \
-filter_complex "scale=1280:720" \
-pix_fmt yuv420p \
-vcodec libx265 \
-ar 22050 -ab 64k -ac 1 -acodec aac \
-threads 4 \
-preset veryfast \
-f segment \
-segment_list test.m3u8 \
-segment_time 5 \
-y /Users/numberwolf/Documents/webroot/VideoMissile/VideoMissilePlayer/res/hls1/v-%03d.ts
- mpeg-ts
ffmpeg -ss 20 -t 10 -i ./res/xinxiaomen.mp4 \
-vcodec libx265 -x265-params "bframes=0:keyint=10" -r 24 -filter_complex "scale=720:1280" -preset fast -maxrate 800k -bufsize 800k \
-acodec aac -ar 22050 -ac 1 \
-pix_fmt yuv420p \
-f mpegts -y ./res/veilside2.ts