H264碼流處理詳解

 碼流(Data Rate)是指視頻文件在單位時間內使用的數據流量,也叫碼率,是視頻編碼中畫面質量控制中最重要的部分。一樣分辨率下,視頻文件的碼流越大,壓縮比就越小,畫面質量就越好。算法

1、簡介 H.264的主要目標:1.高的視頻壓縮比 2.良好的網絡親和性 解決方案: (1)VCL video coding layer 視頻編碼層。VCL:核心算法引擎,塊,宏塊及片的語法級別的定義 (2)NAL:NAL network abstraction layer 網絡提取層。片級以上的語法級別(如序列參數集和圖像參數集),同時支持如下功能:獨立片解碼,起始碼惟一保證,SEI以及流 格式編碼數據傳送。緩存

註釋: VCL設計目標:儘量地獨立於網絡的狀況下進行高效的編解碼,NAL設計目標:根據不一樣的網絡把數據打包成相應的格式,將VCL產生的比特字符串適配到各類各樣的網絡和多元環境中。NALU頭結構:NALU類型(5bit)、重要性指示位(2bit)、禁止位(1bit)。 NALU類型:1~12由H.264使用,24~31由H.264之外的應用使用。 重要性指示:標誌該NAL單元用於重建時的重要性,值越大,越重要。 禁止位:網絡發現NAL單元有比特錯誤時可設置該比特爲1,以便接收方丟掉該單元。安全

二.NAL語法語義服務器

NAL層句法:在編碼器輸出的碼流中,數據的基本單元是句法元素。句法表徵句法元素的組織結構。語義闡述句法元素的具體含義。分組都有頭部,解碼器能夠很方便的檢測出NAL的分界,依次取出NAL進行解碼。但爲了節省碼流,H.264沒有另外在NAL的頭部設立表示起始位置的句法元素。若是編碼數據是存儲在介質上的,因爲NAL是依次緊密相連的,解碼器就沒法在數據流中分辨出每一個NAL的起始位置和終止位置。解決方案:在每一個NAL前添加起始碼:0X000001網絡

3、H.264的NAL層處理框架

結構示意圖: NAL以NALU(NAL unit)爲單元來支持編碼數據在基於分組交換技術網絡中傳輸。 它定義了符合傳輸層或存儲介質要求的數據格式,同時給出頭信息,從而提供了視頻編碼和外部世界的接口。 NALU:定義了可用於基於分組和基於比特流系統的基本格式 RTP封裝:只針對基於NAL單元的本地NAL接口。分佈式

Ⅲ種不一樣的數據形式: SODB 數據比特串:最原始的編碼數據 RBSP 原始字節序列載荷:在SODB的後面填加告終尾比特(RBSP trailing bits 一個bit「1」)若干比特0以便字節對齊 EBSP 擴展字節序列載荷:在RBSP基礎上填加了仿校驗字節(0X03)它的緣由是: 在NALU加到Annexb上時,須要添加每組 NALU以前的開始碼StartCodePrefix,若是該NALU對應的slice爲一幀的開始則用4位字節表示,ox00000001,不然用3位 字節表示ox000001.爲了使NALU主體中不包括與開始碼相沖突的,在編碼時,每遇到兩個字節連續爲0,就插入一個字節的0x03。解碼時將 0x03去掉。也稱爲脫殼操做 處理過程: 1. 將VCL層輸出的SODB封裝成nal_unit, Nal_unit是一個通用封裝格式,能夠適用於有序字節流方式和IP包交換方式。 2. 針對不一樣的傳送網絡(電路交換|包交換),將nal_unit 封裝成針對不一樣網絡的封裝格式。 第一步的具體過程: VCL層輸出的比特流SODB(String Of Data Bits),到nal_unit之間,通過了如下三步處理: 1.SODB字節對齊處理後封裝成RBSP(Raw Byte Sequence Payload)。 2.爲防止RBSP的字節流與有序字節流傳送方式下的SCP(start_code_prefix_one_3bytes,0x000001)出現字節競 爭情形,循環檢測RBSP前三個字節,在出現字節競爭時在第三字節前加入emulation_prevention_three_byte (0x03)。 具體方法: nal_unit( NumBytesInNALunit ) {ide

forbidden_zero_bit函數

nal_ref_idc性能

nal_unit_type

NumBytesInRBSP = 0

for( i = 1; i < NumBytesInNALunit; i++ ) {

if( i + 2 < NumBytesInNALunit && next_bits( 24 ) = = 0x000003 ) {

rbsp_byte[ NumBytesInRBSP++ ]

rbsp_byte[ NumBytesInRBSP++ ]

i += 2

emulation_prevention_three_byte

} else

rbsp_byte[ NumBytesInRBSP++ ]

}

}

  1. 防字節競爭處理後的RBSP再加一個字節的header(forbidden_zero_bit+ nal_ref_idc+ nal_unit_type),封裝成nal_unit.

