?? ps2ts.cpp
字號:
/******************************************************************************** ps2ts.cpp: MPEG1 and MPEG2 PS to MPEG2 TS converter*-------------------------------------------------------------------------------* (c)1999-2001 VideoLAN* $Id: ps2ts.cpp,v 1.4 2002/05/14 22:10:08 bozo Exp $** Authors: Benoit Steiner <benny@via.ecp.fr>* Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr>** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License* as published by the Free Software Foundation; either version 2* of the License, or (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.**-------------------------------------------------------------------------------* TO DO: Fonction de lecture d'un TS -> Si erreur, alors le flag bEror est mis********************************************************************************///------------------------------------------------------------------------------// Preamble//------------------------------------------------------------------------------// There is no preamble since this file is to be included in the files which// use the template: look at vector.h for further explanation//------------------------------------------------------------------------------// Local definitions//------------------------------------------------------------------------------// Status#define SKIPPED_DATA -97#define UNKNOWN_DATA -98#define END_OF_STREAM -99//------------------------------------------------------------------------------////------------------------------------------------------------------------------template <class Reader, class TsProvider> C_Ps2Ts<Reader, TsProvider>::C_Ps2Ts(Reader* pReader, TsProvider* pTsProvider, unsigned int iMaxBufferedTs, unsigned int iMpegVersion) : m_cPgrmDescriptor(iMpegVersion), m_cPat(0, 0, 0), m_cPmt(0, 0, 0, 0, 0x50), m_cPendingTS(NO){ ASSERT(pReader); ASSERT(pTsProvider); ASSERT(iMaxBufferedTs > 1); ASSERT(iMpegVersion == 1 || iMpegVersion == 2); m_pReader = pReader; m_pTsProvider = pTsProvider; m_iMaxBufferedTs = iMaxBufferedTs; m_iDataType = UNKNOWN_DATA; m_iStatus = NO_ERR; m_pDelayedPacket = NULL; m_bDiscontinuity = false; ZERO(m_pCurrentData); m_bSendPSI = m_bGenPat = m_bGenPmt = m_bResetPSI = true; m_iTSCounter = 0; if(iMpegVersion == 1) m_iPackHeaderLen = MPEG1_PACK_HEADER_LEN; else m_iPackHeaderLen = MPEG2_PACK_HEADER_LEN;}//------------------------------------------------------------------------------////------------------------------------------------------------------------------template <class Reader, class TsProvider> C_Ps2Ts<Reader, TsProvider>::~C_Ps2Ts(){ // The packets belong to the netlist, so don't delete them twice for(unsigned int i = 0; i < m_cPendingTS.Size(); i++) { C_TsPacket* pPacket = m_cPendingTS.Remove(0); ASSERT(pPacket); m_pTsProvider->ReleasePacket(pPacket); }}//------------------------------------------------------------------------------////------------------------------------------------------------------------------// The data in the buffer can be anything: only rely on DataType and DataLen//------------------------------------------------------------------------------template <class Reader, class TsProvider> int C_Ps2Ts<Reader, TsProvider>::Synch(){ int iRc = m_pReader->Read(m_bBuff, START_CODE_LEN); ASSERT(iRc >= 0); m_iStatus = (iRc != START_CODE_LEN); unsigned int iPos = START_CODE_LEN; // Check the last bytes read to look for a start code while((U32_AT(m_bBuff[iPos-START_CODE_LEN]) != PES_H_PACK_HEADER) && !m_iStatus) { iRc = m_pReader->Read(m_bBuff+iPos, 1); ASSERT(iRc >= 0); m_iStatus = (iRc != 1); iPos++; if(iPos >= sizeof(m_bBuff)) { printf("Looping in Synch !!!!!!!!! (buffer size=%d)\n", sizeof(m_bBuff)); memcpy(m_bBuff, &m_bBuff[sizeof(m_bBuff)-(START_CODE_LEN-1)], (START_CODE_LEN-1)); iPos = START_CODE_LEN-1; } } // Check the last bytes read to detect why we left the loop if(U32_AT(m_bBuff[iPos-START_CODE_LEN]) != PES_H_PACK_HEADER) { // We left the while loop because of a read error m_iStatus = GEN_ERR; } else { printf("Synchronised with PS stream\n"); m_iDataType = PES_H_PACK_HEADER; iRc = m_pReader->Read(m_bBuff+iPos, PES_SIZE_LEN); ASSERT(iRc >= 0); m_iStatus = (iRc != PES_SIZE_LEN); m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF); m_iDataLen = U16_AT(m_bBuff[iPos]); } return m_iStatus;}//------------------------------------------------------------------------------////------------------------------------------------------------------------------template <class Reader, class TsProvider> C_TsPacket* C_Ps2Ts<Reader, TsProvider>::GetPacket(){ if(m_cPendingTS.Size() == 0) { if(!m_bSendPSI) { if(m_pDelayedPacket) { m_cPendingTS.PushEnd(m_pDelayedPacket); m_pDelayedPacket = NULL; } else { int iRc = FetchPackets(); if(iRc && !m_bSendPSI) { do { if(iRc == UNKNOWN_DATA) { iRc = Synch(); if(!iRc) iRc = FetchPackets(); } else if(iRc == SKIPPED_DATA) iRc = FetchPackets(); } while((iRc == SKIPPED_DATA || iRc == UNKNOWN_DATA) && !m_bSendPSI); } else if(!m_bSendPSI) { // Check if we will have to insert PSI on the next iteration: we // add the PSI in the stream every half second // (For 1.5 Mbps streams, about 1000 TS packets are sent every second) m_bSendPSI = m_bResetPSI = (m_iTSCounter % 500 <= m_iMaxBufferedTs);// printf("mitscounter: %d\n", m_iTSCounter); } } } if(m_bSendPSI) { if(m_bGenPat) { *m_cPat.GetLowLevelPat() = m_cPgrmDescriptor.m_sPat; m_cPat.Generate(); m_cPat.GetLowLevelPat()->p_first_program = NULL; m_bGenPat = false; } if(m_bGenPmt) { m_cPgrmDescriptor.m_sPmt.i_version = (m_cPgrmDescriptor.m_sPmt.i_version + 1) & 0x1f; *m_cPmt.GetLowLevelPmt() = m_cPgrmDescriptor.m_sPmt; m_cPmt.Generate(); m_cPmt.GetLowLevelPmt()->p_first_es = NULL; m_cPmt.GetLowLevelPmt()->p_first_descriptor = NULL; m_bGenPmt = false; } if(m_bResetPSI) { m_cPat.TsReset(); m_cPmt.TsReset(); m_bResetPSI = false; } for(unsigned int i = m_cPendingTS.Size(); i < m_iMaxBufferedTs; i++) { C_TsPacket* pPacket = m_pTsProvider->GetPacket(); ASSERT(pPacket); if(m_cPat.TsHasNext()) { m_cPat.TsWrite(pPacket); m_cPendingTS.PushEnd(pPacket); m_iTSCounter++; } else if(m_cPmt.TsHasNext()) { m_cPmt.TsWrite(pPacket); m_cPendingTS.PushEnd(pPacket); m_iTSCounter++; } else { m_bSendPSI = false; m_pTsProvider->ReleasePacket(pPacket); if(m_pDelayedPacket) { m_cPendingTS.PushEnd(m_pDelayedPacket); m_pDelayedPacket = NULL; } } if(!m_cPat.TsHasNext() && !m_cPmt.TsHasNext()) m_bSendPSI = false; } } } ASSERT(m_cPendingTS.Size() > 0); ASSERT(m_cPendingTS.Size() <= m_iMaxBufferedTs); // Return the first packet if(m_cPendingTS.Size() > 0) return m_cPendingTS.Remove(0); else return NULL;}//------------------------------------------------------------------------------////------------------------------------------------------------------------------template <class Reader, class TsProvider> int C_Ps2Ts<Reader, TsProvider>::FetchPackets(){ ASSERT(!m_iStatus || m_iStatus == SKIPPED_DATA || m_iStatus == UNKNOWN_DATA); u8 iPosInTs = 0; C_TsPacket* pPacket = m_pTsProvider->GetPacket(); ASSERT(pPacket); // Handle the pack header if any at the current position in the stream if(m_iDataType == PES_H_PACK_HEADER) { m_iStatus = ParsePackHeader(pPacket, &iPosInTs); // There also can be a system header following the pack header if(m_iDataType == PES_H_SYSTEM_HEADER && !m_iStatus) { m_iStatus = ParseSystemHeader(pPacket, &iPosInTs); } // Leave now if something wrong occured if(m_iStatus != NO_ERR) return GEN_ERR; } // No we must have reached the beginning of a PES packet or the end of // the stream if(IsDataPesHeader(m_iDataType)) { // This is a data PES m_iStatus = ParsePES(pPacket, &iPosInTs); } else { // This is a control PES switch(m_iDataType) { case PES_H_PADDING: {// printf("Padding pes encountered\n"); //m_iStatus = ParsePadding(pPacket, &iPosInTs); m_iStatus = ParsePES(pPacket, &iPosInTs); break; } case PES_H_PGRM_MAP: {// printf("Program map pes encountered\n"); m_iStatus = ParsePgrmMap(pPacket, &iPosInTs); // A foutre dans parse pgrm_map_pes quand le pes est completement fini m_bSendPSI = m_bResetPSI = true; break; } case PES_H_PRIVATE_2: case PES_H_PGRM_DIR: { // Not interessting -> Trash// printf("not interesting pes encountered -> trash \n"); m_iStatus = SkipPES(pPacket, &iPosInTs); break; } case PES_H_END_OF_PS: { // Just return NULL printf("end of ps encountered\n"); m_pTsProvider->ReleasePacket(pPacket); m_iStatus = END_OF_STREAM; break; } default: { printf("unknown packet (%x) encoutered\n", m_iDataType); m_pTsProvider->ReleasePacket(pPacket); m_iStatus = UNKNOWN_DATA; } } } return m_iStatus;}//------------------------------------------------------------------------------////------------------------------------------------------------------------------template <class Reader, class TsProvider> int C_Ps2Ts<Reader, TsProvider>::ParsePackHeader(C_TsPacket* pPacket, u8* pPosInTs){ ASSERT(pPacket);// printf("Parsing PACK_HEADER\n"); int iRc = m_pReader->Read(m_bBuff+LOOK_AHEAD_LEN, m_iPackHeaderLen); ASSERT(iRc >= 0); iRc = (iRc != m_iPackHeaderLen); // No stuffing by default u8 iStuffLen = 0; if(m_iPackHeaderLen == MPEG1_PACK_HEADER_LEN) { // Parse the SCR (MPEG1 format) u64 iHighBits = m_bBuff[START_CODE_LEN] & 0x0E; u64 iMiddleBits = U16_AT(m_bBuff[START_CODE_LEN+1]) & 0xFFFE; u64 iLowBits = U16_AT(m_bBuff[START_CODE_LEN+3]) & 0xFFFE; ASSERT((m_bBuff[START_CODE_LEN] & 0x01)); ASSERT((m_bBuff[START_CODE_LEN+2] & 0x01)); ASSERT((m_bBuff[START_CODE_LEN+4] & 0x01)); u64 iSCR = iHighBits << 29 | iMiddleBits << 14 | iLowBits >> 1;// printf("Date mpeg1: %Ld\n", iSCR);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -