mirror of
https://github.com/horsicq/Detect-It-Easy.git
synced 2026-06-24 01:54:08 +00:00
215 lines
6.4 KiB
Text
215 lines
6.4 KiB
Text
// DIE's signature file
|
|
// Author: Jason Hood <jadoxa@yahoo.com.au>
|
|
/*
|
|
Ref: http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm
|
|
http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header
|
|
*/
|
|
|
|
init("audio","MP3 Audio File");
|
|
|
|
includeScript("duration");
|
|
|
|
var MP3={
|
|
aVersion:["2.5","2","1"],
|
|
aLayer: ["III","II","I"],
|
|
aRatev1: [32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320, // Layer III
|
|
32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384, // Layer II
|
|
32,64,96,128,160,192,224,256,288,320,352,384,416,448], // Layer I
|
|
aRatev2: [ 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160, // Layers III & II
|
|
32,48,56,64,80,96,112,128,144,160,176,192,224,256], // Layer I
|
|
aFreq: [11025,12000, 8000, // v2.5
|
|
22050,24000,16000, // v2
|
|
44100,48000,32000], // v1
|
|
aCh: ["Stereo","Joint stereo","Dual mono","Mono"],
|
|
|
|
header: function(nOffset)
|
|
{
|
|
// AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
|
|
var nHeader=Binary.readBEDword(nOffset);
|
|
if((nHeader&0xFFE00000)!=~~0xFFE00000) // AAAAAAAAAAA
|
|
{
|
|
return null;
|
|
}
|
|
var nVer=(nHeader>>>19)&3; // BB
|
|
if(nVer==1) // reserved
|
|
{
|
|
return null;
|
|
}
|
|
if(nVer>1)
|
|
{
|
|
--nVer;
|
|
}
|
|
var nLayer=(nHeader>>>17)&3; // CC
|
|
if(nLayer==0) // reserved
|
|
{
|
|
return null;
|
|
}
|
|
--nLayer;
|
|
var nBitrateIndex=(nHeader>>>12)&15; // EEEE
|
|
if(nBitrateIndex==0||nBitrateIndex==15) // free/bad
|
|
{
|
|
return null;
|
|
}
|
|
--nBitrateIndex;
|
|
var nSamplingIndex=(nHeader>>>10)&3; // FF
|
|
if(nSamplingIndex==3) // reserved
|
|
{
|
|
return null;
|
|
}
|
|
var nPadding=(nHeader>>>9)&1; // G
|
|
var nChannelMode=(nHeader>>>6)&3; // II
|
|
|
|
var nBitrate=nVer==2?this.aRatev1[nLayer*14+nBitrateIndex]
|
|
:this.aRatev2[(nLayer==2)*14+nBitrateIndex];
|
|
var nFreq=this.aFreq[nVer*3+nSamplingIndex];
|
|
var nTime;
|
|
if(nLayer==2) // Layer I
|
|
{
|
|
nTime=384/nFreq;
|
|
}
|
|
else if(nLayer==1||nVer==2) // Layer II or v1,Layer III
|
|
{
|
|
nTime=1152/nFreq;
|
|
}
|
|
else // v2/2.5,Layer III
|
|
{
|
|
nTime=576/nFreq;
|
|
}
|
|
var bVBR=1;
|
|
var nVBR=Binary.findString(nOffset,40,"Xing");
|
|
if(nVBR==-1)
|
|
{
|
|
nVBR=Binary.findString(nOffset,40,"Info");
|
|
bVBR=0;
|
|
}
|
|
if(nVBR!=-1&&(Binary.readByte(nVBR+7)&1))
|
|
{
|
|
nTime*=Binary.readBEDword(nVBR+8);
|
|
nOffset=bVBR?-1:-2;
|
|
}
|
|
else if(Binary.compare("'VBRI'",nOffset+32))
|
|
{
|
|
nTime*=Binary.readBEDword(nVBR+46);
|
|
nOffset=-1;
|
|
}
|
|
else
|
|
{
|
|
if(nLayer==2) // Layer I
|
|
{
|
|
nOffset+=Math.floor(12000*nBitrate/nFreq+nPadding)*4;
|
|
}
|
|
else
|
|
{
|
|
// 125 = 1000/8 = kilobits to bytes
|
|
nOffset+=Math.floor(125*nBitrate*nTime+nPadding);
|
|
}
|
|
}
|
|
return [this.aVersion[nVer],
|
|
this.aLayer[nLayer],
|
|
nBitrate,
|
|
nFreq,
|
|
this.aCh[nChannelMode],
|
|
nTime,
|
|
nOffset];
|
|
}
|
|
}
|
|
|
|
function detect(bShowType,bShowVersion,bShowOptions)
|
|
{
|
|
if(Binary.getSize()>=128)
|
|
{
|
|
if(Binary.compare("'TAG'",Binary.getSize()-128))
|
|
{
|
|
sOptions="ID3v1";
|
|
}
|
|
var nOffset=0,bID3v2=0;
|
|
if(Binary.compare("'ID3'"))
|
|
{
|
|
nOffset=(Binary.readByte(6)<<21)
|
|
|(Binary.readByte(7)<<14)
|
|
|(Binary.readByte(8)<<7)
|
|
|(Binary.readByte(9));
|
|
nOffset+=10;
|
|
if(sOptions=="")
|
|
{
|
|
sOptions="ID3v2";
|
|
}
|
|
else
|
|
{
|
|
sOptions+="&2";
|
|
}
|
|
bID3v2=1;
|
|
}
|
|
else if(Binary.compare("'WAVEfmt '........55",8))
|
|
{
|
|
nOffset=Binary.findString(50,50,"data")+8;
|
|
}
|
|
var aResult1,aResult=null;
|
|
aResult1=MP3.header(nOffset);
|
|
if(aResult1==null)
|
|
{
|
|
if(bID3v2)
|
|
{
|
|
// There may be some junk between the ID3 tag & the data (Win7
|
|
// sample music files - C:\Users\Public\Music\Sample Music).
|
|
// Since the ID3 tag is a fair indicator of an MP3, do a search
|
|
// for v1,Layer III header.
|
|
nOffset=Binary.findSignature(nOffset,768,"FFFB");
|
|
aResult1=MP3.header(nOffset);
|
|
}
|
|
if(aResult1==null)
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
if(aResult1[6]>0)
|
|
{
|
|
aResult=MP3.header(aResult1[6]);
|
|
if(aResult==null)
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
bDetected=1;
|
|
// Assume version, layer & channels don't change.
|
|
sVersion="v"+aResult1[0]+",Layer "+aResult1[1];
|
|
|
|
if(bShowOptions)
|
|
{
|
|
var nFrames=1;
|
|
var nRateSum=aResult1[2];
|
|
var nFreqSum=aResult1[3];
|
|
var nSeconds=aResult1[5];
|
|
var bVBR=0,bVF=0;
|
|
while(aResult!=null)
|
|
{
|
|
nFrames++;
|
|
nRateSum+=aResult[2];
|
|
nFreqSum+=aResult[3];
|
|
nSeconds+=aResult[5];
|
|
if(aResult[2]!=aResult1[2])
|
|
{
|
|
bVBR=1;
|
|
}
|
|
if(aResult[3]!=aResult1[3])
|
|
{
|
|
bVF=1;
|
|
}
|
|
aResult=MP3.header(aResult[6]);
|
|
}
|
|
sOptions=sOptions.append(Math.round(nRateSum/nFrames)+"kbps");
|
|
if(bVBR)
|
|
{
|
|
sOptions+="(avg)";
|
|
}
|
|
sOptions=sOptions.append(Math.round(nFreqSum/nFrames)+"Hz");
|
|
if(bVF)
|
|
{
|
|
sOptions+="(avg)";
|
|
}
|
|
sOptions=sOptions.append(aResult1[4],duration(nSeconds));
|
|
}
|
|
}
|
|
|
|
return result(bShowType,bShowVersion,bShowOptions);
|
|
}
|