程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 數字電視中TS包解碼函數

數字電視中TS包解碼函數

編輯:C++入門知識

[cpp] 
/***************************************************************************** 
* dvbpsi_PushPacket                數字電視中TS包解碼函數注解
*****************************************************************************
* Injection of a TS packet into a PSI decoder.
*****************************************************************************/ 
void dvbpsi_PushPacket(dvbpsi_handle h_dvbpsi, uint8_t* p_data) 

    uint8_t i_expected_counter;         /* 存儲下一個數據包的連續計數器數字 */ 
    dvbpsi_psi_section_t* p_section;    /* 當前段指針 */ 
    uint8_t* p_payload_pos;             /* 當前位置指針 */ 
    uint8_t* p_new_pos = NULL;      /* Beginning of the new section,updated to NULL when the new section is handled */ 
    int i_available;                    /* 包中可用字節數 */ 
    /* TS start code */ 
    if(p_data[0] != 0x47)                //同步字節(sync byte:1B),應為0x47  
    { 
        DVBPSI_ERROR("PSI decoder", "not a TS packet"); 
        return; 
    } 
    /* 連續檢查 */ 
    i_expected_counter = (h_dvbpsi->i_continuity_counter + 1) & 0xf;     /*連續計數器累加1*/ 
    h_dvbpsi->i_continuity_counter = p_data[3] & 0xf;                //TS頭部最後4比特為連續計數器  
    if(i_expected_counter != h_dvbpsi->i_continuity_counter)          /*判斷是否是連續傳送的包*/ 
    { 
        DVBPSI_ERROR_ARG("PSI decoder", 
        "TS discontinuity (received %d, expected %d)", 
        h_dvbpsi->i_continuity_counter, i_expected_counter); 
        h_dvbpsi->b_discontinuity = 1;               //將不連續標志置1  
        if(h_dvbpsi->p_current_section)          //刪除當前段  
        { 
            dvbpsi_DeletePSISections(h_dvbpsi->p_current_section);   //釋放空間  
            h_dvbpsi->p_current_section = NULL; 
        } 
    } 
    /* 判斷是否有有效負載,沒有就返回*/ 
    if(!(p_data[3] & 0x10))  //第28bit標識有無調整段  
    { 
        return; 
    } 
    /* 跳過自適應長度區 */ 
    if(p_data[3] & 0x20)                            //第27bit標識有無自適應區(adaption field)  
        p_payload_pos = p_data + 5 + p_data[4];     //5為包頭4字節及1字節的自適應長度 p_data[4]自適應區長度  
    else 
        p_payload_pos = p_data + 4; 
    /* Unit start -> skip the pointer_field and a new section begins */ 
    if(p_data[1] & 0x40)        //即"payload unit start indicator"bit位 有效荷載單元起始批示符位,值為1表示存在確定的起始信息  
    { 
        p_new_pos = p_payload_pos + *p_payload_pos + 1; //指向包數據起始位置  
        p_payload_pos += 1; //跳過長度指示的1個字節  
    } 
    p_section = h_dvbpsi->p_current_section; 
    /* If the psi decoder needs a begginning of section and a new section
    begins in the packet then initialize the dvbpsi_psi_section_t structure */ 
    if(p_section == NULL) 
    { 
        if(p_new_pos) 
        { 
            /* 為結構分配內存空間 */ 
            h_dvbpsi->p_current_section 
            = p_section 
            = dvbpsi_NewPSISection(h_dvbpsi->i_section_max_size); 
            /* 更新當前位置指針 */ 
            p_payload_pos = p_new_pos; 
            /* 有指針指向新段 */ 
            p_new_pos = NULL; 
            /* Just need the header to know how long is the section */ 
            h_dvbpsi->i_need = 3;         //在前3個字節中包含了表ID、section syntax indicator和長度批示,能確定是那種表,有多長  
            h_dvbpsi->b_complete_header = 0; 
        } 
        else 
        { 
            /* No new section => return */ 
            return; 
        } 
    } 
    /* Remaining bytes in the payload */ 
    i_available = 188 + p_data - p_payload_pos; //有效載荷長度  
    while(i_available > 0) 
    { 
        if(i_available >= h_dvbpsi->i_need) 
        { 
            /* 有足夠的字節存儲頭部或整個段的信息 */ 
            memcpy(p_section->p_payload_end, p_payload_pos, h_dvbpsi->i_need); 
            p_payload_pos += h_dvbpsi->i_need; 
            p_section->p_payload_end += h_dvbpsi->i_need; 
            i_available -= h_dvbpsi->i_need; 
            if(!h_dvbpsi->b_complete_header) 
            { 
                /* Header is complete */ 
                h_dvbpsi->b_complete_header = 1; 
                /* Compute p_section->i_length and update h_dvbpsi->i_need */ 
                //不懂?????????  
                h_dvbpsi->i_need = p_section->i_length = ((uint16_t)(p_section->p_data[1] & 0xf)) << 8 | p_section->p_data[2]; //從第12個比特位到第24個比特位為長度批示段  
                /* 檢查段是否超過最大長度 */ 
                if(h_dvbpsi->i_need > h_dvbpsi->i_section_max_size - 3) //包頭3個字節  
                { 
                    DVBPSI_ERROR("PSI decoder", "PSI section too long"); 
                    dvbpsi_DeletePSISections(p_section); 
                    h_dvbpsi->p_current_section = NULL; 
                    /* 如果還有新段沒有分析,則繼續*/ 
                    if(p_new_pos) 
                    { 
                        h_dvbpsi->p_current_section 
                        = p_section 
                        = dvbpsi_NewPSISection(h_dvbpsi->i_section_max_size); 
                        p_payload_pos = p_new_pos; 
                        p_new_pos = NULL; 
                        h_dvbpsi->i_need = 3; 
                        h_dvbpsi->b_complete_header = 0; 
                        i_available = 188 + p_data - p_payload_pos; 
                    } 
                    else 
                    { 
                        i_available = 0; 
                    } 
                } 
            } 
            else 
            { 
                /* PSI section is complete */ 
                p_section->b_syntax_indicator = p_section->p_data[1] & 0x80; //讀段語法標志 位  
                p_section->b_private_indicator = p_section->p_data[1] & 0x40; //固定的'0',這是為了防止和ISO13818Video流格式中的控制字沖突而設置的  
                /* 如果存在CRC校驗數據,則更新p_payload_end指針 */ 
                if(p_section->b_syntax_indicator) 
                    p_section->p_payload_end -= 4; 
                if(dvbpsi_ValidPSISection(p_section)) /*調用函數對數據進行CRC校驗*/ 
                { 
                    /* 數據無誤 */ 
                    p_section->i_table_id = p_section->p_data[0]; //從第一個字節讀取表ID,0x00為PAT,0x02為PMT  
                    if(p_section->b_syntax_indicator) 
                    { 
                        p_section->i_extension = (p_section->p_data[3] << 8) 
                        | p_section->p_data[4]; //16bits的當前流ID,DVB內唯一.(事實上很多都是自定義的TS ID)  
                        p_section->i_version = (p_section->p_data[5] & 0x3e) >> 1; //43到47的5bits為版本號碼,標注當前節目的版本.這是個非常有用的參數,當檢測到這個字段改變時,說明TS流中的節目已經變化了,程序必須重新搜索節目  
                        p_section->b_current_next = p_section->p_data[5] & 0x1; //第48比特位,當前還是未來使用標志符,一般情況下為'0'  
                        p_section->i_number = p_section->p_data[6]; //當前段號碼  
                        p_section->i_last_number = p_section->p_data[7]; //最後段號碼(section_number和last_section_number的功能是當PAT內容>184字節時,PAT表會分成多個段(sections),解復用程序必須在全部接收完成後再進行PAT的分析)從for()開始,就是描述了當前流中的頻道數目(N),每一個頻道對應的PMT PID是什麼.解復用程序需要和上圖類似的循環來接收所有的頻道號碼和對應的PMT PID,並把這些信息在緩沖區中保存起來.在後部的處理中需要使用到PMT PID.  
                        p_section->p_payload_start = p_section->p_data + 8; //前面已分析了8個字節,指向新的開始  
                    } 
                    else 
                    { 
                        p_section->p_payload_start = p_section->p_data + 3; 
                    } 
                    h_dvbpsi->pf_callback(h_dvbpsi, p_section); 
                    h_dvbpsi->p_current_section = NULL; 
                } 
                else 
                { 
                    /* PSI section isn't valid => trash it */ 
                    dvbpsi_DeletePSISections(p_section); 
                    h_dvbpsi->p_current_section = NULL; 
                } 
                /* If there is a new section not being handled then go forward
                in the packet */ 
                if(p_new_pos) 
                { 
                    h_dvbpsi->p_current_section 
                    = p_section 
                    = dvbpsi_NewPSISection(h_dvbpsi->i_section_max_size); 
                    p_payload_pos = p_new_pos; 
                    p_new_pos = NULL; 
                    h_dvbpsi->i_need = 3; 
                    h_dvbpsi->b_complete_header = 0; 
                    i_available = 188 + p_data - p_payload_pos; 
                } 
                else 
                { 
                i_available = 0; 
                } 
            } 
        } 
        else 
        { 
            /* There aren't enough bytes in this packet to complete the
            header/section */ 
            memcpy(p_section->p_payload_end, p_payload_pos, i_available); 
            p_section->p_payload_end += i_available; 
            h_dvbpsi->i_need -= i_available; 
            i_available = 0; 
        } 
    } 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved