您的位置:首页 > 其它

将H.264采集卡的输出格式,转换为标准H.264

2011-03-12 23:14 218 查看
市面上有很多种H.264硬压采集, 海康/大华/等等等等
找了半天发现所有的卡接口及其相似,在开发包中都是使用 RegisterStreamDirectReadCallback 注册回调函数来获取压缩后的数据流。
 
在它的回调函数中输出的码流不知道是啥子格式,而我需要标准的H.264码流,保存成flv并同时使用RTMP发布。如果解码后重新编码加重了CPU的负担,不符合要求。难道这就是传说中的海康码? 
 
找啊找啊找啊找,在几乎绝望的情况下发现大华的工具里面居然有一个将 采集卡的录像文件 转换成 标准AVI 的小工具 StreamToAVI.exe。
马上一试,输出的AVI能够被MediaInfo识别,且显示AVI容器的 codec 是 AVC, Main profile. 哟西,看来还是标准的H.264码流啊。
只要能够反向这个工具就能够解析出可爱的NALU了。
 
打开IDA,首先盯上的就是ReadFile API调用
.text:00401CD1                 push    10000h
.text:00401CD6                 push    ecx
.text:00401CD7                 push    ebp
.text:00401CD8                 call    ds:ReadFile
.text:00401CDE                 test    eax, eax
.text:00401CE0                 jz      short loc_401D0F
.text:00401CE2                 mov     eax, [esp+10h]
.text:00401CE6                 cmp     eax, 10000h
.text:00401CEB                 jnb     short loc_401CF5
.text:00401CED                 mov     dword ptr [esp+14h], 1
.text:00401CF5                 mov     edx, [esi+60h]
.text:00401CF8                 push    eax
.text:00401CF9                 push    edx
.text:00401CFA                 mov     ecx, esi
.text:00401CFC                 call    sub_401E30
 

每次读取长度为0x10000 的文件块到内存,然后就call sub_401E30进行处理, 看来 401E30这个函数就是要反向的目标

这个函数是某个类的成员函数,成员变量是由ebp寄存器(this指针)加上偏移量进行操作,看起来真头疼啊

理清类的内存布局以及推测其中某些变量含义,花了3天时间, 虽然人是笨了点,不过好在有耐心。再结合调试跟踪,又花了一个周末的时间摸清了基本的来龙去脉。终于搞出点东西来了!

 

.text:00402231                 mov     eax, [ebp+64h]
.text:00402234                 cmp     eax, 1FDh
.text:00402239                 jz      short loc_40227D
.text:0040223B                 cmp     eax, 1FCh
.text:00402240                 jz      short loc_40227D
.text:00402242                 cmp     eax, 1FBh
.text:00402247                 jz      short loc_40227D
.text:00402249                 cmp     eax, 1FAh
.text:0040224E                 jz      short loc_40227D
.text:00402250                 cmp     eax, 1F0h
.text:00402255                 jz      short loc_40227D
.text:00402257                 cmp     eax, 1F1h
.text:0040225C                 jz      short loc_40227D
 

这个1FD 1FC 1FB 1FA 1F0 应该是类型字段,标明当前的数据类型

 

1F0 是音频编码,略过, 不感兴趣

1FD 和 1FC 是 H.264编码 , 1FD应该是 I帧

1FB 和 1FA 不知道是什么,调试中发现, 我的录像文件从不进入这个分支执行,它应该是另一种编码类型(0x3447504D?),可能是为其它某种型号的硬件准备的。这个就略过了,反正没用。

 

在0x403030处发现一个重要函数

.text:00403030                 mov     ecx, [esp+arg_8]
.text:00403034                 mov     eax, [esp+arg_C]
.text:00403038                 push    ebp
.text:00403039                 mov     ebp, [esp+4+arg_0]
.text:0040303D                 push    esi
.text:0040303E                 push    edi
.text:0040303F                 lea     edi, [ecx+eax]
.text:00403042                 lea     eax, [ebp+1]
.text:00403045                 mov     byte ptr [ebp+0], 0
.text:00403049                 xor     esi, esi
.text:0040304B                 mov     byte ptr [eax], 0
.text:0040304E                 inc     eax
.text:0040304F                 mov     byte ptr [eax], 0
.text:00403052                 inc     eax
.text:00403053                 mov     byte ptr [eax], 1
.text:00403056                 mov     dl, [ecx]
.text:00403058                 inc     eax
.text:00403059                 mov     [eax], dl
.text:0040305B                 inc     eax
.text:0040305C                 inc     ecx
.text:0040305D                 cmp     ecx, edi
.text:0040305F                 jnb     short loc_403084
.text:00403061                 cmp     esi, 2
.text:00403064                 jnz     short loc_403071
.text:00403066                 cmp     byte ptr [ecx], 3
.text:00403069                 ja      short loc_403071
.text:0040306B                 mov     byte ptr [eax], 3
.text:0040306E                 inc     eax
.text:0040306F                 xor     esi, esi
.text:00403071                 mov     dl, [ecx]
.text:00403073                 test    dl, dl
.text:00403075                 jnz     short loc_40307A
.text:00403077                 inc     esi
.text:00403078                 jmp     short loc_40307C
.text:0040307A                 xor     esi, esi
.text:0040307C                 mov     [eax], dl
.text:0040307E                 inc     eax
.text:0040307F                 inc     ecx
.text:00403080                 cmp     ecx, edi
.text:00403082                 jb      short loc_403061
.text:00403084                 mov     ecx, [esp+0Ch+arg_4]
.text:00403088                 sub     eax, ebp
.text:0040308A                 pop     edi
.text:0040308B                 pop     esi
.text:0040308C                 mov     [ecx], eax
.text:0040308E                 pop     ebp
.text:0040308F                 retn    10h
 

这个函数的特征太明显了,连续设置0x00 0x00 0x00 0x01 以及 连续2个零后小于3做处理。

一眼就认出0x40303这个函数肯定是转换成H.264 Annex B format输出

 

围绕这个函数分析,发现卡输出的H.264分2种, 一种就是H.264 Annex B, 还一种就是普通的NALU

 

试着自己写了个解析程序,成功地转换了录像文件。

 

明天继续,离球门不远了 :)

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  h.264 byte avi 工具 codec flv