zoukankan      html  css  js  c++  java
  • h265webplayer

    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,        //视频帧宽度

                        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

  • 相关阅读:
    ElasticSearch「1」本地安裝Elasticsearch 6.0.1 + Elasticsearch-head插件
    HDFS Erasure Coding介绍
    Cassandra VS HBase
    Hadoop入门 【1】 下载源码,构建
    HBase ProcedureV2 分析
    github创建maven项目过程
    ruby, gem install 出现网络错误
    Ketama Consisent Hash
    [转]产品经理 书目录
    [算法]动态规划之最长公共子序列
  • 原文地址:https://www.cnblogs.com/wujianming-110117/p/13292367.html
Copyright © 2011-2022 走看看