mp3format.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:16k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #include "hlxclib/string.h"
- #include "hlxclib/stdlib.h"
- #include "mp3format.h"
- #include "mp3queue.h"
- #include "mhead.h"
- CMp3Format::CMp3Format()
- : CAudioInfoBase(),
- m_pMisc(new CMp3Misc),
- m_nLayer(3),
- m_bMpeg25(0),
- m_bTrustPackets(FALSE),
- m_pFnGetData(GetDataOffsetMPEG1)
- {
- if (m_pMisc)
- m_pMisc->SetParent(this);
- }
- CMp3Format::CMp3Format(CMp3Misc* pMisc)
- : CAudioInfoBase(),
- m_pMisc(pMisc),
- m_nLayer(3),
- m_bMpeg25(0),
- m_pFnGetData(GetDataOffsetMPEG1)
- {
- if (m_pMisc)
- m_pMisc->SetParent(this);
- }
- CMp3Format::~CMp3Format()
- {
- HX_DELETE(m_pMisc);
- }
- BOOL CMp3Format::Init(UINT8 *pHeader,
- UINT32 ulSize)
- {
- MPEG_HEAD h;
- memset(&h, 0, sizeof(h));
- if (!head_info(pHeader, ulSize, &h, m_bTrustPackets))
- return 0;
- // Detect MPEG2.5
- if ((pHeader[1] & 0xF0) == 0xE0)
- m_bMpeg25 = 1;
- // Detect MPEG1/MPEG2
- if(h.id)
- m_pFnGetData = GetDataOffsetMPEG1;
- else
- m_pFnGetData = GetDataOffsetMPEG2;
- m_ySyncWord = pHeader[1];
- UINT32 ulTemp;
- int nTemp;
- GetEncodeInfo(pHeader,
- ulSize,
- ulTemp,
- ulTemp,
- nTemp,
- m_nLayer,
- nTemp);
-
- m_bIsInited = 1;
- return 1;
- }
- BOOL CMp3Format::GetDataOffset(UINT8 *pHeader,
- UINT32 dwSize,
- int &nFrameSize,
- int &nHeaderSize,
- int &nDataOffset)
- {
- return m_pFnGetData(pHeader, dwSize, nFrameSize, nHeaderSize, nDataOffset, m_bTrustPackets);
- }
- void CMp3Format::ClearMainDataBegin(UINT8 *pHeader)
- {
- if (m_nLayer != 3)
- return;
- int nOffset = 4;
- // Check protection bit
- if ((pHeader[1] & 1) == 0)
- nOffset += 2;
- // MPEG1 main_data_begin is 9 bits in MPEG2 it is 8
- pHeader[nOffset] = 0;
-
- if (GetDataOffsetMPEG1 == m_pFnGetData)
- pHeader[nOffset + 1] &= 0x7F;
- }
- BOOL CMp3Format::GetEncodeInfo(UINT8 *pHeader,
- UINT32 dwSize,
- UINT32 &ulBitRate,
- UINT32 &ulSampleRate,
- int &nChannels,
- int &nLayer,
- int &nSamplesPerFrame)
- {
- MPEG_HEAD h;
- INT32 aSampRate[2][3] = // MPEG SPEC x NATIVE RATE
- {
- 22050,24000,16000, // MPEG2
- 44100,48000,32000 // MPEG1
- };
- memset(&h, 0, sizeof(h));
- ulBitRate =
- ulSampleRate = 0;
- nChannels =
- nSamplesPerFrame = 0;
- int nBitRate = 0;
- if (!head_info2(pHeader, dwSize, &h, &nBitRate, m_bTrustPackets))
- {
- ulBitRate = nBitRate;
- return 0;
- }
- ulBitRate = nBitRate;
-
- if (3 == h.mode)
- nChannels = 1;
- else
- nChannels = 2;
- ulSampleRate = aSampRate[h.id][h.sr_index] >> m_bMpeg25;
- // Get the layer so we can work out the bit rate
- switch (h.option)
- {
- case 3:
- nLayer = 1;
- break;
-
- case 2:
- nLayer = 2;
- break;
-
- case 1:
- nLayer = 3;
- }
-
- if((h.option == 1) & (h.id == 0)) // MPEGII Layer III
- {
- nSamplesPerFrame = 576;
- m_pFnGetData = GetDataOffsetMPEG2;
- }
- else if(h.option == 3)
- nSamplesPerFrame = 384; // Layer I
- else
- nSamplesPerFrame = 1152;
- return 1;
- }
- int CMp3Format::ReformatMP3Frame(UINT8 **ppFrame,
- UINT32 dwBytes,
- UINT32 dwPrevBytes)
- {
- // Get the sync info
- int nFrameSize = 0,
- nHeaderSize = 0,
- nDataOffset = 0;
- UINT8 bAcceptFrame = 1;
- UINT8 *pFrame = *ppFrame;
- if (!GetDataOffset(pFrame,
- dwBytes,
- nFrameSize,
- nHeaderSize,
- nDataOffset))
- return 0;
- if (m_nLayer != 3)
- return nFrameSize;
- // nDataOffset points to data before our buffer.
- // We must reformat what we can for the next frame.
- if ((UINT32)nDataOffset > dwPrevBytes)
- {
- nDataOffset = dwPrevBytes;
- bAcceptFrame = 0;
- }
- // Calculate the modified frame size
- UINT8 *pNextFrame = pFrame + nFrameSize;
- int nDataOffset2 = 0,
- nTemp = 0;
-
- // Last frame has just enough data
- if ((int)dwBytes > nFrameSize)
- {
- if (!GetDataOffset(pNextFrame,
- dwBytes - nFrameSize,
- nTemp,
- nTemp,
- nDataOffset2))
- return 0;
- }
- // If this is a self contained frame, do nothing special
- if (!nDataOffset && !nDataOffset2)
- return nFrameSize;
- // Clear main_data_begin offset of current sync
- nTemp = 4;
- // Check protection bit
- if ((pFrame[1] & 1) == 0)
- nTemp += 2;
- //pFrame[nTemp] = 0;
- //
- // MPEG1 main_data_begin is 9 bits in MPEG2 it is 8
- //if (GetDataOffsetMPEG1 == m_pFnGetData)
- // pFrame[nTemp + 1] &= 0x7F;
- // Store the header of current sync
- UINT8 *pHeader = new UINT8[nHeaderSize];
- memcpy(pHeader, pFrame, nHeaderSize); /* Flawfinder: ignore */
- // Move offset data forward
- memmove(pFrame - nDataOffset + nHeaderSize,
- pFrame - nDataOffset,
- nDataOffset);
- // Copy header data before offset data
- memcpy(pFrame - nDataOffset, /* Flawfinder: ignore */
- pHeader,
- nHeaderSize);
- delete [] pHeader;
- *ppFrame -= nDataOffset;
- // Calculate the new frame size
- nFrameSize = (pNextFrame - nDataOffset2) -
- *ppFrame;
- return nFrameSize * bAcceptFrame;
- }
- int CMp3Format::CheckValidFrame(UINT8 *pBuf,
- UINT32 dwSize)
- {
- // Are there enough bytes
- if (dwSize < 4)
- return 0;
- // Is this a sync word
- if ((pBuf[0] != 0xFF) |
- !IsValidSyncWord(pBuf[1]))
- return 0;
-
- MPEG_HEAD head;
- memset(&head, 0, sizeof(head));
- int nRet = head_info(pBuf, dwSize, &head, m_bTrustPackets);
- if (nRet)
- {
- nRet += head.pad;
- if (nRet > (int)dwSize)
- nRet = 0;
- }
- return nRet;
- }
- int CMp3Format::UnformatMP3Frame(CMp3Queue* pQueue,
- UINT8* pDest,
- UINT32 &ulTime)
- {
- tFrameInfo* pInfo = pQueue->GetHead();
- ulTime = pInfo->ulTime;
- // Do we have enough bytes for the frame
- if (pInfo->ulFrameSize - pInfo->ulHdrSize <= pQueue->GetDataBytes())
- {
- int nFrameSize = pInfo->ulFrameSize,
- nRet = pInfo->ulFrameSize;
- memcpy(pDest, pInfo->pHdr, pInfo->ulHdrSize); /* Flawfinder: ignore */
- pDest += pInfo->ulHdrSize;
- memcpy(pDest, pInfo->pData, pInfo->ulDataSize); /* Flawfinder: ignore */
- nFrameSize -= pInfo->ulDataSize + pInfo->ulHdrSize;
- pQueue->RemoveDataBytes(pInfo->ulDataSize);
- pInfo->pData += pInfo->ulDataSize;
- pDest += pInfo->ulDataSize;
- pInfo->ulDataSize = 0;
- int nCopy;
- // Copy data from future frames until we comple this frame
- while (nFrameSize)
- {
- pInfo = pQueue->Next();
- nCopy = min(pInfo->ulDataSize, (UINT32)nFrameSize);
- memcpy(pDest, pInfo->pData, nCopy); /* Flawfinder: ignore */
- pDest += nCopy;
- pInfo->pData += nCopy;
- pInfo->ulDataSize -= nCopy;
- nFrameSize -= nCopy;
- pQueue->RemoveDataBytes(nCopy);
- }
- pQueue->RemoveHead();
- return nRet;
- }
- else
- return 0;
- }
- INT32 CMp3Format::ScanForSyncWord(UINT8 *pBuf,
- INT32 lSize,
- int &nFrameSize)
- {
- UINT8 *pStart = pBuf,
- *pEnd = pBuf + lSize - 4,
- *pTemp = NULL,
- ySyncCheck = 0;
- MPEG_HEAD head;
- int iFrameSize = 0;
- if (lSize < 4)
- return -1;
- nFrameSize = 0;
- for (; pBuf < pEnd; pBuf++)
- {
- if (pBuf[0] != 0xFF)
- continue;
-
- if (m_ySyncWord)
- {
- if (!IsValidSyncWord(pBuf[1]))
- continue;
- }
- else if ((pBuf[1] & 0xE0) != 0xE0)
- continue;
- ySyncCheck = pBuf[1];
- memset(&head, 0, sizeof(head));
- iFrameSize = head_info(pBuf, pEnd-pBuf, &head, m_bTrustPackets);
- // Looks like a valid frame
- if (iFrameSize)
- {
- iFrameSize += head.pad;
- // Check for another frame
- if (pBuf+iFrameSize < pEnd+3)
- {
- pTemp = pBuf + iFrameSize;
- // We do not have consequitve frames..what to do, what to do?
- if ((pTemp[0] != 0xFF) |
- (pTemp[1] != ySyncCheck))
- {
- INT32 lHeaderSize = 0;
- // First, check for know non-mp3 data that may
- // reside in an mp3 stream and terminate a frame.
- BOOL bFoundHdr = FALSE;
-
- if (m_pMisc)
- bFoundHdr = m_pMisc->CheckForHeaders(pTemp,
- pEnd-pTemp+4,
- lHeaderSize);
- if (bFoundHdr)
- nFrameSize = iFrameSize;
- // Next, check if the padding bit was incorrectly set
- else if ((pTemp[-1] == 0xFF) &
- (pTemp[0] == ySyncCheck))
- nFrameSize = iFrameSize;
- // Finally, check if the padding bit was not set and
- // should have been.
- else if ((pTemp[1] == 0xFF) &
- (pTemp[2] == ySyncCheck))
- nFrameSize = iFrameSize;
- // Did not find consequtive frames. Keep looking
- else
- continue;
- }
- else
- {
- // We found a frame
- nFrameSize = iFrameSize;
- }
- }
- // There is one full frame in this buffer
- else if (pBuf+iFrameSize == pEnd+4)
- {
- // We found a frame
- nFrameSize = iFrameSize;
- }
- break;
- }
- }
- if (nFrameSize)
- return pBuf - pStart;
- else
- return -1;
- }
- BOOL CMp3Format::CheckForHeaders(UINT8 *pBuf,
- UINT32 dwSize,
- INT32 &lHeaderSize)
- {
- if (m_pMisc)
- return m_pMisc->CheckForHeaders(pBuf, dwSize, lHeaderSize);
- else
- return FALSE;
- }
- eHeaderType CMp3Format::GetHeaderType()
- {
- if (m_pMisc)
- return m_pMisc->GetHeaderType();
- else
- return eNone;
- }
- // Functions to access the Id3 header values
- UINT8* CMp3Format::GetId3Title(int &nLen)
- {
- if (m_pMisc)
- return m_pMisc->GetId3Title(nLen);
- else
- return NULL;
- }
- UINT8* CMp3Format::GetId3Artist(int &nLen)
- {
- if (m_pMisc)
- return m_pMisc->GetId3Artist(nLen);
- else
- return NULL;
- }
- UINT8* CMp3Format::GetId3Album(int &nLen)
- {
- if (m_pMisc)
- return m_pMisc->GetId3Album(nLen);
- else
- return NULL;
- }
- UINT8* CMp3Format::GetId3Genre(int &nLen)
- {
- if (m_pMisc)
- return m_pMisc->GetId3Genre(nLen);
- else
- return NULL;
- }
- int CMp3Format::GetMetaOffset()
- {
- if (m_pMisc)
- return m_pMisc->GetMetaOffset();
- else
- return 0;
- }
- int CMp3Format::GetMetaRepeat()
- {
- if (m_pMisc)
- return m_pMisc->GetMetaRepeat();
- else
- return 0;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Private Functions
- BOOL CMp3Format::GetDataOffsetMPEG1(UINT8 *pHeader,
- UINT32 dwSize,
- int &nFrameSize,
- int &nHeaderSize,
- int &nDataOffset,
- int trustPackets)
- {
- // Get header info
- MPEG_HEAD h;
- memset(&h, 0, sizeof(h));
- nFrameSize = head_info(pHeader, dwSize, &h, trustPackets);
-
- if (nFrameSize)
- nFrameSize += h.pad;
- // HeaderSize is the sync word, CRC, and side info
- nHeaderSize = 4;
- // Check protection bit
- if ((pHeader[1] & 1) == 0)
- nHeaderSize += 2;
- // Not enough data to check main_data_begin
- if (dwSize < (unsigned int)nHeaderSize + 2)
- return 0;
- // Extract main_data_begin offset (9 bits)
- nDataOffset = (pHeader[nHeaderSize] << 1) +
- (pHeader[nHeaderSize + 1] >> 7);
- // Side info (256 bits for stereo, 136 for mono)
- if (3 == h.mode)
- nHeaderSize += 17;
- else
- nHeaderSize += 32;
- return 1;
- }
- BOOL CMp3Format::GetDataOffsetMPEG2(UINT8 *pHeader,
- UINT32 dwSize,
- int &nFrameSize,
- int &nHeaderSize,
- int &nDataOffset,
- int trustPackets)
- {
- // Get header info
- MPEG_HEAD h;
- memset(&h, 0, sizeof(h));
- nFrameSize = head_info(pHeader, dwSize, &h, trustPackets);
-
- if (nFrameSize)
- nFrameSize += h.pad;
- // HeaderSize is the sync word, CRC, and side info
- nHeaderSize = 4;
- // Check protection bit
- if ((pHeader[1] & 1) == 0)
- nHeaderSize += 2;
- // Not enough data to check main_data_begin
- if (dwSize < (unsigned int)nHeaderSize + 1)
- return 0;
- // Extract main_data_begin offset (8 bits)
- nDataOffset = pHeader[nHeaderSize];
- // Side info (136 bits for stereo, 72 for mono)
- if (3 == h.mode)
- nHeaderSize += 9;
- else
- nHeaderSize += 17;
- return 1;
- }