📄 mpgutil.cpp
字号:
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -