📄 transport.cpp
字号:
/***********************************************************************/
/* transport.cpp :
* REALmagic Quasar Hardware Library
* Created by Kevin Vo
* Copyright 2000 Sigma Designs Inc.
* 355 Fairview Way, Milpitas, CA 95035-3024 USA. All Rights Reserved.
* Sigma Designs Proprietary and Confidential
* Created on 3/20/01
* Description: Parses the transport stream.
/************************************************************************/
#include "pch.h"
#include "manager.h"
#include "splitter.h"
///////////////////////////////////////////////////////////////////
CMpeg2Transport::CMpeg2Transport(MemManager *pMemManager) : CBitParser(pMemManager)
{
m_bProcess = FALSE;
}
///////////////////////////////////////////////////////////////////
CMpeg2Transport::~CMpeg2Transport()
{
if (!m_bStopDemux)
StopDemux();
}
///////////////////////////////////////////////////////////////////
void CMpeg2Transport::SetPlayProgram(WORD wProgram)
{
m_wProgramPlay = wProgram;
}
///////////////////////////////////////////////////////////////////
/****f* MMDemux/CMpeg2Transport::Process
* USAGE
* void Process(CBuffer *pCBuffer)
* DESCRIPTION
* Processes the transport stream.
* PARAMETERS
* CBuffer* pCBuffer - a pointer to the CBuffer object which contains
* the mpeg2.
* RETURN VALUE
* STOP_DEMUX if the buffer is NULL or StopDemux() is called; otherwise, SUCCESS_DEMUX
/**********************************************************************/
int CMpeg2Transport::Process(CBuffer *pCBuffer)
{
if (pCBuffer != NULL)
{
if (!m_bProcess)
{
m_bProcess = TRUE;
m_pVideoCBuffer = m_pMemManager->GetTSBuffer();
m_pAudioCBuffer = m_pMemManager->GetTSBuffer();
m_pVideoBuffer = (BYTE*)m_pVideoCBuffer->GetBuffer();
m_pAudioBuffer = (BYTE*)m_pAudioCBuffer->GetBuffer();
}
m_pCBuffer = pCBuffer;
// Packet is between 2 buffers, newly arrival buffer will use the previous buffer.
// The GetByte() function will move to new buffer when dwBufferIndex reaches
// the end of buffer.
if (m_bPacketBetween2Buffers)
{
m_pBuffer = (BYTE*)m_pPreviousCBuffer->GetBuffer();
// Last known packet index. This is the last packet of previous buffer.
m_dwBufferIndex = m_dwPreviousPacketIndex;
m_dwBufferSize = m_pPreviousCBuffer->GetActualSize();
}
else
{
m_dwBufferIndex = 0;
m_dwBufferSize = m_pCBuffer->GetActualSize();
m_pBuffer = (BYTE*)m_pCBuffer->GetBuffer();
// Save this buffer first. If end of buffer occurs, we still have it. When
// the next buffer arrives, we'll release it. Otherwise, we'll release it if
// END_OF_BUFFER exception isn't thrown. We'll also release it if we get
// PAYLOAD_BETWEEN_2BUFFERS exception.
m_pPreviousCBuffer = m_pCBuffer;
}
// The previous buffer contains pack header, system header, packet header
// and a portion of payload. Current buffer contains the rest of the
// payload (usually size < 2048).
if (m_bPayloadBetween2Buffers)
{
if (!GetMorePayload())
{
m_pCBuffer->Release();
return SUCCESS_DEMUX;
}
m_bPayloadBetween2Buffers = FALSE;
}
int iReturnCode = ParseMpeg2Transport();
if (m_bStopDemux)
{
m_pVideoCBuffer->Release();
m_pAudioCBuffer->Release();
return STOP_DEMUX;
}
else if (iReturnCode == END_OF_BUFFER)
{
m_bPacketBetween2Buffers = TRUE;
m_bEndOfBuffer = FALSE;
}
else
{
if (iReturnCode == PAYLOAD_BETWEEN_2BUFFERS)
m_bPayloadBetween2Buffers = TRUE;
m_pCBuffer->Release();
}
return SUCCESS_DEMUX;
}
else
{
return STOP_DEMUX;
}
}
////////////////////////////////////////////////////////////////////
/****f* MMDemux/CMpeg2Transport::ParseMpeg2Transport
* USAGE
* void ParseMpeg2Tranport()
* DESCRIPTION
* Parses the mpeg2 transport stream
* PARAMETERS
* None.
* RETURN VALUE
* STOP_DEMUX if the buffer is NULL or StopDemux() is called.
* SUCCESS_DEMUX
* END_OF_BUFFER - End of buffer is reached while parsing the stream.
* PAYLOAD_BETWEEN_2BUFFERS -
/**********************************************************************/
int CMpeg2Transport::ParseMpeg2Transport()
{
BYTE bCode = 0;
DWORD dwPreBufferIndex = 0;
while (!m_bStopDemux)
{
bCode = (BYTE)GetByte();
if (m_bEndOfBuffer)
return END_OF_BUFFER;
if (bCode == M2T_SYNC_BYTE)
{
// This TS packet might not be the correct one. If this happens,
// we'll use this index to continue searching for next sync byte.
dwPreBufferIndex = m_dwBufferIndex;
int iResult = GetTransportPacket();
if (m_bEndOfBuffer)
return END_OF_BUFFER;
else if (iResult == 1)
{
// End of buffer. Payload is between 2 buffers.
if ((m_dwBufferIndex + m_dwPayloadLength) >= m_dwBufferSize)
{
m_dwRightPayloadLength = m_dwPayloadLength - (m_dwBufferSize - m_dwBufferIndex);
m_dwPayloadLength = m_dwBufferSize - m_dwBufferIndex;
// m_dwPayloadLength = 0, next buffer contains entire payload.
SetMediaSampleParameters();
return PAYLOAD_BETWEEN_2BUFFERS;
}
// We have a complete packet.
m_dwBufferIndex += m_dwPayloadLength; // Move to first byte of next packet
m_dwPreviousPacketIndex = m_dwBufferIndex;
SetMediaSampleParameters();
}
else if (iResult == -1)
m_dwBufferIndex = dwPreBufferIndex;
}
}
return SUCCESS_DEMUX;
}
////////////////////////////////////////////////////////////////////
/****f* MMDemux/CMpeg2Transport::GetTransportPacket
* USAGE
* int GetTransportPacket()
* DESCRIPTION
* Parses the mpeg2 transport stream packet.
* PARAMETERS
* None.
* RETURN VALUE
* Returns 1 if TS payload presents, 0 if not, -1 if it is an
* invalid TS packet.
/**********************************************************************/
int CMpeg2Transport::GetTransportPacket()
{
BYTE byte = 0;
INT bPreContCounter = 0;
INT wLength = 0;
INT wPrePid = 0;
// Number of bytes have moved so far in the TS packet after the sync byte.
INT wBytesAdvanced = 0;
byte = (BYTE)GetByte();
// BOOL bTransportError = (byte & 0x80) >> 7; // Bit 7
INT bPayloadStart = (byte & 0x40) >> 6; // Bit 6
// BOOL bTransportPriority = (byte & 0x20) >> 5; // Bit 5
wPrePid = m_wPid;
m_wPid = byte & 0x1F; // Bits 4-0
m_wPid = (m_wPid << 8) | (BYTE)GetByte();
byte = (BYTE)GetByte();
INT bScrambling = (byte & 0xC0) >> 6; // Bit 7 & 6
INT bAdaptFieldCtrl = (byte & 0x30) >> 4; // Bit 5 & 4
bPreContCounter = m_bContCounter;
m_bContCounter = byte & 0xF; // Bits 3-0
wBytesAdvanced += 3;
m_bPesPayload = FALSE;
// Adaptation field presents
if ((bAdaptFieldCtrl == 0x2) || (bAdaptFieldCtrl == 0x3))
{
int bAdaptFieldLength = GetAdaptationField(bAdaptFieldCtrl);
if (bAdaptFieldLength == -1)
return -1;
wBytesAdvanced += bAdaptFieldLength;
}
// Payload presents
if ((bAdaptFieldCtrl == 0x1) || (bAdaptFieldCtrl == 0x3))
{
// In the case where the discontinuity state is TRUE, if 2 consecutive TS packets
// of the same PID occur which have the same continuity counter and have adaptation
// field control values set to '01' or '11', the 2nd packet may be discarded.
if ((wPrePid == m_wPid) && (bPreContCounter == m_bContCounter) && m_bDiscIndicator)
{
m_dwPayloadLength = 187 - wBytesAdvanced;
return 1;
}
if (m_wPid == 0x1FFF) // Null packet
{
// Invalid TS packet?
if ((bPayloadStart != 0) || (bAdaptFieldCtrl != 1) || (bScrambling != 0))
return -1;
// Advance to first byte of next packet.
m_dwPayloadLength = 187 - wBytesAdvanced;
return 1;
}
// Either PES packet or PSI data presents
else if (bPayloadStart == 1)
{
// Attempting to get the PES packet header. First 4 bytes of the payload.
DWORD dwSyncCode = GetDWord();
// Above 4 bytes are not at the end of TS packet which can throw exception if
// they are. We need to go back to the beginning of the payload.
m_dwBufferIndex -= 4;
if (((dwSyncCode & 0xFFFFFFF0) == AUDIO_STREAM) ||
((dwSyncCode & 0xFFFFFFF0) == VIDEO_STREAM) || (dwSyncCode == AC3_PCM_DTS_STREAM))
{
m_dwBufferIndex += 4;
wBytesAdvanced += 4;
if ((dwSyncCode & 0xFFFFFFF0) == VIDEO_STREAM)
{
m_bVideoPesHeader = TRUE; // New video PES payload
m_bStreamType = MM_VIDEO;
wLength = StripPESPacketHeader();
m_llVideoPts = m_llPts;
m_bVideoPtsFlag = m_bPtsDtsFlag;
}
else
{
m_bAudioPesHeader = TRUE; // New audio PES payload
m_bStreamType = MM_AUDIO;
if (dwSyncCode == AC3_PCM_DTS_STREAM)
wLength = StripAc3PESPacketHeader();
else
wLength = StripPESPacketHeader();
m_llAudioPts = m_llPts;
m_bAudioPtsFlag = m_bPtsDtsFlag;
}
wBytesAdvanced += wLength;
m_dwPayloadLength = 187 - wBytesAdvanced;
m_bPayloadPtr = m_pBuffer + m_dwBufferIndex;
m_bPesPayload = TRUE;
return 1;
}
else if (dwSyncCode == PADDING_STREAM || dwSyncCode == PRIVATE_STREAM_2 ||
dwSyncCode == PROGRAM_STREAM_MAP || dwSyncCode == ECM_STREAM ||
dwSyncCode == EMM_STREAM || dwSyncCode == PROGRAM_STREAM_DIR ||
dwSyncCode == DSMCC_STREAM || dwSyncCode == TYPE_E_STREAM ||
dwSyncCode == 0x000001B5 || dwSyncCode == 0x000001BA ||
dwSyncCode == 0x000001B3)
{
m_dwPayloadLength = 187 - wBytesAdvanced;
return 1;
}
// Not a PES header. PSI section?
BYTE bPointerField = (BYTE)GetByte();
if (bPointerField > (187 - wBytesAdvanced))
return -1;
// Move the buffer index to the first byte of the section while checking
// for end of buffer.
for (int j = 0; j < bPointerField; j++)
GetByte();
BYTE bTableId = (BYTE)GetByte();
if ((bTableId == 0) || (bTableId == 1) || (bTableId == 2) ||
(bTableId >= 0x40 && bTableId <= 0xFE))
{
wBytesAdvanced += (bPointerField + 2);
switch (bTableId)
{
case 0: // Program association table (section)
if (m_wPid != 0)
return -1;
wLength = GetPASection();
break;
case 1: // Conditional access table (section)
if ((m_wPid != 0) || (bScrambling == 0))
return -1;
wLength = GetCASection();
break;
case 2: // Program Map Table (section). Look for stream type.
if (m_wPid < 0x00010 || m_wPid > 0x1FFE)
return -1;
wLength = GetPMSection();
break;
default:
// wLength = GetPrivateSection();
break;
}
wBytesAdvanced += wLength;
// Don't think there's PES payload after each section table.
// Advance to first byte of next packet.
m_dwPayloadLength = 187 - wBytesAdvanced;
return 1;
}
// No PES header nor PSI section. PES payload then.
else if (m_wPid == m_ProgDef.iVideoElemStreamId || m_wPid == m_ProgDef.iAudioElemStreamId)
{
// Move the buffer index back
m_dwBufferIndex -= (bPointerField + 2);
(m_wPid == m_ProgDef.iVideoElemStreamId) ? (m_bStreamType = MM_VIDEO) : (m_bStreamType = MM_AUDIO);
m_dwPayloadLength = 187 - wBytesAdvanced;
m_bPayloadPtr = m_pBuffer + m_dwBufferIndex;
m_bPesPayload = TRUE;
return 1;
}
else
{
// Move the buffer index back
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -