?? mpeg2.cpp
字號:
/***********************************************************************/
/* mpeg2.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 mpeg2 stream.
/************************************************************************/
#include "pch.h"
#include "manager.h"
#include "splitter.h"
///////////////////////////////////////////////////////////////////
CMpeg2::CMpeg2(MemManager *pMemManager) : CBitParser(pMemManager)
{
}
///////////////////////////////////////////////////////////////////
CMpeg2::~CMpeg2()
{
if (!m_bStopDemux)
StopDemux();
}
///////////////////////////////////////////////////////////////////
void CMpeg2::SetFastForward(BOOL bVal)
{
CBitParser::SetFastForward(bVal);
}
///////////////////////////////////////////////////////////////////
/****f* MMDemux/CMpeg2::Process
* USAGE
* void Process(CBuffer *pCBuffer)
* DESCRIPTION
* Processes the mpeg2 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 CMpeg2::Process(CBuffer *pCBuffer)
{
if (pCBuffer != NULL)
{
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 = ParseMpeg2System();
if (m_bStopDemux)
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/CMpeg2::ParseMpeg2System
* USAGE
* int ParseMpeg2System()
* DESCRIPTION
* Parses the mpeg2 system 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 CMpeg2::ParseMpeg2System()
{
DWORD m_dwCode = 0;
while (!m_bStopDemux)
{
m_dwCode = SyncOnNextStartCode();
if (m_bEndOfBuffer)
return END_OF_BUFFER;
if (m_dwCode == PACK_START_CODE)
{
SkipMpeg2PackHeader();
if (m_bEndOfBuffer)
return END_OF_BUFFER;
}
else if (m_dwCode == SYSTEM_START_CODE)
{
SkipSystemHeader();
if (m_bEndOfBuffer)
return END_OF_BUFFER;
}
else if ((m_dwCode == PADDING_STREAM) || (m_dwCode == PRIVATE_STREAM_2))
{
m_dwPayloadLength = GetWord();
m_dwBufferIndex += m_dwPayloadLength;
m_dwPreviousPacketIndex = m_dwBufferIndex;
}
else if (m_dwCode == PROGRAM_STREAM_MAP)
{
m_dwPayloadLength = GetWord();
m_dwBufferIndex += m_dwPayloadLength;
}
else if (((m_dwCode & 0xFFFFFFF0) == AUDIO_STREAM) ||
((m_dwCode & 0xFFFFFFF0) == VIDEO_STREAM) || (m_dwCode == AC3_PCM_DTS_STREAM))
{
if (m_dwCode == AC3_PCM_DTS_STREAM)
{
GetAc3DtsPacket();
if (m_bEndOfBuffer)
return END_OF_BUFFER;
m_bStreamType = MM_AUDIO;
m_dwAStreamId = m_bSubstreamId;
}
else
{
GetMpeg2Packet();
if (m_bEndOfBuffer)
return END_OF_BUFFER;
DWORD shiftCount = m_dwCode & 0xF;
DWORD newMask = 1 << shiftCount;
if ((m_dwCode & 0xFFFFFFF0) == VIDEO_STREAM)
{
m_bStreamType = MM_VIDEO;
m_dwVStreamId = m_dwCode;
// Determine the correct video channel to play
if (m_AVId.dwVideoStreamId == 0)
{
if (!((m_dwVideoMask >> shiftCount) & 0x1))
{
m_dwVideoMask = m_dwVideoMask | newMask;
m_wVideoChannelCount++;
if (m_wVideoChannelCount == m_wVideoChannelPlay)
m_AVId.dwVideoStreamId = m_dwCode;
MmDebugLogfile((MmDebugLevelTrace, "mpeg2 video channel %d", m_wVideoChannelCount));
}
}
}
else
{
m_bStreamType = MM_AUDIO;
m_dwAStreamId = m_dwCode;
// Determine the correct audio channel to play
if (m_AVId.dwAudioStreamId == 0)
{
if (!((m_dwAudioMask >> shiftCount) & 0x1))
{
m_dwAudioMask = m_dwAudioMask | newMask;
m_wAudioChannelCount++;
if (m_wAudioChannelCount == m_wAudioChannelPlay)
m_AVId.dwAudioStreamId = m_dwCode;
MmDebugLogfile((MmDebugLevelTrace, "mpeg1 audio channel %d", m_wAudioChannelCount));
}
}
}
}
// 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;
// If m_dwPayloadLength = 0, next buffer contains entire payload, send packet
// when next buffer arrives, including the PTS if exists. Otherwise, send it
// now then set the Pts flag to FALSE.
if (m_dwPayloadLength > 0)
{
SetMediaSampleParameters();
m_bPtsDtsFlag = FALSE; // Next packet contains only payload.
m_bNFrameHeaders = 0;
m_iFirstAccessUnit = 1;
}
return PAYLOAD_BETWEEN_2BUFFERS;
}
// We have a complete packet
m_dwBufferIndex += m_dwPayloadLength; // Move to the end of this packet
m_dwPreviousPacketIndex = m_dwBufferIndex;
SetMediaSampleParameters();
}
}
return SUCCESS_DEMUX;
}
/////////////////////////////////////////////////////////////////////////////
/****f* MMDemux/CMpeg2::SkipMpeg2PackHeader
* USAGE
* void SkipMpeg2PackHeader()
* DESCRIPTION
* Skips the pack header parameters which include system_clock_reference,
* marker_bits, stuffing bytes and program_mux_rate.
* PARAMETERS
* None.
* RETURN VALUE
* None.
/**********************************************************************/
void CMpeg2::SkipMpeg2PackHeader()
{
BYTE byte;
INT i = 0;
INT curByte = 1;
INT res_stuff = 0;
ULONGLONG m_ullScrExt = 0;
while (!m_bEndOfBuffer)
{
switch(curByte)
{
// SCR_BASE
case 1:
byte = (BYTE)GetByte();
m_ullScr = (byte & 0x38) >> 1; // 3 bits, bits 5-3 of byte 1
m_ullScr = m_ullScr | (byte & 0x03); // 2 bits, bits 1-0 of byte 1
break;
case 2:
m_ullScr = (m_ullScr << 8) | GetByte(); // 8 bits, byte 2
break;
case 3:
byte = (BYTE)GetByte();
m_ullScr = (m_ullScr << 5) | ((byte & 0xF8) >> 3); // 5 bits, bits 7-3 of byte 3
m_ullScr = (m_ullScr << 2) | (byte & 0x03); // 2 bits, bits 1-0 of byte 3
break;
case 4:
m_ullScr = (m_ullScr << 8) | GetByte(); // 8 bits, byte 4
break;
case 5:
byte = (BYTE)GetByte();
m_ullScr = (m_ullScr << 5) | ((byte & 0xF8) >> 3); // 5 bits, bits 7-3 of byte 5
break;
case 6:
m_ullScrExt = (m_ullScrExt << 8) | (GetByte() >> 1); // 7 bits, bits 7-1 of byte 6
break;
// MUX_RATE
case 7:
GetByte();
break;
case 8:
GetByte();
break;
case 9:
GetByte();
break;
case 10:
res_stuff = (BYTE)GetByte();
// Get the stuffing length, right 3 bits
res_stuff = res_stuff & 0x7; // 00000111
break;
// STUFFING_BYTE
case 11:
default:
if (i >= res_stuff)
return;
GetByte();
i++;
break;
}
curByte++;
}
}
////////////////////////////////////////////////////////////////////
/****f* MMDemux/CMpeg2::GetMpeg2Packet
* USAGE
* void GetMpeg2Packet()
* DESCRIPTION
* Parses the mpeg2 packet header.
* PARAMETERS
* None.
* RETURN VALUE
* None.
/**********************************************************************/
void CMpeg2::GetMpeg2Packet()
{
INT wPacketHeaderLength = 0;
INT wPacketLength = 0;
BYTE byte = 0;
INT curByte = 0;
m_bPtsDtsFlag = FALSE;
m_llPts = 0;
wPacketLength = (WORD)GetWord();
// Skip byte containing scrambling control, priority, alignment, copyright
// and original bits.
GetByte();
wPacketHeaderLength++;
// Get PTS, DTS, ESCR, ESRate, DSM trick mode, additional copy info, CRC and
// extension flags.
byte = (BYTE)GetByte();
wPacketHeaderLength++;
INT bPtsDtsFlag = byte >> 6; // Bits 7 & 6
INT bESCRFlag = (byte & 0x20) >> 5; // Bit 5, must be 0
INT bESRateFlag = (byte & 0x10) >> 4; // Bit 4, must be 0
INT bDSMTrickModeFlag = (byte & 0x8) >> 3; // Bit 3, must be 0
INT bAddCopyInfoFlag = (byte & 0x4) >> 2; // Bit 2, must be 0
INT bCRCFlag = (byte & 0x2) >> 1; // Bit 1, must be 0
INT bExtFlag = byte & 0x1; // Bit 0, 0 or 1
// Get Header Data Length
INT bHeaderDataLength = (BYTE)GetByte();
wPacketHeaderLength++;
// Keep current # of advanced bytes after the PES_header_data_length field.
// Use this to calculate the stuffing bytes.
INT bCurHeaderDataLength = 0;
// Get PTS
if (bPtsDtsFlag == 0x2) // '10'
{
curByte = 0;
while ((curByte < 5) && !m_bEndOfBuffer)
{
switch(curByte)
{
case 0: m_llPts = (LONGLONG(GetByte() & 0x0E) << 29); break;
case 1: m_llPts += (LONGLONG(GetByte()) << 22); break;
case 2: m_llPts += (LONGLONG(GetByte() & 0xFE) << 14); break;
case 3: m_llPts += (LONGLONG(GetByte()) << 7); break;
case 4: m_llPts += (LONGLONG(GetByte() >> 1)); break;
}
curByte++;
}
bCurHeaderDataLength += 5;
m_bPtsDtsFlag = TRUE;
}
else if(bPtsDtsFlag == 0x3) // '11' PTS and DTS present
{
curByte = 0;
while ((curByte < 10) && !m_bEndOfBuffer)
{
switch(curByte)
{
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -