Filter.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:15k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit Filter;
  2.    (*********************************************************************
  3.     * The contents of this file are used with permission, subject to    *
  4.     * the Mozilla Public License Version 1.1 (the "License"); you may   *
  5.     * not use this file except in compliance with the License. You may  *
  6.     * obtain a copy of the License at                                   *
  7.     * http://www.mozilla.org/MPL/MPL-1.1.html                           *
  8.     *                                                                   *
  9.     * Software distributed under the License is distributed on an       *
  10.     * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or    *
  11.     * implied. See the License for the specific language governing      *
  12.     * rights and limitations under the License.                         *
  13.     *                                                                   *
  14.     * (C) 2004 Martin Offenwanger: coder@dsplayer.de                    *
  15.     *********************************************************************)
  16. {
  17. @author(Martin Offenwanger: coder@dsplayer.de)
  18. @created(Apr 22, 2004)
  19. @lastmod(Sep 09, 2004)
  20. }
  21. interface
  22. uses
  23.   WorkerThread, ICYParser, ActiveX, Classes, DirectShow9, BaseClass, Windows,
  24.   Config, StringQueue, Forms;
  25. type
  26.   TAsyncEx = class(TBCBaseFilter, IFileSourceFilter, IAsyncExControl)
  27.   private
  28.     // the actual playback location "supported: URL, File, stream"
  29.     FFileName: string;
  30.     // all loaded filtes will be wrapped into a Filestream
  31.     FFilestream: TFileStream;
  32.     // Basepin Object
  33.     FPin: TBCBasePin;
  34.     FLock: TBCCritSec;
  35.     FStreamsize: int64;
  36.     // Pin state flag
  37.     FPinActive: boolean;
  38.     // Prebuffer loop flag
  39.     Fexitloop: boolean;
  40.     // Ripper Flag
  41.     FRipstream: boolean;
  42.     FPath: string;
  43.     FFile: string;
  44.     function GetOutPin: IPin;
  45.     // creates a Filter pin if streamEnabled=true (URL or IStream)
  46.     procedure CreateFilterPin(AStream: IStream; StreamEnabled: boolean = false;
  47.       URLPin: boolean = false); overload;
  48.     // helper function
  49.     function ParseUrl(Url: string; out host: string; out port: string;
  50.       out Location: string): boolean;
  51.   public
  52.     constructor CreateFromFactory(Factory: TBCClassFactory;
  53.       const Controller: IUnknown); override;
  54.     destructor Destroy; override;
  55.     function GetPin(n: Integer): TBCBasePin; override;
  56.     function GetPinCount: Integer; override;
  57.     function Run(tStart: TReferenceTime): HRESULT; override; stdcall;
  58.     function NonDelegatingRelease: Integer; override; stdcall;
  59.     // IFileSourceFilter
  60.     function Load(pszFileName: PWCHAR;
  61.       const pmt: PAMMediaType): HRESULT; stdcall;
  62.     function GetCurFile(out ppszFileName: PWideChar;
  63.       pmt: PAMMediaType): HRESULT; stdcall;
  64.     // IDSPlayerAsyncSourceControl
  65.     function SetLoadFromStream(Stream: IStream; Length: int64): HRESULT;
  66.       stdcall;
  67.     function SetConnectToIp(Host: PChar; Port: PChar; Location: PChar;
  68.       PreBuffersize: integer; MetaData: LongBool): HRESULT; stdcall;
  69.     function SetConnectToURL(URL: PChar; PreBuffersize: integer;
  70.       MetaData: LongBool): HRESULT; stdcall;
  71.     function SetBuffersize(BufferSize: integer): HRESULT; stdcall;
  72.     function GetBuffersize(out BufferSize: integer): HRESULT; stdcall;
  73.     function SetRipStream(Ripstream: LongBool; Path: PChar;
  74.       Filename: PChar): HRESULT; stdcall;
  75.     function GetRipStream(out Ripstream: LongBool;
  76.       out FileO: PChar): HRESULT; stdcall;
  77.     function SetCallBack(CallBack: IAsyncExCallBack): HRESULT; stdcall;
  78.     function FreeCallback(): HRESULT; stdcall;
  79.     function ExitAllLoops(): HRESULT; stdcall;
  80.     // properties
  81.     property OutPin: IPin read GetOutPin;
  82.   end;
  83. implementation
  84. uses
  85.   SysUtils, StreamOutPin;
  86. function TAsyncEx.ExitAllLoops(): HRESULT; stdcall;
  87. begin
  88.    //     FLock.Lock;
  89.         GFExit := true;
  90.    //     FLock.UnLock;
  91. end;
  92. function TAsyncEx.Run(tStart: TReferenceTime): HRESULT; stdcall;
  93. begin
  94.   if (FGRaph <> nil) and (FPin <> nil) and (GFConnected) then
  95.   begin
  96.     TStreamOutPin(FPin).setActiveGraph(FGRaph);
  97.     RESULT := S_OK;
  98.   end
  99.   else
  100.     RESULT := E_FAIL;
  101. end;
  102. // IDSPlayerAsyncSourceControl begin
  103. function TAsyncEx.SetConnectToURL(URL: PChar; PreBuffersize: integer; MetaData:
  104.   LongBool): HRESULT; stdcall;
  105. var
  106.   Host, Port, Location, URLO: string;
  107. begin
  108.   FLock.lock;
  109.   URLO := copy(URL, 1, length(URL));
  110.   if not ParseUrl(URLO, Host, Port, Location) then
  111.   begin
  112.     result := E_FAIL;
  113.     exit;
  114.   end;
  115.   FLock.unlock;
  116.   result := SetConnectToIp(PChar(Host), PChar(Port), PChar(Location),
  117.     PreBuffersize, MetaData);
  118. end;
  119. function TAsyncEx.SetConnectToIp(Host: PChar; Port: PChar; Location: PChar;
  120.   PreBuffersize: integer; MetaData: LongBool): HRESULT; stdcall;
  121. var
  122.   Datawritten: boolean;
  123.   Application: TApplication;
  124.   i: integer;
  125.   Buffer: string;
  126.   Avdata: int64;
  127. begin
  128.   if GFExit then
  129.   begin
  130.     Result := E_FAIL;
  131.     exit;
  132.   end;
  133.   if GFConnected then
  134.   begin
  135.     Result := E_FAIL;
  136.     exit;
  137.   end;
  138.   try
  139.     FLock.Lock;
  140.     GFPreBufferSize := PreBuffersize;
  141.     GFStringQueue := TStringQueue.Create;
  142.     Datawritten := false;
  143.     Application := TApplication.Create(nil);
  144.     i := 0;
  145.     Avdata := 0;
  146.     Buffer := '';
  147.     GFFileName := 'N/A';
  148.     if GFExit then
  149.     begin
  150.       Result := E_FAIL;
  151.       exit;
  152.     end;
  153.     if GFConnected then
  154.     begin
  155.       Result := E_FAIL;
  156.       exit;
  157.     end;
  158.     CreateFilterPin(TStreamAdapter.Create(nil, soOwned), true, true);
  159.     if FPin <> nil then
  160.       TStreamOutPin(FPin).DoConnect(copy(Host, 0, system.length(Host)),
  161.         copy(Port, 0, system.length(Port)),
  162.         copy(Location, 0, system.length(Location)),
  163.         MetaData);
  164.     SetRipStream(FRipstream, PChar(FPath), PChar(FFile));
  165.     while not Datawritten do
  166.     begin
  167.       if GFExit then
  168.       begin
  169.         Result := E_FAIL;
  170.         FLock.UnLock;
  171.         exit;
  172.       end;
  173.       if g_threadedShoutcastStream = nil then
  174.       begin
  175.         Result := E_FAIL;
  176.         FLock.UnLock;
  177.         exit;
  178.       end;
  179.       if GFStringQueue = nil then
  180.       begin
  181.         Result := E_FAIL;
  182.         FLock.UnLock;
  183.         exit;
  184.       end;
  185.       Sleep(1);
  186.       if GFConnected then
  187.       begin
  188.         Result := E_FAIL;
  189.         FLock.UnLock;
  190.         exit;
  191.       end;
  192.       if (GFFilterCallBack <> nil) and
  193.         (PreBuffersize > 0) and
  194.         (g_threadedShoutcastStream <> nil) then
  195.         GFFilterCallBack.AsyncExFilterState(false, true, false,
  196.           false, (trunc((Avdata * 100) / PreBuffersize)));
  197.       Application.ProcessMessages;
  198.       if GFExit then
  199.       begin
  200.         result := E_FAIL;
  201.         Application.Destroy;
  202.         FLock.UnLock;
  203.         exit;
  204.       end
  205.       else if GFStringQueue = nil then
  206.       begin
  207.         Result := E_FAIL;
  208.         Application.Destroy;
  209.         FLock.UnLock;
  210.         exit;
  211.       end;
  212.       if GFStringQueue.getcount > i then
  213.       begin
  214.         Buffer := Buffer + GFStringQueue.getitem(i);
  215.         inc(i);
  216.       end;
  217.       if (PreBuffersize <= Avdata) then
  218.         Datawritten := true
  219.       else
  220.         Avdata := system.length(Buffer);
  221.     end;
  222.     Application.Destroy;
  223.     Result := S_OK;
  224.   except
  225.     result := E_FAIL;
  226.   end;
  227.   FLock.UnLock;
  228. end;
  229. function TAsyncEx.SetBuffersize(BufferSize: integer): HRESULT; stdcall;
  230. begin
  231.   Result := S_OK;
  232.   { if the buffersize is too small and when the min buffersize is not available
  233.     the min buffersize will be automaticly set in TAsyncIO.SyncRead.
  234.     Reason: at this point the min buffersize might not known }
  235.   if GFMinBuffersize < BufferSize then
  236.     // copy the value is slower but more savety to prevent crashes
  237.     GFBufferSize := strtoint(copy(inttostr(BufferSize), 1,
  238.       length(inttostr(BufferSize))));
  239. end;
  240. function TAsyncEx.GetBuffersize(out BufferSize: integer): HRESULT; stdcall;
  241. begin
  242.   Result := S_OK;
  243.   // copy the value is slower but more safety, to prevent crashes
  244.   BufferSize := strtoint(copy(inttostr(GFBufferSize), 1,
  245.     length(inttostr(GFBufferSize))));
  246. end;
  247. function TAsyncEx.SetRipStream(Ripstream: LongBool; Path: PChar;
  248.   Filename: PChar): HRESULT; stdcall;
  249. begin
  250.   FRipstream := Ripstream;
  251.   FPath := copy(Path, 1, length(Path));
  252.   FFile := copy(
  253.     FFilename, 1, length(Filename));
  254.   RESULT := S_OK;
  255.   if g_threadedShoutcastStream <> nil then
  256.   begin
  257.     g_threadedShoutcastStream.SetRipStream(Ripstream, Path, FFile);
  258.     RESULT := S_OK;
  259.   end;
  260. end;
  261. // TAsyncEx.GetRipStream is not implemented yet
  262. function TAsyncEx.GetRipStream(out Ripstream: LongBool;
  263.   out FileO: PChar): HRESULT; stdcall;
  264. var
  265.   fileL: string;
  266.   {*l_ripstream: boolean;*}
  267. begin
  268.   fileL := '';
  269.   {*l_ripstream := false;*}
  270.   RESULT := E_FAIL;
  271.   {*  if g_shoutCastStream <> nil then
  272.       begin
  273.                 g_shoutCastStream.get_ripStream(l_ripstream,l_file);
  274.                 Ripstream := l_ripstream;
  275.                 FileO := copy(l_file,1,length(l_file));
  276.                 RESULT := S_OK;
  277.       end;   *}
  278. end;
  279. function TAsyncEx.SetLoadFromStream(Stream: IStream; Length: int64): HRESULT; stdcall;
  280. begin
  281.   FStreamsize := Length;
  282.   CreateFilterPin(Stream, true);
  283. //  CreateFilterPin(TStreamAdapter.Create(@Stream, soOwned), true);
  284.   GFFileName := 'In TStream Mode is Filename not available';
  285.   Result := S_OK;
  286. end;
  287. function TAsyncEx.SetCallBack(CallBack: IAsyncExCallBack): HRESULT; stdcall;
  288. begin
  289.   GFFilterCallBack := CallBack;
  290.   Result := S_OK;
  291. end;
  292. function TAsyncEx.FreeCallback(): HRESULT; stdcall;
  293. begin
  294.   if Assigned(GFFilterCallBack) then
  295.   begin
  296.     GFFilterCallBack.AsyncExICYNotice(ICYName, 'N/A');
  297.     GFFilterCallBack.AsyncExICYNotice(ICYGenre, 'N/A');
  298.     GFFilterCallBack.AsyncExICYNotice(ICYURL, 'N/A');
  299.     GFFilterCallBack.AsyncExICYNotice(ICYBitrate, 'N/A');
  300.     GFFilterCallBack.AsyncExFilterState(false, false, false, false, 0);
  301.     GFFilterCallBack := nil;
  302.   end;
  303.   result := S_OK;
  304. end;
  305. // IDSPlayerAsyncSourceControl end
  306. // IFileSourceFilter begin
  307. function TAsyncEx.Load(pszFileName: PWCHAR;
  308.   const pmt: PAMMediaType): HRESULT; stdcall;
  309. begin
  310.   if Length(pszFileName) > MAX_PATH then
  311.   begin
  312.     result := ERROR_FILENAME_EXCED_RANGE;
  313.     exit;
  314.   end;
  315.   FFileName := GCFFilterID + ' (' + ExtractFileName(pszFileName) + ')';
  316.   FFilestream := TFileStream.Create(pszFileName, fmOpenRead or
  317.     fmShareDenyWrite);
  318.   FStreamsize := FFilestream.Size;
  319.   CreateFilterPin(TStreamAdapter.Create(FFilestream, soOwned), true);
  320.   GFFileName := pszFileName;
  321.   if FFileName = pszFileName then
  322.     Result := E_OUTOFMEMORY
  323.   else
  324.     result := S_OK;
  325. end;
  326. function TAsyncEx.GetCurFile(out ppszFileName: PWideChar;
  327.   pmt: PAMMediaType): HRESULT;
  328. begin
  329.   // no need to set a Mediatype at this point
  330.   ppszFileName := StringToOleStr(copy(FFileName, 1, Length(FFileName)));
  331.   result := S_OK;
  332. end;
  333. // IFileSourceFilter end
  334. constructor TAsyncEx.CreateFromFactory(Factory: TBCClassFactory;
  335.   const Controller: IUnknown);
  336. begin
  337.   inherited CreateFromFactory(Factory, Controller);
  338.   FLock := TBCCritSec.Create;
  339.   FFilestream := nil;
  340.   FFile := '';
  341.   g_threadedShoutcastStream := nil;
  342.   GFFilterCallBack := nil;
  343.   // 300kb as default
  344.   GFBufferSize := 300 * 1000;
  345.   GFMinBuffersize := 0;
  346.   GFStringQueue := nil;
  347.   GFConnected := false;
  348.   GFStreamLength := 0;
  349.   GFFileName := '';
  350.   GFMayjorType := '';
  351.   Fexitloop := false;
  352.   GFExit := false;
  353.   // create the Filter Pin without Stream (blank pin)
  354.   CreateFilterPin(TStreamAdapter.Create(TMemoryStream.Create, soOwned), false);
  355. end;
  356. procedure TAsyncEx.CreateFilterPin(AStream: IStream;
  357.   streamEnabled: boolean = false; URLPin: boolean = false);
  358. var
  359.   Hr: HRESULT;
  360. begin
  361.   inherited Create(GCFFilterID, nil, TBCCritSec.Create, GUID_NULL, Hr);
  362.   if streamEnabled then
  363.   begin
  364.     if URLPin then
  365.       // create a URL stream pin
  366.       FPin := TStreamOutPin.Create(GCFPinID, Self, FLock, Hr,
  367.         GCFPinID, nil, true, 0, true, true)
  368.     else
  369.       // create a filestream pin
  370.       FPin := TStreamOutPin.Create(GCFPinID, Self, FLock, Hr,
  371.         GCFPinID, AStream, true, FStreamsize, true);
  372.     // maintain a ref on the pin
  373.     FPin.NonDelegatingAddRef;
  374.     // destructor flag
  375.     FPinActive := true;
  376.   end
  377.   else
  378.   begin
  379.     FPin := nil;
  380.     FPinActive := false;
  381.   end;
  382. end;
  383. destructor TAsyncEx.Destroy;
  384. begin
  385.   GFExit := true;
  386.   if FFilestream <> nil then
  387.   begin
  388.     FFilestream.Destroy;
  389.     FFilestream := nil;
  390.   end;
  391.   if g_threadedShoutcastStream <> nil then
  392.   begin
  393.     g_threadedShoutcastStream.Destroy;
  394.     g_threadedShoutcastStream := nil;
  395.   end;
  396.   if GFStringQueue <> nil then
  397.   begin
  398.     GFStringQueue.Destroy;
  399.     GFStringQueue := nil;
  400.   end;
  401.   if FPinActive then
  402.     TStreamOutPin(FPin).FreeAllObjects;
  403.   FLock.Destroy;
  404. end;
  405. function TAsyncEx.GetOutPin: IPin;
  406. begin
  407.   if FPin <> nil then
  408.     Result := FPin;
  409. end;
  410. function TAsyncEx.GetPin(n: Integer): TBCBasePin;
  411. begin
  412.   if n = 0 then
  413.     Result := FPin
  414.   else
  415.     Result := nil;
  416. end;
  417. function TAsyncEx.GetPinCount: Integer;
  418. begin
  419.   if FPin <> nil then
  420.     Result := 1
  421.   else
  422.     Result := 0;
  423. end;
  424. function TAsyncEx.NonDelegatingRelease: Integer;
  425. begin
  426.   Result := inherited NonDelegatingRelease;
  427.   if Result = 1 then
  428.     // the pin has a ref on us, "if FPin <> nil" then release it
  429.     if FPin <> nil then
  430.       FPin.NonDelegatingRelease;
  431. end;
  432. // helper functions
  433. function TAsyncEx.ParseUrl(URL: string; out Host: string; out Port: string;
  434.   out Location: string): boolean;
  435. var
  436.   Pos1: integer;
  437.   Pos2: integer;
  438.   Temp: string;
  439. begin
  440.   result := false;
  441.   if length(URL) = 0 then
  442.     exit;
  443.   // check for http string
  444.   Pos1 := pos('http://', URL);
  445.   if Pos1 = 0 then
  446.     exit;
  447.   result := true;
  448.   Temp := copy(URL, Pos1 + length('http://'), length(URL) - Pos1);
  449.   // look for port offset
  450.   Pos1 := pos(':', Temp);
  451.   // check if a port is given
  452.   if Pos1 = 0 then
  453.   begin
  454.     // no port.. , set def. port and location
  455.     Host := Temp;
  456.     Port := '80';
  457.     Location := '/';
  458.     exit;
  459.   end;
  460.   Host := copy(Temp, 1, Pos1 - 1);
  461.   // look for location offset
  462.   Pos2 := pos('/', Temp);
  463.   // check if location is given
  464.   if Pos2 = 0 then
  465.   begin
  466.     // no location.. , set def. location
  467.     Temp := copy(Temp, Pos1 + 1, length(Temp) - Pos1);
  468.     Port := Temp;
  469.     Location := '/';
  470.     exit;
  471.   end;
  472.   Port := copy(Temp, Pos1 + 1, Pos2 - Pos1 - 1);
  473.   Location := copy(Temp, Pos2, length(Temp) - Pos2 + 1);
  474. end;
  475. initialization
  476.   TBCClassFactory.CreateFilter(TAsyncEx, GCFFilterID, CLSID_AsyncEx,
  477.     CLSID_LegacyAmFilterCategory, MERIT_DO_NOT_USE, 1, @Pins);
  478. end.