在之前的《SkeyeRTSPLive高效转码之SkeyeVideoDecoder高效解码》系列文章中我们已经将视频解码成了原始图像数据(YUV/RGB),然后根据不同的转码需求进行编码。如视频分辨率缩放,调整码率,多码率输出等;为了解决转码过程中编码高分辨率高质量或者高压缩率(如H265)耗时的问题,我们采用Nvidia硬件驱动编码器进行编码,以追求最高效率的转码和最低的推送延迟。
SkeyeVideoEncoder基Nvidia独立显卡的硬件编码库SkeyeNvEncoder
1. 接口声明如下:
class SkeyeNvEncoder
{
public:
//codec: 编码格式 0=h264, 1=h265/hevc
int InitNvEncoder(int width,int height,int fps=25, int bitrate=4096, int gop=50, int qp=28, int rcMode=/*NV_ENC_PARAMS_RC_2_PASS_QUALITY*/NV_ENC_PARAMS_RC_CONSTQP,
char* encoderPreset = "Default", int codec = 0,int nDeviceType=0, int nDeviceID=0 );
//H264获取SPS和PPS
int GetSPSAndPPS(unsigned char*sps,long&spslen,unsigned char*pps,long&ppslen);
//H265获取VPS,SPS和PPS
int GetH265VPSSPSAndPPS(unsigned char*vps, long&vpslen, unsigned char*sps, long&spslen, unsigned char*pps, long&ppslen);
// 编码InputFormat我们固定为YUV420PL(I420),可修改为NV12, YUY2 等等在Init()时进行格式转换, [12/18/2016 dingshuai]
unsigned char* NvEncodeSync(unsigned char* pYUV420, int inLenth, int& outLenth, bool& bKeyFrame);
//关闭编码器,停止编码
int CloseNvEncoder();
};
2. SkeyeNvEncoder编码库调用流程
- 第一步,初始化编码器及其参数
//初始化编码器参数
int InitNvEncoder(int width,int height,int fps, int bitrate, int gop,
int qp, int rcMode, char* encoderPreset , int codec, int nDeviceType, int nDeviceID)
{
//初始化设置参数 -- Start
memset(&m_encodeConfig, 0, sizeof(EncodeConfig));
m_encodeConfig.width = width;
m_encodeConfig.height = height;
m_nVArea = width*height;
m_nCheckyuvsize = m_nVArea*3/2;
//编码器识别的码率是bps, 但是我们输入的是kbps, so*1024
m_encodeConfig.bitrate = bitrate*1024;
//多通道编码优化图像质量只有在低延迟模式下工作(LOW_LATENCY)
m_encodeConfig.rcMode = rcMode;//NV_ENC_PARAMS_RC_2_PASS_QUALITY
m_encodeConfig.encoderPreset = encoderPreset; //NV_ENC_PARAMS_RC_2_PASS_QUALITY;
//默认指定低延时模式以及图像的压缩格式(HQ,HP,LOSSLESS ......)
m_encodeConfig.presetGUID = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
// I帧间隔 [12/16/2016 dingshuai]
m_encodeConfig.gopLength = gop;//NVENC_INFINITE_GOPLENGTH;
//CUDA
m_encodeConfig.deviceType = nDeviceType;
m_encodeConfig.deviceID = nDeviceID;
m_encodeConfig.codec = codec;//NV_ENC_H264;
m_encodeConfig.fps = fps;
m_encodeConfig.qp = qp;
m_encodeConfig.i_quant_factor = DEFAULT_I_QFACTOR;
m_encodeConfig.b_quant_factor = DEFAULT_B_QFACTOR;
m_encodeConfig.i_quant_offset = DEFAULT_I_QOFFSET;
m_encodeConfig.b_quant_offset = DEFAULT_B_QOFFSET;
m_encodeConfig.pictur