第二步的具體過程: case1:有序字節流的封裝

byte_stream_nal_unit( NumBytesInNALunit ) {

while( next_bits( 24 ) != 0x000001 )

zero_byte

if( more_data_in_byte_stream( ) ) {

start_code_prefix_one_3bytes nal_unit( NumBytesInNALunit )

}

} 相似H.320和MPEG-2/H.222.0等傳輸系統,傳輸NAL做爲有序連續字節或比特流,同時要依靠數據自己識別NAL單元邊界。在這樣的應用系 統中,H.264/AVC規範定義了字節流格式,每一個NAL單元前面增長3個字節的前綴,即同步字節。在比特流應用中,每一個圖像須要增長一個附加字節做爲 邊界定位。還有一種可選特性,在字節流中增長附加數據,用作擴充發送數據量,能實現快速邊界定位,恢復同步

Case2:IP網絡的RTP打包封裝

分組打包的規則

(1)額外開銷要少,使MTU尺寸在100~64k字節範圍均可以; 

(2)不用對分組內的數據解碼就能夠判別該分組的重要性; 

(3)載荷規範應當保證不用解碼就可識別因爲其餘的比特丟失而形成的分組不可解碼; 

(4)支持將NALU分割成多個RTP分組;

 (5)支持將多個NALU聚集在一個RTP分組中。

RTP的頭標能夠是NALU的頭標,並能夠實現以上的打包規則。 

一個RTP分組裏放入一個NALU,將NALU(包括同時做爲載荷頭標的NALU頭)放入RTP的載荷中,設置RTP頭標值。爲了不IP層對大分組的再 一次分割,片分組的大小通常都要小於MTU尺寸。因爲包傳送的路徑不一樣,解碼端要從新對片分組排序,RTP包含的次序信息能夠用來解決這一問題。

NALU分割

對於預先已經編碼的內容,NALU可能大於MTU尺寸的限制。雖然IP層的分割可使數據塊小於64千字節,但沒法在應用層實現保護,從而下降了非等重保 護方案的效果。因爲UDP數據包小於64千字節,並且一個片的長度對某些應用場合來講過小,因此應用層打包是RTP打包方案的一部分。 

新的討論方案(IETF)應當符合如下特徵: 

(1)NALU的分塊以按RTP次序號升序傳輸; 

(2)可以標記第一個和最後一個NALU分塊; 

(3)能夠檢測丟失的分塊。

NALU合併

一些NALU如SEI、參數集等很是小,將它們合併在一塊兒有利於減小頭標開銷。已有兩種集合分組: 

(1)單一時間集合分組(STAP),按時間戳進行組合; 

(2)多時間集合分組(MTAP),不一樣時間戳也能夠組合。

NAL規範視頻數據的格式,主要是提供頭部信息,以適合各類媒體的傳輸和存儲。NAL支持各類網絡,包括:

1.任何使用RTP/IP協議的實時有線和無線Internet 服務

2.做爲MP4文件存儲和多媒體信息文件服務

3.MPEG-2系統

4.其它網

NAL規定一種通用的格式,既適合面向包傳輸,也適合流傳送。實際上,包傳輸和流傳輸的方式是相同的,不一樣之處是傳輸前面增長了一個起始碼前綴

在相似Internet/RTP面向包傳送協議系統中,包結構中包含包邊界識別字節,在這種狀況下,不須要同步字節。

NAL單元分爲VCL和非VCL兩種

VCL NAL單元包含視頻圖像採樣信息,

非VCL包含各類有關的附加信息,例如參數集(頭部信息,應用到大量的VCL NAL單元)、提升性能的附加信息、定時信息等

參數集:

參數集是不多變化的信息,用於大量VCL NAL單元的解碼,分爲兩種類型:

1.序列參數集,做用於一串連續的視頻圖像,即視頻序列。

兩個IDR圖像之間爲序列參數集。IDR和I幀的區別見下面。

2. 圖像參數集,做用於視頻序列中的一個或多個個別的圖像

序列和圖像參數集機制,減小了重複參數的傳送,每一個VCL NAL單元包含一個標識,指

向有關的圖像參數集,每一個圖像參數集包含一個標識,指向有關的序列參數集的內容

所以,只用少數的指針信息,引用大量的參數,大大減小每一個VCL NAL單元重複傳送的信息。

序列和圖像參數集能夠在發送VCL NAL單元之前發送,而且重複傳送,大大提升糾錯能力。序列和圖像參數集能夠在「帶內」,也能夠用更爲可靠的其餘「帶外」通道傳送。

存儲單元: 一組指定格式的NAL單元稱爲存儲單元,每一個存儲單元對應一個圖像。每一個存儲單元包含一組VCL NAL單元,組成一個主編碼圖像,VCL NAL單元由表示視頻圖像採樣的像條所組成。存儲單元前面能夠加一個前綴,分界存儲單元,附加加強信息(SEI)(如圖像定時信息)也能夠放在主編碼圖像 的前面。主編碼圖像後附加的VCL NAL單元,包含同一圖像的冗餘表示,稱爲冗餘編碼圖像,當主編碼圖像數據丟失或損壞時,可用冗餘編碼圖像解碼。

編碼視頻序列 一個編碼視頻序列由一串連續的存儲單元組成,使用同一序列參數集。每一個視頻序列可獨立解碼。編碼序列的開始是即時刷新存儲單元(IDR)。IDR是一個I幀圖像,表示後面的圖像不用參考之前的圖像。一個NAL單元流可包含一個或更多的編碼視頻序列。

RTP協議: 實時傳輸協議(Real-time Transport Protocol,RTP)是在Internet上處理多媒體數據流的一種網絡協議,利用它可以在一對一(單播)或者一對多(multicast,多播) 的網絡環境中實現傳流媒體數據的實時傳輸。RTP一般使用UDP來進行多媒體數據的傳輸,但若是須要的話可使用TCP或者ATM等其它協議,整個RTP 協議由兩個密切相關的部分組成:RTP數據協議和RTP控制協議。實時流協議(Real Time Streaming Protocol, RTSP)最先由Real Networks和Netscape公司共同提出,它位於RTP和RTCP之上,其目的是但願經過IP網絡有效地傳輸多媒體數據。

RTP數據協議 RTP數據協議負責對流媒體數據進行封包並實現媒體流的實時傳輸,每個RTP數據報都由頭部(Header)和負載(Payload)兩個部分組成,其中頭部前12個字節的含義是固定的,而負載則能夠是音頻或者視頻數據。RTP數據報的頭部格式如圖1所示:

其中比較重要的幾個域及其意義以下: CSRC記數(CC)  表示CSRC標識的數目。CSRC標識緊跟在RTP固定頭部以後,用來表示RTP數據報的來源,RTP協議容許在同一個會話中存 在多個數據源,它們能夠經過RTP混合器合併爲一個數據源。例如,能夠產生一個CSRC列表來表示一個電話會議,該會議經過一個RTP混合器將全部講話者 的語音數據組合爲一個RTP數據源。

負載類型(PT)  標明RTP負載的格式,包括所採用的編碼算法、採樣頻率、承載通道等。例如,類型2代表該RTP數據包中承載的是用ITU G.721算法編碼的語音數據,採樣頻率爲8000Hz,而且採用單聲道。

序列號  用來爲接收方提供探測數據丟失的方法,但如何處理丟失的數據則是應用程序本身的事情,RTP協議自己並不負責數據的重傳。

時間戳  記錄了負載中第一個字節的採樣時間,接收方可以時間戳可以肯定數據的到達是否受到了延遲抖動的影響,但具體如何來補償延遲抖動則是應用程序自 己的事情。從RTP數據報的格式不難看出,它包含了傳輸媒體的類型、格式、序列號、時間戳以及是否有附加數據等信息,這些都爲實時的流媒體傳輸提供了相應 的基礎。RTP協議的目的是提供實時數據(如交互式的音頻和視頻)的端到端傳輸服務,所以在RTP中沒有鏈接的概念,它能夠創建在底層的面向鏈接或面向非 鏈接的傳輸協議之上;RTP也不依賴於特別的網絡地址格式,而僅僅只須要底層傳輸協議支持組幀(Framing)和分段(Segmentation)就足 夠了;另外RTP自己還不提供任何可靠性機制,這些都要由傳輸協議或者應用程序本身來保證。在典型的應用場合下,RTP通常是在傳輸協議之上做爲應用程序 的一部分加以實現的,如圖2所示:

RTCP控制協議 RTCP控制協議須要與RTP數據協議一塊兒配合使用,當應用程序啓動一個RTP會話時將同時佔用兩個端口,分別供RTP和RTCP使用。RTP自己並不能 爲按序傳輸數據包提供可靠的保證,也不提供流量控制和擁塞控制,這些都由RTCP來負責完成。一般RTCP會採用與RTP相同的分發機制,向會話中的全部 成員週期性地發送控制信息,應用程序經過接收這些數據,從中獲取會話參與者的相關資料,以及網絡情況、分組丟失機率等反饋信息,從而可以對服務質量進行控 制或者對網絡情況進行診斷。

RTCP協議的功能是經過不一樣的RTCP數據報來實現的,主要有以下幾種類型:

SR  發送端報告,所謂發送端是指發出RTP數據報的應用程序或者終端,發送端同時也能夠是接收端。

RR  接收端報告,所謂接收端是指僅接收但不發送RTP數據報的應用程序或者終端。

SDES  源描述,主要功能是做爲會話成員有關標識信息的載體,如用戶名、郵件地址、電話號碼等,此外還具備向會話成員傳達會話控制信息的功能。

BYE  通知離開,主要功能是指示某一個或者幾個源再也不有效,即通知會話中的其餘成員本身將退出會話。

APP  由應用程序本身定義,解決了RTCP的擴展性問題,而且爲協議的實現者提供了很大的靈活性。

RTCP數據報攜帶有服務質量監控的必要信息,可以對服務質量進行動態的調整,並可以對網絡擁塞進行有效的控制。因爲RTCP數據報採用的是多播方式,所以會話中的全部成員均可以經過RTCP數據報返回的控制信息,來了解其餘參與者的當前狀況。

在一個典型的應用場合下,發送媒體流的應用程序將週期性地產生髮送端報告SR,該RTCP數據報含有不一樣媒體流間的同步信息,以及已經發送的數據報和字節 的計數,接收端根據這些信息能夠估計出實際的數據傳輸速率。另外一方面,接收端會向全部已知的發送端發送接收端報告RR,該RTCP數據報含有已接收數據報 的最大序列號、丟失的數據報數目、延時抖動和時間戳等重要信息,發送端應用根據這些信息能夠估計出往返時延,而且能夠根據數據報丟失機率和時延抖動狀況動 態調整發送速率,以改善網絡擁塞情況,或者根據網絡情況平滑地調整應用程序的服務質量。

RTSP實時流協議

做爲一個應用層協議,RTSP提供了一個可供擴展的框架,它的意義在於使得實時流媒體數據的受控和點播變得可能。總的說來,RTSP是一個流媒體表示協 議,主要用來控制具備實時特性的數據發送,但它自己並不傳輸數據,而是必須依賴於下層傳輸協議所提供的某些服務。RTSP能夠對流媒體提供諸如播放、暫 停、快進等操做,它負責定義具體的控制消息、操做方法、狀態碼等,此外還描述了與RTP間的交互操做。

RTSP在制定時較多地參考了HTTP/1.1協議,甚至許多描述與HTTP/1.1徹底相同。RTSP之因此特地使用與HTTP/1.1相似的語法和操 做,在很大程度上是爲了兼容現有的Web基礎結構,正因如此,HTTP/1.1的擴展機制大均可以直接引入到RTSP中。

由RTSP控制的媒體流集合能夠用表示描述(Presentation Description)來定義,所謂表示是指流媒體服務器提供給客戶機的一個或者多個媒體流的集合,而表示描述則包含了一個表示中各個媒體流的相關信 息,如數據編碼/解碼算法、網絡地址、媒體流的內容等。

雖然RTSP服務器一樣也使用標識符來區別每一流鏈接會話(Session),但RTSP鏈接並無被綁定到傳輸層鏈接(如TCP等),也就是說在整個 RTSP鏈接期間,RTSP用戶可打開或者關閉多個對RTSP服務器的可靠傳輸鏈接以發出RTSP 請求。此外,RTSP鏈接也能夠基於面向無鏈接的傳輸協議(如UDP等)。

RTSP協議目前支持如下操做:

檢索媒體  容許用戶經過HTTP或者其它方法向媒體服務器提交一個表示描述。如表示是組播的,則表示描述就包含用於該媒體流的組播地址和端口號;若是表示是單播的, 爲了安全在表示描述中應該只提供目的地址。

邀請加入  媒體服務器能夠被邀請參加正在進行的會議,或者在表示中回放媒體,或者在表示中錄製所有媒體或其子集,很是適合於分佈式教學。

添加媒體  通知用戶新加入的可利用媒體流,這對現場講座來說顯得尤爲有用。與HTTP/1.1相似,RTSP請求也能夠交由代理、通道或者緩存來進行處理。

3. JM86中的處理

涉及的函數:

流程圖:

I幀和IDR幀的區別:

1. 在 H.264 中 I 幀並不具備隨機訪問的能力,這個功能由 IDR 承擔。之前的標準中由 I 幀承擔。

2. IDR 會致使 DPB (參考幀列表——這是關鍵所在)清空,而 I 不會。

3. I和IDR幀其實都是I幀,都是使用幀內預測的。可是IDR幀的做用是馬上刷新,使錯誤不致傳播,從IDR幀開始,從新算一個新的序列開始編碼。

4. IDR圖像必定是I圖像,但I圖像不必定是IDR圖像。一個序列中能夠有不少的I圖像,I圖像以後的圖像能夠引用I圖像之間的圖像作運動參考。

H.264 NAL格式及分析器程序源代碼

NAL分析器程序源代碼

#include "stdio.h" #include "stdlib.h"

#include "nalucommon.h"

//##################################### //#本程序檢查一個緩衝區裏面有幾個NALU # //#輸出每一個NALU的類型到輸出文件 # //#輸入爲一個帶有標記/NALU+標記/的文件# //#####################################

void main(void) { FILE *pSrc; FILE *pRep;

if((pSrc=fopen("H264.rec","r+b"))==NULL) exit(-1); else printf("open src file succeed\n"); if((pRep=fopen("H264.rep","w+t"))==NULL) exit(-1); else printf("open report file succeed\n"); ReportNalu(pSrc,pRep); fclose(pSrc); fclose(pRep); }

#include <memory.h>

#ifndef NALUCOMMON_H #define NALUCOMMON_H

typedef struct { int startcodeprefix_len; //! 4 for parameter sets and first slice in picture, 3 for everything else

(suggested) unsigned len; //! Length of the NAL unit (Excluding the start code, which does not belong

to the NALU) unsigned max_size; //! Nal Unit Buffer size int nal_unit_type; //! NALU_TYPE_xxxx int nal_reference_idc; //! NALU_PRIORITY_xxxx int forbidden_bit; //! should be always FALSE unsigned char *buf; //! conjtains the first byte followed by the EBSP } NALU_t;

#define MAXRBSPSIZE 64000

#define NALU_TYPE_SLICE 1 #define NALU_TYPE_DPA 2 #define NALU_TYPE_DPB 3 #define NALU_TYPE_DPC 4 #define NALU_TYPE_IDR 5 #define NALU_TYPE_SEI 6 #define NALU_TYPE_SPS 7 #define NALU_TYPE_PPS 8 #define NALU_TYPE_AUD 9 #define NALU_TYPE_EOSEQ 10 #define NALU_TYPE_EOSTREAM 11 #define NALU_TYPE_FILL 12

#define NALU_PRIORITY_HIGHEST 3 #define NALU_PRIORITY_HIGH 2 #define NALU_PRIRITY_LOW 1 #define NALU_PRIORITY_DISPOSABLE 0

#ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif

#ifndef BOOL #define BOOL unsigned int #endif

void ReportNalu(FILE* src,FILE* rep); void ParseRecBuf(unsigned char p,int bufsize,FILE pReport); int ShowBits (unsigned char buffer[],int totbitoffset,int bytecount, int numbits); BOOL next_bits(unsigned char *p,int bufpos,int bs,int id ); static int FindStartCode (unsigned char *Buf, int bufpos, int bufsize, int next_start_pos, BOOL fIRFD); BOOL gETNALandPROC(unsigned char *p,int bufpos,int bufsize, BOOL fisrtfd,NALU_t *mNal,int inc_SIZE,FILE

*pReport); #endif

//############################################################ //# src 文件格式以下
//# #-#-#-#-#-B-INT32LEN-T264DST - #-#-#-#-B-INT32LEN # //# 1 1 1 1 1 1 4 INT32LEN # //############################################################

void ReportNalu(FILE* src,FILE* rep) { unsigned char tempbuf[1]; unsigned char *pBuf; int *dstlen; int fpos=0; int fstart=0; int FileSize=0; int BufSize; int dstpacketid=0; unsigned int SymState=0; fseek(src,0,SEEK_END); FileSize=ftell(src); printf("the src file size is %d \n",FileSize); fseek(src,0,SEEK_SET); do {

while (fread(tempbuf,sizeof(unsigned char),1,src)) { if(tempbuf=="#") SymState++; else { fpos=fstart+1; SymState=0; fseek(src,fpos,SEEK_SET); } if(SymState==4) {fpos+=4;break;} }

fread(tempbuf,sizeof(unsigned char),1,src);

if(tempbuf=="B") { SymState++; fpos+=1; } else { fpos=fstart+1; fseek(src,fpos,SEEK_SET); }

if(SymState==5)
{
dstpacketid++; fprintf(rep,"the %d dstpacket\n",dstpacketid); dstlen=(int*)malloc(sizeof(int)); fread(dstlen,sizeof(unsigned char),4,src); BufSize=(int*)dstlen; pBuf=(unsigned char*)malloc(sizeof(unsigned char)*BufSize); fpos+=4; fread(pBuf,sizeof(unsigned char),BufSize,src); ParseRecBuf(pBuf,BufSize,rep); fstart=fpos; free(dstlen); free(pBuf); }

} while(fpos!=FileSize);//

}

//#################################################### //# unsigned char p --T264 encode的一個dst長度爲len# //# int bufsize --buffer的大小 # //##FILE pReport --文件指針,存放NAL的分析結果 # //####################################################

