目前openh264官网只有一些问答,关键的开发资料全在github页的的wiki页面(https://github.com/cisco/openh264/wiki)
同样官方的二进制库也在github页的release页面上提供下载(https://github.com/cisco/openh264/releases)
此文章所述皆为windows平台,其他平台使用类似。此文章所使用的openh264版本为1.6,openh264没有提供导入库,只能使用动态加载的方式使用。
首先使用LoadLibrary
和GetProcAddress
API获取到dll提供的函数接口。一共有6个接口
WelsCreateDecoder;
WelsCreateSVCEncoder;
WelsDestroyDecoder;
WelsDestroySVCEncoder;
WelsGetCodecVersion;
WelsGetCodecVersionEx;
调用WelsCreateDecoder
接口可以获取解码器对象。
调用WelsCreateSVCEncoder
接口可以获取编码器对象。
此节内容并没有在官方文档中写明,所以在此特别说明。
获取到的是一个c++对象指针,通过这个指针,可以调用对象的方法。对象的头文件在源码的codec\api\svc
目录下的codec_api.h
(官方文档中对此也没有做出说明)。
通过WelsCreateSVCEncoder
接口获取到的对象是ISVCEncoder
类型指针。
首先调用对象的GetDefaultParams
方法获取到默认的参数结构,然后覆盖自己的参数,具体值根据实际情况决定,参数的含义参考文档。
其中需要注意的是iSpatialLayerNum
,指定要输出几路码流,通常设为1。
然后要将参数中的sSpatialLayers
码流参数数组的参数也填为指定码流的参数。数组元素的数量由iSpatialLayerNum
决定。
调用对象的InitializeExt
方法,传入修改过的参数,初始化编码器对象。
然后调用
int videoFormat = videoFormatI420;
SetOption(ENCODER_OPTION_DATAFORMAT, &videoFormat);
设置传入图像的格式,目前只支持yuv420,所以这句是固定的。
至此编码器参数设置的已经完成。
真正的编码需要调用对象的EncodeFrame
方法。方法需要两个参数,一个SSourcePicture
指针类型的用来存放待编码的yuv数据,一个SFrameBSInfo
指针类型的用来获取编码后的NAL单元数据。
SSourcePicture
类型的对象内容如下:
iPicWidth
:传入图像宽度。
iPicHeight
:传入图像高度。
iColorFormat
:传入图像格式,目前只有一种videoFormatI420
。
iStride
:yuv3个通道的行宽数组。
pData
:yuv3个通道的数据指针数组。
调用EncodeFrame
方法,传入正确填充的SSourcePicture
指针类型的参数和置零的SFrameBSInfo
指针类型参数。
然后查看返回值,如果返回值为0并且SFrameBSInfo
类型参数的eFrameType
字段不等于videoFrameTypeSkip
说明有数据被编码出来。
数据存放在SFrameBSInfo
类型参数的sLayerInfo
结构数组中。其中每个结构体中的pBsBuf
表示编码得到的数据,
而长度是结构体pNalLengthInByte
int数组加起来的和,数组的长度由结构体的iNalCount
成员表示。
而编码得到的数据内存不需要释放,编码器每次调用对象的EncodeFrame
方法时会重用这块内存,也就是说编码出来的数据的在下次调用对象的EncodeFrame
方法前有效。在销毁编码器的时候释放这块内存。
调用编码器的对象的Uninitialize
方法,然后调用WelsDestroySVCEncoder
接口,传入之前获得的编码器对象指针。即可销毁对象,释放资源。
通过WelsCreateDecoder
接口获取到的对象是ISVCDecoder
类型指针。
建立一个SDecodingParam
类型的空的参数结构体,,具体值根据实际情况决定,参数的含义参考文档。需要特别说明的是bParseOnly
字段,便是是否要仅仅解析内容,通常用来测试,所以正常使用的时候设为false
。
调用解码器对象的Initialize
方法,传入填充正确的SDecodingParam
类型参数。
真正的解码需要调用解码器对象的DecodeFrameNoDelay
方法,此方法需要4个参数,第一个unsigned char
指针类型参数表示传入的NAL单元起始的地址,第二个int
型参数表示NAL单元的长度。第三个unsigned char
指针数组类型参数用来接收解码完的图像数据,需要提前分配好数组空间,但是实际的每个指针指向的内存不用分配。第四个是置空的SBufferInfo
指针类型参数,获取解码的数据的一些信息。
调用解码器对象的DecodeFrameNoDelay
方法,传入对应的参数,接收返回值,如果返回后等于0并且,SBufferInfo
类型参数中的iBufferStatus
等于1。就代表成功解码出了数据。
解码出的图像数据按照通道分别存放在传入的第三个参数的指针数组里。SBufferInfo
类型参数中的UsrData.sSystemBuffer.iWidth
指示图像的宽度,SBufferInfo
类型参数中的UsrData.sSystemBuffer.iHeight
指示图像的高度,SBufferInfo
类型参数中的sDstBufInfo.UsrData.sSystemBuffer.iStride
数组指示每个通道的行宽。
根据这3个参数就可以将解码得到数据中的有效的图像数据拿出来。
调用解码器的对象的Uninitialize
方法,然后调用WelsDestroyDecoder
接口,传入之前获得的解码器对象指针。即可销毁对象,释放资源。