?? mpeg1.cpp
字號:
/***********************************************************************/
/* mpeg1.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 mpeg1 stream.
/************************************************************************/
#include "pch.h"
#include "manager.h"
#include "splitter.h"
///////////////////////////////////////////////////////////////////
CMpeg1::CMpeg1(MemManager *pMemManager) : CBitParser(pMemManager)
{
}
///////////////////////////////////////////////////////////////////
CMpeg1::~CMpeg1()
{
if (!m_bStopDemux)
StopDemux();
}
///////////////////////////////////////////////////////////////////
/****f* MMDemux/CMpeg1::Process
* USAGE
* void Process(CBuffer *pCBuffer)
* DESCRIPTION
* Processes the mpeg1 stream.
* PARAMETERS
* CBuffer* pCBuffer - a pointer to the CBuffer object which contains
* the mpeg1.
* RETURN VALUE
* STOP_DEMUX if the buffer is NULL or StopDemux() is called; otherwise, SUCCESS_DEMUX
/**********************************************************************/
int CMpeg1::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 = ParseMpeg1System();
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/CMpeg1::ParseMpeg1System
* USAGE
* void ParseMpeg1System()
* DESCRIPTION
* Parses the mpeg1 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 CMpeg1::ParseMpeg1System()
{
DWORD m_dwCode = 0;
while (!m_bStopDemux)
{
m_dwCode = SyncOnNextStartCode();
if (m_bEndOfBuffer)
return END_OF_BUFFER;
if (m_dwCode == PACK_START_CODE)
{
SkipMpeg1PackHeader(); // Can re-throw an exception if end of buffer
if (m_bEndOfBuffer)
return END_OF_BUFFER;
}
else if (m_dwCode == SYSTEM_START_CODE)
{
SkipSystemHeader(); // Can re-throw an exception if end of buffer
if (m_bEndOfBuffer)
return END_OF_BUFFER;
}
else if (((m_dwCode & 0xFFFFFFF0) == AUDIO_STREAM) ||
((m_dwCode & 0xFFFFFFF0) == VIDEO_STREAM))
{
GetMpeg1Packet();
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, "mpeg1 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.
}
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/CMpeg1::SkipMpeg1PackHeader
* USAGE
* void SkipMpeg1PackHeader()
* DESCRIPTION
* Parses the mpeg1 pack header.
* PARAMETERS
* None.
* RETURN VALUE
* None.
/**********************************************************************/
void CMpeg1::SkipMpeg1PackHeader()
{
m_ullScr = 0;
// System clock reference bytes and marker bits (5 bytes - 33 bits).
m_ullScr = (GetByte() >> 1) & 0x7; // 3 bits, bits 3-1
m_ullScr = (m_ullScr << 8) & GetByte(); // 8 bits
m_ullScr = (m_ullScr << 7) & (GetByte() >> 1); // 7 bits, bits 7-1
m_ullScr = (m_ullScr << 8) & GetByte(); // 8 bits
m_ullScr = (m_ullScr << 7) & (GetByte() >> 1); // 7 bits, bits 7-1
// Multiplex rate and marker bits (3 bytes).
GetWord();
GetByte();
}
////////////////////////////////////////////////////////////////////
/****f* MMDemux/CMpeg1::GetMpeg1Packet
* USAGE
* void GetMpeg1Packet()
* DESCRIPTION
* Parses the mpeg1 packet header.
* PARAMETERS
* None.
* RETURN VALUE
* None.
/**********************************************************************/
void CMpeg1::GetMpeg1Packet()
{
INT wPacketHeaderLength = 0;
INT wPacketLength = 0;
BYTE byte = FALSE;
m_bPtsDtsFlag = FALSE;
m_llPts = 0;
// Get packet Length, 2 bytes
wPacketLength = (WORD)GetWord();
byte = (BYTE)ShowByte();
if (byte != PRIVATE_STREAM_2)
{
// Stuffing bytes
byte = (BYTE)ShowByte();
while (byte >> 7)
{
GetByte();
wPacketHeaderLength++;
byte = (BYTE)ShowByte();
}
// StdBufferScale and StdBufferSize, 2 bytes
byte = (BYTE)ShowByte();
if ((byte >> 6) == 0x1)
{
GetWord();
wPacketHeaderLength += 2;
}
// Get PTS and DTS
byte = (BYTE)ShowByte();
if ((byte >> 4) == 0x2) // '10' PTS presents
{
m_llPts = (LONGLONG(GetByte() & 0x0E) << 29);
m_llPts += (LONGLONG(GetByte()) << 22);
m_llPts += (LONGLONG(GetByte() & 0xFE) << 14);
m_llPts += (LONGLONG(GetByte()) << 7);
m_llPts += (LONGLONG(GetByte() >> 1));
wPacketHeaderLength += 5;
m_bPtsDtsFlag = TRUE;
}
else if((byte >> 4) == 0x3) // '11' PTS and DTS present
{
m_llPts = (LONGLONG(GetByte() & 0x0E) << 29);
m_llPts += (LONGLONG(GetByte()) << 22);
m_llPts += (LONGLONG(GetByte() & 0xFE) << 14);
m_llPts += (LONGLONG(GetByte()) << 7);
m_llPts += (LONGLONG(GetByte() >> 1));
// Get DTS, same as getting PTS
m_llDts = (LONGLONG(GetByte() & 0x0E) << 29);
m_llDts += (LONGLONG(GetByte()) << 22);
m_llDts += (LONGLONG(GetByte() & 0xFE) << 14);
m_llDts += (LONGLONG(GetByte()) << 7);
m_llDts += (LONGLONG(GetByte() >> 1));
wPacketHeaderLength += 10;
m_bPtsDtsFlag = TRUE;
}
else // Neither PTS or DTS flags were set, set to 0xF
{
GetByte();
wPacketHeaderLength++;
}
}
// Pointer of the beginning of payload
m_bPayloadPtr = m_pBuffer + m_dwBufferIndex;
// Actual packet data size
m_dwPayloadLength = wPacketLength - wPacketHeaderLength;
}
/////////////////////////////////////////////////////////////////////////////
/****f* MMDemux/CMpeg1::SkipSystemHeader
* USAGE
* void SkipSystemHeader
* DESCRIPTION
* Parses the mpeg1 system header
* PARAMETERS
* None.
* RETURN VALUE
* None.
/**********************************************************************/
void CMpeg1::SkipSystemHeader()
{
BYTE byte = 0;
WORD wHeaderLength = 0;
wHeaderLength = (WORD)GetWord();
// Rate bound and marker bits (3 bytes).
GetWord();
GetByte();
// Audio bound, fixed flag, CSPS flag.
GetByte();
// System audio clock flag, system video clock flag, marker bit, video bound bits.
GetByte();
// Reserved byte
GetByte();
// Skip Std_buffer_bound_scale and Std_buffer_size_bound
while (TRUE)
{
byte = (BYTE)ShowByte();
if ((byte >> 7) == 1) // first bit is 1, skip 3 bytes
{
GetByte(); // Stream Id
GetWord(); // buffer bound scale and buffer size bound
}
else
break;
}
}
///////////////////////////////////////////////////////////////////
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -