Peergine 扩展设备输入输出C接口说明 v1.6
1. 概述
Peergine中间件在常用的操作系统平台上,都支持了视频采集和压缩功能。视频采集通常调用操作系统的标准API,压缩使用软件编码。
但在一些专用的设备上,视频采集API专有,不标准。而且,设备上可能支持硬件压缩,编解码器的API也是专有。这使得Peergine不能应用在更多专用的设备上,因而,Peergine中间件开放一套视频I/O接口,让应用程序可以在中间件外部采集视频并且进行压缩编码,然后再输入到Peergine中间件里面来。这样一来,Peergine中间件的系统环境适应性就有了很大的增强。本文所述的扩展输入输出接口在系统中的位置如下图所示:

扩展输入输出接口分为5套接口,分别是:
1)视频输入接口,在头文件pgLibDevVideoIn.h中声明。
2)视频输出接口,在头文件pgLibDevVideoOut.h中声明。
3)音频输入接口,在头文件pgLibDevAudioIn.h中声明。
4)音频输出接口,在头文件pgLibDevAudioOut.h中声明。
5)音频转换接口,在头文件pgLibDevAudioConvert.h中声明。
调用API流程的样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// 定义LOG输出回调函数 void LogOutput(unsigned int uLevel, const char* lpszOut) { printf(lpszOut); } //注册视频采集 pgDevVideoInSetCallback(&s_stCallback_VideoIn); //音频采集,音频播放 pgDevAudioInSetCallback(&s_stCallback_AudioIn); pgDevAudioOutSetCallback(&s_stACallback_AudioOut); // 调用P2P直播实例初始化函数 pgLiveInitialize(); // 开始事件接收。必须持续、及时的接收和处理事件。建议在一个单独的线程中循环接收事件。 pgLiveEvent(); // 调用其他业务功能的函数,根据实际需要调用具体的API。 pgLiveVideoStart、pgLiveVideoStop、pgLiveAudioStart、pgLiveAudioStop // 清理P2P直播实例。如果音频、视频已经打开,必须先关闭,然后再执行清理实例的操作。 pgLiveCleanup(); |
2. 视频输入API接口(pgLibDevVideoIn.h)
1)说明
从Peergine中间件的1.42.0版本开始,增加了内置的H.264和H.265输入组帧功能,应用程序可以在pfnVideoInOpen()回调函数里面,调用pgDevVideoInSetParam()函数设置
PG_DEV_VIDEO_IN_PARAM_ASSEM_FRAME参数项,启用或关闭内置输入组帧功能。
2)常量:
PG_DEV_VIDEO_IN_FMT_E:视频输入格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
typedef enum tagPG_DEV_VIDEO_IN_FMT_E { PG_DEV_VIDEO_IN_FMT_RGB24, // 视频帧编码格式为RGB24 PG_DEV_VIDEO_IN_FMT_YUV422SP, // 视频帧编码格式为YUV422SP PG_DEV_VIDEO_IN_FMT_YUV420SP, // 视频帧编码格式为YUV420SP PG_DEV_VIDEO_IN_FMT_YUYV, // 视频帧编码格式为YUYV PG_DEV_VIDEO_IN_FMT_YV12, // 视频帧编码格式为YV12 PG_DEV_VIDEO_IN_FMT_MJPEG, // 视频帧编码格式为JPEG A PG_DEV_VIDEO_IN_FMT_VP8, // 视频帧编码格式为VP8 PG_DEV_VIDEO_IN_FMT_H264, // 视频帧编码格式为H.264 PG_DEV_VIDEO_IN_FMT_H265, // 视频帧编码格式为H.265 PG_DEV_VIDEO_IN_FMT_I420, // 视频帧像素格式为I420 PG_DEV_VIDEO_IN_FMT_BUTT } PG_DEV_VIDEO_IN_FMT_E; |
PG_DEV_VIDEO_IN_FLAG_E:视频输入标志位
1 2 3 |
typedef enum tagPG_DEV_VIDEO_IN_FLAG_E { PG_DEV_VIDEO_IN_FLAG_KEY_FRAME = 0x0001, // 当前输入的视频帧为关键帧 } PG_DEV_VIDEO_IN_FLAG_E; |
PG_DEV_VIDEO_IN_CTRL_E:视频输入控制命令
typedef enum tagPG_DEV_VIDEO_IN_CTRL_E {
PG_DEV_VIDEO_IN_CTRL_PULL_KEY_FRAME, // 立即输入一个关键帧
PG_DEV_VIDEO_IN_CTRL_BUTT
} PG_DEV_VIDEO_IN_CTRL_E;
PG_DEV_VIDEO_IN_PARAM_E:视频输入参数的条目
1 2 3 4 5 6 7 8 |
typedef enum tagPG_DEV_VIDEO_IN_PARAM_E { PG_DEV_VIDEO_IN_PARAM_NO, // 摄像头编号参数 PG_DEV_VIDEO_IN_PARAM_FACING, // 摄像头方向(前置/后置) PG_DEV_VIDEO_IN_PARAM_ROTATE, // 摄像头采集的视频角度 PG_DEV_VIDEO_IN_PARAM_IMG_ROTATE, // 摄像头采集得到的视频图像数据的存储角度 PG_DEV_VIDEO_IN_PARAM_ASSEM_FRAME, // 启用/禁用中间件内部的视频组帧功能 PG_DEV_VIDEO_IN_PARAM_BUTT } PG_DEV_VIDEO_IN_PARAM_E; |
参数条目的说明:
PG_DEV_VIDEO_IN_PARAM_NO:摄像头编号参数
调用pgDevVideoInSetParam()设置最后选用的摄像头的编号。从uValue参数传入摄像头的编号,uValue的有效范围为0~65534(摄像头编号的具体数值依赖各个操作系统上的摄像头接口定义)。
PG_DEV_VIDEO_IN_PARAM_FACING:摄像头方向(前置/后置)
调用pgDevVideoInSetParam()设置摄像头方向(前置还是后置)。从uValue参数传入方向值:1为前置,0为后置。
PG_DEV_VIDEO_IN_PARAM_ROTATE:摄像头采集的视频角度
调用pgDevVideoInGetParam()获取摄像头的采集视频角度,然后按照这个角度打开摄像头。pgDevVideoInGetParam()的返回值为摄像头的采集角度,有效值为0、90、180、270,默认值为0。
PG_DEV_VIDEO_IN_PARAM_IMG_ROTATE:摄像头采集得到的视频图像数据的存储角度
调用pgDevVideoInSetParam()设置摄像头采集端的数据的旋转角度。从uValue参数传入角度值,有效值为有效值为0、90、180、270,默认值为0。
PG_DEV_VIDEO_IN_PARAM_ASSEM_FRAME:启用/禁用中间件内部的视频组帧功能
调用pgDevVideoInSetParam()设置是否启用Peergine中间件内置的H264、H265组帧功能。uValue的值,1为启用内置组帧、0为禁用(默认值)。
3)结构体:
PG_DEV_VIDEO_IN_CALLBACK_S:视频输入回调接口结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
typedef struct tagPG_DEV_VIDEO_IN_CALLBACK_S { // 打开视频采集设备,开始视频采集 int (*pfnVideoInOpen)(unsigned int uDevNO, unsigned int uPixBytes, unsigned int uWidth, unsigned int uHeight, unsigned int uBitRate, unsigned int uFrmRate, unsigned int uKeyFrmRate); // 停止视频采集,关闭视频采集设备 void (*pfnVideoInClose)(int iDevID); // 发送控制命令给视频采集设备 void (*pfnVideoInCtrl)(int iDevID, unsigned int uCtrl, unsigned int uParam); } PG_DEV_VIDEO_IN_CALLBACK_S; |
3)API函数:
pgDevVideoInSetCallback:设置视频输入回调接口
1 2 3 4 5 6 |
/** * 描述:设备回调接口 * 阻塞方式:非阻塞,立即返回。 * lpstCallback:[IN] 回调接口结构指针 */ void pgDevVideoInSetCallback(const PG_DEV_VIDEO_IN_CALLBACK_S* lpstCallback); |
pgDevVideoInCaptureProc:视频帧数据输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/** * 描述:输入视频帧数据到 Peergine中间件中 * 注意事项: * 1)每次必须输入一个完整的视频帧。不能分片,也不能一次输入多帧。 * 2)如果输入的视频格式是H264或者H265,则必须周期性地输入I帧。 * 3)如果输入的视频格式是H264或者H265,则输入的每个I帧必须附带SPS头。 * 阻塞方式:阻塞,视频帧数据缓冲到 Peergine中间件队列后返回 * iDevID: [IN] 设备ID。回调函数'pfnVideoInOpen'的返回值 * lpData: [IN] 视频帧数据的缓冲区指针 * uDataSize: [IN] 视频帧数据的长度(字节) * uFormat: [IN] 视频帧的格式,见枚举 'PG_DEV_VIDEO_IN_FMT_E' * uFlag: [IN] 标志位,见枚举 'tagPG_DEV_VIDEO_IN_FLAG_E' */ void pgDevVideoInCaptureProc(int iDevID, const void* lpData, unsigned int uDataSize, unsigned int uFormat, unsigned int uFlag); |
pgDevVideoInSetParam:设置视频输入参数
1 2 3 4 5 6 7 8 9 10 |
/** * 设置与 'uDevNO' 相关联的输入参数到SDK * 注意: 本函数只能在回调函数'pfnVideoInOpen'的内部调用 * uDevNO: [in] 回调函数'pfnVideoInOpen'的 'uDevNO' 参数 * uItem: [in] 输入参数的条目id,见枚举 'PG_DEV_VIDEO_IN_PARAM_E' * uValue: [in] 设置的参数的值 * 返回值: <0: 失败,>=0: 成功 */ int pgDevVideoInSetParam(unsigned int uDevNO, unsigned int uItem, unsigned int uValue); |
pgDevVideoInGetParam:获取视频输入参数
1 2 3 4 5 6 7 8 9 |
/** * 从SDK获取与 'uDevNO' 相关联的输入参数 * 注意: 本函数只能在回调函数'pfnVideoInOpen'的内部调用 * uDevNO: [in] 回调函数'pfnVideoInOpen'的 'uDevNO' 参数 * uItem: [in] 输入参数的条目id,见枚举 'PG_DEV_VIDEO_IN_PARAM_E' * 返回值: <0: 失败,>=0: 获取的参数值 */ int pgDevVideoInGetParam(unsigned int uDevNO, unsigned int uItem); |
5)回调函数:
pfnVideoInOpen:打开视频采集设备进行采集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/** * 描述:打开视频采集设备进行采集。 * 注意:采集的视频图像的分辨率必须与传入的uWidth和uHeight参数一致。 * uDevNO: [IN] 视频采集设备的编号,Android系统为CameraInfo.facing的值(前置/后置)。 * uPixBytes: [IN] 像素的字节数,目前只支持3字节。 * uWidth: [IN] 视频的宽度(像素) * uHeight: [IN] 视频的高度(像素) * uBitRate: [IN] 视频的码率(可选) * uFrmRate: [IN] 视频的帧率(可选) * uKeyFrmRate:[IN] 关键帧率,每隔多少视频帧有1个关键帧 * 返回值:小于0失败,大于0返回设备ID。 */ int (*pfnVideoInOpen)(unsigned int uDevNO, unsigned int uPixBytes, unsigned int uWidth, unsigned int uHeight, unsigned int uBitRate, unsigned int uFrmRate, unsigned int uKeyFrmRate); |
pfnVideoInClose:关闭视频采集设备停止采集
1 2 3 4 5 |
/** * 描述:关闭视频采集设备停止采集。 * iDevID:[IN] 视频采集设备的ID,也就是’ pfnVideoInOpen’回调函数的返回值。 */ void (*pfnVideoInClose)(int iDevID); |
pfnVideoInCtrl:接收到字符串数据
1 2 3 4 5 6 7 |
/** * 描述:接收到字符串数据。 * iDevID: [IN] 视频采集设备的ID,也就是’pfnVideoInOpen’回调函数的返回值。 * uCtrl: [IN] 控制命令,参考枚举’PG_DEV_VIDEO_IN_CTRL_E’定义。 * uParam: [IN] 参数,未使用。 */ void (*pfnVideoInCtrl)(int iDevID, unsigned int uCtrl, unsigned int uParam); |
3. 视频输出API接口(pgLibDevVideoOut.h)
1)说明
从Peergine中间件的1.42.0版本开始,增加了获取视频流的帧率的功能,应用程序可以在pfnVideoOutOpen()回调函数里面,调用pgDevVideoOutGetParam()函数获取
PG_DEV_VIDEO_OUT_PARAM_FRAME_RATE参数项的值,就是当前视频流的帧率。
2)常量:
PG_DEV_VIDEO_OUT_FMT_E:视频输入格式
1 2 3 4 5 6 7 8 |
typedef enum tagPG_DEV_VIDEO_OUT_FMT_E { PG_DEV_VIDEO_OUT_FMT_RGB24, PG_DEV_VIDEO_OUT_FMT_MJPEG, PG_DEV_VIDEO_OUT_FMT_VP8, PG_DEV_VIDEO_OUT_FMT_H264, PG_DEV_VIDEO_OUT_FMT_H265, PG_DEV_VIDEO_OUT_FMT_BUTT } PG_DEV_VIDEO_OUT_FMT_E; |
PG_DEV_VIDEO_OUT_FLAG_E:视频输出标志位
1 2 3 |
typedef enum tagPG_DEV_VIDEO_OUT_FLAG_E { PG_DEV_VIDEO_OUT_FLAG_KEY_FRAME = 0x0001, // 图像为关键帧 } PG_DEV_VIDEO_OUT_FLAG_E; |
PG_DEV_VIDEO_OUT_EVENT_E:视频输出事件
1 2 3 |
typedef enum tagPG_DEV_VIDEO_OUT_EVENT_E { PG_DEV_VIDEO_OUT_EVENT_PAINT, // 强制重绘图像 } PG_DEV_VIDEO_OUT_EVENT_E; |
PG_DEV_VIDEO_OUT_FILL_MODE_E:视频输出图像填充模式
1 2 3 4 5 6 |
typedef enum tagPG_DEV_VIDEO_OUT_FILL_MODE_E { PG_DEV_VIDEO_OUT_FILL_MODE_DST_IN_SRC, // 等长宽比伸缩,填满目标区域,裁剪图像超出的部分。 PG_DEV_VIDEO_OUT_FILL_MODE_SRC_IN_DST, // 等长宽比伸缩,保持图像整幅,黑色填充目标区域边框。 PG_DEV_VIDEO_OUT_FILL_MODE_SRC_FIT_DST, // 不等长宽比伸缩,图像刚好填充目标区域。 } PG_DEV_VIDEO_OUT_FILL_MODE_E; |
PG_DEV_VIDEO_OUT_ROTATE_E:视频输出图像旋转角度
1 2 3 4 5 6 |
typedef enum tagPG_DEV_VIDEO_OUT_ROTATE_E { PG_DEV_VIDEO_OUT_ROTATE_0, PG_DEV_VIDEO_OUT_ROTATE_90, // 顺时针旋转90度 PG_DEV_VIDEO_OUT_ROTATE_180, // 顺时针旋转180度 PG_DEV_VIDEO_OUT_ROTATE_270, // 顺时针旋转270度 } PG_DEV_VIDEO_OUT_ROTATE_E; |
PG_DEV_VIDEO_OUT_PARAM_E:视频输出参数的条目
1 2 3 4 5 6 |
typedef enum tagPG_DEV_VIDEO_OUT_PARAM_E { PG_DEV_VIDEO_OUT_PARAM_PIXEL_FORMAT, // 输出的视频像素数据的格式: I402或RGB24 PG_DEV_VIDEO_OUT_PARAM_FRAME_RATE, // 视频输出的帧率 PG_DEV_VIDEO_OUT_PARAM_BUTT } PG_DEV_VIDEO_OUT_PARAM_E; |
参数条目的说明:
PG_DEV_VIDEO_OUT_PARAM_PIXEL_FORMAT:输出的视频像素数据的格式: I402或RGB24
调用pgDevVideoOutGetParam()获取当前Peergine中间件输出的视频图像的像素数据的格式,有效值为’PG_DEV_VIDEO_OUT_FMT_RGB24’和’PG_DEV_VIDEO_OUT_FMT_I420’。
调用pgDevVideoOutSetParam()修改Peergine中间件输出视频图像的像素数据的格式,从uValue参数传入像素的格式类型,有效值为’PG_DEV_VIDEO_OUT_FMT_RGB24’和’PG_DEV_VIDEO_OUT_FMT_I420’。
PG_DEV_VIDEO_OUT_PARAM_FRAME_RATE:视频输出的帧率
调用pgDevVideoOutGetParam()获取视频流的帧率。
3)结构体:
PG_DEV_VIDEO_OUT_CALLBACK_S:视频输出回调接口结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
typedef struct tagPG_DEV_VIDEO_OUT_CALLBACK_S { // 打开视频输出设备 int (*pfnVideoOutOpen)(unsigned int uDevNO); // 关闭视频输出设备 void (*pfnVideoOutClose)(int iDevID); // 播放显示视频帧图像 void (*pfnVideoOutImage)(int iDevID, const void* lpData, unsigned int uDataSize, unsigned int uFormat, unsigned int uFlag, int iPosX, int iPosY, unsigned int uWidth, unsigned int uHeight, unsigned int uFillMode, unsigned int uRotate); // 清除视频图像显示窗口 void (*pfnVideoOutClean)(int iDevID); } PG_DEV_VIDEO_OUT_CALLBACK_S; |
3)API函数:
pgDevVideoOutSetCallback:设置视频输出回调接口
1 2 3 4 5 6 |
/** * 描述:设备回调接口 * 阻塞方式:非阻塞,立即返回。 * lpstCallback:[IN] 回调接口结构指针 */ void pgDevVideoOutSetCallback(const PG_DEV_VIDEO_OUT_CALLBACK_S* lpstCallback); |
pgDevVideoOutEventProc:视频输出事件处理
1 2 3 4 5 6 7 8 |
/** * 描述:发送视频输出事件到 Peergine中间件中 * 阻塞方式:阻塞,视频帧数据缓冲到 Peergine中间件队列后返回 * iDevID: [IN] 设备ID。回调函数'pfnVideoOutOpen'的返回值 * uEvent: [IN] 视频帧的格式,见枚举 'PG_DEV_VIDEO_OUT_EVENT_E' * lpParam: [IN] 事件的参数 */ void pgDevVideoOutEventProc(int iDevID, unsigned int uEvent, const void* lpParam); |
pgDevVideoOutSetPixFormat:设置视频输出的像素数据格式
1 2 3 4 5 6 7 8 9 10 11 |
/** * 描述:设置视频输出的像素数据格式。 * 此函数必须在回调函数pfnVideoOutOpen()的函数体内调用。 * 阻塞方式:非阻塞,立即返回 * uDevNO: [IN] 视频输出设备的编号。也就是回调函数pfnVideoOutOpen()的uDevNO输入参数 * uFormat: [IN] 视频帧的格式。有效值为: * ’PG_DEV_VIDEO_OUT_FMT_RGB24’或’PG_DEV_VIDEO_OUT_FMT_I420’。 * 返回值:0为失败,非0为成功。 */ unsigned int pgDevVideoOutSetPixFormat(unsigned int uDevNO, unsigned int uFormat) |
pgDevVideoOutSetParam:设置视频输出的参数
1 2 3 4 5 6 7 8 9 10 11 |
/** * 描述:设置视频输出的参数。 * 此函数必须在回调函数pfnVideoOutOpen()的函数体内调用。 * 阻塞方式:非阻塞,立即返回 * uDevNO: [IN] 视频输出设备的编号。也就是回调函数pfnVideoOutOpen()的uDevNO输入参数 * uItem: [IN] 参数项条目。有效值参考枚举‘PG_DEV_VIDEO_OUT_PARAM_E’ * uValue: [IN] 参数项的值。有效值为参考枚举‘PG_DEV_VIDEO_OUT_PARAM_E’的参数说明 * 返回值:小于0为失败,等于0为成功。 */ int pgDevVideoOutSetParam(unsigned int uDevNO, unsigned int uItem, unsigned int uValue) |
pgDevVideoOutGetParam:获取视频输出的参数
1 2 3 4 5 6 7 8 9 10 |
/** * 描述:获取视频输出的参数。 * 此函数必须在回调函数pfnVideoOutOpen()的函数体内调用。 * 阻塞方式:非阻塞,立即返回 * uDevNO: [IN] 视频输出设备的编号。也就是回调函数pfnVideoOutOpen()的uDevNO输入参数 * uItem: [IN] 参数项条目。有效值参考枚举‘PG_DEV_VIDEO_OUT_PARAM_E’ * 返回值:小于0为失败,大于等于0位获取到参数值。 */ int pgDevVideoOutGetParam(unsigned int uDevNO, unsigned int uItem) |
5)回调函数:
pfnVideoOutOpen:打开视频输出设备
1 2 3 4 5 6 |
/** * 描述:打开视频输出设备。 * uDevNO: [IN] 视频输出设备的编号。 * 返回值:小于0失败,大于0返回设备ID。 */ int (*pfnVideoOutOpen)(unsigned int uDevNO); |
pfnVideoOutClose:关闭视频输出设备
1 2 3 4 5 |
/** * 描述:关闭视频输出设备。 * iDevID:[IN] 视频输出设备的ID,也就是’pfnVideoOutOpen’回调函数的返回值。 */ void (*pfnVideoOutClose)(int iDevID); |
pfnVideoOutImage:播放显示视频帧图像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/** * 描述:播放显示视频帧图像。 * iDevID: [IN] 视频输出设备的ID,也就是’pfnVideoOutOpen’回调函数的返回值。 * lpData: [IN] 视频数据指针。 * uDataSize: [IN] 视频数据长度。 * uFormat: [IN] 图像格式,参考枚举’PG_DEV_VIDEO_OUT_FMT_E’定义。 * uFlag: [IN] 标志位,参考枚举’PG_DEV_VIDEO_OUT_FLAG_E’定义。 * iPosX: [IN] 显示图像的左上角横坐标。 * iPosY: [IN] 显示图像的左上角纵坐标。 * uWidth: [IN] 图像宽度。 * uHeight: [IN] 图像高度。 * uFillMode: [IN] 图像的填充模式,参考枚举’PG_DEV_VIDEO_OUT_FILL_MODE_E’定义。 * uRotate: [IN] 图像的旋转角度,参考枚举’PG_DEV_VIDEO_OUT_ROTATE_E’定义。 */ void (*pfnVideoOutImage)(int iDevID, const void* lpData, unsigned int uDataSize, unsigned int uFormat, unsigned int uFlag, int iPosX, int iPosY, unsigned int uWidth, unsigned int uHeight, unsigned int uFillMode, unsigned int uRotate); |
pfnVideoOutClean:清除视频播放窗口
1 2 3 4 5 |
/** * 描述:清除视频播放窗口。 * iDevID: [IN] 视频输出设备的ID,也就是’pfnVideoOutOpen’回调函数的返回值。 */ void (*pfnVideoOutClean)(int iDevID); |
4. 音频输入API接口(pgLibDevAudioIn.h)
1)说明
从Peergine中间件的1.42.0版本开始,增加了内置的音频输入数据转换的功能,应用程序可以在pfnAudioInOpen()回调函数里面,调用pgDevAudioInSetParam()函数设置输入的音频流数据的参数的值,就可以启用Peergine中间件内置的音频输入数据转换的功能。
2)常量:
PG_DEV_ AUDIO _IN_FMT_E:音频输入格式
1 2 3 4 5 6 |
typedef enum tagPG_DEV_AUDIO_IN_FMT_E { PG_DEV_AUDIO_IN_FMT_PCM16, // 音频编码格式为PCM16。默认尾端,采样率11025,帧率25,每帧采样441,每帧大小882.其他格式 PG_DEV_AUDIO_IN_FMT_G711A, // 音频编码格式为G711A。 PG_DEV_AUDIO_IN_FMT_AAC, // 音频编码格式为AAC。 PG_DEV_AUDIO_IN_FMT_BUTT } PG_DEV_AUDIO_IN_FMT_E; |
其他规格说明
一般默认使用PCM16格式进行传输,PCM16也是只支持特定规格的音频数据,具体规格是
格式 | PCM16 |
尾端 | 默认 |
采样率 | 11025 |
帧率 | 25 |
每帧采样 | 441 |
每帧数据大小 | 882 |
3)结构体:
PG_DEV_AUDIO_IN_CALLBACK_S:音频输入回调接口结构
1 2 3 4 5 6 7 8 9 |
typedef struct tagPG_DEV_AUDIO_IN_CALLBACK_S { // 打开音频采集设备,开始音频采集 int (*pfnAudioInOpen)(unsigned int uDevNO, unsigned int uSampleBits, unsigned int uSampleRate, unsigned int uChannels, unsigned int uPackBytes); // 停止音频采集,关闭音频采集设备 void (*pfnAudioInClose)(int iDevID); } PG_DEV_AUDIO_IN_CALLBACK_S; |
4)API函数:
pgDevAudioInSetCallback:设置音频输入回调接口
1 2 3 4 5 6 |
/** * 描述:设备回调接口 * 阻塞方式:非阻塞,立即返回。 * lpstCallback:[IN] 回调接口结构指针 */ void pgDevAudioInSetCallback(const PG_DEV_AUDIO_IN_CALLBACK_S* lpstCallback); |
pgDevAudioInRecordProc把采集到的音频数据输入到中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/** * 描述:把采集到的音频数据输入到中间件。 * 注意:输入的音频数据的采样率必须为11025,一次输入的音频数据长度必须为441个采样点。 * 如果采集到的音频数据的格式和帧长不符合以上2点,则需要使用“音频转换API接口”进行转换。 * 阻塞方式:阻塞,音频数据缓冲到 Peergine中间件队列后返回 * iDevID: [IN] 设备ID。回调函数'pfnVideoInOpen'的返回值。 * lpData: [IN] 音频数据的缓冲区指针。 * uDataSize: [IN] 音频数据的长度(字节),(注意:一次输入的音频数据长度必须为441个采样点) * uFormat: [IN] 音频的格式,见枚举 ' PG_DEV_AUDIO_IN_FMT_E ' * uDelayMs: [IN] 音频从 采集、传输 到 播放 的延时,给0可以自动适配。给合适的值可以优化用户体验。 */ void pgDevAudioInRecordProc(int iDevID, const void* lpData, unsigned int uDataSize, unsigned int uFormat, unsigned int uDelayMs); |
5)回调函数:
pfnAudioInOpen:打开音频采集设备进行采集
1 2 3 4 5 6 7 8 9 10 11 |
/** * 描述:打开音频采集设备进行采集。 * uDevNO: [IN] 音频采集的设备编号,当有多个音频采集设备时区分不同的设备。 * uSampleBits: [IN] 音频的采样位数,默认16bit。 * uSampleRate: [IN] 音频的采样率,默认11025。 * uChannels: [IN] 声道数,默认单声道。 * uPackBytes: [IN] 每个数据包的字节数(只支持441个采样点)。 * 返回值:小于0失败,大于0返回设备ID。 */ int (*pfnAudioInOpen)(unsigned int uDevNO, unsigned int uSampleBits, unsigned int uSampleRate, unsigned int uChannels, unsigned int uPackBytes); |
pfnAudioInClose:关闭音频采集设备停止采集
1 2 3 4 5 |
/** * 描述:关闭音频采集设备,停止采集。 * iDevID:[IN] 音频采集设备的ID,也就是’ pfnAudioInOpen’回调函数的返回值。 */ void (*pfnAudioInClose)(int iDevID); |
5. 音频输出API接口(pgLibDevAudioOut.h)
1)说明
从Peergine中间件的1.42.0版本开始,增加了内置的音频输出数据转换的功能,应用程序可以在pfnAudioOutOpen()回调函数里面,调用pgDevAudioOutSetParam()函数设置输出的音频流数据的参数的值,就可以启用Peergine中间件内置的音频输出数据转换的功能。
2)常量:
PG_DEV_AUDIO_OUT_FMT_E:音频输出格式
1 2 3 4 5 6 |
typedef enum tagPG_DEV_AUDIO_OUT_FMT_E { PG_DEV_AUDIO_OUT_FMT_PCM16, // 输出音频的编码格式是PCM16。 PG_DEV_AUDIO_OUT_FMT_G711A, // 输出音频的编码格式是G711A。 PG_DEV_AUDIO_OUT_FMT_AAC, // 输出音频的编码格式是AAC。 PG_DEV_AUDIO_OUT_FMT_BUTT } PG_DEV_AUDIO_OUT_FMT_E; |
3)结构体:
PG_DEV_AUDIO_OUT_CALLBACK_S:音频输出回调接口结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
typedef struct tagPG_DEV_AUDIO_OUT_CALLBACK_S { // 打开音频播放设备 int (*pfnAudioOutOpen)(unsigned int uDevNO, unsigned int uSampleBits, unsigned int uSampleRate, unsigned int uChannels, unsigned int uPackBytes); // 关闭音频播放设备 void (*pfnAudioOutClose)(int iDevID); // 播放音频数据 int (*pfnAudioOutPlay)(int iDevID, const void* lpData, unsigned int uDataSize, unsigned int uFormat); } PG_DEV_AUDIO_OUT_CALLBACK_S; |
4)API函数:
pgDevAudioOutSetCallback:设置音频输出回调接口
1 2 3 4 5 6 |
/** * 描述:设备回调接口。 * 阻塞方式:非阻塞,立即返回。 * lpstCallback: [IN] 回调接口结构指针。 */ void pgDevAudioOutSetCallback (const PG_DEV_AUDIO_IN_CALLBACK_S* lpstCallback); |
pgDevAudioOutPlayedProc:反馈实际已经播放的音频数据长度
1 2 3 4 5 6 7 8 |
/** * 描述:反馈实际已经在声卡上播放的音频数据长度给中间件。 * 阻塞方式:阻塞,取出的音频数据播放完成返回。 * iDevID: [IN] 设备ID。回调函数’ pfnAudioOutOpen’的返回值。 * uPlayedSize: [IN] 已经在声卡上实际累计播放的音频数据长度(BYTE)。 * uDelayMs: [IN] 音频播放延时。给0可以自动适配,给合适的值(160ms左右)可以优化用户体验。 */ void pgDevAudioOutPlayedProc(int iDevID, unsigned int uPlayedSize, unsigned int uDelayMs); |
pgDevAudioOutPlaySilent:开启SDK输出静音数据的机制
1 2 3 4 5 6 7 8 |
/** * 描述:开启SDK输出静音数据的机制。 * 阻塞方式:非阻塞,立即返回。 * uDevNO: [IN] 扬声器编号,与回调函数’pfnAudioOutOpen’的uDevNO参数相同。 * uEnable: [IN] 是否开启。1为开启,0关闭,默认为0。 * 返回值:0失败,非0成功 */ unsigned int pgDevAudioOutPlaySilent(unsigned int uDevNO, unsigned int uEnable); |
5)回调函数:
pfnAudioOutOpen:打开音频播放设备
1 2 3 4 5 6 7 8 9 10 11 |
/** * 描述:打开音频播放设备。 * uDevNO: [IN] 音频播放的设备编号,当有多个音频播放设备时区分不同的设备。 * uSampleBits: [IN] 音频的采样位数,默认16bit。 * uSampleRate: [IN] 音频的采样率,默认11025。 * uChannels: [IN] 声道数,默认单声道。 * uPackBytes: [IN] 每个数据包的字节数(只支持441个采样点)。 * 返回值:小于0失败,大于0返回设备ID。 */ int (*pfnAudioOutOpen)(unsigned int uDevNO, unsigned int uSampleBits, unsigned int uSampleRate, unsigned int uChannels, unsigned int uPackBytes); |
pfnAudioOutClose:关闭音频播放设备
1 2 3 4 5 |
/** * 描述:关闭音频播放设备。 * iDevID: [IN] 音频播放设备的ID,也就是’ pfnAudioOutOpen’回调函数的返回值。 */ void (*pfnAudioOutClose)(int iDevID); |
pfnAudioOutPlay:播放音频数据
1 2 3 4 5 6 7 8 9 10 11 |
/** * 描述:播放音频数据。 * 注意:输出的音频数据的采样率为11025,音频数据长度为441个采样点。 * 如果播放接口的音频数据的格式和帧长不符合以上2点,则需要使用“音频转换API接口”进行转换。 * iDevID: [IN] 音频播放设备的ID,也就是’ pfnAudioOutOpen’回调函数的返回值。 * lpData: [IN]要播放的音频数据。 * uDataSize: [IN]要播放的音频数据长度(字节数),(只支持441个采样点)。 * uFormat: [IN] 音频的格式, 详情请看枚举 'PG_DEV_AUDIO_OUT_FMT_E'. */ int (*pfnAudioOutPlay)(int iDevID, const void* lpData, unsigned int uDataSize, unsigned int uFormat); |
6. 音频转换API接口(pgLibDevAudioConvert.h)
1)说明:
在Peergine系统以及由Peergine经过裁剪和封装衍生出来的系列SDK中,音频通话的数据都是以统一的采样率和帧长度进行通信传输的。Peergine使用的统一音频采样率为11025,音频的帧长度为441个采样点。但是,当Peergine和SDK应用在各种设备上时,有些设备上的音频采集和播放就不一定支持11025的采样率和441个采样点的帧长度。所以, Peergine和SDK提供了一套音频转换的API来进行音频采样率、帧长度,以及格式的转换。以便在Peergine和SDK与设备之间进行音频采集和播放对接时,有更强的适应性。
音频转换以“转换队列”的方式实现,使用步骤为:
- (1)创建转换队列(传入转换参数)
- (2)把待转换的音频数据压入队列(每次压入一帧数据)
- (3)从队列弹出转换后的音频数据(每次弹出一帧数据)
- (4)重复(2)和(3)步,直到完成所有数据转换
- (5)销毁转换队列
以下“API函数”章节详细叙述的音频转换API的说明。
2)常量:
PG_DEV_AUDIO_CVT_FMT_E:音频转换格式
1 2 3 4 5 6 7 8 9 |
/** * 音频转换的格式枚举 */ typedef enum tagPG_DEV_AUDIO_CVT_FMT_E { PG_DEV_AUDIO_CVT_FMT_PCM16 = 0, // PCM16格式 PG_DEV_AUDIO_CVT_FMT_G711A = 1, // G711A(PCMA) 格式 PG_DEV_AUDIO_CVT_FMT_G711U = 2, // G711U(PCMU) 格式 PG_DEV_AUDIO_CVT_FMT_AAC = 3, // AAC 格式(只有包含软件AAC编码的SDK中支持) } PG_DEV_AUDIO_CVT_FMT_E; |
3)API函数:
pgDevAudioConvertAlloc:创建转换队列
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/** * 描述:创建转换队列 * 参数: * uDirect: [in] 转换方向:0为录音转换(设备到SDK),1为放音转换(SDK到设备) * uDstFormat: [in] 转换后的音频数据格式,见枚举‘PG_DEV_AUDIO_CVT_FMT_E’ * uDevSampleRate: [in] 设备端音频数据的采样率。 * 有效值:8000, 16000, 32000, 11025, 22050, 44100 * uDevSampleSize: [in] 设备端每帧音频数据的采样点数。 * 返回值: * 小于0: 失败, 大于0: 转换队列的ID */ int pgDevAudioConvertAlloc(unsigned int uDirect, unsigned int uDstFormat, unsigned int uDevSampleRate, unsigned int uDevSampleSize); |
pgDevAudioConvertFree:销毁转换队列
1 2 3 4 5 6 7 8 |
/** * 描述:销毁转换队列 * 参数: * iCvtID: [in] 转换队列的ID(pgDevAudioConvertAlloc()函数的返回值) * 返回值: * 无 */ void pgDevAudioConvertFree(int iCvtID); |
pgDevAudioConvertPush:把待转换的音频数据压入到队列中
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * 描述:把待转换的音频数据压入到队列中 * 参数: * iCvtID: [in] 转换队列的ID(pgDevAudioConvertAlloc()函数的返回值) * uSrcFormat: [in] 转换前的音频数据格式,见枚举‘PG_DEV_AUDIO_CVT_FMT_E’ * lpSrcData: [in] 转换前的数据缓冲区地址 * uSrcDataSize: [in] 转换前的数据长度 * 返回值: * 小于0: 失败, 大于等于0: 已经压入到队列的数据长度(通常等于uSrcDataSize) */ int pgDevAudioConvertPush(int iCvtID, unsigned int uSrcFormat, const void* lpSrcData, unsigned int uSrcDataSize); |
pgDevAudioConvertPop:把转换后的数据从队列弹出(只弹出数据缓冲区的地址)
1 2 3 4 5 6 7 8 9 10 |
/** * 描述:把转换后的数据从队列弹出(只输出数据缓冲区的地址) * 参数: * iCvtID: [in] 转换队列的ID(pgDevAudioConvertAlloc()函数的返回值) * ppDstData: [out] 转换后的音频数据缓冲区地址的指针(注意:pgDevAudioConvertFree()后不能再引用) * lpuDstDataSize: [in] 转换后的数据长度 * 返回值: * 小于0: 失败,等于0: 队列中没有转换后的数据,大于0:转换后的数据长度 */ int pgDevAudioConvertPop(int iCvtID, void **ppDstData, unsigned int* lpuDstDataSize); |
pgDevAudioConvertPopS:把转换后的数据从队列弹出(把数据从队列复制出来)
1 2 3 4 5 6 7 8 9 10 |
/** * 描述:把转换后的数据从队列弹出(把数据从队列复制出来) * 参数: * iCvtID: [in] 转换队列的ID(pgDevAudioConvertAlloc()函数的返回值) * lpDstData: [out] 接收转换后的音频数据缓冲区地址 * uDstDataSize: [in] 接收转换后的音频数据缓冲区的长度 * 返回值: * 小于0: 失败,等于0: 队列中没有转换后的数据,大于0:转换后的数据长度 */ int pgDevAudioConvertPopS(int iCvtID, void *lpDstData, unsigned int uDstDataSize); |
7. 代码样例:
1)音频/视频采集播放样例伪码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
// 假设这是视频采集处理回调函数,得到视频帧数据。 void OnPreviewFrame(void *lpFrmData, unsigned int uFrmSize) { // 调用硬件编码器,把视频帧压缩成H.264格式。 // H264 Codec . . . void* pCmpData = 压缩后的数据指针; unsigned int uCmpSize = 压缩后的数据长度; unsigned int uFlag = 0; if (是关键帧) { uFlag |= PG_DEV_VIDEO_IN_FLAG_KEY_FRAME; } // 把视频帧数据输入到Peergine中间件. pgDevVideoInCaptureProc(1234, pCmpData, uCmpSize, PG_DEV_VIDEO_IN_FMT_H264, uFlag); } // 实现视频采集回调接口。 static int VideoInOpen(unsigned int uDevNO, unsigned int uPixBytes, unsigned int uWidth, unsigned int uHeight, unsigned int uBitRate, unsigned int uFrmRate, unsigned int uKeyFrmRate) { // 打开视频设备,进行视频采集。 // . . . return 1234; // 采集设备的ID } static void VideoInClose(int iDevID) { // 关闭视频采集设备,停止采集。 // . . . } static void VideoInCtrl(int iDevID, unsigned int uCtrl, unsigned int uParam) { // 控制视频采集。 if (uCtrl == PG_DEV_VIDEO_IN_CTRL_PULL_KEY_FRAME) { // 强制编码器立即产生一个关键帧. // ... } } /**********************************************************************************/ //以下是音频输入扩展接口使用的示例伪代码 // 假设这是音频采集处理回调函数,得到音频数据。 void OnAudioCapture(void* lpData, unsigned int uDataSize) { // 其他音频数据处理。 // 例如:压缩编码…… // 将音频数据输入到Peergine中间件. pgDevAudioInCaptureProc(1234, lpData, uDataSize, PG_DEV_AUDIO_IN_FMT_PCM16, 0); } // 打开音频采集设备进行采集 static int AudioInOpen(unsigned int uDevNO, unsigned int uSampleBits, unsigned int uSampleRate, unsigned int uChannels, unsigned int uPackBytes) { // 打开音频采集设备,开始采集音频。 // …… return 1234; // 采集设备的ID } //停止音频采集处理回调线程,释放设备ID static void AudioInClose(int iDevID) { // 关闭音频采集设备,停止音频采集 } /**********************************************************************************/ //以下是音频输出扩展接口使用的示例伪代码 //假设这是音频播放完毕通知函数。 static unsigned int s_uPlayedSize = 0; void OnAudioPlayedProc(void* lpData,unsigned int uDataSize) { // 已经播放的数据长度累计。 s_uPlayedSize += uDataSize; // 调用pgDevAudioOutPlayedProc通知中间件已经播放的数据长度 pgDevAudioOutPlayedProc(1234, s_uPlayedSize, 0); } //启动一个从中间件获取音频数据的线程 static int AudioOutOpen(unsigned int uDevNO, unsigned int uSampleBits, unsigned int uSampleRate, unsigned int uChannels, unsigned int uPackBytes) { // 打开音频播放设备 // …… // 统计数据清零 s_uPlayedSize = 0; Return 1234;//播放设备ID } static void AudioOutClose(int iDevID) { // 关闭音频播放设备 } //音频播放函数 int AudioOutPlay(int iDevID, const void* lpData, unsigned int uDataSize, unsigned int uFormat) { //调用播放设备播放音频数据 // ……… return uDataSize; } // 音频输入回调函数指针结构 static PG_DEV_AUDIO_IN_CALLBACK_S s_stCallback_AudioIn = { AudioInOpen, AudioInClose }; // 音频输出回调函数指针结构 static PG_DEV_AUDIO_OUT_CALLBACK_S s_stACallback_AudioOut = { AudioOutOpen, AudioOutClose, AudioOutPlay }; // 视频输入回调函数指针结构 static PG_DEV_VIDEO_IN_CALLBACK_S s_stCallback_VideoIn = { VideoInOpen, VideoInClose, VideoInCtrl }; //注册音频和视频的所有回调结构体 void RegisterVideoAndAudio(void) { //注册视频输入的回调函数 pgDevVideoInSetCallback(&s_stCallback_VideoIn); //注册音频输入的回调函数 pgDevAudioInSetCallback(&s_stCallback_AudioIn); //注册音频输出的回调函数 pgDevAudioOutSetCallback(&s_stACallback_AudioOut); } int main() { …… //注册音频和视频的所有回调结构体 RegisterVideoAndAudio(); ……… //直播初始化 pgLiveInitialize(); ………… //某些条件满足,开始 pgLiveVideoStart(); pgLiveAudioStart(); ……… //某些条件满足,结束 pgLiveVideoStop(); pgLiveAudioStop(); ……… } |
2)音频录音转换样例伪码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// 假设设备端录音的格式是PCM16,采样率是8000,帧长是320个采样点。伪码如下: static int s_iCvtIDIn = -1; static int s_iDevID_AudioIn = -1; static int AudioInOpen(unsigned int uDevNO, unsigned int uSampleBits, unsigned int uSampleRate, unsigned int uChannels, unsigned int uPackBytes) { // 创建录音转换队列 s_iCvtIDIn = pgDevAudioConvertAlloc(0, PG_DEV_AUDIO_CVT_FMT_PCM16, 8000, 320); s_iDevID_AudioIn = 1234; return s_iDevID_AudioIn; } static void AudioInClose(int iDevID) { // 销毁转换队列 pgDevAudioConvertFree(s_iCvtIDIn); s_iDevID_AudioIn = -1; } // 假设这是设备上音频采集数据输入函数 static void OnAudioInDataCallback(void *lpData, unsigned int uDataSize) { // 把采集到的音频帧数据压入到队列。 if (pgDevAudioConvertPush(s_iCvtIDIn, PG_DEV_AUDIO_CVT_FMT_PCM16, lpData, uDataSize) <= 0) { return; } // 有可能转换前的音频帧的采样点数是转换后的音频帧的几倍,所以要循环弹出多次。 while (1) { //从队列弹出转换后的音频帧数据。 unsigned char ucDataPop[2048]; int iPopSize = pgDevAudioConvertPopS(s_iCvtIDIn, ucDataPop, sizeof(ucDataPop)); if (iPopSize <= 0) { break; } // 把转换后的音频帧输入给Peergine SDK pgDevAudioInRecordProc(s_iDevID_AudioIn, ucDataPop, iPopSize, PG_DEV_AUDIO_IN_FMT_PCM16, 0); } ... } |
3)音频放音转换样例伪码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
// 假设设备端放音的格式是PCM16,采样率是16000,帧长是640个采样点。伪码如下: static int s_iCvtIDOut = -1; static int s_iDevID_AudioOut = -1; static int AudioOutOpen(unsigned int uDevNO, unsigned int uSampleBits, unsigned int uSampleRate, unsigned int uChannels, unsigned int uPackBytes) { // 创建放音转换队列 s_iCvtIDOut = pgDevAudioConvertAlloc(1, PG_DEV_AUDIO_CVT_FMT_PCM16, 16000, 640); s_iDevID_AudioOut = 1234; return s_iDevID_AudioOut; } static void AudioOutClose(int iDevID) { // 销毁转换队列 pgDevAudioConvertFree(s_iCvtIDOut); s_iDevID_AudioOut = -1; } static int AudioOutPlay(int iDevID, const void* lpData, unsigned int uDataSize, unsigned int uFormat) { // 把播放的音频数据压入队列 int iRet = pgDevAudioConvertPush(s_iCvtIDOut, uFormat, lpData, uDataSize); if (iRet <= 0) { return -1; } // 有可能转换前的音频帧的采样点数是转换后的音频帧的几倍,所以要循环弹出多次。 while (1) { // 从队列弹出转换后的数据。 unsigned char ucDataPop[2048]; int iPopSize = pgDevAudioConvertPopS(s_iCvtIDOut, ucDataPop, sizeof(ucDataPop)); if (iPopSize <= 0) { break; } // 把转换后的音频帧数据在设备放音接口上播放。 dev_audio_play(ucDataPop, iPopSize); } return uDataSize; } |
8. 附录
1)修改记录
版本号 |
修改内容 |
备注 |
1.0 |
初始版本 | |
1.1 |
修改伪码的VideoInCtrl()函数,增加强制产生关键帧的说明。 | |
1.2 |
在概述中添加结构层次图,以及注意事项。 添加关于Audio输入输出接口的说明。 升级代码样例,添加Audio的代码,优化代码结构。 | |
1.3 |
1)增加视频输出回调接口说明 2)增加H265编解码格式 3)修改以前版本的描述错误 | |
1.5 |
增加音频转换API接口和样例伪码 | |
1.6 |
1)增加pgDevAudioOutPlaySilent()函数 2)增加pgDevAudioConvertAlloc()函数的uDevSampleRate参数的有效值说明。 |