简单解析海康PS流获取H264

在用海康SDK获取H264视频流的时候,其实从海康的SDK里面基本是没有的,海康的SDK介绍使用是通过自身的PlayM4解码成图片的,并非我们想要的H264。项目里面使用的是海康提供的AnalyzeData库,但是我并没有从海康官网找到下载,应该是PS格式解析库。

分析

其实通过Wireshark本地抓包,抓摄像头IP的包,在程序请求后会发现确实是TCP连接上的PS格式的流,在设置了视频格式为H264的情况下我们就可以进行解包了。

网上确实有很多解包的代码,但是我使用过,某些情况下就产生了core了,很明显了内存使用有问题,打算自己实现。在查看了PS的规范,我觉得不太可能实现了,基于我们的目的通过最简单的方式取出H264即可,其他信息暂时忽略。

格式

好在PS包格式也不是特别难,PS包开始以 0x00 0x00 0x01 0xba ,然后内部包含了很多PES包,开始标志之后,紧接着看第14字节(包含00 00 01 ba)的值,该值与0x07与之后就是扩展长度,也就是说包长为扩展长度加14。跳过上述长度后,就开始了PES包。

PES包也是以0x00 0x00 0x01 XX 开始,其中XX是各个包不同,视频包为0xe0,音频包为0xc0。 类似的确认包格式后,接着就是2个字节的长度(注意都是大端字节序,下同),这个长度表示后续数据长度,跳过起始的6个字节后,我们处理视频包的数据时,第三个字节表示扩展头大小,因此跳过3加扩展头大小,剩下的就是H264裸流数据了,注意自己计算各个长度的大小。

通过上面简单的算法,很容易就拿到了H264数据 了,音频也是类似的,不过我暂时不关心。

代码

C++实现的PS提取H264的类实现如下

class PsPacketParser {
public:
void Parse(const char* data, size_t size) {
if (size < 14 || 0xba010000 != *(int32_t*)data) return;
int extlen = uint8_t(data[13]) & 0x07;
if (size <= 14 + extlen) return;

const char * buffer = data + (14 + extlen);
int length = size - extlen - 14;
while (length > 0) {
if(length < 6) break;
int32_t chunk_flag = *(int32_t*)buffer;
uint16_t chunk_size = ntohs(*(uint16_t*)(buffer + 4));
if (chunk_size + 6 > length) break;

switch (chunk_flag) {
case 0xe0010000:
ParsePes(buffer + 6, chunk_size);
break;
}

buffer += (6 + chunk_size);
length -= (6 + chunk_size);
}
}

std::string& h264() {
return cache_;
}

private:
void ParsePes(const char* data, size_t size) {
if(size > 3){
int32_t len = uint8_t(data[2]) + 3;
if(size > len) cache_.append(data + len, size - len);
}
}

private:
std::string cache_;
};

上面的代码入口参数为单个PS包,如果拿到的不是单个包,通过0x00 0x00 0x01 0xba分割即可,这块处理也不难,或者根据上述代码改造成缓存版即可。其他语言也可以根据上面的算法思路简单处理,已通过C#实现,确实相对简单,至少比第三方库使用方便多了。

最近的文章

使用内存映射实现本地缓存

本来程序中一些数据需要在下次重启后能够恢复继续使用,一般比较好的办法是直接嵌入sqlite数据库或者嵌入leveldb,但是需要引入第三方库,略麻烦,因此打算自己实现。 实现思路自己实现最简单就是使用WinAPI操作INI文件,一个读API一个写API,非常简单方便,但是曾经出现过一个项被写两次的问 …

技术 继续阅读
更早的文章

GB28181云台控制

最近完成了GB28181的云台控制功能,记录下相关代码。 参考要实现GB28181的云台控制,基本不用参考其他文档了,直接查看标准文档即可,当然COPY别人现成代码也是很爽的,不过百度相关代码其实也不多,是不是搞这块的人不多呢。这里主要要说的是,云台控制就是发送了消息,相机会一直执行,直到其他命令或 …

技术 继续阅读