void ParseRecBuf(unsigned char p,int bufsize,FILE pReport) {

int bufpos=0; int bUFSTART=0; struct NALU_t *mNal; BOOL isfirst; BOOL starcode_ex; BOOL zero_ex; BOOL trail_ex; int nALSIZE=0; int nal_id=0; BOOL firstfd=FALSE;

while (bufpos<bufsize) { if( !next_bits(p,bufpos,bufsize, 24 ) && !next_bits(p,bufpos,bufsize,32 ) && next_bits( p,bufpos,bufsize,8 )) {bufpos+=8;isfirst=TRUE;firstfd=TRUE;}// leading_zero_8bits //f(8) else{ isfirst=FALSE; }

if(!next_bits( p,bufpos,bufsize,24 ) &&
next_bits( p,bufpos,bufsize,8 ) )
{
bufpos+=8;//zero_byte f(8) zero_ex=TRUE; if( bufpos<bufsize && next_bits(p,bufpos,bufsize, 24 ) ) {
bufpos+=24; // start_code_prefix_one_3bytes f(24) starcode_ex=TRUE; mNal=(struct NALU_t* )malloc(sizeof( NALU_t)); if(gETNALandPROC(p,bufpos,bufsize,firstfd,mNal,nALSIZE,pReport))

{

nal_id++;
   fprintf(pReport," id of the nal packet above is %d\n",nal_id);
bufpos+=(nALSIZE>>3);
if(( bufpos<bufsize)  &&
 (!next_bits(p,bufpos,bufsize, 24 )) &&  
 (!next_bits(p,bufpos,bufsize, 32 ) ) &&
 (next_bits(p,bufpos, bufsize,8 )))
{
 bufpos+=8; trail_ex=TRUE ;
}
else trail_ex=FALSE;
free(mNal);

} else printf("cannot get any nal units\n"); } else{starcode_ex=FALSE;}
} else { zero_ex=FALSE; }

if (!zero_ex || !starcode_ex) bufpos=bUFSTART+1; else bUFSTART=bufpos; } }

//############################################ //#unsigned char *p =--buffer containing NALU# //#int bufpos--current buffer position # //#int bs---buffersize # //#int id # //# id=24 ----0x000001----FALSE # //# id=32 ----0x00000001---FALSE # //# id=8 ----0x00------TRUE # //############################################ BOOL next_bits(unsigned char *p,int bufpos,int bs,int id ) { BOOL rERULT; switch(id) { case 8:
if(ShowBits(p,bufpos,bs,8)==0x00) rERULT=TRUE ; else rERULT=FALSE; break; case 24: if(ShowBits(p,bufpos,bs,24)!=0x000001) rERULT=FALSE; else rERULT=TRUE; break; case 32 : if(ShowBits(p,bufpos,bs,32)!=0x00000001) rERULT=FALSE; else rERULT=TRUE; break; default: break; } return rERULT; }

//############################################## // # \brief # // # Reads bits from the bitstream buffer # // # \param buffer # // # buffer containing VLC-coded data bits # // # \param totbitoffset # // # bit offset from start of partition # // # \param bytecount # // # total bytes in bitstream # // # \param numbits # // # number of bits to read # // ############################################# int ShowBits (unsigned char buffer[],int totbitoffset,int bytecount, int numbits) {

register int inf; long byteoffset; // byte from start of buffer int bitoffset; // bit from start of byte

byteoffset= totbitoffset/8; bitoffset= 7-(totbitoffset%8);

inf=0; while (numbits) { inf <<=1; inf |= (buffer[byteoffset] & (0x01<<bitoffset))>>bitoffset; numbits--; bitoffset--; if (bitoffset < 0) { byteoffset++; bitoffset += 8; if (byteoffset > bytecount) { return -1; } } }

return inf; // return absolute offset in bit from start of frame }

//######################################################################### // # \brief

#

// # returns if new start code is found at byte aligned position buf. # // # new-startcode is of form N 0x00 bytes, followed by a 0x01 byte. # // # \return

#

// # 1 if start-code is found or \n # // # 0, indicating that there is no start code # // # # // # \param Buf # // # pointer to byte-stream # // # \param bufpos # // # indicates current bufpos. //# \bufsize // # indicates total buffer size # // # \param next_star_pos # // # indicates the next_start_code pos # // # \param fIRFD // # is firs nal already found // ######################################################################## static int FindStartCode (unsigned char *Buf, int bufpos, int bufsize, int next_start_pos, BOOL fIRFD) { int info; int tPOS; int tSTART=bufpos; BOOL sTARFOUND=FALSE; info = 1; while (!sTARFOUND && tSTART<bufsize) { for (tPOS = 0; tPOS < 3; tPOS++) if(Buf[tSTART+tPOS] != 0) info = 0;
if(Buf[tSTART+tPOS] != 1) info = 0; if (info==0) tSTART++;
else sTARFOUND=TRUE; } if (fIRFD && sTARFOUND) {
if(Buf[tSTART-1]==0 && Buf[tSTART-2]==0) { info=2;//trailing zero found next_start_pos=tSTART-2;} else {info=1; next_start_pos=tSTART;}
} return info; }

//##################################### //# unsigned char *p # //# int bufpos # //# NALU_t *mNal # //# int n_SIZE # //# # //# # //##################################### BOOL gETNALandPROC(unsigned char *p, int bufpos, int bufsize, BOOL fisrtfd, NALU_t *mNal, int inc_SIZE, FILE *pReport) { BOOL getNfailed=FALSE; int nal_BUFSIZE=0; int next_start_point=0; int mNal_size=0; int b_bufpos=bufpos/8; unsigned int finresult; BOOL info=TRUE; finresult=FindStartCode (p,b_bufpos,bufsize,next_start_point,fisrtfd); if (finresult==1 || finresult==2) { nal_BUFSIZE=next_start_point-b_bufpos-1; inc_SIZE=nal_BUFSIZE; mNal->buf=(unsigned char *)malloc(sizeof(unsigned char)*nal_BUFSIZE); mNal->len=nal_BUFSIZE; memcpy (mNal->buf, &p[b_bufpos+1], mNal->len); mNal->forbidden_bit = (mNal->buf[0]>>7) & 1; mNal->nal_reference_idc = (mNal->buf[0]>>5) & 3; mNal->nal_unit_type = (mNal->buf[0]) & 0x1f; fprintf(pReport,"#########################################################################\n"); fprintf(pReport,"nal len is %d\n",mNal->len); fprintf(pReport,"fobidden bit is % d\n",mNal->forbidden_bit); fprintf(pReport,"nal_reference_idc is d%\n",mNal->nal_reference_idc); switch(mNal->nal_unit_type) { case NALU_TYPE_SLICE : fprintf(pReport," nal type is * NALU_TYPE_SLICE\n"); break; case NALU_TYPE_DPA: fprintf(pReport,"nal type is * NALU_TYPE_DPA\n"); break; case NALU_TYPE_DPB : fprintf(pReport,"nal type is * NALU_TYPE_DPB\n"); break; case NALU_TYPE_DPC: fprintf(pReport,"nal type is * NALU_TYPE_DPC\n"); break; case NALU_TYPE_IDR: fprintf(pReport,"nal type is * NALU_TYPE_IDR\n"); break; case NALU_TYPE_SEI: fprintf(pReport,"nal type is * NALU_TYPE_SEI\n"); break; case NALU_TYPE_SPS: fprintf(pReport,"nal type is * NALU_TYPE_SPS\n"); break; case NALU_TYPE_PPS: fprintf(pReport,"nal type is * NALU_TYPE_PPS\n"); break; case NALU_TYPE_AUD: fprintf(pReport,"nal type is * NALU_TYPE_AUD\n"); break; case NALU_TYPE_EOSEQ: fprintf(pReport,"nal type is * NALU_TYPE_EOSEQ\n"); break; case NALU_TYPE_EOSTREAM: fprintf(pReport,"nal type is * NALU_TYPE_EOSTREAM\n"); break; case NALU_TYPE_FILL : fprintf(pReport,"nal type is * NALU_TYPE_FILL\n"); break; default: break; } fprintf(pReport,"nal start code len is %d\n",mNal->startcodeprefix_len); fprintf(pReport,"#########################################################################\n"); free(mNal->buf); mNal->buf=NULL; } else info=FALSE; return info; }

相關文章
相關標籤/搜索