//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
//
/******************************Module*Header*******************************\
* Module Name: Decoder.cpp
*
* Implements a prototype Mpeg Video Software codec. It just consume
* the passed in packets.
*
\**************************************************************************/
#include "MpgVideo.h"
/* -------------------------------------------------------------------------
** CVideoDecoder
** -------------------------------------------------------------------------
*/
/******************************Public*Routine******************************\
* CVideoDecoder
*
* Constructor and destructor
*
\**************************************************************************/
CVideoDecoder::CVideoDecoder(CMpegVideoCodec *pMpegCodec)
: m_pCodec(pMpegCodec) {}
/******************************Public*Routine******************************\
* ResetVideo
*
*
*
\**************************************************************************/
DWORD
CVideoDecoder::ResetVideo()
{
CAutoLock lck(this);
return DECODE_SUCCESS;
}
/******************************Public*Routine******************************\
* DecodeFrame
*
*
*
\**************************************************************************/
DWORD
CVideoDecoder::DecodeFrame(
VideoCtrl *pCtrl
)
{
CAutoLock lck(this);
BOOL Done = FALSE;
DWORD rc = DECODE_SUCCESS;
m_pCtrl = pCtrl;
if ((m_pCtrl->dwCtrl & 0xffff) == DECODE_DIS) {
LPBYTE lpOutputBuffer = m_pCodec->GetDecodeBufferAndFormat();
if (lpOutputBuffer == NULL) {
rc = DECODE_ERR_QUARTZ;
}
return rc;
}
m_pCtrl->dwSkipFlag = 1;
while (!Done) {
DWORD sc = NextStartCode();
switch (sc) {
case PICTURE_START_CODE:
DbgLog((LOG_TRACE, 2, TEXT("PICTURE_START_CODE")));
m_pCtrl->pFrameStartPos = m_pCtrl->pCmprRead;
rc = SkipFrame();
Done = TRUE;
break;
case SEQUENCE_HEADER_CODE:
DbgLog((LOG_TRACE, 2, TEXT("SEQUENCE_HEADER_CODE")));
Discard32Bits();
break;
case SEQUENCE_END_CODE:
DbgLog((LOG_TRACE, 2, TEXT("SEQUENCE_END_CODE")));
Discard32Bits();
Done = TRUE;
break;
case GROUP_START_CODE:
DbgLog((LOG_TRACE, 2, TEXT("GROUP_START_CODE")));
Discard32Bits();
break;
case (DWORD)-1:
//
// We didn't find a valid start code.
//
rc = DECODE_ERR_DATA;
Done = TRUE;
break;
default:
DbgLog((LOG_TRACE, 2, TEXT("Unexpected start code %#X"), sc));
Discard32Bits();
break;
}
}
if (!m_pCtrl->dwSkipFlag) {
LPBYTE lpOutputBuffer = m_pCodec->GetDecodeBufferAndFormat();
if (lpOutputBuffer == NULL) {
rc = DECODE_ERR_QUARTZ;
}
}
return rc;
}
/*****************************Private*Routine******************************\
* NextStartCode
*
* Returns the next start code of -1 if none found within the buffer limits.
* Advances pCmprRead to point to begining of the start code.
*
\**************************************************************************/
DWORD
CVideoDecoder::NextStartCode()
{
LPBYTE lpCurr = m_pCtrl->pCmprRead;
LPBYTE lpEnd = m_pCtrl->pCmprWrite;
int sm = 0;
DWORD StartCode = 0x00000100L;
while ((lpCurr < lpEnd) && sm < 3) {
switch (sm) {
case 0:
lpCurr = (LPBYTE)memchr(lpCurr, 0, lpEnd - lpCurr);
if (lpCurr != NULL) lpCurr++, sm = 1;
else lpCurr = lpEnd;
break;
case 1:
if (*lpCurr++ == 0) sm = 2;
else sm = 0;
break;
case 2:
if (*lpCurr == 1) sm = 3;
else if (*lpCurr == 0) sm = 2;
else sm = 0;
lpCurr++;
break;
}
}
//
// When we get here we have either run out of buffer or found the first
// 3 bytes of a valid start code.
//
// If we have the first three bytes of the start code. The next
// byte completes the start code.
//
// Don't forget to put back the start code bytes that we have just
// read otherwise they would be lost forever.
//
if (lpCurr >= lpEnd) {
StartCode = (DWORD)-1;
}
else {
StartCode += *lpCurr;
}
lpCurr -= sm;
m_pCtrl->pCmprRead = lpCurr;
return StartCode;
}
/*****************************Private*Routine******************************\
* Discard32Bits
*
* Throw away the next 32 bits
*
\**************************************************************************/
void
CVideoDecoder::Discard32Bits()
{
m_pCtrl->pCmprRead += 4;
}
/*****************************Private*Routine******************************\
* SkipFrame
*
*
*
\**************************************************************************/
DWORD
CVideoDecoder::SkipFrame()
{
DWORD dwX;
//
// If there isn't enough room for the information required then
// then return 0L
//
if (m_pCtrl->pCmprRead > (m_pCtrl->pCmprWrite - 8)) {
return DECODE_ERR_DATA;
}
Discard32Bits(); // Eat the picyure start code
dwX = ByteSwap(*(UNALIGNED DWORD *)m_pCtrl->pCmprRead);
m_pCtrl->pCmprRead += 4;
m_pCtrl->dwTemporalReference = (dwX & 0xFFC00000) >> 22;
m_pCtrl->dwFrameType = (dwX & 0x00380000) >> 19;
switch (m_pCtrl->dwCtrl & 0xffff) {
case DECODE_NULL:
m_pCtrl->dwSkipFlag = 1;
break;
case DECODE_I:
m_pCtrl->dwSkipFlag = (m_pCtrl->dwFrameType != FTYPE_I);
break;
case DECODE_IP:
m_pCtrl->dwSkipFlag = (m_pCtrl->dwFrameType == FTYPE_B);
break;
case DECODE_IPB:
m_pCtrl->dwSkipFlag = 0;
break;
}
for (; ; ) {
dwX = NextStartCode();
if (dwX == (DWORD)-1) {
return DECODE_ERR_DATA;
}
else {
BYTE Code = (BYTE)(dwX & 0xFF);
if (Code == 0x00 || Code > 0xAF) {
return DECODE_SUCCESS;
}
else {
Discard32Bits();
}
}
}
}