TS 碼流率計算總結


TS 碼流率計算總結

——By 風波邪人

1         transport_rate計算公式

 

其中, ,PCR字段編碼在MPEG-2 TS包的自適應字段(Adaptation field)的6個Byte中,其中6 bits為預留位,42 bits為有效位,其在TS包中的編碼位置見下圖,PCR分兩部分編碼,一個以STC頻率的1/300(90KHz)為單位,稱為PCR_base,共33bit;另一個以STC頻率(27MHz)為單位,稱為PCR_ext,共9bit。

i指包含PCR_base 字段的最后一個bit的字節,PCR(i)表示這個字節到達TS系統目標解碼器(T-STD)的時間,具體定義請參見參考文獻1。通過PCR值不但可以獲得正確的解碼時間, 還可以計算TS速率等與時間有關的信息。這里的I’-I’’意思是連個包含PCR的數據包之間的字節差值。

 

圖1  PCR字段編碼在TS包中的位置

2         TS數據包分析

 

圖2  Transport Packet

 

 

 

圖3  TS包結構

 

TS流數據包是由:包頭+自適應區(可選)+報數據(凈荷)組成,Sync-byte同步字節為0x47。這里要用到pf(有效載荷標識), 因為它有效時 Table 2-6 Transport Stream adaptation field才有效,我們要抓取的PCR數據就在adaptation field中,接着往下看Table 2-6就會發現,只有PCR_flag == 1 時,我們要找的program_clock_reference_base 和 program_clock_reference_extension才有效。故,由此一連串的因果關系可以很明顯的看出抓取PCR的過程了。

 

圖4  Transport Stream Adaptation Field

 

圖5  TS數據包內容

3         利用程序抓取PCR數據

在抓取PCR數據之前做一項工作,就是用程序讀取 視頻文件內容,在能正確讀取文件內容的基礎上才能抓取PCR數據。我是先根據TS包的結構特點和PCR數據存在的幾個條件一起考慮寫了一個簡單的程序,提取出了PCR數據。通過一個小程序將得到的PCR數據處理成PCR_base和PCR_ext部分,在通過 公式將PCR(i)得到,從而得出transport_rate。

代碼如下:

#include <iostream>

#include <iomanip>

using namespace std;

 

#define _FORMAT     0

 

#if _FORMAT == 1

#define FORMAT      dec

#else

#define FORMAT      hex

#endif

 

int PCR_OK = 0, OPCR_OK = 0, SP_CD_OK = 0;

 

// TS數據包

 

class TS{                                                   //Byte

private:

int sync_byte;                              //8bit

short ei;                                        //1bit

short pusi;                                             //1bit

short tpr;                                      //1bit

int PID;                                          //13bit

short scr_flags;                           //2bit

short af;                                        //1bit

short pf;                                        //1bit

short cc;                                        //4bit

int adpt_flength;                        //8bit

short flag;                                              //1bit

unsigned long PCR[2];               //48bit

unsigned long OPCR[2];            //48bit

int splice_countdown;               //8bit

unsigned char buf_data[179];     //179byte

public:

void display(int i);

int undecoder(FILE * fp);

 

};

 

//數據顯示

 void TS::display(int i)

{

           cout<<setw(3)<<setiosflags(ios::right)<<dec<<i;

           cout<<"----"<<endl;

           cout<<"Item             "<<"Info"<<endl;

 

           //cout.setf(ios::showbase);

           cout.setf(ios::hex);

 

           cout<<"sync_byte       : "<<FORMAT<<sync_byte<<endl;

           cout<<"ei              : "<<ei<<endl;

           cout<<"pusi            : "<<pusi<<endl;

           cout<<"tpr             : "<<tpr<<endl;

           cout<<"PID             : "<<PID<<endl;

           cout<<"scr_flags       : "<<scr_flags<<endl;

           cout<<"af              : "<<af<<endl;

           cout<<"pf              : "<<pf<<endl;

           cout<<"cc              : "<<cc<<endl;

           cout<<"adpt_flength    : "<<adpt_flength<<endl;

          

           //output flag

           cout<<"flag            : "<<flag;

           cout<<"                binary :";

           int j;

           //output flag binary

           for(j = 0; j < 8; j++)

           {

                    if(!j)

                             cout<<dec<<((flag>>(7-j)) & 0x01);

                    else if(j%4 )

                             cout<<dec<<((flag>>(7-j)) & 0x01);

                    else

                    {       

                             cout<<'_';cout<<dec<<((flag>>(7-j)) & 0x01);

                    }

                   

           }

           cout<<endl;

          

           if(PCR_OK)

           {

                    PCR_OK = 0;

                    //output PCR

                    cout<<"PCR             : "<<FORMAT<<PCR[0]<<PCR[1]<<endl;

           }

 

           if(OPCR_OK)

           {

                    OPCR_OK = 0;

                    //output OPCR

                   cout<<"OPCR            : "<<FORMAT<<OPCR[0]<<OPCR[1]<<endl;

           }

 

           //output splice_countdown

           if(SP_CD_OK)

           {

                    SP_CD_OK = 0;

                    cout<<"splice_countdown: "<<FORMAT<<splice_countdown<<endl;

           }

}

 

int TS::undecoder(FILE * fp)

{

           unsigned char buf[6];

           int z=0;

           unsigned int ch, ch1;

 

           ch = fgetc(fp);

           sync_byte = ch;

           ch = fgetc(fp);

           ei = (ch & 0x80)>>7 ;                                                       //transport_error_indicator

 

           pusi = (ch & 0x40)>>6;                                                    //payload_unit_start_indicator

           tpr = (ch & 0x20)>>5;                                                      //transport_priority

 

           ch1 = fgetc(fp);                                                                

           PID = ((ch & 0x1f)<<8) | ch1;                               //PID

          

           ch = fgetc(fp);

           scr_flags = (ch & 0xc0)>>6;                                           //transport_scrambling_control

           af = (ch & 0x20)>>5;                                                        //adaptation_field_control

           pf = (ch & 0x10)>>4;

           cc = (ch & 0x0f);                                                               //continuity_counter

          

           ch = fgetc(fp);

           adpt_flength = ch;                                                           //adaptation_field_length

 

           ch = fgetc(fp);

           flag = ch;                                                                            //adaptation_field_flag

        //-------6B

 

           //adaptation field 有效

           //自適應區長度不為0

           if(af && adpt_flength )

           {

                    // 當 PCR_flag 有效時,讀 PCR值到緩存  , 6B

                    if( flag &0x10)

                    {

                             for(z=0;z<6;z++)

                             {

                                       buf[z] = fgetc(fp);                                                             //讀取PCR數據

                             }

 

                             PCR[0] = (buf[0]<<16) | (buf[1]<<8) | buf[2];

                             PCR[1] = (buf[3]<<16) | (buf[4]<<8) | buf[5];

                             PCR_OK = 1;                                                                                         //PCR數據讀取完畢標志

                    }

                    else

                             fseek(fp, 6, 1);                                                                  //移動文件指針

 

                    // 當 OPCR_flag 有效時,讀 OPCR值到緩存  ,6B

                    if(flag & 0x08)

                    {

                             for(z=0;z<6;z++)

                             {

                                       buf[z] = fgetc(fp);

                             }

                             OPCR[0] = (buf[0]<<16) | (buf[1]<<8) | buf[2];

                             OPCR[1] = (buf[3]<<16) | (buf[4]<<8) | buf[5];

                             OPCR_OK = 1;

                    }

                    else

                             fseek(fp, 6, 1);

 

                    if(flag & 0x04)     // 1B

                    {

                             ch  = fgetc(fp);                                                                //讀取splice_countdown 數據

                             splice_countdown = ch;

                             SP_CD_OK = 1;

                    }

                    else

                             fseek(fp, 1, 1);

                   

                    //文件指針移到下一個TS包起始位置

                    fseek(fp, 0xbb - 0x12, 1);   //0 top position, 1 current position, 2 button position

           }

           else

                    fseek(fp, 0xbb - 0x05, 1);   //0 top position, 1 current position, 2 button position

 

           return 1;

}

 

void compute()

{

long pcr_in1,pcr_in2,pcr_base_H, pcr_base_L, pcr_base,pcr_base_header,pcr_ext;

    while(1)

{

           cout.setf(ios::hex);

           cout<<"input 0 end"<<endl;

           cin>>hex>>pcr_in1;

           if(pcr_in1 == 0)

                    return ;

           cin>>pcr_in2;

           pcr_base_H = pcr_in1;

 

           pcr_base_L = pcr_in2 >>15;

 

           if(pcr_base_H & 0x800000)

                    pcr_base_header = 1;

           else

                    pcr_base_header = 0;

           pcr_base = (pcr_base_H<<9) | pcr_base_L;

 

           pcr_ext = pcr_in2 & 0x0001ff;

 

           cout<<"PCR_BASE:"<<hex<<pcr_base_header<<hex<<pcr_base<<endl;

           cout<<"PCR_EXT:"<<hex<<pcr_ext<<endl;

          

 

 

}

}

 

 

void find()

{        

TS ts;

FILE * fp;

fp = fopen("ysgq.trp","rb");

 

if(fp != NULL)

           cout<<"FILE OPEN SUCCESS"<<endl;

else

{

           cout<<"FILE OPEN FAIL"<<endl;

           exit(0);

}

int count = 0;

for(int c = 0; !feof(fp) ; c++)               //讀取TS流文件

{

 

           if(ts.undecoder(fp))                    //解碼成功

           {

                    if(PCR_OK || OPCR_OK)           //找到PCR

                    {

                            

                             ts.display(c);                       //打印該包的信息

                             count ++;

                             if(count == 10)

                                       break;

                    }

                    else

                             ;

           }

           else

           {

                    cout<<"Read file fail!"<<endl;

                    break;

           }

 

}

 

fclose(fp);

}

 

 

int main()

{

// 數據類型顯示

#if _FORMAT == 0

           cout<<"hex"<<endl;

#endif

#if _FORMAT == 1

           cout<<"dec"<<endl;

#endif

 

 

//===================================         

int sel;

while(1)

{

           cout<<"0:compute \n1:find"<<endl;

           cin>>sel;

 

           switch(sel)

           {

                    case 0:compute();break;                   //計算PCR(i)_base , PCR(i)_ext

                    case 1:find();break;                    //尋找PCR

                    default:break;

           }

}

 

//====================================

 

 

return 0;

}

在啟動程序之后,會有一個菜單選項,0表示:計算PCR(i)值,加入用程序抓取到的PCR數據為A45D3456FE41,則先輸入A45D34,按回車鍵再輸入56FE41,回車即可得到PCR_base和PCR_ext。通過計算器求得PCR(i)。

 

4         利用公式計算transport_rate。

在以上工作做好之后利用公式計算是很容易的事情。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM