Commit 44fce2b4 authored by Cyril Deguet's avatar Cyril Deguet

These files were not to be removed !

parent b59b5ff8
/*******************************************************************************
* ps2ts.cpp: MPEG1 and MPEG2 PS to MPEG2 TS converter
*-------------------------------------------------------------------------------
* (c)1999-2001 VideoLAN
* $Id: ps2ts.cpp,v 1.3 2002/04/27 01:17:44 asmax 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_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_bDiscontinuity = false;
ZERO(m_pCurrentData);
m_bSendPSI = false;
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)
{
m_bSendPSI = false;
m_iTSCounter += 2;
// printf("!!! Sending PSI !!!\n");
ASSERT(m_iMaxBufferedTs >= 2);
// Push the PAT
C_TsPacket* pPacket = m_pTsProvider->GetPacket();
ASSERT(pPacket);
m_cPgrmDescriptor.WritePAT(pPacket);
m_cPendingTS.PushEnd(pPacket);
// Now push the PMT
ZERO(pPacket);
pPacket = m_pTsProvider->GetPacket();
ASSERT(pPacket);
m_cPgrmDescriptor.WritePMT(pPacket);
m_cPendingTS.PushEnd(pPacket);
}
else
{
int iRc = FetchPackets();
if(iRc)
{
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);
}
else
{
// 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_iTSCounter % 500 <= m_iMaxBufferedTs);
// printf("mitscounter: %d\n", m_iTSCounter);
}
}
}
// 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 = 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);
// Build the TS header to put this date
*pPosInTs = pPacket->BuildAdaptionField(iSCR);
}
else
{
// Parse the SCR (MPEG2 format)
u64 iHighBits = m_bBuff[START_CODE_LEN] & 0x38;
u64 iMiddleBits = U32_AT(m_bBuff[START_CODE_LEN]) & 0x03FFF800;
u64 iLowBits = U32_AT(m_bBuff[START_CODE_LEN+2]) & 0x03FFF800;
ASSERT((m_bBuff[START_CODE_LEN] & 0x4));
ASSERT((m_bBuff[START_CODE_LEN+2] & 0x4));
ASSERT((m_bBuff[START_CODE_LEN+4] & 0x4));
u64 iSCR = iHighBits << 27 | iMiddleBits << 4 | iLowBits >> 11;
// Kludge pour tester horloge
// struct timeval sTimeval;
// gettimeofday(&sTimeval, NULL);
// printf("Date mpeg2: %Ld, date systeme %d (en s)\n", iSCR, sTimeval.tv_sec);
// Build the TS header to put this date
*pPosInTs = pPacket->BuildAdaptionField(iSCR);
// if(iSCR - m_iPrevSCR > 800)
// printf("time : %Ld ; delta : %Ld\n", iSCR, iSCR - m_iPrevSCR);
if(m_iPrevSCR >= iSCR)
{
printf("Time discontinuity in PS stream\n");
m_bDiscontinuity = true;
}
m_iPrevSCR = iSCR;
// Read additional stuffing bytes if any (MPEG2 only)
if(m_iPackHeaderLen == 10 + START_CODE_LEN)
{
iStuffLen = m_bBuff[m_iPackHeaderLen-1] & 0x7;
if(iStuffLen && !iRc)
{
iRc = m_pReader->Read(m_bBuff+LOOK_AHEAD_LEN+m_iPackHeaderLen, iStuffLen);
ASSERT(iRc >= 0);
iRc = (iRc != iStuffLen);
}
// printf("Stuffing of size %d found: actual length is: %d\n", iStuffLen, m_iPackHeaderLen+iStuffLen);
}
}
// Look Ahead of 6
m_iDataType = U32_AT(m_bBuff[m_iPackHeaderLen+iStuffLen]);
m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
m_iDataLen = U16_AT(m_bBuff[m_iPackHeaderLen+iStuffLen+START_CODE_LEN]);
m_bPESStart = true;
//printf("Next data will be: %X (len: %d)\n", m_iNextData, m_iNextLength);
// printf("Next data will be: %X (len: %d)\n", m_iDataType, m_iDataLen);
return iRc;
}
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
template <class Reader, class TsProvider>
int C_Ps2Ts<Reader, TsProvider>::ParseSystemHeader(C_TsPacket* pPacket, u8* iPosInTs)
{
// printf("Parsing SYSTEM_HEADER\n");
int iRc = m_pReader->Read(m_bBuff, m_iDataLen+LOOK_AHEAD_LEN);
ASSERT(iRc >= 0);
iRc = (iRc != m_iDataLen+LOOK_AHEAD_LEN);
// printf("Length: %d\n", m_iDataLen);
m_iDataType = U32_AT(m_bBuff[m_iDataLen]);
m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
m_iDataLen = U16_AT(m_bBuff[m_iDataLen+START_CODE_LEN]);
return iRc;
}
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
template <class Reader, class TsProvider>
int C_Ps2Ts<Reader, TsProvider>::ParsePES(C_TsPacket* pPacket, u8* pPosInTs)
{
ASSERT(pPacket);
ASSERT(pPosInTs);
// Pour le debug uniquement
// if(m_bPESStart)
// {
// printf("Parsing PES of type %x\n", m_iDataType);
// printf("PES Length: %d (without the 6 first bytes)\n", m_iDataLen);
// }
// else
// printf("Continuing to parse PES (remaining length: %d)\n", m_iDataLen);
// This variable only exists to speed up the process of looking the value of
// pPosInTs
u8 iPos;
// Write the data in the TS that depends on our position in the PES
if(m_bPESStart)
{
// Write the header with the bUnitStart flag set to true
ASSERT(m_pCurrentData);
ASSERT(m_pCurrentData->GetId() == (m_iDataType&0xFF));
u8 iCounter = m_pCurrentData->GetCounter();
u16 iPid = m_pCurrentData->GetPid();
iPos = pPacket->BuildHeader(iPid, true, iCounter);
// We can have parsed an adaption field if the PES comes just after a
// pack header
if(iPos < *pPosInTs)
{
if(iPid == m_cPgrmDescriptor.GetPcrPid())
{
// The adaption_field_control has been overwritten so that the bit
// which indicates an adaption_field is no more set to 1
byte* pTsPayload = (byte*)(*pPacket);
pTsPayload[iPos-1] |= 0x20;
// Set the right position
iPos = *pPosInTs;
if(m_bDiscontinuity)
{
ASSERT(pPacket->HasPCR());
ASSERT(pPacket->SetDiscontinuityFlag());
pPacket->SetDiscontinuityFlag();
m_bDiscontinuity = false;
}
}
}
// Write the beginning of the PES packet (corresponds to the look ahead)
byte* pTsPayload = (byte*)(*pPacket);
SET_U32_TO(pTsPayload[iPos], m_iDataType);
SET_U16_TO(pTsPayload[iPos+START_CODE_LEN], m_iDataLen);
iPos += START_CODE_LEN + PES_SIZE_LEN;
}
else
{
// We shouldn't have any adaption field
ASSERT(*pPosInTs == 0);
// Write the header with the bUnitStart flag set to false
ASSERT(m_pCurrentData);
ASSERT(m_pCurrentData->GetId() == (m_iDataType&0xFF));
u8 iCounter = m_pCurrentData->GetCounter();
u16 iPid = m_pCurrentData->GetPid();
iPos = pPacket->BuildHeader(iPid, false, iCounter);
}
// Now read the data carried in the PES
for(unsigned int i = 0; i < m_iMaxBufferedTs; i++)
{
// Fill the Ts packet
if(m_iDataLen >= TS_PACKET_LEN - iPos)
{
// Fill the remaining payload of the TS packet
m_iStatus = m_pReader->Read(((byte*)(*pPacket)+iPos), TS_PACKET_LEN-iPos);
ASSERT(m_iStatus >= 0);
m_iStatus = (m_iStatus != TS_PACKET_LEN-iPos);
m_iDataLen -= (TS_PACKET_LEN-iPos);
//-----------------
if(m_bPESStart)
{
if(*((byte*)(*pPacket) + iPos - 3) == PES_ID_PRIVATE_1)
{
// printf("Id : 0x%x", *((byte*)(*pPacket) + iPos - 3));
u8 iOffset = *((byte*)(*pPacket) + iPos + 2);
// printf(" Offset : 0x%x", iOffset);
u8 iPrivateId = *((byte*)(*pPacket) + iPos + 3 + iOffset);
// printf(" PrivateId : 0x%x", iPrivateId);
/* if((iPrivateId & 0xf0) == 0x80)
{*/
m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF,
iPrivateId);
u16 iPid = m_pCurrentData->GetPid();
u16 iData = U16_AT(*((byte*)(pPacket) + 1));
// printf(" Data : 0x%x", iData);
iPid = (iPid & 0x1fff) | (iData & 0xe000);
// printf(" NewPid : 0x%x", iPid);
SET_U16_TO(*((byte*)(pPacket) + 1), iPid);
*((byte*)(pPacket) + 3) = (m_pCurrentData->GetCounter() & 0x0f) |
(*((byte*)(pPacket) + 3) & 0xf0);
/* }*/
// printf("\n");
}
}
//-----------------
}
else
{
// m_iDataLen shouldn't be null
ASSERT(m_iDataLen > 0);
// printf("Stuffing needed: iPos=%d, DataLen=%d\n", iPos, m_iDataLen);
// Write the end of the PES packet in the TS packet
if(m_bPESStart)
{
// We have already written the PES start code and the pes length at the
// beginning of the TS packet, which will be erased by the stuffing bytes:
// we must rewrite them
iPos = pPacket->AddStuffingBytes(m_iDataLen+START_CODE_LEN+PES_SIZE_LEN);
byte* pTsPayload = (byte*)(*pPacket);
SET_U32_TO(pTsPayload[iPos], m_iDataType);
SET_U16_TO(pTsPayload[iPos+START_CODE_LEN], m_iDataLen);
iPos += START_CODE_LEN+PES_SIZE_LEN;
}
else
{
// Simply add the stuffing bytes at the end of the TS header
iPos = pPacket->AddStuffingBytes(m_iDataLen);
}
m_iStatus = m_pReader->Read(((byte*)(*pPacket)+iPos), m_iDataLen);
ASSERT(m_iStatus >= 0);
m_iStatus = (m_iStatus != m_iDataLen);
//-----------------
if(m_bPESStart)
{
if(*((byte*)(*pPacket) + iPos - 3) == PES_ID_PRIVATE_1)
{
// printf("Id : 0x%x", *((byte*)(*pPacket) + iPos - 3));
u8 iOffset = *((byte*)(*pPacket) + iPos + 2);
// printf(" Offset : 0x%x", iOffset);
u8 iPrivateId = *((byte*)(*pPacket) + iPos + 3 + iOffset);
// printf(" PrivateId : 0x%x", iPrivateId);
/* if((iPrivateId & 0xf0) == 0x80)
{*/
m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF,
iPrivateId);
u16 iPid = m_pCurrentData->GetPid();
u16 iData = U16_AT(*((byte*)(pPacket) + 1));
// printf(" Data : 0x%x", iData);
iPid = (iPid & 0x1fff) | (iData & 0xe000);
// printf(" NewPid : 0x%x", iPid);
SET_U16_TO(*((byte*)(pPacket) + 1), iPid);
*((byte*)(pPacket) + 3) = (m_pCurrentData->GetCounter() & 0x0f) |
(*((byte*)(pPacket) + 3) & 0xf0);
/* }*/
// printf("\n");
}
}
//-----------------
// All data have been read
m_iDataLen = 0;
}
// We are no more at the beginning of the PES yet
m_bPESStart = false;
// Put the TS packet in the list of pending TS
m_cPendingTS.PushEnd(pPacket);
ZERO(pPacket);
// Increase the number of TS packets that have been build
m_pCurrentData->IncreaseCounter();
m_iTSCounter++;
// Prepare the next iteration if we must loop
if(m_iDataLen > 0)
{
// There is a second condition for looping since we don't read
// the complete PES in a single operation
if(i < m_iMaxBufferedTs - 1)
{
// Get another TS packet to fill
pPacket = m_pTsProvider->GetPacket();
ASSERT(pPacket);
// Build the new TS header
ASSERT(m_pCurrentData);
ASSERT(m_pCurrentData->GetId() == (m_iDataType&0xFF));
u8 iCounter = m_pCurrentData->GetCounter();
u16 iPid = m_pCurrentData->GetPid();
iPos = pPacket->BuildHeader(iPid, false, iCounter);
}
}
else
{
// Look ahead for next iteration
m_iStatus = m_pReader->Read(m_bBuff, LOOK_AHEAD_LEN);
ASSERT(m_iStatus >= 0);
m_iStatus = (m_iStatus != LOOK_AHEAD_LEN);
m_iDataType = U32_AT(m_bBuff[0]);
m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
m_iDataLen = U16_AT(m_bBuff[4]);
m_bPESStart = true;
// printf("Next data will be: %x (len = %d)\n", m_iDataType, m_iDataLen);
// Don't loop
break;
}
}
return m_iStatus;
}
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
template <class Reader, class TsProvider>
int C_Ps2Ts<Reader, TsProvider>::SkipPES(C_TsPacket* pPacket, u8* iPosInTs)
{
// Release the TS packet, we won't need it
m_pTsProvider->ReleasePacket(pPacket);
int iRc = m_pReader->Seek(m_iDataLen, SEEK_CUR);
if(iRc)
m_iStatus = FILE_ERR;
else
{
// Look ahead for next iteration
m_iStatus = m_pReader->Read(m_bBuff, LOOK_AHEAD_LEN);
ASSERT(m_iStatus >= 0);
m_iStatus = (m_iStatus != LOOK_AHEAD_LEN);
m_iDataType = U32_AT(m_bBuff[0]);
m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
m_iDataLen = U16_AT(m_bBuff[4]);
m_bPESStart = true;
// printf("Next data will be: %x (len = %d)\n", m_iDataType, m_iDataLen);
if(m_iStatus == NO_ERR)
m_iStatus = SKIPPED_DATA;
}
return m_iStatus;
}
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
template <class Reader, class TsProvider>
int C_Ps2Ts<Reader, TsProvider>::ParsePgrmMap(C_TsPacket* pPacket, u8* iPosInTs)
{
// printf("Parsing pgrm map PES: WARNING, code never tested\n");
// printf("Pgrm map length: %d\n", m_iDataLen);
ASSERT(false);
while(m_iDataLen >= sizeof(m_bBuff))
{
/* int iRc = */m_pReader->Read(m_bBuff, sizeof(m_bBuff));
m_iDataLen -= sizeof(m_bBuff);
}
// push PAT et PMT dans la liste des pendingpackets
return NO_ERR;
}
/*******************************************************************************
* ps2ts.h: MPEG1 and MPEG2 PS to TS converter
*-------------------------------------------------------------------------------
* (c)1999-2001 VideoLAN
* $Id: ps2ts.h,v 1.3 2002/04/27 01:17:44 asmax 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.
*
*-------------------------------------------------------------------------------
* Note: since the compiler also need the generic implementation code of the
* template to build the type specific byte code, the .cpp file must have to be
* also included in the source file
*
*******************************************************************************/
#ifndef _PS2TS_H_
#define _PS2TS_H_
template <class Reader, class TsProvider> class C_Ps2Ts
{
public:
C_Ps2Ts(Reader* pReader, TsProvider* pTsProvider, unsigned int iMaxBufferedTs,
unsigned int iMpegVersion);
~C_Ps2Ts();
// Find the first pack header in the stream
int Synch();
//
C_TsPacket* GetPacket();
// To check whenever GetPacket returns NULL
int GetStatus() { return m_iStatus; };
C_ProgramDescriptor* GetPgrmDescriptor() { return &m_cPgrmDescriptor; };
protected:
int FetchPackets();