📄 mmutils.cpp
字号:
#include "pch.h"
#include "mmdebug.h"
#include "mmutils.h"
#ifndef READ_BUFFERSIZE
#define READ_BUFFERSIZE 0x40000 // 256KB
//#define READ_BUFFERSIZE 0x80000 // 512KB
//#define READ_BUFFERSIZE 0x100000 // 1MB
#endif
////////////////////////////////////////////////////////////////////
void CheckSubStreamId(INT iSubStreamId, AudioSubtype* audioSubtype,
MM_AUDIO_FORMAT* bAudioFormat)
{
switch (iSubStreamId >> 3)
{
case AC3_SUBSTREAM_ID:
if (!audioSubtype->bIsAc3)
{
audioSubtype->bIsAc3 = TRUE;
MmDebugLogfile((MmDebugLevelTrace, "AUDIO_FORMAT_AC3"));
}
if (!audioSubtype->bIsDts && !audioSubtype->bIsPcm)
*bAudioFormat = MM_MEDIASUBTYPE_DOLBY_AC3;
break;
case DTS_SUBSTREAM_ID:
if (!audioSubtype->bIsDts)
{
audioSubtype->bIsDts = TRUE;
MmDebugLogfile((MmDebugLevelTrace, "AUDIO_FORMAT_DTS"));
}
if (!audioSubtype->bIsAc3 && !audioSubtype->bIsPcm)
*bAudioFormat = MM_MEDIASUBTYPE_DTS;
break;
case PCM_SUBSTREAM_ID:
if (!audioSubtype->bIsPcm)
{
audioSubtype->bIsPcm = TRUE;
MmDebugLogfile((MmDebugLevelTrace, "AUDIO_FORMAT_PCM"));
}
if (!audioSubtype->bIsAc3 && !audioSubtype->bIsDts)
*bAudioFormat = MM_MEDIASUBTYPE_PCM;
break;
case SDDS_SUBSTREAM_ID:
MmDebugLogfile((MmDebugLevelTrace, "AUDIOSUBTYPE_SDDS"));
break;
}
}
////////////////////////////////////////////////////////////////////
/****f* MMDemux/IdentifyAudioSubtype
* USAGE
* MM_AUDIO_FORMAT IdentifyAudioSubtype(char *pSourceFile, AudioSubtype* audioSubtype,
* int iStreamType = FT_UNKNOWN)
* MM_AUDIO_FORMAT IdentifyAudioSubtype(unsigned char* pBuffer, unsigned long dwLength,
* AudioSubtype* audioSubtype, int iStreamType = FT_UNKNOWN)
* DESCRIPTION
* Identify the audio subtype of a file.
* PARAMETERS
* char *pSourceFile - Pointer to the source file name
* AudioSubtype* audioSubtype -
* RETURN VALUE
* MM_MEDIASUBTYPE_MPEG1Payload if audio subtype is of type audio stream
* (for both mpeg1 and mpeg2).
* MM_MEDIASUBTYPE_DOLBY_AC3 if audio subtype is of Ac3 stream.
* MM_MEDIASUBTYPE_PCM if audio subtype is of PCM stream.
* MM_MEDIASUBTYPE_DTS if the stream contains both AC3 and DTS.
* NOTES
* If using with COM Interface, MM_AUDIO_FORMAT has format as GUID.
* Else, MM_AUDIO_FORMAT has format as INT.
/**********************************************************************/
MM_AUDIO_FORMAT IdentifyAudioSubtype(char *pSourceFile, AudioSubtype* audioSubtype,
int iStreamType)
{
BYTE bBuffer[READ_BUFFERSIZE];
DWORD dwReadSize = 0;
INT i = 0;
MM_AUDIO_FORMAT audio = MM_MEDIASUBTYPE_NULL;
FILE *pPlayfile;
if ((pPlayfile = fopen(pSourceFile, "rb")) == NULL)
{
printf("Unable to open file!\n");
return MM_MEDIASUBTYPE_NULL;
}
dwReadSize = fread(bBuffer, sizeof(char), READ_BUFFERSIZE, pPlayfile);
if (iStreamType == FT_UNKNOWN)
iStreamType = IdentifyHeader(bBuffer, dwReadSize);
audio = IdentifyAudioSubtype(bBuffer, dwReadSize, audioSubtype, iStreamType);
if (audio == MM_MEDIASUBTYPE_NULL)
{
for (i = 0; i < 3; i++)
{
dwReadSize = fread(bBuffer, sizeof(char), READ_BUFFERSIZE, pPlayfile);
audio = IdentifyAudioSubtype(bBuffer, dwReadSize, audioSubtype, iStreamType);
if (audio != MM_MEDIASUBTYPE_NULL)
break;
}
}
fclose(pPlayfile);
return audio;
}
////////////////////////////////////////////////////////////////////
MM_AUDIO_FORMAT IdentifyAudioSubtype(unsigned char* pBuffer, unsigned long dwLength,
AudioSubtype* audioSubtype, int iStreamType)
{
DWORD dwBufferIndex = 0;
DWORD dwCode = 0;
BYTE byte = 0;
INT wPacketLength = 0;
INT wHeaderDataLength = 0;
MM_AUDIO_FORMAT bAudioFormat = MM_MEDIASUBTYPE_NULL;
if (iStreamType == FT_UNKNOWN)
iStreamType = IdentifyHeader(pBuffer, dwLength);
if (iStreamType == FT_AC3_AUDIO)
{
audioSubtype->bIsAc3 = TRUE;
return MM_MEDIASUBTYPE_DOLBY_AC3;
}
if (iStreamType == FT_DTS_AUDIO)
{
audioSubtype->bIsDts = TRUE;
return MM_MEDIASUBTYPE_DTS;
}
if (iStreamType == FT_MPEG2_TRANSPORT)
{
while (dwBufferIndex < dwLength)
{
byte = *(pBuffer + dwBufferIndex++);
if (byte == M2T_SYNC_BYTE)
{
// Number of bytes have moved so far in the TS packet after the sync byte.
INT wBytesAdvanced = 0;
// Transport error indicator, payload unit start indicator, transport priority and PID
dwBufferIndex += 2;
// Transport scrambling control, adaptation field control, continuity counter
if (dwBufferIndex >= dwLength)
break;
byte = *(pBuffer + dwBufferIndex++);
INT bAdaptFieldCtrl = (byte & 0x30) >> 4; // Bit 5 & 4
wBytesAdvanced += 3;
// Adaptation field presents
if ((bAdaptFieldCtrl == 0x2) || (bAdaptFieldCtrl == 0x3))
{
INT bAdaptFieldLength = 0;
bAdaptFieldLength = *(pBuffer + dwBufferIndex++);
if (bAdaptFieldCtrl == 0x2 && bAdaptFieldLength != 183)
continue;
else if (bAdaptFieldCtrl == 0x3 && bAdaptFieldLength < 0 &&
bAdaptFieldLength > 182)
continue;
dwBufferIndex += bAdaptFieldLength;
wBytesAdvanced += bAdaptFieldLength;
}
// Payload presents
if ((bAdaptFieldCtrl == 0x1) || (bAdaptFieldCtrl == 0x3))
{
if (dwBufferIndex + (187 - wBytesAdvanced) >= dwLength)
break;
DWORD nextTSIndex = dwBufferIndex + (187 - wBytesAdvanced);
while (dwBufferIndex < nextTSIndex)
{
dwCode = (dwCode << 8) | *(pBuffer + dwBufferIndex++);
if ((dwCode & 0xF0FFFFFF) == AUDIO_STREAM)
{
MmDebugLogfile((MmDebugLevelTrace, "AUDIO_FORMAT_MPEG1"));
audioSubtype->bIsMpeg1 = TRUE;
return MM_MEDIASUBTYPE_MPEG1Payload;
}
else if (dwCode == AC3_PCM_DTS_STREAM)
{
// Assume it's AC3 for now.
MmDebugLogfile((MmDebugLevelTrace, "AUDIO_FORMAT_AC3"));
audioSubtype->bIsAc3 = TRUE;
return MM_MEDIASUBTYPE_DOLBY_AC3;
wPacketLength = *(pBuffer + dwBufferIndex++);
wPacketLength = (wPacketLength << 8) | *(pBuffer + dwBufferIndex++);
// Scrambling control, priority, alignment, copyright and original or copy bits.
dwBufferIndex++;
// PTS, DTS, ESCR, ESRate, DSM trick mode, additional copy info, CRC and
// extension flags.
dwBufferIndex++;
// Get Header Data Length
wHeaderDataLength = *(pBuffer + dwBufferIndex++);
dwBufferIndex += wHeaderDataLength;
// Sub stream id: AC3 (10000***b), DTS (10001***b), PCM (10100***b), SUB (001*****b),
// SDDS (10010***b)
if (dwBufferIndex >= dwLength)
break;
BYTE bSubStreamId = *(pBuffer + dwBufferIndex++);
wHeaderDataLength++;
if ((bSubStreamId >> 5) != SUB_SUBSTREAM_ID)
{
// Skip number of frame headers and first access unit pointer
dwBufferIndex += 3;
wHeaderDataLength += 3;
CheckSubStreamId(bSubStreamId, audioSubtype, &bAudioFormat);
if ((bSubStreamId >> 3) == PCM_SUBSTREAM_ID)
{
dwBufferIndex++;
if (dwBufferIndex >= dwLength)
break;
byte = *(pBuffer + dwBufferIndex++);
INT iQuantizationWordLength = (byte >> 6) & 0x3;
INT iSampleRate = (byte >> 4) & 0x3;
INT iNumAudioChannels = (byte & 0x7) + 1;
audioSubtype->pcmAudio.iBitsPerSample = quantization_table[iQuantizationWordLength];
audioSubtype->pcmAudio.iSampleRate = pcm_sample_rate_table[iSampleRate];
audioSubtype->pcmAudio.iNumAudioChannels = iNumAudioChannels;
dwBufferIndex++;
}
}
}
}
}
}
}
}
else // Program stream
{
while (dwBufferIndex < dwLength)
{
dwCode = (dwCode << 8) | *(pBuffer + dwBufferIndex++);
if (dwCode == PACK_START_CODE)
{
dwBufferIndex += 9; // SCR and Mux rate
if (dwBufferIndex >= dwLength)
break;
INT res_stuff = *(pBuffer + dwBufferIndex++) & 0x7; // Pack stuffing length,
dwBufferIndex += res_stuff;
dwCode = 0;
}
else if (dwCode == SYSTEM_START_CODE)
{
dwBufferIndex += 8;
while (TRUE)
{
if (dwBufferIndex >= dwLength)
break;
byte = *(pBuffer + dwBufferIndex);
if ((byte >> 7) == 1) // first bit is 1, skip 3 bytes
dwBufferIndex += 3; // Stream id, buffer bound scale and bufer size bound (3 bytes).
else
break;
}
dwCode = 0;
}
else if ((dwCode == PADDING_STREAM) || (dwCode == PRIVATE_STREAM_2) ||
(dwCode == PROGRAM_STREAM_MAP))
{
if (dwBufferIndex >= dwLength)
break;
wPacketLength = *(pBuffer + dwBufferIndex++);
if (dwBufferIndex >= dwLength)
break;
wPacketLength = (wPacketLength << 8) | *(pBuffer + dwBufferIndex++);
dwBufferIndex += wPacketLength;
dwCode = 0;
}
else if ((dwCode & 0xF0FFFFFF) == VIDEO_STREAM)
{
if (dwBufferIndex >= dwLength)
break;
wPacketLength = *(pBuffer + dwBufferIndex++);
if (dwBufferIndex >= dwLength)
break;
wPacketLength = (wPacketLength << 8) | *(pBuffer + dwBufferIndex++);
dwBufferIndex += wPacketLength;
dwCode = 0;
}
else if ((dwCode & 0xF0FFFFFF) == AUDIO_STREAM)
{
MmDebugLogfile((MmDebugLevelTrace, "AUDIO_FORMAT_MPEG1"));
audioSubtype->bIsMpeg1 = TRUE;
return MM_MEDIASUBTYPE_MPEG1Payload;
}
else if (dwCode == AC3_PCM_DTS_STREAM)
{
if (dwBufferIndex + 2 >= dwLength)
break;
wPacketLength = *(pBuffer + dwBufferIndex++);
wPacketLength = (wPacketLength << 8) | *(pBuffer + dwBufferIndex++);
// Scrambling control, priority, alignment, copyright and original or copy bits.
dwBufferIndex++;
// PTS, DTS, ESCR, ESRate, DSM trick mode, additional copy info, CRC and extension flags.
dwBufferIndex++;
// Get Header Data Length
if (dwBufferIndex > dwLength)
break;
wHeaderDataLength = *(pBuffer + dwBufferIndex++);
dwBufferIndex += wHeaderDataLength;
// Sub stream id: AC3 (10000***b), DTS (10001***b), PCM (10100***b), SUB (001*****b)
if (dwBufferIndex >= dwLength)
break;
BYTE bSubStreamId = *(pBuffer + dwBufferIndex++);
wHeaderDataLength++;
if ((bSubStreamId >> 5) != SUB_SUBSTREAM_ID)
{
// Number of frame headers and first access unit pointer
dwBufferIndex += 3;
wHeaderDataLength += 3;
CheckSubStreamId(bSubStreamId, audioSubtype, &bAudioFormat);
if ((bSubStreamId >> 3) == PCM_SUBSTREAM_ID)
{
dwBufferIndex++;
if (dwBufferIndex >= dwLength)
break;
byte = *(pBuffer + dwBufferIndex++);
INT iQuantizationWordLength = (byte >> 6) & 0x3;
INT iSampleRate = (byte >> 4) & 0x3;
INT iNumAudioChannels = (byte & 0x7) + 1;
audioSubtype->pcmAudio.iBitsPerSample = quantization_table[iQuantizationWordLength];
audioSubtype->pcmAudio.iSampleRate = pcm_sample_rate_table[iSampleRate];
audioSubtype->pcmAudio.iNumAudioChannels = iNumAudioChannels;
dwBufferIndex++;
}
}
dwBufferIndex += (wPacketLength - wHeaderDataLength);
}
}
}
return bAudioFormat;
}
////////////////////////////////////////////////////////////////////
/****f* MMDemux/IdentifyHeader
* USAGE
* UINT IdentifyHeader(char *pFileName)
* UINT IdentifyHeader(const BYTE *pSearchBuffer, DWORD dwSearchBufferSize)
* DESCRIPTION
* Search for any MPEG header in order to identify the file type.
* PARAMETERS
* BYTE *pSearchBuffer : buffer where to load the data.
* DWORD dwSearchBufferSize : number of bytes to search. Note that the size
* of the valid data must be dwSearchBlockSize + 4.
* RETURN VALUE
* FT_AC3_AUDIO for audio AC3
* FT_MPEG_VIDEO for elementary video
* FT_MPEG_AUDIO for elementary audio
* FT_MPEG_SYSTEM for mpeg1 system
* FT_MPEG2_SYSTEM for mpeg2 system
* FT_AC3_AUDIO for elementary audio AC3
* FT_PES for pes stream
* FT_MPEG4_VIDEO for mpeg4 elementary video
/**********************************************************************/
UINT IdentifyHeader(char *pFileName)
{
UINT mpeg4type = CheckMPG4type(pFileName);
if(mpeg4type == FT_UNKNOWN)
{
BYTE bBuffer[READ_BUFFERSIZE];
DWORD dwSearchBufferSize = 0;
FILE *pFile = fopen(pFileName, "rb");
if (!pFile)
return FT_UNKNOWN;
dwSearchBufferSize = fread(bBuffer, 1, READ_BUFFERSIZE, pFile);
fclose(pFile);
return IdentifyHeader(bBuffer, dwSearchBufferSize);
}
else if(mpeg4type == FT_QUICKTIME)
return FT_UNKNOWN;
else
return mpeg4type;
}
////////////////////////////////////////////////////////////////////
UINT IdentifyHeader(const BYTE *pSearchBuffer, DWORD dwSearchBufferSize)
{
const BYTE *pBuffer = pSearchBuffer;
DWORD dwCanBeSystem = 0;
DWORD dwCanBeSystem2 = 0;
DWORD dwCanBeMPEGAudio = 0;
DWORD dwCanBeAC3Audio = 0;
DWORD dwCanBeDtsAudio = 0;
DWORD dwCanBeVideo = 0;
DWORD dwCanBeVideo2 = 0;
DWORD dwCanBeVideo4 = 0;
DWORD dwBufferPos;
WORD wAudioStart = 0;
const TCHAR* sVTS = "DVDVIDEO-VTS";
const TCHAR* sVMG = "DVDVIDEO-VMG";
if (IsAc3Reverse(pBuffer, dwSearchBufferSize))
{
MmDebugLogfile((MmDebugLevelTrace, "Filetype: AC3_AUDIO"));
return FT_AC3_AUDIO;
}
else if (IsPESFile(pBuffer, dwSearchBufferSize))
{
MmDebugLogfile((MmDebugLevelTrace, "Filetype: PES"));
return FT_PES;
}
// Refuse to open RIFF (AVI and WAV files)
if (memcmp(pSearchBuffer, "RIFF", 4) == 0)
{
MmDebugLogfile((MmDebugLevelTrace, "Filetype: FT_UNKNOWN"));
return FT_UNKNOWN;
}
// Refuse to open Midi (MID files)
if (memcmp(pSearchBuffer, "MThd", 4) == 0)
{
MmDebugLogfile((MmDebugLevelTrace, "Filetype: FT_UNKNOWN"));
return FT_UNKNOWN;
}
for (dwBufferPos = 0; dwBufferPos < dwSearchBufferSize; dwBufferPos++)
{
if (memcmp(sVTS, pBuffer, 12) == 0)
{
MmDebugLogfile((MmDebugLevelTrace, "Filetype: DVT_VTS"));
return FT_DVD_VTS;
}
else if (memcmp(sVMG, pBuffer, 12) == 0)
{
MmDebugLogfile((MmDebugLevelTrace, "Filetype: DVT_VMG"));
return FT_DVD_VMG;
}
if ( MATCHBYTESTREAM(pBuffer, VIDEO_OBJECT_SEQUENCE_START_CODE) || // reserved in Mpeg2
MATCHBYTESTREAM(pBuffer, VOP_START_CODE) ) // reserved in Mpeg2
{
MmDebugLogfile((MmDebugLevelTrace, "Filetype: VideoMpeg4"));
// for now I care only about mpeg4 video ID <-> VideoObjectLayer
return FT_MPEG4_VIDEO;
}
else if (MATCHBYTESTREAM(pBuffer, PACK_START_CODE))
{
if ((* (pBuffer+4))>>6 == 0x01)
{
DWORD dwCanbeMAX = max (dwCanBeVideo,
max( dwCanBeAC3Audio, dwCanBeMPEGAudio));
if (dwCanbeMAX > 8)
{
// May be not a system stream if we have found 8 headers before
if (dwBufferPos == 0)
dwCanBeSystem2 += 6;
else
dwCanBeSystem2 += 2;
}
else
{
MmDebugLogfile((MmDebugLevelTrace, "Filetype: MPEG2_SYSTEM"));
return FT_MPEG2_SYSTEM;
}
}
else if ((*(pBuffer+4)) >> 4 == 0x02)
{
DWORD dwCanbeMAX = max (dwCanBeVideo,
max( dwCanBeAC3Audio, dwCanBeMPEGAudio));
if (dwCanbeMAX > 8)
{
// May be not a system stream if we have found 8 headers before
if (dwBufferPos == 0)
dwCanBeSystem += 6;
else
dwCanBeSystem += 2;
}
else
{
MmDebugLogfile((MmDebugLevelTrace, "Filetype: MPEG_SYSTEM"));
return FT_MPEG_SYSTEM;
}
}
}
else if ((*pBuffer) == M2T_SYNC_BYTE)
{
BOOL bFound = TRUE;
DWORD dwAd = 0;
INT ind = 0;
for (; (ind < 20) && (dwBufferPos+dwAd < dwSearchBufferSize); ind++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -