unit main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ActiveX, DirectShow9; type TForm1 = class(TForm) Button1: TButton; OpenDialog1: TOpenDialog; procedure Button1Click(Sender: TObject); private { Private 宣言 } F_GraphBuilder : IGraphBuilder; F_AudioRenderer : IBaseFilter; public { Public 宣言 } end; var Form1: TForm1; function GetUnconnectedPin(pFilter : IBaseFilter; PinDir : PIN_DIRECTION; var ppPin : IPin) : HResult; function ConnectFilters(pGraph : IGraphBuilder; pOut : IPin; pDest : IBaseFilter) : HResult; overload; function ConnectFilters(pGraph : IGraphBuilder; pSrc : IBaseFilter; pDest : IBaseFilter) : HResult; overload; function CreateBaseFilter(var ABaseFilter : IBaseFilter; ACategory : TGUID; sFriendryName : WideString) : HResult; implementation uses DSUtil; {$R *.dfm} function GetUnconnectedPin(pFilter : IBaseFilter; PinDir : PIN_DIRECTION; var ppPin : IPin) : HResult; //http://msdn.microsoft.com/ja-jp/library/cc973418.aspx var li_Ret : HResult; pEnum : IEnumPins; pPin : IPin; pTmp : IPin; ThisPinDir : TPinDirection ; begin ppPin := nil; pEnum := nil; pPin := nil; li_Ret := pFilter.EnumPins(pEnum); if (FAILED(li_Ret)) then begin Result := li_Ret; Exit; end; while (pEnum.Next(1, pPin, nil) = S_OK) do begin pPin.QueryDirection(ThisPinDir); if (ThisPinDir = PinDir) then begin pTmp := nil; li_Ret := pPin.ConnectedTo(pTmp); if (SUCCEEDED(li_Ret)) then begin // 既に接続済み、必要なピンではない。 pTmp := nil; end else begin // 未接続、これが必要なピンである。 pEnum := nil; ppPin := pPin; Result := S_OK; Exit; end; end; pPin := nil; end; pEnum := nil; // 一致するピンが見つからなかった。 Result := E_FAIL; end; function ConnectFilters( pGraph : IGraphBuilder; // フィルタ グラフ マネージャ。 pOut : IPin; // アップストリーム フィルタの出力ピン。 pDest : IBaseFilter // ダウンストリーム フィルタ。 ) : HResult; //http://msdn.microsoft.com/ja-jp/library/cc973418.aspx var PinDir : TPinDirection; pIn : IPin; begin if (pGraph = nil) or (pOut = nil) or (pDest = nil) then begin Result := E_POINTER; Exit; end; pOut.QueryDirection(PinDir); if (PinDir <> PINDIR_OUTPUT) then begin Result := E_FAIL; Exit; end; // ダウンストリーム フィルタの入力ピンを検索する。 pIn := nil; Result := GetUnconnectedPin(pDest, PINDIR_INPUT, pIn); if (FAILED(Result)) then begin Exit; end; // 接続を試す。 Result := pGraph.Connect(pOut, pIn); pIn := nil; end; function ConnectFilters( pGraph : IGraphBuilder; pSrc : IBaseFilter; pDest : IBaseFilter ) : HResult; //http://msdn.microsoft.com/ja-jp/library/cc973418.aspx var pOut : IPin; begin if (pGraph = nil) or (pSrc = nil) or (pDest = nil) then begin Result := E_POINTER; Exit; end; // 最初のフィルタの出力ピンを検索する。 pOut := nil; Result := GetUnconnectedPin(pSrc, PINDIR_OUTPUT, pOut); if (FAILED(Result)) then begin Exit; end; Result := ConnectFilters(pGraph, pOut, pDest); pOut := nil; end; function CreateBaseFilter(var ABaseFilter : IBaseFilter; ACategory : TGUID; sFriendryName : WideString) : HResult; //登録フィルタを列挙 //http://msdn.microsoft.com/ja-jp/library/cc371168.aspx //http://msdn.microsoft.com/ja-jp/library/cc353921.aspx //http://www.geekpage.jp/programming/directshow/list-capture-device-2.php //http://miraiware.net/memo/dshow-device.html var l_CreateDevEnum : ICreateDevEnum; l_EnumMoniker : IEnumMoniker; l_Moniker : IMoniker; l_PropertyBag : IPropertyBag; l_varName : OleVariant; ls_Name : WideString; begin Result := CoCreateInstance( CLSID_SystemDeviceEnum, nil, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, l_CreateDevEnum ); if (FAILED(Result)) then begin Exit; end; try Result := l_CreateDevEnum.CreateClassEnumerator(ACategory, l_EnumMoniker, 0); if (Result <> S_OK) then begin Exit; end; //モニカを列挙する。 while(l_EnumMoniker.Next(1, l_Moniker, nil) = S_OK) do begin try Result := l_Moniker.BindToStorage(nil, nil, IID_IPropertyBag, l_PropertyBag); if (Succeeded(Result)) then begin // フィルタのフレンドリ名を取得するには、次の処理を行う。 VariantInit(l_varName); l_PropertyBag.Read('FriendlyName', l_varName, nil); ls_Name := WideString(l_varName); VariantClear(l_varName); if (WideUpperCase(ls_Name) = WideUpperCase(sFriendryName)) then begin //フィルタ作成。 Result := l_Moniker.BindToObject(nil, nil, IID_IBaseFilter, ABaseFilter); Exit; end; end; finally l_PropertyBag := nil; l_Moniker := nil; end; end; //フィルタが作成された場合は途中でExitするのでここに来る場合は作成失敗であるのでE_Failを返す。 Result := E_FAIL; finally l_EnumMoniker := nil; l_CreateDevEnum := nil; end; end; procedure TForm1.Button1Click(Sender: TObject); var li_Ret : HResult; l_WMASFReader : IBaseFilter; l_FileSourceFilter : IFileSourceFilter; l_MediaControl : IMediaControl; begin if (OpenDialog1.Execute) then begin F_AudioRenderer := nil; F_GraphBuilder := nil; //グラフ作成 CoCreateInstance( CLSID_FilterGraph, nil, CLSCTX_INPROC, IID_IGraphBuilder, F_GraphBuilder ); //ファイル読み込み。 li_Ret := F_GraphBuilder.RenderFile(PWideChar(WideString(OpenDialog1.FileName)), nil); if (FAILED(li_Ret)) then begin //amazonのmp3は↑だと失敗するのでWM ASF Readerを使う。 //WM ASF Readerは自分で作成してグラフに追加しておかなければならない。 //更に繋ぐオーディオレンダラーも(デフォルトのものであっても)自分で作成してグラフに追加しておかなくてはならない。 CoCreateInstance( CLSID_WMAsfReader, nil, CLSCTX_INPROC_SERVER, IID_IBaseFilter, l_WMASFReader ); //http://www.codeproject.com/KB/directx/saveimagefromstreamingurl.aspx F_GraphBuilder.AddFilter(l_WMASFReader, 'WM ASF Reader'); l_WMASFReader.QueryInterface(IID_IFileSourceFilter, l_FileSourceFilter); l_FileSourceFilter.Load(PWideChar(WideString(OpenDialog1.FileName)), nil); l_FileSourceFilter := nil; CreateBaseFilter(F_AudioRenderer, CLSID_AudioRendererCategory, 'Default DirectSound Device'); F_GraphBuilder.AddFilter(F_AudioRenderer, 'Default DirectSound Device'); li_Ret := ConnectFilters(F_GraphBuilder, l_WMASFReader, F_AudioRenderer); l_WMASFReader := nil; end; F_GraphBuilder.QueryInterface(IMediaControl, l_MediaControl); l_MediaControl.Run; l_MediaControl := nil; end; end; end.