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_flv.pas | 334 ++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 plugins/Watrack/formats/fmt_flv.pas (limited to 'plugins/Watrack/formats/fmt_flv.pas') diff --git a/plugins/Watrack/formats/fmt_flv.pas b/plugins/Watrack/formats/fmt_flv.pas new file mode 100644 index 0000000000..b8e23f5809 --- /dev/null +++ b/plugins/Watrack/formats/fmt_flv.pas @@ -0,0 +1,334 @@ +{FLV file format} +unit fmt_FLV; +{$include compilers.inc} + +interface +uses wat_api; + +function ReadFLV(var Info:tSongInfo):boolean; cdecl; + +implementation +uses windows,common,io,srv_format; + +type + tFLVHeader = packed record + Signature:array [0..2] of AnsiChar; // FLV + Version :byte; + flags :byte; + Offset :dword; // reversed byte order + end; +type + tFLVStream = packed record + PreviousTagSize :dword; + TagType :byte; + BodyLength :array [0..2] of byte; + Timestamp :array [0..2] of byte; + TimestampExtended:byte; + StreamID :array [0..2] of byte; +// Body + end; +{ + twork = record + endptr:PAnsiChar; + Info :pSongInfo; + key :PAnsiChar; + len :cardinal; + end; +} +// FLVTagTypes +const + FLV_AUDIO = 8; + FLV_VIDEO = 9; + FLV_META = 18; + +const + BufSize = 128*1024; + +type + pArr = ^tArr; + tArr = array [0..7] of byte; + + transform=packed record + case byte of + 0: (txt:array [0..3] of AnsiChar); + 1: (num:dword); + end; + trecode=packed record + case byte of + 0: (i:int64); + 1: (d:double); + end; + +function Reverse(buf:int64;len:integer):int64; +var + i:integer; +begin + result:=0; + for i:=0 to len-1 do + result:=(result shl 8)+tArr(buf)[i]; +end; + +function ProcessValue(var ptr:PAnsiChar;key:pAnsiChar;var Info:tSongInfo):integer; +var + tmp:int64; + i,len:integer; + recode:trecode; + code:integer; + codec:transform; + value:array [0..63] of AnsiChar; +begin + result:=1; + code:=ord(ptr^); // type of value + ptr^:=#0; // finalization for key name + inc(ptr); // value data pointer + + case code of // v10.1 specification + + // Numeric, Double (8 bytes) + 0: begin + move(ptr^,tmp,8); + recode.i:=Reverse(tmp,8); + i:=trunc(recode.d); + if StrCmp(key,'duration' )=0 then Info.total :=i + else if StrCmp(key,'totalduration')=0 then Info.total :=i + else if StrCmp(key,'width' )=0 then Info.width :=i + else if StrCmp(key,'height' )=0 then Info.height:=i + else if StrCmp(key,'audiodatarate')=0 then Info.kbps :=i + else if StrCmp(key,'framerate' )=0 then Info.fps :=trunc(recode.d*100) + else if StrCmp(key,'audiosize' )=0 then + begin + if Info.kbps=0 then + Info.kbps:=trunc((recode.d*8)/(Info.total*1000)) + end + else if StrCmp(key,'videocodecid')=0 then + begin + case i of + 2: codec.txt:='H263'; + 3: codec.txt:='Scrn'; + 4,5: codec.txt:='VP6 '; + 6: codec.txt:='Src2'; + 7: codec.txt:='AVC '; + end; + Info.codec:=codec.num; + end; + + inc(ptr,8); + end; + + // Boolean, UI8 + 1: begin + if StrCmp(key,'stereo')=0 then Info.channels:=ORD(ptr^)+1; + + inc(ptr); + end; + + // String + 2: begin + i:=Reverse(pWord(ptr)^,2); inc(ptr,2); + + if StrCmp(key,'creationdate')=0 then + begin + move(ptr^,value[0],i); + value[i]:=#0; + AnsiToWide(value,Info.year); + end; + + inc(ptr,i); + end; + + // Object + 3: begin + repeat + len:=Reverse(pWord(ptr)^,2); inc(ptr,2); // key name length + key:=ptr; inc(ptr,len); // key name + + result:=ProcessValue(ptr,key,Info); + until result<=0; + + if result<0 then + result:=1; + end; + + // Movie clip, reserved + 4: begin + end; + + // NULL + 5: begin + end; + + // Undefined + 6: begin + end; + + // reference, UI16 + 7: begin + inc(ptr,2); + end; + + // ECMA array + 8: begin + i:=pdword(ptr)^; inc(ptr,4); + i:=Reverse(i,4); + while i>0 do + begin + + len:=Reverse(pWord(ptr)^,2); inc(ptr,2); // key name length + key:=ptr; inc(ptr,len); // key name + + result:=ProcessValue(ptr,key,Info); + + if result=0 then break + else if result<0 then + begin + result:=1; + break; + end; + dec(i); + end; + end; + + // Object end marker, UI8[3]=0,0,9 + 9: begin + result:=-1; + inc(ptr,3); + end; + + 10: // array, 4 bytes - num of elements, elements + begin + i:=pdword(ptr)^; inc(ptr,4); + i:=Reverse(i,4); + while i>0 do + begin + result:=ProcessValue(ptr,nil,Info); + if result=0 then exit + else if result<0 then + begin + result:=1; + break; + end; + dec(i); + end; + end; + + // Date, Double + UI16 (UTC) + 11: begin + inc(ptr,8); + inc(ptr,2); + end; + + // LongString, 4 bytes = len, len - string + 12: begin + i:=pdword(ptr)^; inc(ptr,4); + i:=Reverse(i,4); + + inc(ptr,i); + end; + + end; +end; + +function ReadFLV(var Info:tSongInfo):boolean; cdecl; +var + f:THANDLE; + codec:transform; + FLVHdr:tFLVHeader; + StrmHdr:tFLVStream; + i,len:integer; + buf,pp,p,endbuf:PAnsiChar; +begin + result:=false; + f:=Reset(Info.mfile); + if f=THANDLE(INVALID_HANDLE_VALUE) then + exit; + + mGetMem(buf,BufSize); + endbuf:=buf+BlockRead(f,buf^,BufSize); + p:=buf; + CloseHandle(f); + move(p^,FLVHdr,SizeOf(tFLVHeader)); + if (FLVHdr.Signature[0]='F') and (FLVHdr.Signature[1]='L') and + (FLVHdr.Signature[2]='V') and (FLVHdr.Version=1) then + begin + inc(p,SizeOf(tFLVHeader)); + result:=true; + while (p0) do + begin + move(p^,StrmHdr,SizeOf(tFLVStream)); + inc(p,SizeOf(tFLVStream)); + len:=(StrmHdr.BodyLength[0] shl 16)+(StrmHdr.BodyLength[1] shl 8)+ + StrmHdr.BodyLength[2]; + pp:=p; + case StrmHdr.TagType of + + FLV_AUDIO: begin + Info.channels:=(ord(p^) and 1)+1; + // samplesize is (S_Byte and 2) shr 1 = 8 or 16 + case (ord(p^) and $C) shr 2 of + 0: Info.khz:=5; + 1: Info.khz:=11; + 2: Info.khz:=22; + 3: Info.khz:=44; + end; + FLVHdr.flags:=FLVHdr.flags and not 4; + end; + + FLV_VIDEO: begin + case ord(p^) and $0F of + 2: codec.txt:='H263'; + 3: codec.txt:='Scrn'; + 4,5: codec.txt:='VP6 '; + 6: codec.txt:='Src2'; + 7: codec.txt:='AVC '; + end; + Info.codec:=codec.num; + FLVHdr.flags:=FLVHdr.flags and not 1; + end; + + FLV_META: begin + if (StrmHdr.TagType and $40)=0 then // not encripted + begin + if pByte(p)^=2 then // string + begin + Inc(p); + i:=Reverse(pWord(p)^,2); inc(p,2); + if StrCmp(p,'onMetaData',i)=0 then // Metadata processing start + begin + inc(p,i); + ProcessValue(p,nil,Info); // metadata, no need key name, our info + // checking for video + if Info.codec<>0 then + FLVHdr.flags:=FLVHdr.flags and not 1; + // checking for audio + if (Info.khz<>0) and (Info.channels<>0) then + FLVHdr.flags:=FLVHdr.flags and not 4; + // break; // if metainfo is enough + end; + end; + end; + end; + + end; + p:=pp+len; + end; + end; + mFreeMem(buf); +end; + +var + LocalFormatLink:twFormat; + +procedure InitLink; +begin + LocalFormatLink.Next:=FormatLink; + + LocalFormatLink.This.proc :=@ReadFLV; + LocalFormatLink.This.ext :='FLV'; + LocalFormatLink.This.flags:=WAT_OPT_VIDEO; + + FormatLink:=@LocalFormatLink; +end; + +initialization + InitLink; +end. -- cgit v1.2.3