//==========================================================================; // // 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 - 1998 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(); } } } }