MPGUTIL.CPP
上传用户:tuheem
上传日期:2007-05-01
资源大小:21889k
文件大小:21k
- //==========================================================================;
- //
- // 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) 1996 - 1997 Microsoft Corporation. All Rights Reserved.
- //
- //--------------------------------------------------------------------------;
- /* MPEG 1 & 2 parsing routines */
- #include "stdafx.h"
- #include <streams.h>
- #include "mpegdef.h"
- #include <mmreg.h>
- #include "mpgutil.h"
- //#ifdef DEBUG
- LPCTSTR PictureTypes[8] = { TEXT("forbidden frame type"),
- TEXT("I-Frame"),
- TEXT("P-Frame"),
- TEXT("B-Frame"),
- TEXT("D-Frame"),
- TEXT("Reserved frame type"),
- TEXT("Reserved frame type"),
- TEXT("Reserved frame type")
- };
- LPCTSTR PelAspectRatios[16] = { TEXT("Forbidden"),
- TEXT("1.0000 - VGA etc"),
- TEXT("0.6735"),
- TEXT("0.7031 - 16:9, 625 line"),
- TEXT("0.7615"),
- TEXT("0.8055"),
- TEXT("0.8437 - 16:9, 525 line"),
- TEXT("0.8935"),
- TEXT("0.9375 - CCIR601, 625 line"),
- TEXT("0.9815"),
- TEXT("1.0255"),
- TEXT("1.0695"),
- TEXT("1.1250 - CCIR601, 525 line"),
- TEXT("1.1575"),
- TEXT("1.2015"),
- TEXT("Reserved") };
- LPCTSTR PictureRates[16] = { TEXT("Forbidden"),
- TEXT("23.976"),
- TEXT("24"),
- TEXT("25"),
- TEXT("29.97"),
- TEXT("30"),
- TEXT("50"),
- TEXT("59.94"),
- TEXT("60"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved") };
- //#endif // DBG
- const LONG PictureTimes[16] = { 0,
- (LONG)((double)10000000 / 23.976),
- (LONG)((double)10000000 / 24),
- (LONG)((double)10000000 / 25),
- (LONG)((double)10000000 / 29.97),
- (LONG)((double)10000000 / 30),
- (LONG)((double)10000000 / 50),
- (LONG)((double)10000000 / 59.94),
- (LONG)((double)10000000 / 60)
- };
- const float fPictureRates[] =
- {
- (float)0,
- (float)23.976,
- (float)24,
- (float)25,
- (float)29.97,
- (float)30,
- (float)50,
- (float)59.94,
- (float)60.0
- };
- const LONG AspectRatios[16] = { 0,
- 393700,
- (LONG)(393700.0 * 0.6735),
- (LONG)(393700.0 * 0.7031),
- (LONG)(393700.0 * 0.7615),
- (LONG)(393700.0 * 0.8055),
- (LONG)(393700.0 * 0.8437),
- (LONG)(393700.0 * 0.8935),
- (LONG)(393700.0 * 0.9375),
- (LONG)(393700.0 * 0.9815),
- (LONG)(393700.0 * 1.0255),
- (LONG)(393700.0 * 1.0695),
- (LONG)(393700.0 * 1.1250),
- (LONG)(393700.0 * 1.1575),
- (LONG)(393700.0 * 1.2015),
- 0
- };
- /* Bit rate tables */
- const WORD BitRates[3][16] =
- {{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 },
- { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 },
- { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 }
- };
- BOOL inline TESTBIT(const BYTE * pbData, int n)
- {
- return 0 != (pbData[n >> 3] & (0x80 >> (n & 7)));
- }
- /* Parse system header
- Parameters :
- pbData - pointer to data containing the system header
- cbData - length of data
- Returns :
- Number of bytes processed (0 if the header doesn't fit
- in the data or 4 if the header is invalid)
- */
- LONG ParseSystemHeader(const BYTE * pbData, DWORD cbData)
- {
- BOOL bHasAudio = FALSE;
- BOOL bHasVideo = FALSE;
- ASSERT(cbData >= 4);
- ASSERT(*(UNALIGNED DWORD *)pbData == DWORD_SWAP(SYSTEM_HEADER_START_CODE));
- /* Checkt the length */
- if (cbData < 6) {
- return 0;
- }
- DWORD dwLen = 6 + pbData[5] + (pbData[4] << 8);
- if (dwLen < SYSTEM_HEADER_BASIC_LENGTH) {
- DbgLog((LOG_ERROR, 1, TEXT("Invalid System Header length")));
- return 4;
- }
- if (cbData < dwLen) {
- return 0;
- }
- /* Check the marker bits */
- if (0 == (pbData[6] & 0x80) ||
- 0 == (pbData[8] & 0x01) ||
- 0 == (pbData[10] & 0x20)) {
- DbgLog((LOG_ERROR, 1, TEXT("Invalid System Header Marker bits")));
- return 4;
- }
- /* Parse the 'buffer bounds and scale' list */
- const BYTE * pbNext = pbData + SYSTEM_HEADER_BASIC_LENGTH;
- DWORD cbLeft = dwLen - SYSTEM_HEADER_BASIC_LENGTH;
- for ( ; cbLeft >= 3; cbLeft -= 3, pbNext += 3) {
- if (pbNext[0] == AUDIO_GLOBAL) {
- bHasAudio = TRUE;
- } else
- if (pbNext[0] == VIDEO_GLOBAL) {
- bHasVideo = TRUE;
- } else {
- if (pbNext[0] < PROGRAM_STREAM_MAP) {
- DbgLog((LOG_ERROR, 1, TEXT("Invalid stream id in system header")));
- return 4;
- }
- if (IsVideoStreamId(pbNext[0])) {
- bHasVideo = TRUE;
- } else
- if (IsAudioStreamId(pbNext[0])) {
- bHasAudio = TRUE;
- }
- }
- }
- if (cbLeft != 0) {
- DbgLog((LOG_ERROR, 1, TEXT("Invalid system header length")));
- return 4;
- }
- DbgLog((LOG_TRACE, 4, TEXT("System Header %s, %s"),
- bHasAudio ? TEXT("audio") : TEXT("No audio"),
- bHasVideo ? TEXT("video") : TEXT("No video")));
- return dwLen;
- }
- /* Parse an MPEG-1 packet */
- DWORD ParseMPEG1Packet(
- const BYTE * pbData,
- DWORD cbData,
- MPEG_PACKET_DATA *pPacketData,
- DWORD * Pts
- )
- {
- ZeroMemory((PVOID)pPacketData, sizeof(*pPacketData));
- DWORD dwStartCode = DWORD_SWAP(*(UNALIGNED DWORD *)pbData);
- DbgLog((LOG_TRACE, 4, TEXT("Parse packet %d bytes"), cbData));
- /* Send it to the right stream */
- if (cbData < 6) {
- return 0;
- }
- /* Find the length */
- DWORD dwLen = ((LONG)pbData[4] << 8) + (LONG)pbData[5] + 6;
- DbgLog((LOG_TRACE, 4, TEXT("Packet length %d bytes"), dwLen));
- if (dwLen > cbData) {
- return 0;
- }
- pPacketData->dwPacketLen = dwLen;
- /* Pull out PTS if any */
- DWORD dwHeaderSize = 6;
- if (dwStartCode != PRIVATE_STREAM_2) {
- DWORD dwPts = 6;
- for (;;) {
- if (dwPts >= dwLen) {
- return 4;
- }
- if (pbData[dwPts] & 0x80) {
- /* Stuffing byte */
- if (pbData[dwPts] != 0xFF) {
- return 4;
- }
- dwPts++;
- continue;
- }
- /* Check for STD (nextbits == '01') -
- we know the next bit is 0 so check the next one after that
- */
- if (pbData[dwPts] & 0x40) { // STD stuff
- dwPts += 2;
- continue;
- }
- /* No PTS - normal case */
- if (pbData[dwPts] == 0x0F) {
- dwHeaderSize = dwPts + 1;
- break;
- }
- if ((pbData[dwPts] & 0xF0) == 0x20 ||
- (pbData[dwPts] & 0xF0) == 0x30) {
- /* PTS or PTS and DTS */
- dwHeaderSize = (pbData[dwPts] & 0xF0) == 0x20 ? dwPts + 5 :
- dwPts + 10;
- if (dwHeaderSize > dwLen) {
- return 4;
- }
- if (!GetClock(pbData + dwPts, &pPacketData->llPts)) {
- *Pts = dwPts;
- return 4;
- }
- pPacketData->bHasPts = TRUE;
- break;
- } else {
- return 4;
- break;
- }
- }
- }
- pPacketData->dwHeaderLen = dwHeaderSize;
- return dwLen;
- }
- BOOL ParseSequenceHeader(const BYTE *pbData, LONG lData, SEQHDR_INFO *pInfo)
- {
- ASSERT(*(UNALIGNED DWORD *)pbData == DWORD_SWAP(SEQUENCE_HEADER_CODE));
- /* Check random marker bit */
- if (!(pbData[10] & 0x20)) {
- DbgLog((LOG_ERROR, 2, TEXT("Sequence header invalid marker bit")));
- return FALSE;
- }
- DWORD dwWidthAndHeight = ((DWORD)pbData[4] << 16) +
- ((DWORD)pbData[5] << 8) +
- ((DWORD)pbData[6]);
- pInfo->lWidth = dwWidthAndHeight >> 12;
- pInfo->lHeight = dwWidthAndHeight & 0xFFF;
- DbgLog((LOG_TRACE, 2, TEXT("Width = %d, Height = %d"),
- pInfo->lWidth,
- pInfo->lHeight));
- /* the '8' bit is the scramble flag used by sigma designs - ignore */
- BYTE PelAspectRatioAndPictureRate = pbData[7];
- if ((PelAspectRatioAndPictureRate & 0x0F) > 8) {
- PelAspectRatioAndPictureRate &= 0xF7;
- }
- DbgLog((LOG_TRACE, 2, TEXT("Pel Aspect Ratio = %s"),
- PelAspectRatios[PelAspectRatioAndPictureRate >> 4]));
- DbgLog((LOG_TRACE, 2, TEXT("Picture Rate = %s"),
- PictureRates[PelAspectRatioAndPictureRate & 0x0F]));
- if ((PelAspectRatioAndPictureRate & 0xF0) == 0 ||
- (PelAspectRatioAndPictureRate & 0x0F) == 0) {
- DbgLog((LOG_ERROR, 2, TEXT("Sequence header invalid ratio/rate")));
- return FALSE;
- }
- pInfo->tPictureTime = (LONGLONG)PictureTimes[PelAspectRatioAndPictureRate & 0x0F];
- pInfo->fPictureRate = fPictureRates[PelAspectRatioAndPictureRate & 0x0F];
- pInfo->lTimePerFrame = MulDiv((LONG)pInfo->tPictureTime, 9, 1000);
- /* Pull out the bit rate and aspect ratio for the type */
- pInfo->dwBitRate = ((((DWORD)pbData[8] << 16) +
- ((DWORD)pbData[9] << 8) +
- (DWORD)pbData[10]) >> 6);
- if (pInfo->dwBitRate == 0x3FFFF) {
- DbgLog((LOG_TRACE, 2, TEXT("Variable video bit rate")));
- pInfo->dwBitRate = 0;
- } else {
- pInfo->dwBitRate *= 400;
- DbgLog((LOG_TRACE, 2, TEXT("Video bit rate is %d bits per second"),
- pInfo->dwBitRate));
- }
- #if 0
- #pragma message (REMIND("Get pel aspect ratio right don't call GDI - it will create a thread!"))
- /* Get a DC */
- HDC hdc = GetDC(GetDesktopWindow());
- ASSERT(hdc != NULL);
- /* Guess (randomly) 39.37 inches per meter */
- LONG lNotionalPelsPerMeter = MulDiv((LONG)GetDeviceCaps(hdc, LOGICALPELSX),
- 3937, 100);
- #else
- LONG lNotionalPelsPerMeter = 2000;
- #endif
- pInfo->lXPelsPerMeter = lNotionalPelsPerMeter;
- pInfo->lYPelsPerMeter = MulDiv(
- lNotionalPelsPerMeter,
- AspectRatios[PelAspectRatioAndPictureRate >> 4],
- 10000);
- /* Pull out the vbv */
- pInfo->lvbv = ((((LONG)pbData[10] & 0x1F) << 5) |
- ((LONG)pbData[11] >> 3)) * 2048;
- DbgLog((LOG_TRACE, 2, TEXT("vbv size is %d bytes"), pInfo->lvbv));
- /* Check constrained parameter stuff */
- if (pbData[11] & 0x04) {
- DbgLog((LOG_TRACE, 2, TEXT("Constrained parameter video stream")));
- if (pInfo->lvbv > 40960) {
- DbgLog((LOG_ERROR, 1, TEXT("Invalid vbv (%d) for Constrained stream"),
- pInfo->lvbv));
- /* Have to let this through too! bisp.mpg has this */
- /* But constrain it since it might be random */
- pInfo->lvbv = 40960;
- }
- } else {
- DbgLog((LOG_TRACE, 2, TEXT("Non-Constrained parameter video stream")));
- }
- /* tp_orig has a vbv of 2048 (!) */
- if (pInfo->lvbv < 20000) {
- DbgLog((LOG_TRACE, 2, TEXT("Small vbv (%d) - setting to 40960"),
- pInfo->lvbv));
- pInfo->lvbv = 40960;
- }
- pInfo->lActualHeaderLen = SequenceHeaderSize(pbData);
- CopyMemory((PVOID)pInfo->RawHeader, (PVOID)pbData, pInfo->lActualHeaderLen);
- return TRUE;
- }
- HRESULT GetVideoMediaType(CMediaType *cmt, BOOL bPayload, const SEQHDR_INFO *pInfo)
- {
- cmt->majortype = MEDIATYPE_Video;
- cmt->subtype = bPayload ? MEDIASUBTYPE_MPEG1Payload :
- MEDIASUBTYPE_MPEG1Packet;
- VIDEOINFO *videoInfo =
- (VIDEOINFO *)cmt->AllocFormatBuffer(FIELD_OFFSET(MPEG1VIDEOINFO, bSequenceHeader[pInfo->lActualHeaderLen]));
- if (videoInfo == NULL) {
- return E_OUTOFMEMORY;
- }
- RESET_HEADER(videoInfo);
- videoInfo->dwBitRate = pInfo->dwBitRate;
- videoInfo->rcSource.right = pInfo->lWidth;
- videoInfo->bmiHeader.biWidth = pInfo->lWidth;
- videoInfo->rcSource.bottom = pInfo->lHeight;
- videoInfo->bmiHeader.biHeight = pInfo->lHeight;
- videoInfo->bmiHeader.biXPelsPerMeter = pInfo->lXPelsPerMeter;
- videoInfo->bmiHeader.biYPelsPerMeter = pInfo->lYPelsPerMeter;
- videoInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- videoInfo->AvgTimePerFrame = pInfo->tPictureTime;
- MPEG1VIDEOINFO *mpgvideoInfo = (MPEG1VIDEOINFO *)videoInfo;
- mpgvideoInfo->cbSequenceHeader = pInfo->lActualHeaderLen;
- CopyMemory((PVOID)mpgvideoInfo->bSequenceHeader,
- (PVOID)pInfo->RawHeader,
- pInfo->lActualHeaderLen);
- mpgvideoInfo->dwStartTimeCode = pInfo->dwStartTimeCode;
- cmt->SetFormatType(&FORMAT_MPEGVideo);
- return S_OK;
- }
- BOOL CheckAudioHeader(const BYTE * pbData)
- {
- /* Just check it's valid */
- #pragma message (REMIND("Check audio header"))
- if ((pbData[2] & 0x0C) == 0x0C) {
- DbgLog((LOG_ERROR, 2, TEXT("Invalid audio sampling frequency")));
- return FALSE;
- }
- if ((pbData[1] & 0x08) != 0x08) {
- DbgLog((LOG_ERROR, 2, TEXT("Invalid audio ID bit = 0")));
- return FALSE;
- }
- if (((pbData[1] >> 1) & 3) == 0x00) {
- DbgLog((LOG_ERROR, 2, TEXT("Invalid audio Layer")));
- return FALSE;
- }
- if (((pbData[2] >> 2) & 3) == 3) {
- DbgLog((LOG_ERROR, 2, TEXT("Invalid sample rate")));
- return FALSE;
- }
- if ((pbData[2] >> 4) == 0x0F) {
- DbgLog((LOG_ERROR, 2, TEXT("Invalid bit rate")));
- return FALSE;
- }
- return TRUE;
- }
- LONG SampleRate(const BYTE * pbData)
- {
- switch ((pbData[2] >> 2) & 3) {
- case 0:
- return 44100;
- case 1:
- return 48000;
- case 2:
- return 32000;
- default:
- DbgBreak("Unexpected Sample Rate");
- return 44100;
- }
- }
- BOOL ParseAudioHeader(const BYTE * pbData, MPEG1WAVEFORMAT *pFormat)
- {
- if (!CheckAudioHeader(pbData)) {
- return FALSE;
- }
- pFormat->wfx.wFormatTag = WAVE_FORMAT_MPEG;
- /* Get number of channels from Mode */
- switch (pbData[3] >> 6) {
- case 0x00:
- pFormat->fwHeadMode = ACM_MPEG_STEREO;
- break;
- case 0x01:
- pFormat->fwHeadMode = ACM_MPEG_JOINTSTEREO;
- break;
- case 0x02:
- pFormat->fwHeadMode = ACM_MPEG_DUALCHANNEL;
- break;
- case 0x03:
- pFormat->fwHeadMode = ACM_MPEG_SINGLECHANNEL;
- break;
- }
- pFormat->wfx.nChannels =
- (WORD)(pFormat->fwHeadMode == ACM_MPEG_SINGLECHANNEL ? 1 : 2);
- pFormat->fwHeadModeExt = (WORD)(1 << (pbData[3] >> 4));
- pFormat->wHeadEmphasis = (WORD)((pbData[3] & 0x03) + 1);
- pFormat->fwHeadFlags = (WORD)(((pbData[2] & 1) ? ACM_MPEG_PRIVATEBIT : 0) +
- ((pbData[3] & 8) ? ACM_MPEG_COPYRIGHT : 0) +
- ((pbData[3] & 4) ? ACM_MPEG_ORIGINALHOME : 0) +
- ((pbData[1] & 1) ? ACM_MPEG_PROTECTIONBIT : 0) +
- ((pbData[1] & 0x08) ? ACM_MPEG_ID_MPEG1 : 0));
- int Layer;
- /* Get the layer so we can work out the bit rate */
- switch ((pbData[1] >> 1) & 3) {
- case 3:
- pFormat->fwHeadLayer = ACM_MPEG_LAYER1;
- Layer = 1;
- break;
- case 2:
- pFormat->fwHeadLayer = ACM_MPEG_LAYER2;
- Layer = 2;
- break;
- case 1:
- pFormat->fwHeadLayer = ACM_MPEG_LAYER3;
- Layer = 3;
- break;
- case 0:
- return (FALSE);
- }
- /* Get samples per second from sampling frequency */
- pFormat->wfx.nSamplesPerSec = SampleRate(pbData);
- pFormat->dwHeadBitrate =
- (DWORD)BitRates[Layer - 1][pbData[2] >> 4] * 1000;
- pFormat->wfx.nAvgBytesPerSec = pFormat->dwHeadBitrate / 8;
- /* Deal with free format (!) */
- #pragma message (REMIND("Handle variable bit rate (index 0)"))
- if (pFormat->wfx.nSamplesPerSec != 44100 &&
- /* Layer 3 can sometimes switch bitrates */
- !(Layer == 3 && /* !m_pStreamList->AudioLock() && */
- (pbData[2] >> 4) == 0)) {
- if (Layer == 1) {
- pFormat->wfx.nBlockAlign = (WORD)
- (4 * ((pFormat->dwHeadBitrate * 12) / pFormat->wfx.nSamplesPerSec));
- } else {
- pFormat->wfx.nBlockAlign = (WORD)
- ((144 * pFormat->dwHeadBitrate) / pFormat->wfx.nSamplesPerSec);
- }
- } else {
- pFormat->wfx.nBlockAlign = 1;
- }
- pFormat->wfx.wBitsPerSample = 0;
- pFormat->wfx.cbSize = sizeof(MPEG1WAVEFORMAT) - sizeof(WAVEFORMATEX);
- pFormat->dwPTSLow = 0;
- pFormat->dwPTSHigh = 0;
- return TRUE;
- }
- BOOL GetClock(const BYTE * pData, LONGLONG *Clock)
- {
- BYTE Byte1 = pData[0];
- DWORD Word2 = ((DWORD)pData[1] << 8) + (DWORD)pData[2];
- DWORD Word3 = ((DWORD)pData[3] << 8) + (DWORD)pData[4];
- /* Do checks */
- if ((Byte1 & 0xE0) != 0x20 ||
- (Word2 & 1) != 1 ||
- (Word3 & 1) != 1) {
- DbgLog((LOG_TRACE, 2, TEXT("Invalid clock field - 0x%2.2X 0x%4.4X 0x%4.4X"),
- Byte1, Word2, Word3));
- return FALSE;
- }
- LARGE_INTEGER liClock;
- liClock.HighPart = (Byte1 & 8) != 0;
- liClock.LowPart = (DWORD)((((DWORD)Byte1 & 0x6) << 29) +
- (((DWORD)Word2 & 0xFFFE) << 14) +
- ((DWORD)Word3 >> 1));
- *Clock = liClock.QuadPart;
- return TRUE;
- }
- BOOL SetClock(BYTE * pData, LONGLONG *Clock)
- {
- LARGE_INTEGER liClock;
- liClock.QuadPart = *Clock;
- BYTE Byte = ((BYTE)(liClock.HighPart & 1) << 3) +
- ((BYTE)(liClock.LowPart >> 29) & 0x06);
- pData[0] = (pData[0] & 0xf1 ) | Byte;
- Byte = (BYTE)(liClock.LowPart >> 22);
- pData[1] = Byte;
- Byte = (BYTE)(liClock.LowPart >> 14) & 0xfe;
- pData[2] = (pData[2] & 0x01) | Byte;
- Byte = (BYTE)(liClock.LowPart >> 7);
- pData[3] = Byte;
- Byte = (BYTE)(liClock.LowPart << 1) & 0xfe;
- pData[4] = (pData[4] &0x01) | Byte;
- /*
- BYTE Byte1 = pData[0];
- DWORD Word2 = ((DWORD)pData[1] << 8) + (DWORD)pData[2];
- DWORD Word3 = ((DWORD)pData[3] << 8) + (DWORD)pData[4];
- */
- /* Do checks */
- /*
- if ((Byte1 & 0xE0) != 0x20 ||
- (Word2 & 1) != 1 ||
- (Word3 & 1) != 1) {
- DbgLog((LOG_TRACE, 2, TEXT("Invalid clock field - 0x%2.2X 0x%4.4X 0x%4.4X"),
- Byte1, Word2, Word3));
- return FALSE;
- }
- liClock.HighPart = (Byte1 & 8) != 0;
- liClock.LowPart = (DWORD)((((DWORD)Byte1 & 0x6) << 29) +
- (((DWORD)Word2 & 0xFFFE) << 14) +
- ((DWORD)Word3 >> 1));
- */
- return TRUE;
- }
- /* Find the next start code */
- BOOL NextStartCode(const BYTE * *ppbData, DWORD *pdwLeft)
- {
- const BYTE * pbData = *ppbData;
- DWORD dwLeft = *pdwLeft;
- while (dwLeft > 4 &&
- (*(UNALIGNED DWORD *)pbData & 0x00FFFFFF) != 0x00010000) {
- dwLeft--;
- pbData++;
- }
- *ppbData = pbData;
- *pdwLeft = dwLeft;
- return dwLeft >= 4;
- }