几年前写的将TS码流中的PAT、PMT、SDT、EIT分离的代码;不多说,有兴趣的参考下;
/*******************************************************************************
TS Parse Code
data:2011.1.15
yanxi.jiang
*******************************************************************************/
#include "Stdio.h"
#include "Conio.h"
#include "io.h"
#include "string.h"
#include "TsParser.h"
/*****************************************************************************
PSI/SI PID DEFINE
******************************************************************************/
#define PID_PAT 0x00
#define PID_SDT 0x11
#define PID_EIT 0x12
/* SD:188 bytes HD:204 bytes */
#define TSSDLen 188
#define TSSyncByte 0x47
#define SectionMaxLen (1024)
/*******************************************************************************/
#define TsDataLenRead (188*5)
#define PsiMaxSectionNum (100)
#define PIDFilterNum (10)
/*=================================Table parse define===========================*/
typedef struct Ts_Parser_Para
{
unsigned char PrePsicc;
unsigned char PsiCCError;
unsigned int PsiPreTotalPayloadLenth;
int PsiSecHandle;
int PsiSecMaxLen;
unsigned long TsPsiSecCount;
unsigned char *pTsPsitSecBuffTemp;
}Parser_Para;
char *TSPath;
Parser_Para PAT_Parser,EIT_Parser,SDT_Parser,TXT_Parser,NIT_Parser,PMT_Parser;
static unsigned long PatSecNum = 0;
unsigned int PIDLIST[PIDFilterNum] = {0};
/*==============================================================================*/
void SetFilePath(char *path)
{
TSPath = path;
}
/*******************************************************************************
input: void
output: return ts file handle on first position
-1 means file open failed
*******************************************************************************/
int GetTsFileStartHandle(void)
{
int TSPacketHandle = 0;
TSPacketHandle = open(TSPath,0x01|0x8000 ,0);
return TSPacketHandle;
}
/*******************************************************************************
input: void
output: return ts file length (byte)
*******************************************************************************/
unsigned long GetTsFileLen(void)
{
FILE*fp;
unsigned long longBytes;
fp = fopen(TSPath,"r");/* localfile文件名 */
fseek(fp,0,SEEK_END);
longBytes = ftell(fp);/* longBytes就是文件的长度*/
fclose(fp);
return longBytes;
}
/*******************************************************************************
输入:FileHandle 句柄
返回:输入句柄位置与同步字节的Offset大小
-1 means Get Packet SyncByte failed
Note:当函数执行后,句柄被恢复原有Value
*******************************************************************************/
int GetFirstSyncOffsetInFile(int FileHandle)
{
unsigned char Count = 0;
unsigned char Sync0,Sync1,Sync2;
while(Count < TSSDLen)
{
read(FileHandle, &Sync0, 1);
lseek(FileHandle, (TSSDLen-1), SEEK_CUR);
read(FileHandle, &Sync1, 1);
lseek(FileHandle, (TSSDLen-1), SEEK_CUR);
read(FileHandle, &Sync2, 1);
lseek(FileHandle, -(TSSDLen+TSSDLen+1), SEEK_CUR);
if((Sync0 == TSSyncByte) && (Sync1 == TSSyncByte) && (Sync2 == TSSyncByte))
{
lseek(FileHandle, -Count, SEEK_CUR);/*恢复句柄原有Value*/
return (Count);
}
Count++;
lseek(FileHandle, 1, SEEK_CUR);
}
lseek(FileHandle, -Count, SEEK_CUR);/*恢复句柄原有Value*/
return -1;
}
#if 0
/*******************************************************************************
input: TsPacketBuff 一个被确认的TSPacket开始handle
Output:该TSPackt的PID
*******************************************************************************/
unsigned int GetPidInTsPacket(int FileHandle)
{
unsigned int PidDate = 0xFFFF;
unsigned char PidHigh,PidLow;
lseek(FileHandle, 1, SEEK_CUR);
read(FileHandle, &PidHigh, 1);
read(FileHandle, &PidLow, 1);
lseek(FileHandle, -2, SEEK_CUR);
PidDate = 0x1fff & ((PidHigh<<8)&0xff00) | (PidLow&0x00ff);
return PidDate;
}
#else
/*******************************************************************************
input: TsPacketBuff 一个被确认的TSPacket开始地址
Output:该TSPackt的PID
*******************************************************************************/
unsigned int GetPidInTsPacket(unsigned char *TsPacketBuff)
{
unsigned int PidDate = 0xffff;
PidDate = 0x1fff & ((TsPacketBuff[1] << 8)&0xff00) | (TsPacketBuff[2]&0x00ff);
return PidDate;
}
#endif
/*******************************************************************************
input: PID pBuff
Output: void
note: parse ts packet,and collect section to buffer
*******************************************************************************/
void PsiTransportStreamParser(Parser_Para *pPsiTableTemp,unsigned char *pBuff)
{
unsigned char transport_error_indicator = 0;
unsigned char payload_unit_start_indicator = 0;
unsigned char adaptation_field_control = 0,adaptation_field_Len = 0;
unsigned char continuity_counter = 0;
unsigned char PayloadLenth = 0;
unsigned char PayloadStartPositionOffset = 0;
/*================================ packet flag parsing ===============================*/
transport_error_indicator = pBuff[1]&0x80;
payload_unit_start_indicator = (pBuff[1]&0x40)>>5;
adaptation_field_control = (pBuff[3] >> 4)&0x03;
adaptation_field_Len = pBuff[4];
continuity_counter = pBuff[3]&0x0f;
if(transport_error_indicator == 0x01)
return;/*Check TEI bit of flag*/
/*================================ adptation field parsing ============================*/
switch (adaptation_field_control)
{
case 0x00: /* reserved */
goto EXIT;
case 0x01: /* payload only */
PayloadLenth = TSSDLen - 4;
PayloadStartPositionOffset = 4;
break;
case 0x02: /* af only */
goto EXIT;
case 0x03: /* af + payload */
PayloadLenth = TSSDLen - (adaptation_field_Len + 1) - 4;
PayloadStartPositionOffset = 4 + (adaptation_field_Len + 1);
break;
}
PayloadLenth -= 1;/*jump PSI pointer_field,one byte*/
PayloadStartPositionOffset += 1;
/*=============================== collect psi section ================================*/
if( (( ++(pPsiTableTemp->PrePsicc) % 0x10 ) != continuity_counter) &&
(((pPsiTableTemp->TsPsiSecCount) > 0) || ((pPsiTableTemp->PsiPreTotalPayloadLenth) > 0)) )
pPsiTableTemp->PsiCCError = 1;
pPsiTableTemp->PrePsicc = continuity_counter;
if(payload_unit_start_indicator)
{
if( (pPsiTableTemp->PsiPreTotalPayloadLenth > 0) && (pPsiTableTemp->PsiCCError == 0) )
{
lseek(pPsiTableTemp->PsiSecHandle, (pPsiTableTemp->PsiSecMaxLen)*(pPsiTableTemp->TsPsiSecCount), SEEK_SET);
pPsiTableTemp->TsPsiSecCount++;
write(pPsiTableTemp->PsiSecHandle,pPsiTableTemp->pTsPsitSecBuffTemp,pPsiTableTemp->PsiPreTotalPayloadLenth);
}
pPsiTableTemp->PsiPreTotalPayloadLenth = 0;/*last section has collected*/
memset(pPsiTableTemp->pTsPsitSecBuffTemp,0,pPsiTableTemp->PsiSecMaxLen);
pPsiTableTemp->PsiCCError = 0;
memcpy(pPsiTableTemp->pTsPsitSecBuffTemp,&pBuff[PayloadStartPositionOffset],PayloadLenth);
pPsiTableTemp->PsiPreTotalPayloadLenth += PayloadLenth;
}
else
{
if(pPsiTableTemp->PsiCCError == 1)
{
pPsiTableTemp->PsiPreTotalPayloadLenth = 0;
memset(pPsiTableTemp->pTsPsitSecBuffTemp,0,pPsiTableTemp->PsiSecMaxLen);
return;
}
if( (pPsiTableTemp->PsiPreTotalPayloadLenth + PayloadLenth) <= pPsiTableTemp->PsiSecMaxLen )
{
memcpy(&pPsiTableTemp->pTsPsitSecBuffTemp[pPsiTableTemp->PsiPreTotalPayloadLenth],&pBuff[PayloadStartPositionOffset],PayloadLenth);
pPsiTableTemp->PsiPreTotalPayloadLenth += PayloadLenth;
}
}
EXIT:
return;
}
/*******************************************************************************
input: pPatSec: one pat section,pPMTProNumPID
Output: Num of Program
note: collect PMT PID and Pro num
*******************************************************************************/
unsigned char TsGetPmtPid(unsigned char *pPatSec,unsigned long *pPMTProNumPID)
{
int Section_lenth = 0,point = 0;
unsigned char i = 0;
unsigned long temp = 0;
temp = (pPatSec[1]&0x0F);
temp = temp << 8;
temp += pPatSec[2];
Section_lenth = temp;
Section_lenth -= 9;/*jump version number section number,CRC...*/
point = 8;
while(Section_lenth >=4 )
{
if(pPatSec[point] != 0)/*program 0 means that is network pid */
{
/*Program number*/
temp = pPatSec[point];
temp = temp << 8;
temp += pPatSec[point+1];
pPMTProNumPID[i] = temp << 16;
/*Program map pid*/
temp = pPatSec[point+2];
temp = (temp&0x1F) << 8;
temp += pPatSec[point+3];
pPMTProNumPID[i] += temp;
i++;
}
point += 4;
Section_lenth -= 4;
}
return i;
}
void TsInitPidFilter(void)
{
memset(PIDLIST,0xFFFF,PIDFilterNum);
}
void TsAddPidToFilter(unsigned int PID)
{
unsigned char i;
for(i = 0;i < PIDFilterNum; i++)
{
if(PIDLIST[i] == 0xFFFF)
break;
}
PIDLIST[i] = PID;
}
/*******************************************************************************
input: packet PID
Output: return PAT_Parser/SDT_Parser ... address in ppPsiPara
note: check Is PID in PID Filter list
*******************************************************************************/
unsigned char TsGetFlag_PIDInFilter(Parser_Para **ppPsiPara,unsigned int PID,unsigned char PMT)
{
unsigned char i = 0;
while(i < PIDFilterNum)
{
if(PIDLIST[i] == 0xFFFF)return 0;
if(PIDLIST[i] == PID)
break;
i++;
}
if(i < PIDFilterNum)
{
switch(PID)
{
case PID_PAT:*ppPsiPara = &PAT_Parser;break;
case PID_SDT:*ppPsiPara = &SDT_Parser;break;
case PID_EIT:*ppPsiPara = &EIT_Parser;break;
default:if(PMT){*ppPsiPara = &PMT_Parser;break;}
else return 0;
}
return 1;
}
return 0;
}
void TsSetPatSecNumValue(unsigned long Num)
{
PatSecNum = Num;
}
unsigned long TsGetPatSecNumValue(void)
{
return PatSecNum;
}
void TsPSIParser(void)
{
int TSPacketHandle,Offset;
unsigned int PID;
unsigned long TsFileLen,i;
Parser_Para **ppPsiPara;
TSPacketHandle = GetTsFileStartHandle();
TsFileLen = GetTsFileLen();/*get file len*/
if(TSPacketHandle > 0)
{
/******************************************Section buffer*************************************************/
unsigned char Num = 1 + 1 + 4;
unsigned char *pbuff = (unsigned char *)calloc(SectionMaxLen*Num,1);/*pat(1024) sdt(1024) eit(4096)*/
if(pbuff == NULL)
return;
memset(pbuff,0,SectionMaxLen*Num);
memset(&PAT_Parser,0x00,sizeof(Parser_Para));
memset(&SDT_Parser,0x00,sizeof(Parser_Para));
memset(&EIT_Parser,0x00,sizeof(Parser_Para));
PAT_Parser.PsiSecMaxLen = SectionMaxLen;
SDT_Parser.PsiSecMaxLen = SectionMaxLen;
EIT_Parser.PsiSecMaxLen = SectionMaxLen*4;
PAT_Parser.pTsPsitSecBuffTemp = (unsigned char *)pbuff;
pbuff += PAT_Parser.PsiSecMaxLen;
SDT_Parser.pTsPsitSecBuffTemp = (unsigned char *)pbuff;
pbuff += SDT_Parser.PsiSecMaxLen;
EIT_Parser.pTsPsitSecBuffTemp = (unsigned char *)pbuff;
/******************************************Section buffer*************************************************/
pbuff = (unsigned char *)calloc(TsDataLenRead,1);
if(pbuff == NULL)
return;
PAT_Parser.PsiSecHandle = open("C:\\PatSec.dat",0x04|0x8000|0x100 ,0);
SDT_Parser.PsiSecHandle = open("C:\\SdtSec.dat",0x04|0x8000|0x100 ,0);
EIT_Parser.PsiSecHandle = open("C:\\EitSec.dat",0x04|0x8000|0x100 ,0);
TsInitPidFilter();
TsAddPidToFilter(PID_PAT);
TsAddPidToFilter(PID_SDT);
TsAddPidToFilter(PID_EIT);
while(TsFileLen > TsDataLenRead)
{
Offset = GetFirstSyncOffsetInFile(TSPacketHandle);/*利用文件的Handle,取得 指定句柄后的第一个TSPacket Offset*/
if(Offset < 0)
{
lseek(TSPacketHandle, TSSDLen, SEEK_CUR);
TsFileLen -= TSSDLen;
}
else
{
lseek(TSPacketHandle, Offset, SEEK_CUR); /*讲句柄移动到TSPacket开始*/
read(TSPacketHandle,pbuff,TsDataLenRead);
for(i = 0;i < TsDataLenRead;i += TSSDLen)
{
PID = GetPidInTsPacket(&pbuff[i]);
if( TsGetFlag_PIDInFilter(ppPsiPara,PID,0) )
PsiTransportStreamParser(*ppPsiPara,&pbuff[i]);
}
TsFileLen -= TsDataLenRead;
}
}
TsSetPatSecNumValue(PAT_Parser.TsPsiSecCount);
if(PAT_Parser.pTsPsitSecBuffTemp != (void *)0)
free(PAT_Parser.pTsPsitSecBuffTemp);
if(SDT_Parser.pTsPsitSecBuffTemp != (void *)0)
free(SDT_Parser.pTsPsitSecBuffTemp);
if(EIT_Parser.pTsPsitSecBuffTemp != (void *)0)
free(EIT_Parser.pTsPsitSecBuffTemp);
close(PAT_Parser.PsiSecHandle);
close(SDT_Parser.PsiSecHandle);
close(EIT_Parser.PsiSecHandle);
close(TSPacketHandle);
free(pbuff);
}
}
void TsPMTParser(void)
{
int TSPacketHandle,Offset;
unsigned int PID,PmtNum;
unsigned long TsFileLen,i;
unsigned long PMTProNumPID[20];/*high 16 bits is Pro num and low 16 bits is PID*/
Parser_Para **ppPsiPara;
TSPacketHandle = GetTsFileStartHandle();
TsFileLen = GetTsFileLen();/*get file len*/
if(TSPacketHandle > 0)
{
/******************************************Section buffer*************************************************/
unsigned char Num = 1;
unsigned char *pbuff = (unsigned char *)calloc(SectionMaxLen*Num,1);
if(pbuff == NULL)
return;
memset(pbuff,0,SectionMaxLen*Num);
memset(&PMT_Parser,0x00,sizeof(Parser_Para));
PMT_Parser.PsiSecMaxLen = SectionMaxLen;
PMT_Parser.pTsPsitSecBuffTemp = (unsigned char *)pbuff;
/******************************************Section buffer*************************************************/
pbuff = (unsigned char *)calloc(TsDataLenRead,1);
if(pbuff == NULL)
return;
PAT_Parser.PsiSecHandle = open("C:\\PatSec.dat",0x01|0x8000 ,0);
PMT_Parser.PsiSecHandle = open("C:\\PmtSec.dat",0x04|0x8000|0x100 ,0);
TsInitPidFilter();
TsAddPidToFilter(PID_PAT);
TsAddPidToFilter(PID_SDT);
TsAddPidToFilter(PID_EIT);
if(TsGetPatSecNumValue() > 0)/* Get PMT Pid in TransportStream file*/
{
memset(PMT_Parser.pTsPsitSecBuffTemp,0x00,SectionMaxLen);
lseek(PAT_Parser.PsiSecHandle, 0, SEEK_SET);
read(PAT_Parser.PsiSecHandle, PMT_Parser.pTsPsitSecBuffTemp, SectionMaxLen);
PmtNum = TsGetPmtPid(PMT_Parser.pTsPsitSecBuffTemp,PMTProNumPID);
for(;PmtNum > 0;PmtNum--)
{
lseek(TSPacketHandle, 0, SEEK_SET);
TsFileLen = GetTsFileLen();/*get file len*/
memset(PMT_Parser.pTsPsitSecBuffTemp,0x00,SectionMaxLen);
TsInitPidFilter();
TsAddPidToFilter(PMTProNumPID[PmtNum-1]&0xFFFF);
while(TsFileLen > TsDataLenRead)
{
Offset = GetFirstSyncOffsetInFile(TSPacketHandle);/*利用文件的Handle,取得 指定句柄后的第一个TSPacket Offset*/
if(Offset < 0)
{
lseek(TSPacketHandle, TSSDLen, SEEK_CUR);
TsFileLen -= TSSDLen;
}
else
{
lseek(TSPacketHandle, Offset, SEEK_CUR); /*讲句柄移动到TSPacket开始*/
read(TSPacketHandle,pbuff,TsDataLenRead);
for(i = 0;i < TsDataLenRead;i += TSSDLen)
{
PID = GetPidInTsPacket(&pbuff[i]);
if( TsGetFlag_PIDInFilter(ppPsiPara,PID,1) )
PsiTransportStreamParser(*ppPsiPara,&pbuff[i]);
}
TsFileLen -= TsDataLenRead;
}
}
}
}
if(PMT_Parser.pTsPsitSecBuffTemp != (void *)0)
free(PAT_Parser.pTsPsitSecBuffTemp);
close(PAT_Parser.PsiSecHandle);
close(PMT_Parser.PsiSecHandle);
close(TSPacketHandle);
free(pbuff);
}
}
void main(void)
{
SetFilePath("F:\\FRA14-4.ts");
TsPSIParser();
TsPMTParser();
getch();
return ;
}