Skip to content

KSC265codec_sdk_doc

zhuzhengzz edited this page Jul 3, 2017 · 1 revision

KSC265编解码器SDK文档


[TOC]

编解码器公用数据类型和接口

编解码器接口公用基本数据类型, 位于qy265def.h

错误码

// ****************************************
// error type
// ****************************************
enum
{
    QY_OK = (0x00000000),          // Success codes
    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 = (0x00000007), // reference picture not found, can be ignored
    QY_BITSTREAM_ERROR = (0x00000009), // detecting bitstream error, can be ignored
};

错误码分为三大类状态:

  • 等于0: QY_OK,表示完全正常
  • 大于0: 虽然当前不能正常解码,但解码器本身并没有出错。比如还没有找到有效的随机访问点,而当前给解码器的NALS并不是随机访问点(QY_SEARCHING_ACCESS_POINT);比如找不到参考帧,或者检测出码流比特错误,依靠解码器自身的鲁棒性,后续解码可以照常进行
  • 小于0: 表示解码器本身发生了一些异常和错误,比如遇到不支持的feature,或者内存耗尽等

设置输出日志回调函数

typedef void  (*QYLogPrintf)(const char* msg);
void QY265SetLogPrintf ( QYLogPrintf pFuncCB);

如果没有设置输出日志回调函数,编解码器android默认输出到logcat,其他平台默认到标准输出。 可以用自定义输出日志函数QYLogPrintf pFuncCB代替编解码器默认输出日志函数。

编码器SDK接口

QY265编码器输入视频源为YUV4:2:0 8bit, 输出符合HEVC/H.265 main profile规范的码流. 接口文件为qy265enc.h

创建编码器

void* QY265EncoderOpen(QY265EncConfig* pCfg, int *errorCode);
  • 功能:创建一个编码器实例
  • 返回值:编码器实例的指针
  • 参数:
    • QY265EncConfig* pCfg 编码器基本配置参数
    • int *errorCode 返回错误码

###编码器基本配置参数

// ****************************************
// base configuration
// ****************************************
//app type
typedef enum QY265Tune_tag{
    QY265TUNE_DEFAULT = 0,
    QY265TUNE_SELFSHOW = 1,
    QY265TUNE_GAME = 2,
    QY265TUNE_MOVIE = 3,
    QY265TUNE_SCREEN = 4
}QY265Tune;

typedef enum QY265Preset_tag{
    QY265PRESET_SUPERFAST = 0,
    QY265PRESET_VERYFAST = 1,
    QY265PRESET_FAST = 2,
    QY265PRESET_MEDIUM = 3,
    QY265PRESET_SLOW = 4,
    QY265PRESET_VERYSLOW = 5,
    QY265PRESET_PLACEBO = 6,
}QY265Preset;

typedef enum QY265Latency_tag{
    QY265LATENCY_ZERO = 0,
    QY265LATENCY_LOWDELAY = 1,
    QY265LATENCY_LIVESTREMING = 2,
    QY265LATENCY_OFFLINE = 3,
}QY265Latency;

//base configuration
typedef struct QY265EncConfig{
    void* pAuth;        //QYAuth, invalid if don't need aksk auth
    QY265Tune tune;    //
    QY265Preset preset;
    QY265Latency latency;
    int iHeaderBeforeKeyframe; //whether output vps,sps,pps before key frame, default 1. dis/enable 0/1
    int picWidth;          // input frame width
    int picHeight;         // input frame height
    double frameRate;      // input frame rate
    int bframes;           // num of bi-pred frames, -1: using default
    int temporalLayer;     // works with QY265LATENCY_ZERO, separate P frames into temporal layers, 0 or 1

    int rc;                // rc type 0 disable,1 cbr,2 abr,3 crf, default 2
    int bitrateInkbps;     // target bit rate in kbps, valid when rctype is cbr abd vbr
    int vbv_buffer_size;   // buf size of vbv
    int vbv_max_rate;      // max rate of vbv
    int qp;                // valid when rctype is disable, default 26
    int crf;               // valid when rctype is crf,default 24
    int iIntraPeriod;      // I-Frame period
    int qpmin;              //minimal qp, valid when rc != 0, 0~51
    int qpmax;              //maximal qp, valid when rc != 0, 1~51, qpmax = 0 means 51
    //* Execute Properties
    int iWavefront;       //enable wave front parallel
    int enFrameParallel;   //enable frame parallel
    int threads;           // number of threads used in encoding ( for wavefront, frame parallel, or enable both )
    //* vui_parameters
    //vui_parameters_present_flag equal to 1 specifies that the vui_parameters() syntax in struct vui should set by usr
    int vui_parameters_present_flag;
    struct{
        /* video_signal_type_present_flag.  If this is set then
         * video_format, video_full_range_flag and colour_description_present_flag
         * will be added to the VUI. The default is false */
        int video_signal_type_present_flag;
        /* Video format of the source video.  0 = component, 1 = PAL, 2 = NTSC,
         * 3 = SECAM, 4 = MAC, 5 = unspecified video format is the default */
        int video_format;
        /* video_full_range_flag indicates the black level and range of the luma
         * and chroma signals as derived from E′Y, E′PB, and E′PR or E′R, E′G,
         * and E′B real-valued component signals. The default is false */
        int video_full_range_flag;
        /* colour_description_present_flag in the VUI. If this is set then
         * color_primaries, transfer_characteristics and matrix_coeffs are to be
         * added to the VUI. The default is false */
        int colour_description_present_flag;
        /* colour_primaries holds the chromacity coordinates of the source
         * primaries. The default is 2 */
        int colour_primaries;
        /* transfer_characteristics indicates the opto-electronic transfer
         * characteristic of the source picture. The default is 2 */
        int transfer_characteristics;
        /* matrix_coeffs used to derive the luma and chroma signals from
         * the red, blue and green primaries. The default is 2 */
        int matrix_coeffs;
    }vui;
    //* debug
    int logLevel;
    int calcPsnr;          //0:not calc psnr; 1: print total psnr; 2: print each frame
    int shortLoadingForPlayer;  //reduce b frames after I frame, for shorting the loading time of VOD for some players
}QY265EncConfig;

void* pAuth: 鉴权信息, 不做鉴权时忽略。做鉴权在下一节说明 QY265Tune tune: 应用场景. 目前使用default即可 QY265Preset preset: 速度档次. 支持从superfast到placebo, 默认值为veryfast. QY265Latency latency: 延迟档次, 默认值为QY265LATENCY_OFFLINE.

QY265LATENCY_ZERO = 0 应用于实时通信, 零延迟.
QY265LATENCY_LOWDELAY = 1 应用于实时通信, 低延迟
QY265LATENCY_LIVESTREMING = 2 应用于实时直播, 只有几帧的延迟
QY265LATENCY_OFFLINE = 3  应用于离线, 不考虑延迟大小

int bHeaderBeforeKeyframe:是否在关键帧前面都插入参数集vps/sps/pps. 0:否, 1:是. 默认值为1, 表示插入参数集. int picWidth, picHeight:输入图像分辨率. double frameRate:输入帧率. int bframes: 相邻两个前向参考图像间最大使用的B帧数目. 不配置或值为-1时, 表示使用默认数目7. 目前支持0,1,3,7. int temporalLayer: 是否使用时间分级, 在QY265LATENCY_ZERO和QY265LATENCY_LOWDELAY两个延迟档次使用. 0:关闭, 1:打开. 默认值为0, 关闭. int rc:0: 定QP;1: CBR; 2: ABR; 3: CRF, 默认值为1, CBR. int bitrateInkbps:目标码率, 单位为kbps, 当rc = 1, 2时有效. 默认值为500. int qp:量化参数, 当rc=0时有效, 默认值为30. int qpmin: 码率控制过程中, 帧级使用的最小qp, 当rc不等于0时有效, 默认值0. int qpmax:码率控制过程中, 帧级使用的最大qp, 当rc不等于0时有效, 默认值51. int vbv_buffer_size:码率控制过程中, vbv缓冲区大小, 单位为kbits. int vbv_max_rate:码率控制过程中, vbv缓冲区内的编码码率上限, 单位为kbps. int crf:作用类似于qp, rc=3时有效, 默认值30. int iIntraPeriod:关键帧间隔, 单位为帧数, 默认值256. int threads:线程数, =0表示自动识别CPU核数;>0表示线程数目 int enWavefront:是否启动wpp并行. 默认配置:threads值为0时, 启动;threads值为1时, 关闭;threads值为其他值时, 智能计算. int enFrameParallel:是否启动帧级并行. 默认配置:threads值为0时, 启动;threads值为1时, 关闭;threads值为其他值时, 智能计算. int vui_parameters_present_flag: 不使用VUI相关配置时, 设为0, 否则设为1. 默认值0. int logLevel:默认值为0. 其他取值为, -1: dbg; 0: info; 1:warn; 2:err; 3:fatal. int shortLoadingForPlayer: 缩短播放器首次loading数据时间,默认值0. 设置为1有效。

销毁编码器

void QY265EncoderClose(void* pEncoder);
  • 功能:销毁一个编码器实例
  • 返回值:无
  • 参数:编码器实例的指针

编码一帧图像

int QY265EncoderEncodeFrame(void* pEncoder, QY265Nal** pNals, int* iNalCount, QY265Picture* pInpic, QY265Picture* pOutpic, int bForceLogo);
  • 功能:编码一帧YUV图像
  • 返回值:错误码, 0表示正常
  • 参数:
  • void* pEncoder 编码器实例的指针
  • QY265Nal** pNals编码生成的NAL单元的指针, pNals[i]表示第i个NAL单元的指针
  • int* iNalCount 编码生成的NAL单元的数目
  • QY265Picture* pInpic输入YUV图像结构体指针, 与输出pNals不同步
  • QY265Picture* pOutpic输出图像帧信息, 作为输出pNals的辅助信息, 与输出pNals同步. 仅为参考使用, 丢弃不影响正常编码
  • int bForceLogo, 调试使用, 恒为0

输出NAL单元

typedef struct QY265Nal
{
    int naltype;
    int tid;
    int iSize;
    unsigned int pts;
    unsigned char* pPayload;
}QY265Nal;

int naltype:符合标准规定的NAL类型 int tid:时间层级, 0为最关键的层级, 值大的时间层级会使用值小的时间层级作参考 int iSize:NAL单元的大小, 单位为字节. 包含起始码. unsigned int pts:显示时间标签 unsigned char* pPayload:NAL数据的起始指针

图像帧信息

// input frame data and info
typedef struct QY265YUV{
    int iWidth;                 // input frame width
    int iHeight;                // input frame height
    unsigned char* pData[3];    // input frame Y U V
    int iStride[3];             // stride for Y U V
}QY265YUV;
// input frame data and info
typedef struct QY265Picture{
    int iSliceType; // specified by output pictures
    int poc;        // ignored on input
    long long pts;
    long long dts;
    QY265YUV* yuv;
}QY265Picture;

int iWidth, iHeight:图像帧的宽高 unsigned char* pData[3]:YUV数据Buffer的起始地址 int iStride[3]:YUV数据Buffer像素行间的步长, 大于等于宽度 int iSliceType:图像slice类型, 输入时不用指定, 默认为0即可 int poc:图像POC值, 输入时不用指定 unsigned int pts:显示时间标签 unsigned int dts:解码时间标签, 输入时不用指定

编码参数集

int QY265EncoderEncodeHeaders(void* pEncoder,QY265Nal** pNals,int* iNalCount);
  • 功能:编码vps/sps/pps参数集
  • 返回值:错误码, 0表示正常
  • 参数:
  • void* pEncoder 编码器实例的指针
  • QY265Nal** pNals编码生成的NAL单元的指针, pNals[i]表示第i个NAL单元的指针
  • int* iNalCount 编码生成的NAL单元的数目

关键帧请求

void QY265EncoderKeyFrameRequest(void* pEncoder);
  • 功能:发起编码关键帧的请求, 编码器将会在下一次调用QY265EncoderEncodeFrame时编码关键帧
  • 返回值:无
  • 参数:void* pEncoder 编码器实例的指针

查询延迟帧数目

int QY265EncoderDelayedFrames(void* pEncoder);
  • 功能:查询编码器延迟尚未编码的帧数, 只在序列结束时使用, 如果返回值大于0, 说明还有延迟的帧尚未完成编码, 需要继续调用QY265EncoderEncodeFrame直至所有帧完成编码
  • 返回值:延迟帧数目, 等于0表示已经编完
  • 参数:void* pEncoder 编码器实例的指针

生成默认配置参数

int QY265ConfigDefault(QY265EncConfig* pConfig, QY265Preset preset, QY265Tune tune, QY265Latency latency);
  • 功能:通过指定preset, tune, latency生成pConfig默认配置参数
  • 返回值: 错误码
  • 参数:
  • QY265EncConfig* pConfig: 基本配置参数指针
  • QY265Preset preset: 指定速度档次
  • QY265Tune tune: 指定应用场景
  • QY265Latency latency: 指定延迟档次

改变编码配置参数

void QY265EncoderReconfig(void* pEncoder,QY265EncConfig* pCfg);
  • 功能:改变基本配置参数,主要用于码率,帧率的调整。

解码器SDK接口

QY265解码器支持符合HEVC/H.265 main profile规范的码流. 接口文件为qy265dec.h

创建解码器

void* QY265DecoderCreate(QY265DecConfig* pDecConfig, int * pStat);
  • 功能:创建一个解码器实例
  • 返回值:解码器实例的指针
  • 参数:
  • QY265DecConfig* pDecConfig 解码器基本配置参数
  • int* pStat 返回错误码, 0表示正常

解码器基本配置参数

// config parameters for Decoder
typedef struct QY265DecConfig {
    void* pAuth;            //QYAuth, invalid if don't need aksk auth
    int threads;               // number of threads used in decoding (0: auto)
    bool bEnableOutputRecToFile;  // For debug: write reconstruct YUV to File
    char* strRecYuvFileName;      // For debug: file name of YUV
                                  // when bEnableOutputRecToFile = 1
    int logLevel;               //For debug: log level
}QY265DecConfig;

void* pAuth: 鉴权信息, 不做鉴权时忽略 int threads:线程数, =0表示自动识别CPU核数;>0表示线程数目 bool bEnableOutputRecToFile 是否输出重建YUV文件, 调试使用 char* strRecYuvFileName 输出重建YUV文件名, bEnableOutputRecToFile=1时有效, 调试使用 int logLevel 默认为0

销毁解码器

void QY265DecoderDestroy(void* pDecoder);
  • 功能:销毁一个解码器实例
  • 返回值:无
  • 参数:解码器实例的指针

解码器改变参数

void QY265DecoderSetDecConfig(void *pDecoder, QY265DecConfig* pDecConfig, int * pStat);
  • 功能:解码器执行过程中, 改变配置参数
  • 返回值:无
  • 参数:
  • void* pDecoder 解码器实例的指针
  • QY265DecConfig* pCfg解码器基本配置参数
  • int* pStat 返回错误码, 0表示正常

解码一个或多个NAL单元

void QY265DecodeFrame(void *pDecoder, unsigned char* pData, int iLen, int * pStat, const long long pts);
  • 功能:解码一个或多个NAL单元, 必须是整数个NAL单元
  • 返回值:无
  • 参数:
  • void* pDecoder 解码器实例的指针
  • unsigned char* pData 码流数据起始地址
  • int iLen 码流数据长度, 单位为字节
  • const long long pts NAL单元对应显示时间标签

获取解码输出

void QY265DecoderGetDecodedFrame(void *pDecoder, QY265Frame* pFrame, int * pStat, int bForceLogo);
  • 功能:获取解码输出, 与QY265DecodeFrame异步. 与QY265DecoderReturnFrame配套使用, 如果获取到有效输出帧, 在使用完毕后必须调用QY265DecoderReturnFrame归还
  • 返回值:无
  • 参数:
  • void* pDecoder 解码器实例的指针
  • QY265Frame* pFrame 解码输出帧信息, 详见以下
  • int* pStat 返回错误码, 0表示正常

解码输出帧信息

// information of decoded frame
typedef struct QY265FrameInfo {
    int nWidth;     // frame width
    int nHeight;    // frame height
    long long pts;  // time stamp
    bool bIllegalStream; // input bit stream is illegal
}QY265FrameInfo;

// decoded frame with data and information
typedef struct QY265Frame {
    int  bValid; //if == 0, no more valid output frame
    unsigned char* pData[3]; // Y U V
    short iStride[3];        // stride for each component
    QY265FrameInfo frameinfo;
}QY265Frame;

int nWidth nHeight:解码输出帧的图像宽高 long long pts:解码输出帧对应显示时间标签 bool bIllegalStream:just ignored int bValid:是否获取到有效解码输出帧, 1为有效 unsigned char* pData[3] 解码输出帧存, YUV buffer起始地址 short iStride[3] 解码输出帧存, YUV buffer像素行步长

归还解码输出帧存

void QY265DecoderReturnDecodedFrame( void *pDecoder, QY265Frame* pFrame);
  • 功能:归还解码输出帧存, 与QY265DecoderGetOutput 配套使用, 获取到的有效帧存在使用完毕后, 调用本函数归还帧存.
  • 返回值:无
  • 参数:
  • void* pDecoder 解码器实例的指针
  • QY265Frame* pFrame 解码输出帧信息, 应与QY265DecoderGetOutput获取到的有效帧信息相同

Flush解码器

void QY265DecodeFlush(void *pDecoder, int bClearCachedPics, int * pStat);
  • 功能:因为解码NAL单元与获取解码输出为异步关系, 所以解码器中可能存在剩余尚未解码完成的若干NAL单元. 调用本函数将使解码器完成所有已经输入的NAL单元的解码. 然后配合QY265DecoderGetOutput获取剩余的解码输出. 一般在码流结束或者播放器拖曳时使用.
  • 返回值:无
  • 参数:
  • void* pDecoder 解码器实例的指针
  • int bClearCachedPics 是否清除缓冲的图像. 在码流结束时, 置为false, 不清除, 得到所有输出帧;在播放器拖曳或其他情况下, 置为true, 清除之前的图像帧, 重新开始
  • int* pStat 返回错误码, 0表示正常

#鉴权接口说明 如上所述,编码器基本配置参数QY265EncConfig以及解码器基本配置参数QY265DecConfig中都有void* pAuth变量用于鉴权。 在不同鉴权方式时,将不同的鉴权结构体指针赋予pAuth来实施鉴权认证。鉴权相关的接口定义在qyauth_env.h头文件。

服务端license server鉴权

服务端鉴权通过读取本地密钥文件获得认证,pAuth指向正确的密钥文件即可。详细的鉴权说明见《KSC265编解码器鉴权说明文档》。

服务端鉴权需要-DKSAUTH_PRIVATE_AUTH=1 或者将在qyauth_env.h中将 KSAUTH_PRIVATE_AUTH 的默认值改为1配合ffmpeg wrapper文件使用,因为qyauth_env.h和ffmpeg wrapper文件都是各个平台共用的,只有服务端需要KSAUTH_PRIVATE_AUTH=1,因此我们默认写为0了。

  • 创建示例
    QY265EncConfig cfg;
    cfg.pAuth = "/home/usrXXX/ks265.key";
    //...
    int errCode = 0;
    void* encoder = QY265EncoderOpen(&cfg, &errCode);
    if(errCode == QY_AUTH_INVALID){
        //...
    }
  • 设置报警回调
