在直播系统中,除了直播音视频之外,有时候还想从主播端发布文本信息等,这些信息可以不通过视频传输通道发送给用户播放端,但如果传输的数据想和视频保持精准同步,那最好的办法就是这些信息和视频数据打包在一起传输,并通过h264 sei方式就可以把数据放入h264 Access Unit中传输。
扩展SEI有使用场景:
1、公告广播:推送将相对/绝对时间戳/时间/公告内容发到播放端,播放端实时接收消息并做相应的逻辑处理;
2、冲顶大会:推流端实时将题目分发到播放端,借助于大牛直播SDK低延迟特性,轻松实现“音-画-题”同步接收;
3、直播:推流端将歌词/字幕分发到播放端,播放端实时绘制出歌词;
4、应急指挥/单兵:推送端将GIS信息/现场采集到的数据实时写入并分发到播放端;
5、在线教育:推流端将激光笔和涂鸦操作分发到播放端,播放端实时划圈划线,实现特定特效。
扩展SEI调用demo(以Windows平台为例):
1. 启动推送端软件: SmartPublisherDemo.exe,可到 Github 下载大牛直播SDK的相关测试软件或demo源码。
2. 做如下配置:
3. 可以点击自动发送文本按钮;
4. 打开播放端SmartPlayer.exe查看数据传输播放效果:
扩展SEI调用demo代码说明:
1. 推送端(对应工程:WIN-PublisherSDK-CPP-Demo):
/*++++发送用户自定义数据相关接口++++*/ /* * 1. 目前使用sei机制发送用户自定数据到播放端 * 2. 这种机制有可能会丢失数据, 所以这种方式不保证接收端一定能收到 * 3. 优势:能和视频保持同步,虽然有可能丢失,但一般的需求都满足了 * 4. 目前提供两种发送方式 第一种发送二进制数据, 第二种发送 utf8字符串 */ /* * 设置发送队列大小,为保证实时性,默认大小为3, 必须设置一个大于0的数 * 如果数据超过队列大小,将丢掉队头数据 * 这个接口请在 StartPublisher 之前调用 */ NT_UINT32(NT_API *SetPostUserDataQueueMaxSize)(NT_HANDLE handle, NT_INT32 max_size, NT_INT32 reserve); /* * 清空用户数据队列, 有些情况可能会用到,比如发送队列里面有4条消息再等待发送,又想把最新的消息快速发出去, 可以 * 先清除掉正在排队消息, 再调用PostUserXXX * */ NT_UINT32(NT_API *ClearPostUserDataQueue)(NT_HANDLE handle); /* * 发送二进制数据 * data: 二进制数据 * size:数据大小 * 注意: 1.目前数据大小限制在256个字节以内,太大可能会影响视频传输,如果有特殊需求,需要增大限制,请联系我们 * 2. 如果积累的数据超过了设置的队列大小,之前的队头数据将被丢弃 * 3. 必须再调用StartPublisher之后再发送数据 */ NT_UINT32(NT_API *PostUserData)(NT_HANDLE handle, const NT_BYTE* data, NT_UINT32 size, NT_INT32 reserve); /* * 发送utf8字符串 * utf8_str: utf8字符串 * 注意: 1. 字符串长度不能超过256, 太大可能会影响视频传输,如果有特殊需求,需要增大限制,请联系我们 * 2. 如果积累的数据超过了设置的队列大小,之前的队头数据将被丢弃 * 3. 必须再调用StartPublisher之后再发送数据 */ NT_UINT32(NT_API *PostUserUTF8StringData)(NT_HANDLE handle, NT_PCSTR utf8_str, NT_INT32 reserve); /*----发送用户自定义数据相关接口----*/
2. 播放端(对应工程:WIN-PlayerSDK-CPP-Demo):
/* 设置用户数据回调 */ NT_UINT32(NT_API *SetUserDataCallBack)(NT_HANDLE handle, NT_PVOID call_back_data, NT_SP_SDKUserDataCallBack call_back); /* 设置视频sei数据回调 */ NT_UINT32(NT_API *SetSEIDataCallBack)(NT_HANDLE handle, NT_PVOID call_back_data, NT_SP_SDKSEIDataCallBack call_back);
/* * * 用户数据回调,目前是推送端发送过来的 * data_type: 数据类型,1:表示二进制字节类型. 2:表示utf8字符串 * data:实际数据, 如果data_type是1的话,data类型是const NT_BYTE*, 如果data_type是2的话,data类型是 const NT_CHAR* * size: 数据大小 * timestamp: 视频时间戳 * reserve1: 保留 * reserve2: 保留 * reserve3: 保留 */ typedef NT_VOID(NT_CALLBACK* NT_SP_SDKUserDataCallBack)(NT_HANDLE handle, NT_PVOID user_data, NT_INT32 data_type, NT_PVOID data, NT_UINT32 size, NT_UINT64 timestamp, NT_UINT64 reserve1, NT_INT64 reserve2, NT_PVOID reserve3 ); /* * * 视频的sei数据回调 * data: sei 数据 * size: sei 数据大小 * timestamp:视频时间戳 * reserve1: 保留 * reserve2: 保留 * reserve3: 保留 * 注意: 目前测试发现有些视频有好几个sei nal, 为了方便用户处理,我们把解析到的所有sei都吐出来,sei nal之间还是用 00 00 00 01 分隔, 这样方便解析 * 吐出来的sei数据目前加了 00 00 00 01 前缀 */ typedef NT_VOID(NT_CALLBACK* NT_SP_SDKSEIDataCallBack)(NT_HANDLE handle, NT_PVOID user_data, NT_BYTE* data, NT_UINT32 size, NT_UINT64 timestamp, NT_UINT64 reserve1, NT_INT64 reserve2, NT_PVOID reserve3 );
SEI优势
1. 不依赖于相关协议,rtsp和rtmp都可以,其他协议只要播放端支持SEI解析的都可以使用;
2. 兼容性很好,如果播放端不支持自定义SEI数据解析,把SEI数据丢给H264解码器,解码器只是忽略掉,并不影响正常播放,上述操作也可以用VLC来播放,播放正常,只是不显示SEI消息;
3. 在视频帧携带,完全和视频保持同步,这个是其他传输通道无法做到的。