1.背景
工作中用到IPCamera支持双摄(即一个IPCamera带两个摄像头),IPC端将两个摄像头的画面上下拼接成了一个画面发布dash到云端,并且携带SEI信息。SEI信息中带两个frame(x, y, width, height),app端(iOS、安卓)根据这个信息拆分画面通过opengl展示到两个view上,以便以不同的排列方式展示双摄画面。
2. 使用ffplay播放单个画面,请参考:
ffplay+SDL2+opengles在iOS中使用(参考ijkplayer)_ffplay swift ios-优快云博客
3. ffp_handleSEI方法用于将AVPacket中的SEI信息读取到multi成员变量中。
//根据视频获取的AVPacket获取SEI中的双摄画面信息,以便根据这些信息拆分显示双摄。
void FSPlay::ffp_handleSEI(AVPacket *pkt) {
//如果不需要查询SEI信息(单摄不需要查询)或multi数据已经获取过了(仅获取一次即可),则直接返回。
if (!needSearchSEI || multi.acquired) {
return;
}
//将AVPacket的data、size数据传入sei_saas_data_without_nal_unit方法获取实际的SEI buf,内部通过查询前后256byte的数据查找对应的uuid,找到uuid后其后边就是SEI对应的数据。
//NAL引导码 + NAL帧类型(SEI) + SEI帧类型(用户自定义类型) + 数据长度 + UUID + 净荷数据 + 0X80
//引导码为0x00 0x00 0x00 0x01或者 0x00 0x00 0x01,NAL帧类型为6,SEI帧类型为5,数据长度为UUID长度+ 净荷数据长度 0x80为尾部固定。
fsbase::ByteBuf buf = fsbase::sei_saas_data_without_nal_unit(pkt->data, pkt->size);
if (buf.size() > 0) {
fsbase::sei_frame_t f;
//通过SEI的buf data创建sei_frame结构体。
fsbase::sei_frame_make(buf.data(), 0, &f);
//如果saas_data有效时执行if代码。
if (f.saas_data != NULL && f.saas_len > 0) {
//根据saas_data构建multi结构体。
std::shared_ptr<fsbase::multi_rect_t> multi_cpp = fsbase::sei_query_multi_rect(f.saas_data, f.saas_len);
//如果multi_cpp有效时执行if代码。
if (multi_cpp != NULL) {
//如果count数量为2的时候说明是对的,继续执行if
if (multi_cpp->count + 1 >= 2) {
//将acquired设置为1表示已经获取过multi数据了,后续可以直接使用,不需要重复获取了。
multi.acquired = 1;
//从multi_cpp中读取rects[0]的x