SkillAgentSearch skills...

H265webplayer

h265webplayer是金山云的Web端H.265视频播放器,该播放器Web SDK让您可以在支持WebAssembly的浏览器上播放FLVhttp-flv协议的直播视频和mp4格式的点播视频。

Install / Use

/learn @ksvc/H265webplayer
About this skill

Quality Score

0/100

Supported Platforms

Universal

Tags

README

h265webplayer

h265webplayer是金山云的Web端H.265视频播放器,该播放器Web SDK让您可以在支持WebAssembly的浏览器上播放MP4格式的点播视频,FLV http-flv协议的直播视频。

h265-screenshot

支持的功能

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
    });

配置参数说明

配置参数 | 参数类型 | 默认值 | 描述
-|-|-|- isLive | boolean | false | 区分直播点播的参数。 目前此播放器只支持mp4格式,之后还会集成flv和m3u8格式 | type | string | mp4 | 区分视频封装格式 | enableSkipFrame | boolean | false | 是否允许跳帧参数。在解码器能力不够时,可以将enableSkipFrame 设置为true。此时会跳过一些不重要的非参考帧不进行解码,以便能流畅播放 | token | string | f8ce4d1adb97c46f28161a368529b557(有效期到年底) | 播放器鉴权token。一旦token过期,h265 pc sdk将无法使用,过期通知将通过error事件给出 | wasmFilePath | string | https://ks3-cn-beijing.ksyun.com/ksplayer/h265/wasm_resource/libqydecoder.wasm | 用于指定wasm解码库的位置 | url | string | https://ks3-cn-beijing.ksyun.com/ksplayer/h265/mp4_resource/moov_head_265.mp4 | 视频流地址。 | timeToDecideWaiting | number | 1000(ms) | 暂停多久算卡顿 | bufferTime | number | 0(ms) | 启播前缓冲视频时长 | isShowStatistics | boolean | false | 是否在控制台输出统计信息 | audioElement | HTMLAudioElement | - | 音频 audio dom 元素 | canvas | HTMLCanvasElement | - | 画布 canvas dom 元素 |

播放器支持的方法

方法 | 描述 -|-| load() | 重新加载视频 | play() | 开始播放视频 | pause() | 暂停当前播放的视频 | destroy() | 销毁播放器 |

播放器支持的属性

方法 | 描述 -|-| currentTime | 设置或返回视频中的当前播放位置(以秒计) | muted | 设置或返回音频/视频是否静音 | duration | 返回当前音频/视频的长度(以秒计) | volume | 设置或返回音频/视频的音量 | mediaInfo | 返回视频媒体信息 |

播放器支持的事件

事件 | 描述 -|-| READY | 播放器初始化完毕时触发 | MEDIAINFO | 播放器解封装后获取到视频元数据信息时触发 | PLAY | 视频由暂停恢复为播放时触发 | PAUSE | 视频暂停时触发 | LOADSTART | 播放器开始加载数据时触发 | VOLUMECHANGE | 当音量改变时触发 | ERROR | 发生错误时触发 | WAITING | 出现卡顿,需要缓存下一帧数据时触发 | PLAYING | 播放时触发 | ENDED | 播放结束时触发 | RELOAD | 解码能力不足时触发 |

获取视频编码格式方法

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>

控制条功能 | 实现方法 | 描述 -|-|-| Load | load()| 初始化播放器以及加载视频流 | Start | start() | 播放视频 | Pause | pause() | 暂停视频 | Muted | muted() | 静音 | UnMuted | muted() | 非静音 | Fullscreen | fullscreen() | 播放器全屏, 按esc键退出全屏 | SeekTo | seekto() | 触发seek功能,时间点根据input[name="ks-seek-to"]的value值来决定,时间单位为(秒) | currentTime | 通过订阅 player 的 ONTIMEUPDATE 事件获取到的第二个回调参数 currentTime | 当前播放时间 | Duration | 通过订阅 player 的 MEDIAINFO 事件获取到的第二个回调参数 data 中的 audioDuration | 视频时长 |

控制条功能具体实现逻辑可以参考demo

播放器能力监测

方法名 | 调用方式 | 描述 -|-|-| isSupportH265 | h265js.isSupportH265()| 返回此浏览器或者此设备是否支持H.265播放 |

第二种方式:基于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);
  • 参数
    • decoder: 通过QY265DecoderCreate接口创建的解码器实例

解码一个NAL单元 QY265DecodeFrameEnSkip

qy265decoder.QY265DecodeFrameEnSkip(decoder, naluData, length, returnCode, pts, shouldSkip);
  • 参数
    • decoder: 通过QY265DecoderCreate接口创建的解码器实例
    • naluData: NAL单元数据,Uint8Array类型
    • length: NAL单元数据字节数
    • returnCode: 返回码,returnCode对应地址保存0(QY_OK)表示正常
    • pts: NAL单元对应的显示时间标签
    • shouldSkip: true/false, 表示是否应该跳过该NAL单元的解码

获取解码输出 QY265DecoderGetDecodedFrameEm

let frame = qy265decoder.QY265DecoderGetDecodedFrameEm(decoder, returnCode, 0);
  • 参数
    • decoder: 通过QY265DecoderCreate接口创建的解码器实例
    • returnCode: 返回码
  • 返回值: 解码输出帧

判断解码输出帧是否有效 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, 清除之前的图像帧, 重新开始
View on GitHub
GitHub Stars217
CategoryDevelopment
Updated1mo ago
Forks46

Languages

HTML

Security Score

80/100

Audited on Feb 26, 2026

No findings