📄 recog_util.cpp
字号:
/*============================================================================*
*
* (c) 1995-2003 RealNetworks, Inc. Patents pending. All rights reserved.
*
*
* Recognition helpers for recognizing file datatype given buffer and filename
*
*============================================================================*/
#include <e32svr.h>
#include <apmrec.h>
#include <apmstd.h>
#include "mpa_frame_header.h"
#include "hxassert.h"
#include "hxsym_mimetypes.h"
#include "recog_util.h"
namespace RecogUtil
{
//
// constants
//
// magic numbers
_LIT8(KMagicRMF, ".RMF");
_LIT8(KMagic3GPP, "ftyp3gp");
_LIT8(KMagicMPEG4, "moov");
_LIT8(KMagicAMR, "#!AMR");
_LIT8(KMagicSDP, "v=");
enum RecognitionLevel
{
ECertain=CApaDataRecognizerType::ECertain,
EProbable=CApaDataRecognizerType::EProbable,
EPossible=CApaDataRecognizerType::EPossible,
EUnlikely=CApaDataRecognizerType::EUnlikely,
ENotRecognized=CApaDataRecognizerType::ENotRecognized
};
void IncRecogLevel(RecognitionLevel& level)
{
switch( level)
{
case ECertain:
// highest level already
break;
case EProbable:
level = ECertain;
break;
case EPossible:
level = EProbable;
break;
case EUnlikely:
case ENotRecognized:
level = EPossible;
break;
default:
HX_ASSERT(false);
break;
}
}
TBool FindScheme(const TDesC& aScheme, const TDesC& aUrl)
{
TInt colonPos = aUrl.Locate(':');
TInt schemePos = KErrNotFound;
schemePos = aUrl.FindF(aScheme);
TBool found = (schemePos >= 0 && aScheme.Length() == colonPos);
return found;
}
TInt IsRMFile(const TDesC& aName, const TDesC8& aBuffer)
{
TInt confidence = ENotRecognized;
const TDesC8& magic = KMagicRMF;
TBool validMagic=ETrue;
TInt i;
for (i=0; i<aBuffer.Length() && i<4; i++)
{
if (aBuffer[i] != magic[i])
{
validMagic = EFalse;
break;
}
}
if (validMagic)
{
confidence = ECertain;
}
return confidence;
}
TInt IsAMRFile(const TDesC& aName, const TDesC8& aBuffer)
{
TInt confidence = ENotRecognized;
const TDesC8& magic = KMagicAMR;
TBool validMagic=ETrue;
TInt i;
for (i=0; i<aBuffer.Length() && i<KMagicAMR().Length(); i++)
{
if (aBuffer[i] != magic[i])
{
validMagic = EFalse;
break;
}
}
if (validMagic)
{
confidence = ECertain;
}
return confidence;
}
TInt IsSMILFile(const TDesC& aName, const TDesC8& aBuffer)
{
//
//<?xml version="1.0"?>
//<smil xmlns="http://www.w3.org/2001/SMIL20/Language">
//<body>
//</body>
//</smil
//
bool bHasExt = false;
TInt confidence = ENotRecognized;
// check for .smi or .smil extension
TInt idxDot = aName.LocateReverse('.');
if(idxDot != KErrNotFound)
{
_LIT(KSmilExtShort, ".smi");
_LIT(KSmilExtLong, ".smil");
TPtrC ptrExt = aName.Mid(idxDot);
if( !ptrExt.CompareF(KSmilExtShort) || !ptrExt.CompareF(KSmilExtLong) )
{
// has extension, therefore probably a smil file
bHasExt = true;
confidence = EProbable;
}
}
// both of these are required smil tags
_LIT8(KXmlSMILTag, "<smil");
_LIT8(KXmlBODYTag, "<body");
if (aBuffer.FindF(KXmlSMILTag) != KErrNotFound)
{
if(bHasExt)
{
// has smil tag as well as extension, therefore certainly a smil file
confidence = ECertain;
}
else
{
// has smil tag but no extension, therefore possibly a smil file
confidence = EPossible;
if(aBuffer.FindF(KXmlBODYTag) != KErrNotFound)
{
// body tag as well, therefore probably a smil file
confidence = EProbable;
}
}
}
return confidence;
}
TInt IsRAMFile(const TDesC& aName, const TDesC8& aBuffer)
{
TBool nameRecognized=EFalse;
TInt confidence = ENotRecognized;
if ((aBuffer.FindF(_L8("rtsp://")) != KErrNotFound ||
aBuffer.FindF(_L8("file://")) != KErrNotFound ||
aBuffer.FindF(_L8("http://")) != KErrNotFound) &&
aBuffer.FindF(_L8("<html>")) == KErrNotFound)
{
confidence = EPossible;
}
if (aName.Length()>4)
{
_LIT(KRamExt, ".ram");
if (aName.Right(4).CompareF(KRamExt)==0)
{
nameRecognized=ETrue;
}
}
if (confidence == EPossible && nameRecognized)
{
confidence = ECertain;
}
return confidence;
}
RecognitionLevel TestForMP3FrameHeaders(const TDesC8& buffer)
{
TInt idxEnd = buffer.Length() - MPA_FRAME_HDR_SZ;
for(TInt idx = 0; idx < idxEnd; ++idx)
{
const unsigned char* pBuf = buffer.Ptr() + idx;
// try and parse mp3 frame at this location
MPAFrameHeader frame;
if( frame.Unpack(pBuf) && (MPA_LAYER3 == frame.m_layer) )
{
// looks like a valid frame so far; now move on past frame (header + data)
pBuf += frame.m_frameSize;
if(pBuf < buffer.Ptr() + idxEnd)
{
// look for second frame header with matching attributes
MPAFrameHeader frame2;
if( frame2.Unpack(pBuf)
&& (frame2.m_version == frame.m_version)
&& (frame2.m_layer == frame.m_layer)
&& (frame2.m_sampleRate == frame.m_sampleRate) )
{
// highly likely this is mp3
return EProbable;
}
}
else
{
// good chance this is mp3 (frame size exceeds the buffer we get)
return EPossible;
}
}
}
return ENotRecognized;
}
TInt IsMP3File(const TDesC& aName, const TDesC8& aBuffer)
{
RecognitionLevel confidence = ENotRecognized;
//RDebug::Print(_L("looking at '%S'"), &aName);
_LIT8(KMagicID3, "ID3");
_LIT(KMP3Ext, ".mp3");
// look for mp3 extension
bool bHasExtension = (0 == aName.Right(4).CompareF(KMP3Ext));
// look for start of ID3v2 header
bool bHasID3 = (0 == aBuffer.Left(3).Compare(KMagicID3));
if(bHasID3)
{
// other MPA types as well as AAC may have an ID3 header; the header
// can be quite long so we often can't find frame headers because the
// buffer is too small
confidence = EPossible;
}
else
{
confidence = TestForMP3FrameHeaders(aBuffer);
}
if(bHasExtension)
{
IncRecogLevel(confidence);
}
return confidence;
}
TInt Is3GPPFile(const TDesC& aName, const TDesC8& aBuffer)
{
_LIT8(KFtyp3gpp, "3gp"); // 3gp4 and 3gp5
TInt confidence = IsISOMediaFile(aName, aBuffer, KFtyp3gpp);
if( ENotRecognized != confidence )
{
TInt index = aBuffer.Find(KFtyp3gpp);
HX_ASSERT(index != KErrNotFound);
if(index != KErrNotFound)
{
// look at character after '3gp'
index += KFtyp3gpp().Length();
HX_ASSERT(index < aBuffer.Length());
if (aBuffer[index] != '4' && aBuffer[index] != '5')
{
// we only recognize 3gp4 and 3gp5
confidence = ENotRecognized;
}
}
}
return confidence;
}
TInt IsMPEG4File(const TDesC& aName, const TDesC8& aBuffer)
{
_LIT8(KFtypMP4, "mp4"); // mp41 and others
return IsISOMediaFile(aName, aBuffer, KFtypMP4);
}
TInt IsMPEG4Audio(const TDesC& aName, const TDesC8& aBuffer)
{
TInt confidence = ENotRecognized;
_LIT8(KSampleEntryMPEG4Video, "mp4v");
_LIT8(KSampleEntryH263Video, "s263");
if (aBuffer.Find(KSampleEntryH263Video) != KErrNotFound &&
aBuffer.Find(KSampleEntryMPEG4Video) != KErrNotFound)
confidence = EProbable;
return confidence;
}
TInt IsSDPFile(const TDesC& aName, const TDesC8& aBuffer)
{
TInt confidence = ENotRecognized;
const TDesC8& magic = KMagicSDP;
TBool validMagic=ETrue;
TInt i;
for (i=0; i<aBuffer.Length() && i<KMagicSDP().Length(); i++)
{
if (aBuffer[i] != magic[i])
{
validMagic = EFalse;
break;
}
}
if (validMagic)
confidence = ECertain;
return confidence;
}
inline
TUint32 UnpackUint32(const TUint8* buf)
{
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
}
TInt IsISOMediaFile(const TDesC& aName, const TDesC8& aBuffer, const TDesC8& brand)
{
_LIT8(KAtomFTYP, "ftyp");
HX_ASSERT(brand.Length() <= 4);
TInt confidence = ENotRecognized;
TInt idx = aBuffer.Find(KAtomFTYP);
if( idx >= 4)
{
// back up to size field; preceeds object identifier
idx -= 4;
// get size of potential atom(box) data
TInt cbAtomData = UnpackUint32(aBuffer.Ptr() + idx) - 8;
// index past size + 'ftype' to beginning of atom data
idx += 8;
TInt cbLeft = aBuffer.Length() - idx;
if( cbLeft > cbAtomData )
{
// likely case since ftyp atom is small and buffer is large; we'll only look at potential ftyp atom
cbLeft = cbAtomData;
}
// now look for matching brand (3gp?, isom, mp4?, etc.)
enum
{
getFirst,
getOthers
} state = getFirst;
// look at 4-byte objects (every field is four bytes in ftyp atom/box)
for(TInt idxLast = idx + cbLeft - 4; idx <= idxLast; idx += 4)
{
TPtrC8 ptr = aBuffer.Mid(idx, brand.Length());
if(0 == ptr.Compare(brand))
{
// found matching brand
confidence = ECertain;
break;
}
if( getFirst == state )
{
// skip past minor version and continue searching for compatible brands
idx += 4;
state = getOthers;
}
}
}
return confidence;
}
} // ns RecogUtil
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -