/* * Copyright(C) 2023 Reconova Information Technologies Co., Ltd. * All rights reserved. * * Hi3516DV500收流封装。 * * Created by Cyberman Wu on Sep 28th, 2023. * */ #ifndef __RW_MPP_API_H__ #define __RW_MPP_API_H__ #ifdef __cplusplus extern "C" { #endif #include /////////////////////////////////////////////////////////////////////////////// // 编码相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// #define NR__VENC_CHN 4 typedef enum VENC_CODEC_type { CODEC_H264 = 0, CODEC_H265 = 1, CODEC_MJPEG = 2 } VENC_CODEC_t; typedef enum VENC_PROFILE { H264_baseline = 0, H264_main = 1, H264_high = 2, H265_main = 0, MJPEG_baseline = 0 } VENC_PROFILE_t; typedef enum VENC_RC { RC_FIXQP = 0, RC_VBR = 1, } VENC_RC_t; /* * 最早我们只需要支持H.264/H.265编码,所以数据结构都是根据这两个定的, * 现在支持MJPEG之后我们还是用这个数据结构,不过图像质量只取IQp,并且 * 取决范围为[1, 99]。 * * ***注意:H.264/H.265的质量参数是值越小图像质量越好;而MJPEG则是值 * 越大图像质量越好。 */ typedef struct venc_rc_fixQp { int IQp; /* RW; Range:[0, 51]; qp of the I frame (H.264/H.265) */ /* RW; Range:[1, 99]; image quality. (MJPEG) */ int PQp; /* RW; Range:[0, 51]; qp of the P frame (H.264/H.265) */ int BQp; /* RW; Range:[0, 51]; qp of the B frame (H.264/H.265) */ } S_venc_rc_fixQp; /* * 最早我们只需要支持H.264/H.265编码,所以数据结构都是根据这两个定的, * 现在支持MJPEG之后我们还是用这个数据结构,不过图像质量只取minIQp/maxIQp, * 并且取决范围为[1, 99]。 * * ***注意:H.264/H.265的质量参数是值越小图像质量越好;而MJPEG则是值 * 越大图像质量越好。 */ typedef struct venc_rc_vbr { // max_bitrate单位是Kbps。 int max_bitrate; /* RW; Range:[2, (160 * 1024)],编码器输出最大码率,单位是kbps。 */ int stats_time; /* RW; Range:[1, 60],单位是秒。 */ // 这些高级属性不再支持配置。 #if 0 // 下面的参数在海思里面是单独配置的,可以不配置而使用系统 // 缺省值(或者是根据码流以及图像大小、帧率自动计算的)。int src_img_spec, int dst_img_spec // 如果全部设置为-1表示使用缺省缺省值,不自己进行配置。 int minIQp; /* RW; Range:[0, 51]; the min I qp (H.264/H.265) */ /* RW; Range:[1, 99]; min image quality allowed (MJPEG)*/ int maxIQp; /* RW; Range:(MinIQp, 51]; the max I qp (H.264/H.265) */ /* RW; Range:[MinIQp, 99]; max image quailty allowed (MJPEG) */ int minQp; /* RW; Range:[0, 51]; the min P B qp (H.264/H.265) */ int maxQp; /* RW; Range:(MinQp, 51]; the max P B qp (H.264/H.265) */ #endif } S_venc_rc_vbr; typedef struct venc_config { /* * 编码器属性 */ // H.264 or H.265 or MJPEG VENC_CODEC_t codec; VENC_PROFILE_t profile; // 输入图像不严格要求,但限制它的最大值有助于节省存储,通常我们直接设置为进入 // 图像的分辨率。 int raw_max_width; int raw_max_height; // 编码输出的图像大小。 int width; int height; /* Group of Picture * 严格来说H.264/H.265的GOP除了帧间隔之前还有其它一些属性,至少海思的是这样的, * 不过我们不留这些配置了,只配置关键帧的间隔。 * 在海思平台上,这个值实际上是在每种RC类型的配置里面;而GOP则是配置了其它一些 * 属性。 */ // 关键帧间隔。对MJPEG编码无意义。 int gop; /* * 码率控制属性 * rate control * 在海思的平台上,这一块相关的控制分在两个部分,分别在不同的接口中使用,输出 * 帧率虽然每个都支持,但出现在每个类型的配置中;源帧率也可配置,但这个配置会 * 导致一些奇怪的问题,所以我们自动内部使用发送给VENC的帧率。 * 这两部分,有一部分还不是所有的类型有,用起来比较麻烦,我们统一到一个接口。 */ VENC_RC_t rc_type; // 编码输出的帧率。 int framerate; // 这个是指向一个S_venc_rc_fixQp或者S_venc_rc_vbr的结构,根据前面的 // rc_type来确定。如果这个指针为NULL,表示使用库里面的缺省配置。 void *rc_param; } S_venc_config; /* * 编码帧 */ typedef struct mpp_venc_frame { uint8_t *data; uint32_t len; int is_key_frame; void *priv; } S_mpp_venc_frame; /////////////////////////////////////////////////////////////////////////////// // 编码相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // 解码相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// #define NR__VDEC_CHN 4 /* * 两种发送模式。配置为FRAME模式,每次发送要求是一个完整的编码帧,而STREAM * 模式则直接一直发送即可,应用中可以不去解析帧结构。 * * 注意: FRAME模式输出的解码图像帧的PTS保留了发送时的PTS,而STREAM模式固定 * 是0,这个是海思的MPP导致的。不过目前我们解码基本上只用于验证算法, * 所以PTS影响不大。 */ #define VDEC_SEND__FRAME 0 #define VDEC_SEND__STREAM 1 typedef struct vdec_config { // H.264 or H.265 or MJPEG VENC_CODEC_t codec; // 编码图像的大小。 int raw_max_width; int raw_max_height; // 输出图像大小。 int width; int height; int send_mode; } S_vdec_config; typedef struct mpp_vdec_frame { uint8_t *data; uint32_t len; // 如果输出一个非0值,发送接口就使用这里输入的值;如果输出0,则发送接口 // 内部自动生成一个PTS(对于STREAM模式PTS无效)。 uint64_t pts; } S_mpp_vdec_frame; /////////////////////////////////////////////////////////////////////////////// // 解码相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // JPEG相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// /* * JPEG图像 */ typedef struct jpeg_img { uint8_t *data; int size; } S_jpeg_img; /////////////////////////////////////////////////////////////////////////////// // JPEG相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // 收流相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// #define NR__VIDEO_CHN 1 #define PIX_FMT__NV21 0 #define PIX_FMT__GRAY 1 /* * 海思平台上图像均采用NV12(YVU420SP),所以这里不设置图像格式参数。 */ typedef struct mpp_img { // 我们同时传物理地址,这样如果能直接使用物理地址就可以少一此处理, // 而不能使用物理地址就忽略它。 uint64_t phy_addr; // 数据格式有可能是NV21或GRAY,具体由后面的pix_fmt来确定。对于灰度 // 也确保了指向的空间大小是NV21,只是灰度数据后面是随机数据。 // 这个实际上比较理想的是直接在收流部分把它封装掉,但因为这个项目 // 追求极致性能,而有些算法能直接用灰度处理,所以这里只保留空间和 // 给出图像格式,具体是否需要用memset()来处理后面VU部分由实际应用sample_vio_sys_init // 根据算法来确定。 union { uint8_t *nv21; uint8_t *gray; }; int width; int height; // 图像一行的实际长度,如果不等于width说明有padding。这个是图像处理中 // 常用的手段。 int linesize; int pix_fmt; // 这个或者增加接口通过priv来获取也可以?但使用起来不太方便。严格来说 // 在图像信息中增加这个时间信息有些怪异,不过目前我们先这样用起来。 uint64_t pts; void *priv; } S_mpp_img; typedef struct video_cfg { // 这两个配置sensor的属性,配置为-1表示使用缺省值;如果有多种属性可以 // 选择的话就配置为最相近的。 // 具体内部的旋转等,我们具体的产品上做不同实现,目前在这个库中封装死。 int sns_w; int sns_h; // 输出图像大小。 int img_w; int img_h; } S_video_cfg; /////////////////////////////////////////////////////////////////////////////// // 收流相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // 缩放相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// #define NR__VSCALE_CHN 4 typedef struct vscale_cfg { int src_max_width; int src_max_height; int width; int height; } S_vscale_cfg; /////////////////////////////////////////////////////////////////////////////// // 缩放相关的一些数据结构 // /////////////////////////////////////////////////////////////////////////////// /* * 初始化平台的MPP功能,分配内存。 * 或者增加一个VB配置的参数,可以由外部来做一些控制?不过这部分目前还没有完成 * 摸透,具体什么样的buffer参数还没太想明白。也可以考虑用做一个缺省初始化, * 后面同时又实现另一个带参数的初始化? * * 参数说明: * 无。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__init(void); /* * 结束收流,释放相关的资源。 * * 参数说明: * 无。()获取到的视频图像, * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__finalize(void); /* * 配置调试级别。0只打印错误信息,值越大测试信息越多。初始化之后 * 缺省是0。 * * 参数说明: * level - 调试级别。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__set_debug(int level); /* * 打开一路视频。 * * 参数说明: * vid - 视频编号。取值范围[0, NR__VIDEO_CHN]。 * vcfg - 视频配置。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__video_start(int vid, S_video_cfg *vcfg); /* * 关闭一路视频。 * * 参数说明: * vid - 视频编号。取值范围[0, NR__VIDEO_CHN]。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__video_stop(int vid); /* * 对于创建的不用回调的一种视频,主动获取一帧视频。这个获取的帧必须调用rw_mpp_free() * 释放之后才会再次调用获取下一帧,否则获取帧会直接返回失败。 * * 参数说明: * vid - 视频编号。取值范围[0, NR__VIDEO_CHN]。 * ori_img - [输出]原始图像。这个是直接旋转好的图像。 * tmout_ms - 最大等待时间,单位是ms。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__video_recv(int vid, S_mpp_img *img, int tmout_ms); /* * 释放rw_mpp_recv获取的帧,参数使用rw_mpp_recv()的输出。 * * 参数说明: * vid - 视频编号。取值范围[0, NR__VIDEO_CHN]。 * img - 视频图像。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__video_free(int vid, S_mpp_img *img); /* * 打开一路视频图像缩放。注意目前只能缩小,不能放大。 * * 参数说明: * sid - 缩放通道编号,取值范围[0, NR__SCALER_CHN)。 * cfg - 缩放通道配置。 * * 返回值: * 0表示成功,小于0表示失败。 */ int rw_mpp__vscale_start(int sid, S_vscale_cfg *cfg); /* * 打开一路视频图像缩放。 * * 参数说明: * sid - 缩放通道编号,取值范围[0, NR__SCALER_CHN)。 * * 返回值: * 0表示成功,小于0表示失败。 */ int rw_mpp__vscale_stop(int sid); /* * 执行图像缩放,获取缩放后的图像。 * * 参数说明: * sid - 缩放通道编号,取值范围[0, NR__SCALER_CHN)。 * src_img - 原始图像。 * scaled_img - 缩放后的图像。会分配底层资源,需要用户及时释放。 * * 返回值: * 0表示成功,小于0表示失败。 */ int rw_mpp__vscale_exec(int sid, S_mpp_img *src_img, S_mpp_img *scaled_img); /* * 执行图像缩放,获取缩放后的图像。 * * 参数说明: * sid - 缩放通道编号,取值范围[0, NR__SCALER_CHN)。 * scaled_img - 缩放后的图像。 * * * 返回值: * 0表示成功,小于0表示失败。 */ int rw_mpp__vscale_free(int sid, S_mpp_img *scaled_img); /* * 打开一路视频编码。 * * 参数说明: * chn - 编码通道,取值范围[0, NR__VENC_CHN)。 * cfg - 编码配置。 * vid - 是否绑定video,传-1的话需要每次调用rw_mpp_vend_send() * 发送一帧编码一帧;而传入视频通道则自动绑定获取数据, * 用户直接接收编码帧。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__venc_start(int chn, S_venc_config *cfg, int vid); /* * 关闭一路视频编码。 * * 参数说明: * chn - 编码通道,取值范围[0, NR__VENC_CHN)。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__venc_stop(int chn); /* * 发送一帧数据做编码。如果编码通道绑定了vid发送会失败。这个没有封装为直接获取 * 编码后的数据,这样更灵活一些,对于绑定了vid的视频编码,直接一直调用 * rw_mpp_venc_recv()收帧即可。 * * 参数说明: * chn - 编码通道,取值范围[0, 4)。 * img - rw_mpp__video_recv()获取到的视频图像,只能修改图像内容, * 不能修改其它值。 */ int rw_mpp__venc_send(int chn, S_mpp_img *img); /* * 接收一帧编码后的数据结果。编码没有设计是直接给原始帧编码出一帧来,分开有时候 * 更灵活一些。 * 参数说明: * chn - 编码通道,取值范围[0, 4)。 * frame - 编码后的视频帧。对于H.264/H.265是NAL格式;对于MJPEG是 * JPEG图像数据。 */ int rw_mpp__venc_recv(int chn, S_mpp_venc_frame *frame, int tmout_ms); /* * 释放rw_mpp__venc_recv()获取到的编码帧。 */ int rw_mpp__venc_free(int chn, S_mpp_venc_frame *frame); /* * 初始化编码器的整体配置。编码器不能使用公共VB,所以需要单独初始化一下。 */ int rw_mpp__vdec_init(void); /* * 反初始化编码器的整体配置。 */ int rw_mpp__vdec_finalize(void); /* * 打开一路视频解码。 * * 参数说明: * chn - 解码通道,取值范围[0, NR__VDEC_CHN)。 * cfg - 编码配置。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__vdec_start(int chn, S_vdec_config *cfg); /* * 关闭一路视频解码。 * * 参数说明: * chn - 解码通道,取值范围[0, NR__VDEC_CHN)。 * * 返回值: * 成功返回0,失败返回错误码。 * */ int rw_mpp__vdec_stop(int chn); /* * 发送一帧数据做解码。 * * 参数说明: * chn - 解码通道,取值范围[0, NR__VDEC_CHN)。 * frame - 编码后的图像帧。 */ int rw_mpp__vdec_send(int chn, S_mpp_vdec_frame *frame); /* * 发送结束。因为解码一般是用文件,有可能多个文件顺序解码,或者同一个文件循环 * 解码。为了避免前后数据混到一起用,所以发送完一个文件之后调用这个接口发送结 * 束通知解码器。 */ int rw_mpp__vdec_send_end(int chn); /* * 接收一帧解码后的数据图像。 * 参数说明: * chn - 解码通道,取值范围[0, NR__VDEC_CHN)。 * img - 编码后的视频图像。 */ int rw_mpp__vdec_recv(int chn, S_mpp_img *img, int tmout_ms); /* * 释放rw_mpp__vdec_recv()获取到的解码。 */ int rw_mpp__vdec_free(int chn, S_mpp_img *img); /* * 初始化JPEG编码。 * * 参数说明: * max_width - 图像最大宽度。 * max_height - 图像最大高度。 * * 返回值: * 0表示成功,小于0表示失败。 */ int rw_mpp__jpeg_init(int max_width, int max_height); /* * 关闭JPEG编码。 * * 参数说明: * 无。 * * 返回值: * 0表示成功,小于0表示失败。 */ int rw_mpp__jpeg_finalize(void); /* * 图像编码。 * * 参数说明: * img - 原始图像,一般是Gray或NV21。这里可以是前面vscale或者video的 * 图像,也可以是用户自己构造的buffer。用户自己构造的buffer这 * 一结构中priv传NULL;物理地址如果是特殊申请的连续的空间并且 * 获取到了就填写,如果没有就直接填0。 * jpeg - JPEG图像。成功后输入JPEG图像的信息,使用完之后需要释放。 * * 返回值: * 0表示成功,小于0表示出错。 */ int rw_mpp__jpeg_enc(S_mpp_img *img, int quality, S_jpeg_img *jpeg); /* * 释放图像编码。 * * 参数说明: * jpeg - 要释放的JPEG图像。 * * 返回值: * 0表示成功,小于0表示出错。 */ int rw_mpp__jpeg_free(S_jpeg_img *jpeg); #ifdef __cplusplus } #endif #endif /* __RW_MPP_API_H__ */