h265webplayer
https://github.com/ksvc/h265webplayer
h265webplayer是金山雲的Web端H.265視頻播放器,該播放器Web SDK讓您可以在支持WebAssembly的瀏覽器上播放MP4格式的點播視頻,FLV http-flv協議的直播視頻。
支持的功能
1、mp4格式的點播(音頻需是aac格式的,其余音頻格式待兼容)。
2、flv格式的直播。
兼容性
目前PC端和移動端都可以使用,使用前請使用播放器提供的isSupportH265接口檢查是否支持播放條件。
demo 有兩種訪問方式
mp4 demo 訪問方式
1、ks3直接訪問,鏈接如下:
https://ks3-cn-beijing.ksyun.com/ksplayer/h265/mp4_demo/index.html
flv demo 訪問方式
1、ks3直接訪問,鏈接如下:
https://ks3-cn-beijing.ksyun.com/ksplayer/h265/outside_demo/v1.1.3/index.html
2、獲取壓縮包后本地創建服務訪問,步驟如下:
播放器Demo壓縮包地址
flv demo zip
https://ks3-cn-beijing.ksyun.com/ai-kie/sdk/h265-pc/h265-pc.zip
播放器Demo運行說明
0. 安裝npm包管理器
參見:Node.js官網
1. 安裝http服務器
npm install http-server -g
2. 啟動服務
cd <demo directory>
npm run start
瀏覽器訪問
http://localhost:8000
說明: 請替換頁面中的拉流地址進行測試
集成h265解碼器有兩種方式
1、直接使用金山自研的h265播放器(推薦) 2、基於H265Decoder開發使用
第一種方式:使用h265播放器
token的意義
用於鑒權,驗證用戶是否擁有訪問的權利以及訪問的時長
如何獲取token
先與商務溝通達成協議后,產品會根據需求提供一個對應的token
h265播放器初始化參數配置
let player = h265js.createPlayer({
isLive: false,
type: 'mp4'
},
{
enableSkipFrame: false,
token: 'f8ce4d1adb97c46f28161a3685232557',
wasmFilePath: 'http://localhost:8000/libqydecoder.wasm',
url: urlInput.value,
timeToDecideWaiting: 50000,
bufferTime: 0,
isShowStatistics: false
},{
audioElement: audioElement,
canvas: canvas,
videoElement: h264VideoEle
});
配置參數說明
播放器支持的方法
播放器支持的屬性
播放器支持的事件
獲取視頻編碼格式方法
player.on(h265js.Events.MEDIAINFO, function(event, data){
codec = data.codec;
if (codec === 'avc1') { // h.264
// 處理h.264視頻相關邏輯
} else if (codec === 'hev1') { // h.265
// 處理h.265視頻相關邏輯
}
});
播放器控制條功能說明
<div class="ks-controls">
<button class="ks-controls-load" onclick="load()">Load</button>
<button onclick="start()">Start</button>
<button onclick="pause()">Pause</button>
<button class="ks-controls-muted" onclick="muted()" data-type="muted">Muted</button>
<button onclick="fullscreen()">Fullscreen</button>
<input type="text" name="ks-seek-to" value="35"/>
<button onclick="seekto()">SeekTo</button>
<div class="ks-time">
<span class="ks-current">00:00:00</span>
/
<span class="ks-duration">00:00:00</span>
</div>
</div>
控制條功能具體實現邏輯可以參考demo
播放器能力監測
第二種方式:基於H265Decoder解碼器
JS接口說明
初始化
import H265Decoder from '<decoder direcotory >/h265decoder.js';
let config = {
wasmFilePath: 'http://localhost:8000/libqydecoder.wasm',
enableSkipFrame: true
};
let decoder;
//加載並編譯wasm解碼庫
H265Decoder.compileWasmInterfaces(config.wasmFilePath, function () {
decoder = new H265Decoder(config);
//設置解碼回調
decoder.set_image_callback(onDecodedFrameCallback);
}
向解碼器隊列送數據
decoder.toBeDecodeQueue.push({
nalu: new Uint8Array(naluData), // naluData 為 ArrayBuffer類型數據
pts: 0, //展示時間戳
isDroppable: false }); // 表示是否可以跳幀
- decoder的toBeDecodeQueue屬性為保存待解碼數據的數組,需自行控制待解碼隊列緩沖區的長度,避免內存溢出
- decoder會自動取出toBeDecodeQueue中的數據給底層wasm解碼器,並在解碼后自動釋放傳入wasm解碼器的待解碼數據
設置解碼輸出圖像回調 set_image_callback
decoder.set_image_callback((image) => {
let w = image.get_width(); //獲取圖像寬度
let h = image.get_height(); //獲取圖像高度
let pts = image.get_pts(); //獲取圖像pts時間戳
// let image_data = new Uint8ClampedArray(w * h * 4);
// for (let i = 0; i < w * h; i++) {
// image_data[i * 4 + 3] = 255;
// }
// //轉換image中的YUV數據到image_data中的RGB數據
// image.transcode(image_data);
//優化: 直接返回YUV數據
let yuvData = image.getYuvDataNew(); //Uint8Array
});
說明: 解碼回調函數的參數image為Image類型,參見h265decoder.js中的定義
其他接口
暫停解碼
decoder.pause();
恢復解碼
decoder.resume();
檢查是否為暫停狀態
if(decoder.isPaused()) {}
啟動解碼器
decoder.start();
說明: 默認情況初始化解碼器時會自動調用啟動解碼器
銷毀解碼器
decoder.free();
接收累積跳幀數通知
decoder.on('skip_frame, (skippedframecount) => {
console.log(skippedframecount);
});
wasm解碼器接口說明
接口函數返回碼說明
const qy265decoder = {
QY_OK : (0x00000000), // Success
QY_FAIL : (0x80000001), // Unspecified error
QY_OUTOFMEMORY : (0x80000002), // Ran out of memory
QY_POINTER : (0x80000003), // Invalid pointer
QY_NOTSUPPORTED : (0x80000004),// Not support feature encoutnered
QY_AUTH_INVALID : (0x80000005), // authentication invalid
QY_SEARCHING_ACCESS_POINT : (0x00000001), // in process of searching first access point
QY_REF_PIC_NOT_FOUND : (0x80000007), // encode complete
QY_NEED_MORE_DATA : (0x00000008), // need more data
QY_BITSTREAM_ERROR : (0x00000009), // detecting bitstream error, can be ignored
QY_TOKEN_INVALID : (0x0000000A) //token invalid
錯誤碼分為三大類狀態:
- 等於0: QY_OK,表示完全正常
- 大於0:雖然當前不能正常解碼,但解碼器本身並沒有出錯
- 小於0:解碼器本身發生了一些異常和錯誤
創建解碼器 QY265DecoderCreate
let returnCode = _malloc(4); //為返回碼分配空間
setValue(returnCode, 0, "i32"); // 返回碼設置為0
let decoder = qy265decoder.QY265DecoderCreate(null, token, returnCode);
if(getValue(returnCode, 'i32') === qy265decoder.QY_OK) { /*解碼器創建成功*/ }
銷毀編碼器 QY265DecoderDestroy
qy265decoder.QY265DecoderDestroy(decoder);
- 參數
判斷解碼輸出幀是否有效 QY265DecoderGetFrameValid
let framevalid = qy265decoder.QY265DecoderGetFrameValid(frame);
- 參數
- frame: QY265DecoderGetDecodedFrameEm接口返回的解碼輸出幀
- 返回值: 解碼輸出幀是否有效, 1為有效
歸還解碼輸出幀 QY265DecoderReturnDecodedFrame
通知解碼器釋放該幀占用的相關內存
qy265decoder.QY265DecoderReturnDecodedFrame(decoder, frame);
- 參數
- decoder: 通過QY265DecoderCreate接口創建的解碼器實例
- frame:QY265DecoderGetDecodedFrameEm接口返回的解碼輸出幀
獲取解碼輸出幀的寬度 QY265GetFrameWidth
let width = qy265decoder.QY265GetFrameWidth(frame, 0);
- 參數
- frame:QY265DecoderGetDecodedFrameEm接口返回的解碼輸出幀
- 返回值: 解碼輸出幀的寬度
獲取解碼輸出幀的高度 QY265GetFrameHeight
let height = qy265decoder.QY265GetFrameHeight(frame, 0);
- 參數
- frame:QY265DecoderGetDecodedFrameEm接口返回的解碼輸出幀
- 返回值: 解碼輸出幀的高度
獲取解碼輸出幀的顯示時間戳 QY265GetFramePts
let pts = qy265decoder.QY265GetFramePts(frame, 0);
- 參數
- frame:QY265DecoderGetDecodedFrameEm接口返回的解碼輸出幀
- 返回值: 解碼輸出幀的顯示時間戳
獲取解碼輸出幀的YUV某個分量 QY265DecoderGetFramePlane
let stride = _malloc(2);
let y = qy265decoder.QY265DecoderGetFramePlane(frame, 0, stride);
let u = qy265decoder.QY265DecoderGetFramePlane(frame, 1, stride);
let v = qy265decoder.QY265DecoderGetFramePlane(frame, 2, stride);
- 參數
- frame:QY265DecoderGetDecodedFrameEm接口返回的解碼輸出幀
- index: YUV分量索引,0表示Y分量,1表示U分量,2表示v分量
- 返回值: YUV某個數據分量的數組,格式為Uint8Array
Flush解碼器 QY265DecodeFlush
因為解碼NAL單元與獲取解碼輸出為異步關系, 所以解碼器中可能存在剩余尚未解碼完成的若干NAL單元. 調用本函數將使解碼器完成所有已經輸入的NAL單元的解碼. 一般在碼流結束或者播放器拖曳時使用.
qy265decoder.QY265DecodeFlush(decoder, bClearCachedPics, returnCode);
- 參數
- decoder: 通過QY265DecoderCreate接口創建的解碼器實例
- bClearCachedPics: 是否清除緩沖的圖像. 在碼流結束時, 置為false, 不清除, 得到所有輸出幀;在播放器拖曳或其他情況下, 置為true, 清除之前的圖像幀, 重新開始
- returnCode: 返回碼,returnCode對應地址保存0(QY_OK)表示正常
YUV渲染器文檔
初始化YUV渲染器
import WebGLCanvas from 'yuvrender.min.js'; // yuvrender.min.js在壓縮包中的demo目錄下
let webGLCanvas = new WebGLCanvas({
canvas: this.canvas, //傳入一個canvas
width: width, //視頻幀寬度
height: height //視頻幀高度
});
- 備注:視頻會根據它真實的寬高比自適應視頻容器canvas的寬高
<canvas id="videoDisplayCanvas" width="1600" height="600">
渲染一幀YUV數據
// 假設yuvData為解碼輸出的一幀圖像的YUV表示(Uint8Array類型)
let ylen = width * height; //視頻寬高
let uvlen = (width / 2) * (height / 2);
webGLCanvas.drawNextOutputPicture({
yData: yuvData.subarray(0, ylen),
uData: yuvData.subarray(ylen, ylen + uvlen),
vData: yuvData.subarray(ylen + uvlen, ylen + uvlen*2)
});
獲取解碼輸出的圖像幀的YUV表示
參見: 設置解碼輸出圖像回調 set_image_callback