Click here to Skip to main content
15,895,011 members
Articles / Desktop Programming / MFC

MPEG Audio Frame Header

Rate me:
Please Sign up or sign in to vote.
4.89/5 (95 votes)
12 Apr 2007LGPL317 min read 901.2K   20.8K   245  
An article about the MPEG audio frame header.
#include "stdafx.h"

#include <math.h>	// for ceil
#include "mpaframe.h"
#include "mpaendoffileexception.h"


// number of bits that are used for CRC check in MPEG 1 Layer 2
// (this table is invalid for Joint Stereo/Intensity Stereo)
// 1. index = allocation table index, 2. index = mono
const DWORD CMPAFrame::m_dwProtectedBitsLayer2[5][2] =
{
	{284,142},	// table a
	{308,154},	// table b
	{42,84},	// table c
	{62,114},	// table d
	{270,135}	// table for MPEG 2/2.5
};

CMPAFrame::CMPAFrame(CMPAStream* pStream, DWORD& dwOffset, bool bFindSubsequentFrame, bool bExactOffset, bool bReverse, CMPAHeader* pCompareHeader) :
	m_pStream(pStream),
	m_dwOffset(dwOffset),
	m_bIsLast(false)
{
	
	// decode header of frame at position dwOffset
	m_pHeader = new CMPAHeader(pStream, m_dwOffset, bExactOffset, bReverse, pCompareHeader);
	m_dwFrameSize = m_pHeader->CalcFrameSize();

	// do extended check?
	if (bFindSubsequentFrame)
	{	
		// calc offset for next frame header
		DWORD dwNewOffset = GetSubsequentHeaderOffset();
		try
		{
			CMPAFrame* pSubsequentFrame = new CMPAFrame(pStream, dwNewOffset, false, true, false, m_pHeader);
			delete pSubsequentFrame;
		}

		/* if no subsequent frame found
			- end of file reached (last frame)
			- corruption in file
				- subsequent frame is at incorrect position (out of detection range)
				- frame was incorrectly detected (very improbable)
		*/
		catch (CMPAEndOfFileException)
		{
			m_bIsLast = true;
		}
		catch (CMPAException& e)
		{
			OutputDebugString(_T("Didn't find subsequent frame"));
			//if (e->GetErrorID() == CMPAException::NoFrameInTolerance
		}
	}
	
}

CVBRHeader* CMPAFrame::FindVBRHeader() const
{
	// read out VBR header (if available), must be freed with delete
	return CVBRHeader::FindHeader(this);
}


CMPAFrame::~CMPAFrame(void)
{
	delete m_pHeader;
}


// returns true if CRC is correct otherwise false
// do only call this function, if header contains a CRC checksum
bool CMPAFrame::CheckCRC() const
{
	if (!m_pHeader->m_bCRC)
		return false;

	DWORD dwProtectedBits;
	
	// which bits should be considered for CRC calculation
	switch(m_pHeader->m_Layer)
	{
		case CMPAHeader::Layer1:
			dwProtectedBits = 4* (m_pHeader->GetNumChannels() * m_pHeader->m_wBound + (32 - m_pHeader->m_wBound));
			break;
		case CMPAHeader::Layer2:
			// no check for Layer II files (not easy to compute number protected bits, need to get allocation bits first)
			return true;
			break;
		// for Layer III the protected bits are the side information
		case CMPAHeader::Layer3:
			dwProtectedBits = m_pHeader->GetSideInfoSize()*8;
		default:
			return true;
	}

	// CRC is also calculated from the last 2 bytes of the header
	dwProtectedBits += MPA_HEADER_SIZE*8 +16;	// +16bit for CRC itself

	DWORD dwByteSize = (DWORD)ceil(dwProtectedBits/8.0); 
	
	// the first 2 bytes and the CRC itself are automatically skipped
	DWORD dwOffset = m_dwOffset;
	WORD wCRC16 = CalcCRC16(m_pStream->ReadBytes(dwByteSize, dwOffset, false), dwProtectedBits);

	// read out crc from frame (it follows frame header)
	dwOffset += + MPA_HEADER_SIZE;
	if (wCRC16 == m_pStream->ReadBEValue(2, dwOffset, false))
		return true;

	return false;
}

// CRC16 check
WORD CMPAFrame::CalcCRC16(BYTE* pBuffer, DWORD dwBitSize)
{
	DWORD n;
	WORD tmpchar, crcmask, tmpi;
	crcmask = tmpchar = 0;
	WORD crc = 0xffff;			// start with inverted value of 0

	// start with byte 2 of header
	for (n = 16;  n < dwBitSize;  n++)
	{
		if (n < 32 || n >= 48) // skip the 2 bytes of the crc itself
		{
			if (n%8 == 0)
			{
				crcmask = 1 << 8;
				tmpchar = pBuffer[n/8];
			}
			crcmask >>= 1;
			tmpi = crc & 0x8000;
			crc <<= 1;
			
			if (!tmpi ^ !(tmpchar & crcmask))
				crc ^= 0x8005;
		}
	}
	crc &= 0xffff;	// invert the result
	return crc;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Web Developer
Germany Germany
Author of the shareware WinCD.

Comments and Discussions