從海康7816的ps流裡獲取資料h264資料
海康7816使用ps流來封裝h.264資料,這裡使用的解碼器無法識別ps流,因此需要將h264資料從ps流裡提取出來
對於ps流的規定可以參考13818-1文件
這裡從7816裡獲取到一些資料取樣
00 00 01 BA 44 73 26 B8 34 01 00 00 03 FE FF FF 00 00 00 0100 00 01 BC00 5A E0 FF 00 24 40 0E 48 4B 00 01 0D AF C5 D3 E0 07 FF FF FF FF 41 12 48 4B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2C 1B E0 00 10 42 0E 00 00 A0 21 02 C0 02 40 12 1F FF 00 1C 21 91 C0 00 0C 43 0A 00 00 FE 00 7D 03 03 E8 03 FF BD BD 00 00 BF BF 00 00 00 00 00 0000 00 01 E0
如上是一個i幀的資料的開始部分,如下是一個非i幀的資料的開始部分
00 00 01 BA 44 73 27 99 34 01 00 00 03 FE FF FF 00 00 00 03 00 00 01 E0 07 12 8C 80 0A 21 1C C9 E6 4D FF FF FF FF F8。。。
可見都是以00 00 01 BA開頭,這是ps的包頭(Program Stream pack header),其中00 00 01是pack_start_code,是一個數據包的開始標識,接下來的1byte(BA)是流標識(stream_id),在文件13818-1的Table 2-33和2.5.3.4節有Program Stream pack header的描述。
這裡把上面i幀的的(Program Stream pack header列出來
00 00 01 BA 44 73 26 B8 34 01 00 00 03 FE FF FF 00 00 00 01
根據文件描述包頭最少有14個位元組,第14個位元組的最後3bit說明了包頭14位元組後填充資料的長度,這裡是pack_stuffing_length=FE&0x07=6,有6byte的填充資料,既是FF FF 00 00 00 01,海康7816使用這部分填充資料來說明每幀的序號,01說明是第1幀資料。
要注意的是包頭可能還有系統標題頭,id為bb,他也是包頭的一部分,並且,他的長度並未算在pack_stufing_length裡,比如:
00 00 01 BB 00 0C 80 CC F5 04 E1 7F E0 E0 E8 C0 C0 20
這裡起始碼後的 00 0C 說明了其後資料的長度,這裡是12個位元組
接在Program Stream pack header後的是以00 00 01 BC開始的一個包,00 00 01是pack_start_code,BC是stream_id流標識,說明跟在Program Stream pack header後的是Program Stream map。文件13818-1的Table 2-35和2.5.4.2節有Program Stream pack header的描述。
跟在00 00 01 BC後的兩位是說明了Program Stream map,他也是pes包的一種,包的長度program_stream_map_length,這裡是00 5A,說明跟在其後的資料長度為90,跳過這其後的90byte資料是以00 00 01 E0開始的包,E表示是GB/TXXXX.2或GB/TAAAA.2視訊流編號xxxx規格的pes包了,0表示流id為0,h264資料就在這個包裡。
從Program Stream map裡我們還能得知pes裡的流是何種流(stream_type和elementary_stream_id表明),以及幀率()等
1110XXXX(0xex)表示視訊資料,111XXXXX表示audio資料,其後的幀有關資訊共5位元組,2位元組PES包長度是00 1A,表示此PES資料包的長度是0x001a 即26位元組;2位元組標準位資訊是8C 80,5位元組中的最後一位元組表示附加資料長度是0A,跟在附加資料長度後的就是視訊資料負載了。
pes包可以有多個,這裡的i幀就把資料放到了多個pes包裡,這裡的非i幀就只有一個pes包
有了以上資訊就已經可以從7816裡剝離出h246資料了,更詳細的說明請參考文件。
擷取一段pes包頭進行分析
00 00 01 E0 00 1A 8C 80 0A 21 1C C9 AE 0D FF FF FF FF FC
00 1A: 2位元組表示長度,表示再這兩個位元組之後的資料長度(如果有附加資料包括了其後的附加資料,和負載資料,我們希望得到的是負載資料,因此要略過附加資料部分)
8C(10 00 1 1 00): 首先是固定值10,。
接下來的兩位為(PES加擾控制欄位)PES_scrambling_control,這裡是00,表示沒有加擾(加密)。剩下的01,10,11由使用者自定義。
接下來第4位為PES優先順序欄位(PES_priority),當為1時為高優先順序,0為低優先順序。這裡為1。
接下來第3位為(資料對齊指示符欄位)PESdata_alignment_indicator,
接下來第2位為版權位,
接下來第1位為版權位,
80(10 000000):
首先是PTS,DTS標誌欄位,這裡是10,表示有PTS,沒有DTS。
接下來第6位是ESCR標誌欄位,這裡為0,表示沒有該段
接下來第5位是ES速率標誌欄位,,這裡為0,表示沒有該段
接下來第4位是DSM特技方式標誌欄位,,這裡為0,表示沒有該段
接下來第3位是附加版權資訊標誌欄位,,這裡為0,表示沒有該段
接下來第2位是PES CRC標誌欄位,,這裡為0,表示沒有該段
接下來第1位是PES擴充套件標誌欄位,,這裡為0,表示沒有該段
0A(10):1個位元組,指出包含在PES分組標題中的可選欄位和任何填充位元組所佔用的總位元組數(既是前面提到的附加資料)。該欄位之前的位元組指出了有無可選欄位(這裡只有PTS)。
因為這裡PTS,DTS標誌欄位是10,那就有5個位元組的PTS段,就是這裡的21 1C C9 AE 0D
最後的五個位元組的FF FF FF FF FC是海康自己的一個自減計數值
#pragma pack(1)
union littel_endian_size
{
unsigned short int length;
unsigned char byte[2];
};
struct pack_start_code
{
unsigned char start_code[3];
unsigned char stream_id[1];
};
struct program_stream_pack_header
{
pack_start_code PackStart;// 4
unsigned char Buf[9];
unsigned char stuffinglen;
};
struct program_stream_map
{
pack_start_code PackStart;
littel_endian_size PackLength;//we mast do exchange
//program_stream_info_length
//info
//elementary_stream_map_length
//elem
};
struct program_stream_e
{
pack_start_code PackStart;
littel_endian_size PackLength;//we mast do exchange
char PackInfo1[2];
unsigned char stuffing_length;
};
#pragma pack()
int inline ProgramStreamPackHeader(char* Pack, int length, char **NextPack, int *leftlength)
{
//printf("[%s]%x %x %x %x\n", __FUNCTION__, Pack[0], Pack[1], Pack[2], Pack[3]);
//通過 00 00 01 ba頭的第14個位元組的最後3位來確定頭部填充了多少位元組
program_stream_pack_header *PsHead = (program_stream_pack_header *)Pack;
unsigned char pack_stuffing_length = PsHead->stuffinglen & '\x07';
*leftlength = length - sizeof(program_stream_pack_header) - pack_stuffing_length;//減去頭和填充的位元組
*NextPack = Pack+sizeof(program_stream_pack_header) + pack_stuffing_length;
if(*leftlength<4) return 0;
//printf("[%s]2 %x %x %x %x\n", __FUNCTION__, (*NextPack)[0], (*NextPack)[1], (*NextPack)[2], (*NextPack)[3]);
return *leftlength;
}
inline int ProgramStreamMap(char* Pack, int length, char **NextPack, int *leftlength, char **PayloadData, int *PayloadDataLen)
{
//printf("[%s]%x %x %x %x\n", __FUNCTION__, Pack[0], Pack[1], Pack[2], Pack[3]);
program_stream_map* PSMPack = (program_stream_map*)Pack;
//no payload
*PayloadData = 0;
*PayloadDataLen = 0;
if(length < sizeof(program_stream_map)) return 0;
littel_endian_size psm_length;
psm_length.byte[0] = PSMPack->PackLength.byte[1];
psm_length.byte[1] = PSMPack->PackLength.byte[0];
*leftlength = length - psm_length.length - sizeof(program_stream_map);
//printf("[%s]leftlength %d\n", __FUNCTION__, *leftlength);
if(*leftlength<=0) return 0;
*NextPack = Pack + psm_length.length + sizeof(program_stream_map);
return *leftlength;
}
inline int Pes(char* Pack, int length, char **NextPack, int *leftlength, char **PayloadData, int *PayloadDataLen)
{
//printf("[%s]%x %x %x %x\n", __FUNCTION__, Pack[0], Pack[1], Pack[2], Pack[3]);
program_stream_e* PSEPack = (program_stream_e*)Pack;
*PayloadData = 0;
*PayloadDataLen = 0;
if(length < sizeof(program_stream_e)) return 0;
littel_endian_size pse_length;
pse_length.byte[0] = PSEPack->PackLength.byte[1];
pse_length.byte[1] = PSEPack->PackLength.byte[0];
*PayloadDataLen = pse_length.length - 2 - 1 - PSEPack->stuffing_length;
if(*PayloadDataLen>0)
*PayloadData = Pack + sizeof(program_stream_e) + PSEPack->stuffing_length;
*leftlength = length - pse_length.length - sizeof(pack_start_code) - sizeof(littel_endian_size);
//printf("[%s]leftlength %d\n", __FUNCTION__, *leftlength);
if(*leftlength<=0) return 0;
*NextPack = Pack + sizeof(pack_start_code) + sizeof(littel_endian_size) + pse_length.length;
return *leftlength;
}
int inline GetH246FromPs(char* buffer,int length,CallbackHead& head, char **h264Buffer, int *h264length)
{
int leftlength = 0;
char *NextPack = 0;
*h264Buffer = buffer;
*h264length = 0;
if(ProgramStreamPackHeader(buffer, length, &NextPack, &leftlength)==0)
return 0;
char *PayloadData=NULL;
int PayloadDataLen=0;
while(leftlength >= sizeof(pack_start_code))
{
PayloadData=NULL;
PayloadDataLen=0;
if(NextPack
&& NextPack[0]=='\x00'
&& NextPack[1]=='\x00'
&& NextPack[2]=='\x01'
&& NextPack[3]=='\xE0')
{
//接著就是流包,說明是非i幀
if(Pes(NextPack, leftlength, &NextPack, &leftlength, &PayloadData, &PayloadDataLen))
{
if(PayloadDataLen)
{
memcpy(buffer, PayloadData, PayloadDataLen);
buffer += PayloadDataLen;
*h264length += PayloadDataLen;
}
}
else
{
if(PayloadDataLen)
{
memcpy(buffer, PayloadData, PayloadDataLen);
buffer += PayloadDataLen;
*h264length += PayloadDataLen;
}
break;
}
}
else if(NextPack
&& NextPack[0]=='\x00'
&& NextPack[1]=='\x00'
&& NextPack[2]=='\x01'
&& NextPack[3]=='\xBC')
{
if(ProgramStreamMap(NextPack, leftlength, &NextPack, &leftlength, &PayloadData, &PayloadDataLen)==0)
break;
}
else
{
//printf("[%s]no konw %x %x %x %x\n", __FUNCTION__, NextPack[0], NextPack[1], NextPack[2], NextPack[3]);
break;
}
}
return *h264length;
}
ps:
這篇文章回復私信挺多的,有的同學讀了成功的獲取了原始的h.264資料,有的同學反映和他們遇到的情況不一樣,比如subi2008同學說他讀出的流有00 00 01 c0標識的pes資料,這個其實是音訊資料,還有遇到00
00 01 bd的,這個是私有流的標識,總之,ps流就解析大家可以參看ps,ts流的文件,裡面的內容都有,表2-18裡說明了所有的流標識。
ps:
另外,有的hk攝像頭回調然後解讀出來的原始h.264碼流,有的一包裡只有分界符資料(nal_unit_type=9)或補充增強資訊單元(nal_unit_type=6),如果直接送入解碼器,有可能會出現問題,這裡的處理方式要麼丟棄這兩個部分,要麼和之後的資料合起來,再送入解碼器裡,如有遇到的朋友可以交流一下:)
相關推薦
從海康7816的ps流裡獲取資料h264資料
海康7816使用ps流來封裝h.264資料,這裡使用的解碼器無法識別ps流,因此需要將h264資料從ps流裡提取出來 對於ps流的規定可以參考13818-1文件 這裡從7816裡獲取到一些資料取樣 00 00 01 BA 44 73 26 B8 34 01 00 00 0
海康ps流轉換h264流
from:http://blog.csdn.net/wwyyxx26/article/details/15224879 海康7816使用ps流來封裝h.264資料,這裡使用的解碼器無法識別ps流,因此需要將h264資料從ps流裡提取出來 對於ps流的規定可以參考13818
從海康螢石看企業經營之不易
作者6年多業內知名半導體工作經驗,目前在國內某BAT企業做產品。 歡迎關注公眾號交流物聯網技術和物聯網產品。 原文連結 https://mp.weixin.qq.com/s?__biz=MzI3NDE2NDMwNQ==&mid=2649905797&idx=1&
從INFORMATION_SCHEMA裡獲取mysql裡的元資料資訊
從INFORMATION_SCHEMA裡獲取mysql裡的元資料資訊 information_schema是MySQL自帶的系統資料庫,儲存了所有的元資料。 information_schema資料庫中的表都是隻讀的,不能進行更新、刪除和插入等操作。 information_sche
從事件物件裡獲取事件資料
事件物件:它是由JavaScript和DOM自動建立產生,它包含著事件的相關資料,如click事件包含了事件觸發位置的座標。如果我們要獲取事件資料,比如要輸出事件資料。 下面的程式碼中,要想獲取事件的座標,需要先訪問到這個自動生成的事件物件,實際上,這個事件物件,不僅是由DOM或JavaScript自動建立
ios開發之從輸入流裡讀入資料
文章來自:http://blog.csdn.net/caryaliu/article/details/7640197 ios cocoa 程式設計,從NSInputStream中讀入資料包括幾個步驟: 1.從資料來源建立和初始化一個NSInputStream例項
Ubuntu下使用Python-opencv獲取海康威視RTSP碼流教程
已更新(前面的方法雖然可行但不能解決根本問題,對不住大家了,讓大家浪費了時間!實際有更簡單的方案,請直接檢視分割線以下的內容) /* 下面這部分內容被作廢了 筆者在釋出這篇部落格之前為了拿到海康威視的碼流費了九牛二虎之力,當然也可能是筆者太菜,但是既然折騰出來
[譯]ios開發之從輸入流裡讀入資料
ios cocoa 程式設計,從NSInputStream中讀入資料包括幾個步驟: 1.從資料來源建立和初始化一個NSInputStream例項 2.將輸入流物件配置到一個run loop,open the stream 3. 通過流物件的delegate函式處理
海康網路攝像機視訊資料的獲取及使用opencv顯示
最近要使用海康威視攝像機獲取資料做處理。主要是藉助Opencv這個工具,所以做了一下步驟。 我用的是基於Qt+opencv的來顯示海康資料的。本人海康的型號為:DS-2CD2820FD 1、海康sdk開發環境的配置(我只給出我的配置路徑,視具體情況而定)
Android RxJava操作符的學習---組合合併操作符---從磁碟或記憶體快取中獲取快取資料
1. 需求場景 2. 功能說明 對於從磁碟 / 記憶體快取中 獲取快取資料 的功能邏輯如下: 3. 具體實現 詳細請看程式碼註釋 // 該2變數用於模擬記憶體快取 & 磁碟快取中的資料 String me
從FILE_OBJECT裡獲取完整NT路徑和DOS路徑
原作者:Tesla.Angela 連結:http://www.m5home.com/bbs/thread-8896-1-1.html 眾所周知在FILE_OBJECT.FileName的路徑是不帶碟符的,於是網上各種QUICK AND DIRTY的程式碼就乾脆直接從FileName裡取得“無
django django中的HTML控制元件及引數傳遞方法 以及 HTML form 裡的資料是怎麼被包成http request 的?如何在瀏覽器裡檢視到這些資料? 從HTML form submit 到 django response是怎麼完成的
https://www.jb51.net/article/136738.htm django中的HTML控制元件及引數傳遞方法 下面小編就為大家分享一篇django中的HTML控制元件及引數傳遞方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
從時間戳裡獲取時間資訊
String date = DateUtils.getToStringShort(articleInfoWebVO.getCreatetime()); //將引數分割 從時間戳裡獲取時間資訊 String[] param = date.split("-"); articleInfoWebVO.set
海思3518EV200 SDK中獲取和儲存H.264碼流詳解
1 /****************************************** 2 step 2: Start to get streams of each channel. 3 ************************************
命令列(CMD) 模式下使用 ffplay 播放海康攝像頭 rtsp 資料
簡述 【海康攝像頭碼流】 主碼流取流: rtsp://admin:[email protected]:554/h264/ch1/main/av_stream 子碼流取流:rtsp://admin:[email protected]:554/h264/ch1/sub/av
js從物接入lot hub mqttws31獲取資料
<script type="text/javascript" src="mqttws31.js"></script> var hostname = '', port = , clientId = '', timeout = , kee
海康視屏監控RTSP服務獲取
海康裝置RTSP流是通過海康視訊服務獲取,因此首先需要確定專案視訊服務平臺是否支援獲取RTSP流,如果不支援需要向海康申請開通。如果服務可以使用,向專案整合方獲取專案視訊服務平臺IP和埠、監控點編號,專案整合方向海康申請獲取視訊服務APPKey和APPsecre
從H264/H265碼流中獲取寬、高及幀率
在做碼流分析時,影象解析度、幀率這類的基本資訊,當然不可少。本文介紹如何從NAL中計算到影象寬、高,還有解析度。於是H264和H265有相似性,就在一起寫了。 一、從碼流獲得寬、高 1、H264 寬高可從SPS欄位計算得到,公式如下: Width = (pic_width_in_mb
趴一趴如何用最簡單的方式從html form表單中獲取到資料
最近網速一直不太好 ~~~不開心 本文采用的是最簡單的方式,僅供自己試驗,畢竟存在一些不安全因素。 看了其他好的的方式發現都太麻煩,所以自己總結下。 是這樣的:input.html頁面中有一段程式碼。
EasyGBS國標流媒體視訊平臺接入海康、大華、宇視的攝像機、硬碟錄影機NVR、國標下級平臺的方案
在上一篇《EasyNVR和EasyDSS雲平臺聯手都不能解決的事情,只有國標GB28181能解決了》我們大致介紹了國標GB/T28181的使用場景,而且初步介紹了EasyGBS國標視訊平臺,那麼,我們就EasyGBS分別接入海康、大華、宇視的IPC網路攝像機或者NVR網路硬碟錄影機的配置