From 864081102a5f252415f41950b3039a896b4ae9c5 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Mon, 8 Oct 2012 18:43:29 +0000 Subject: Awkwars's plugins - welcome to our trunk git-svn-id: http://svn.miranda-ng.org/main/trunk@1822 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Watrack/formats/fmt_mp3.pas | 460 ++++++++++++++++++++++++++++++++++++ 1 file changed, 460 insertions(+) create mode 100644 plugins/Watrack/formats/fmt_mp3.pas (limited to 'plugins/Watrack/formats/fmt_mp3.pas') diff --git a/plugins/Watrack/formats/fmt_mp3.pas b/plugins/Watrack/formats/fmt_mp3.pas new file mode 100644 index 0000000000..5d6c94745a --- /dev/null +++ b/plugins/Watrack/formats/fmt_mp3.pas @@ -0,0 +1,460 @@ +{MP3 file process} +unit fmt_MP3; +{$include compilers.inc} + +interface +uses wat_api; + +function ReadMP3(var Info:tSongInfo):boolean; cdecl; +function ReadMPG(var Info:tSongInfo):boolean; cdecl; + +implementation +uses windows,common,io,tags,srv_format; + +const + ScanSize = 16*1024; // block size to search header +type + tMP3FrameHdr = record + Version :integer; + Layer :cardinal; + Bitrate :cardinal; + Samplerate:cardinal; + Channel :cardinal; //Stereo, Joint, Dual, Mono + Length :cardinal; + CRC :boolean; + _Private :boolean; + Copyright :boolean; + Original :boolean; + isVBR :boolean; + end; + +// ........ ........ 111..... 11111111 syncword +// ........ ........ ...xx... ........ version (11=1, 10=2, 00=2.5) +// ........ ........ .....xx. ........ layer (01=III, 10=II, 11=I) +// ........ ........ .......x ........ crc (0=yes, 1=no) +// xx...... ........ ........ ........ mode (00=stereo, 10=joint, 01=dual, 11=mono) +// ..xx.... ........ ........ ........ mode ext (only for joint stereo) +// ....x... ........ ........ ........ copyright (0=no, 1=yes) +// .....x.. ........ ........ ........ original (0=orig, 1=copy) +// ......xx ........ ........ ........ emphasis (not 10) +// ........ xxxx.... ........ ........ bitrate (not 0000 nor 1111) +// ........ ....xx.. ........ ........ sampling rate (not 11) +// ........ ......x. ........ ........ padded (0=no, 1=yes) +// ........ .......x ........ ........ private bit + +const + btable:array [0..1,0..2,0..15] of word = ( + ( //MPEG 2 & 2.5 + (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0), //Layer III + (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0), //Layer II + (0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256,0) //Layer I + ),( //MPEG 1 + (0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,0), //Layer III + (0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384,0), //Layer II + (0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448,0) //Layer I + ) + ); + stable: array [0..3,0..2] of word = ( + (32000, 16000, 8000), //MPEG 2.5 + ( 0, 0, 0), //reserved + (22050, 24000, 16000), //MPEG 2 + (44100, 48000, 32000) //MPEG 1 + ); + +procedure TranslateFrameHdr(const block:array of byte;var MP3FrameHdr:tMP3FrameHdr); +begin + FillChar(MP3FrameHdr,SizeOf(MP3FrameHdr),0); + if block[0]=$FF then + begin + with MP3FrameHdr do + begin + Version :=(block[1] and $18) shr 3; + Layer :=(block[1] and $06) shr 1; + CRC :=not Odd(block[1]); + Bitrate :=btable[Version and 1][Layer-1][block[2] shr 4]; + Samplerate:=stable[Version][(block[2] and $0C) shr 2]; + _Private :=odd(block[2]); + Channel :=block[3] shr 6; + Copyright :=((block[3] and $08) shr 3)<>0; + Original :=((block[3] and $04) shr 2)<>0; + end; + end; +end; + +procedure CheckVBR(f:THANDLE; var hdr:tMP3FrameHdr); +var + pos,apos:cardinal; + sign:longint; + frames:longint; +begin + pos:=FilePos(f); + hdr.Length:=0; + if hdr.Version=3 then + begin + if hdr.Channel=3 then + apos:=17 + else + apos:=32; + end + else if hdr.Channel=3 then + apos:=9 + else + apos:=17; + Skip(f,apos); + BlockRead(f,sign,4); + hdr.isVBR:=sign=$676E6958; //Xing +//calculate length + if hdr.isVBR then + begin + if hdr.Samplerate<>0 then + begin +// Seek(f,pos+36); + BlockRead(f,sign,4); + if (sign and $01000000)<>0 then + begin + BlockRead(f,frames,4); + frames:=BSwap(frames); + hdr.Length:=Round((1152/hdr.Samplerate)*frames/(4-hdr.Version)); //! + end; + end; + end + else if hdr.Bitrate<>0 then + hdr.Length:=((8*(FileSize(f)-(pos-4))) div 1000) div hdr.Bitrate; +end; + +function SearchStart(f:THANDLE; var l:array of byte):Boolean; +var + CurPos:longint; + Buf:array [0..ScanSize] of byte; + i,j:integer; +begin + CurPos:=FilePos(f)-4; + Seek(f,CurPos); + j:=BlockRead(f,Buf,ScanSize); + i:=0; + while i$F0) then + begin + Seek(f,CurPos+i); + BlockRead(f,l,4); + result:=true; + Exit; + end; + inc(i); + end; + result:=false; +end; + +function ReadMP3(var Info:tSongInfo):boolean; cdecl; +var + f:THANDLE; + l:array [0..3] of byte; + hdr:tMP3FrameHdr; +begin + result:=false; + f:=Reset(Info.mfile); + if f=THANDLE(INVALID_HANDLE_VALUE) then + exit; + ReadID3v2(f,Info); + BlockRead(f,l,4); +// if l[0]<>$FF then + if not SearchStart(f,l) then + Exit; + TranslateFrameHdr(l,hdr); + CheckVBR(f,hdr); + Info.kbps :=hdr.Bitrate; + Info.khz :=hdr.Samplerate div 1000; + Info.total:=hdr.Length; + if hdr.Channel=3 then + Info.channels:=1 + else + Info.channels:=2; + Info.vbr:=ord(hdr.isVBR); + + ReadAPEv2(f,Info); + ReadID3v1(f,Info); + CloseHandle(f); + result:=true; +end; + +const + mpgAudio = 1; + mpgVideo = 2; + mpgVersion = 4; + +type + l2b=array [0..3] of byte; + +function ReadDWord(var p:pAnsiChar;endptr:pAnsiChar):integer; +begin + if (p+4)0; + if i=1 then + begin + result:=ReadByte(p,endptr) or $100; + exit; + end; + end; + until p>=endptr; + result:=0; +end; + +const + BufSize = 256*1024; + +function ReadMPG(var Info:tSongInfo):boolean; cdecl; +var + endptr,buf,p:PAnsiChar; + f:THANDLE; + BlockType:integer; + l:dword; + w:word; + b:byte; + flag:integer; + version,layer:integer; +// vbitrate:integer; +// FrmCnt:integer; +begin + result:=false; + f:=Reset(Info.mfile); + if f=THANDLE(INVALID_HANDLE_VALUE) then + exit; + flag:=mpgAudio+mpgVideo+mpgVersion; + + mGetMem(buf,BufSize); + endptr:=buf+BlockRead(f,buf^,BufSize); + CloseHandle(f); + p:=buf; +// FrmCnt:=0; + while (flag<>0) and (p0 then + begin + flag:=flag and not mpgVersion; + if (ReadByte(p,endptr) and $C0)=$40 then + Info.codec:=$3247504D // MPG2 + else + Info.codec:=$4745504D; // MPEG + end; + end; + $1B3: begin // Video + if (flag and mpgVideo)<>0 then + begin + l:=ReadDWord(p,endptr); + flag:=flag and not mpgVideo; + Info.width :=((l2b(l)[1] and $F0) shr 4)+(l2b(l)[0] shl 4); + Info.height:=((l2b(l)[1] and $0F) shl 8)+l2b(l)[2]; + case l2b(l)[3] and $F of + 1: Info.fps:=2397; + 2: Info.fps:=2400; + 3: Info.fps:=2500; + 4: Info.fps:=2997; + 5: Info.fps:=3000; + 6: Info.fps:=5000; + 7: Info.fps:=5994; + 8: Info.fps:=6000; + end; +// BlockRead(f,l,4); +// vbitrate:=(l2b(l)[0] shl 10)+(l2b(l)[1] shl 2)+(l2b(l)[2] shr 6); + end; + end; + 0,$1B7,$1B9: break; +{ + $1E0: begin + BlockRead(f,w,2); + w:=swap(w); + mGetMem(buf,w); + BlockRead(f,buf^,w); + p:=buf; + for l:=0 to w-4 do + begin + if pdword(p)^=$00010000 then + begin + inc(FrmCnt); + inc(p,4); + end + else + inc(p); + end; + mFreeMem(buf); + end; +} + $1C0: begin // audio + w:=swap(ReadWord(p,endptr)); + if flag and mpgAudio<>0 then + begin + flag:=flag and not mpgAudio; + b:=ReadByte(p,endptr); + dec(w); + if (b and $C0)=$80 then + begin + b:=ReadByte(p,endptr); + l:=ReadByte(p,endptr); + dec(w,2); + if (b and $80)<>0 then + begin + inc(p,5); + dec(w,5); + dec(l,5); + if (b and $40)<>0 then + begin + inc(p,5); + dec(w,5); + dec(l,5); + end; + end; + if l>0 then + begin + inc(p,l); + dec(w,l); + end; + end + else + begin + while (b and $80)<>0 do + begin + dec(w); + if w=0 then break; + b:=ReadByte(p,endptr); + end; + if (b and $40)<>0 then + begin + inc(p); + b:=ReadByte(p,endptr); + dec(w,2); + end; + if (b and $20)<>0 then + begin + inc(p,4); + dec(w,4); + if (b and $10)<>0 then + begin + inc(p,5); + dec(w,5); + end; + end; + end; + l:=ReadDWord(p,endptr); + version:=(l2b(l)[1] and $18) shr 3; + layer :=(l2b(l)[1] and $06) shr 1; + Info.kbps :=btable[version and 1][layer-1][l2b(l)[2] shr 4]; + Info.khz :=(stable[version][(l2b(l)[2] and $0C) shr 2]) div 1000; + Info.channels:=l2b(l)[3] shr 6; + if Info.channels=3 then + Info.channels:=1 + else + Info.channels:=2; +// if w>0 then inc(p,w); + end; +// else + inc(p,w); + end; +{ + $1B5: begin + BlockRead(f,l,4); + if (l2b(l)[0] and $F0)=$10 then + begin + vbitrate:=vbitrate+ + ((((l2b(l)[2] and $1F) shl 7)+(l2b(l)[3] shr 1)) shl 18); + end; + end; +} +{ + $1BD: begin + end; +} + $1C1..$1DF, // audio +//?? $1E0, + $1E1..$1EF, // video + $1BB{,$1BD},$1BE,$1BF: begin // system,private,padding,private + inc(p,swap(ReadWord(p,endptr))); + end; + end; + end; +// vbitrate:=(vbitrate*400) div 1000; +// Info.total:=(FrmCnt*100) div Info.fps; + mFreeMem(buf); + result:=true; +end; + +var + LocalFormatLinkMP3, + LocalFormatLinkMPG, + LocalFormatLinkMPEG:twFormat; + +procedure InitLink; +begin + LocalFormatLinkMP3.Next:=FormatLink; + + LocalFormatLinkMP3.This.proc :=@ReadMP3; + LocalFormatLinkMP3.This.ext :='MP3'; + LocalFormatLinkMP3.This.flags:=0; + + FormatLink:=@LocalFormatLinkMP3; + + LocalFormatLinkMPG.Next:=FormatLink; + + LocalFormatLinkMPG.This.proc :=@ReadMPG; + LocalFormatLinkMPG.This.ext :='MPG'; + LocalFormatLinkMPG.This.flags:=WAT_OPT_VIDEO; + + FormatLink:=@LocalFormatLinkMPG; + + LocalFormatLinkMPEG.Next:=FormatLink; + + LocalFormatLinkMPEG.This.proc :=@ReadMPG; + LocalFormatLinkMPEG.This.ext :='MPEG'; + LocalFormatLinkMPEG.This.flags:=WAT_OPT_VIDEO; + + FormatLink:=@LocalFormatLinkMPEG; +end; + +initialization + InitLink; +end. -- cgit v1.2.3