typedef void  (*QYAuthWarning)();
void QY265SetAuthWarning ( QYAuthWarning pFuncCB);

该接口位于qy265def.h。在异步连接license server通讯故障时,调用用户自定义的回调函数产生报警。

移动端鉴权

android和ios移动端鉴权需要读取有效包名。

iOS

编译的时候需要添加 -framework Foundation -framework UIKit 编译选项。

pAuth传入NULL指针即可。

android

#include <jni.h>
typedef struct _TCounterEnv
{
    JavaVM *jvm;
    jobject context;
}TCounterEnv;

android需要传入jvm和context,将TCounterEnv实例的指针赋值给编解码器基本配置参数QY265EncConfig或QY265DecConfig的pAuth指针。使用示例如下

// config config.pAuth for Decoder
TCounterEnv* tCounterEnv = (TCounterEnv*) malloc(sizeof(TCounterEnv));
    tCounterEnv->context = context;
    env->GetJavaVM(&tCounterEnv->jvm);

    QY265DecConfig config;
    config.bEnableOutputRecToFile = false;
    config.logLevel = 0;
    config.pAuth = tCounterEnv;

    int ret;
    QY265DecoderCreate(&config, &ret);
    __android_log_print(ANDROID_LOG_ERROR, "qyauth", "ret = %d", ret);
  • TCounterEnv使用全局静态变量

上述示例代码中,context需要传入。为方便起见,TCounterEnv建议使用全局静态变量,以下为一个jni文件的例子

TCounterEnv tenv;

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    LOGD( "onload " );
    tenv.jvm = vm;
    return JNI_VERSION_1_4;
}

extern "C" JNIEXPORT void JNICALL Java_net_qyvideo_android_qyffdemo_MainActivity_setAppContext(JNIEnv* env, jobject thiz, jobject context){
    tenv.context = env->NewGlobalRef(context);
}

JNI_OnLoad的时候set jvm; 此外添加一个jni函数set context,该函数在java里面提前调用:

    setAppContext(this.getApplicationContext());

setAppContext设置的Context最好使用APP的Context,而不要使用Activity的Context

  • ffmpeg中使用

ffmpeg中,在open_video之前将TCounterEnv实例的指针传给opaque:

    AVCodecContext *c = video_st.st->codec;
    c->opaque = &tenv;
    open_video(oc, video_codec, &video_st, opt_video);

我们自带的ffmpeg wrapper文件会将opaque的指针赋给cfg的pAuth,如libqy265dec.c中的代码片段(这段代码只用作说明,用户不用修改):

static av_cold int hevc_decode_init(AVCodecContext *avctx) {
     QY265Context *ctx = avctx->priv_data;
     //...
     ctx->params->pAuth = avctx->opaque;
     ctx->m_decoder = QY265DecoderCreate(ctx->params, &ret);

ffmpeg中使用解码器时,有avformat_find_stream_info的过程会打开解码器,也涉及到鉴权,需要在libavformat/utils.c的avformat_find_stream_info函数中//Try to just open decoders的avcodec_open2之前判断是HEVC时设置一下用于鉴权的指针:

// Try to just open decoders, in case this is enough to get parameters.
if (!has_codec_parameters(st, NULL) && st->request_probe <= 0) {
    if (codec && !st->codec->codec){
        //*** add code here
        if(st->codecpar->codec_id == AV_CODEC_ID_HEVC){
            avctx->opaque = &tenv;
        }
        //*** add code finish
        if (avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt) < 0)
            av_log(ic, AV_LOG_WARNING, "Failed to open codec in av_find_stream_info\n");
    }
}