I want to create my own filter and use it in the DirectShow library. The filter seemed to be able to write, but there was a problem with creating a graph. I based my code on the "Creating an Audio Capture Graph" article. At the very end it says that the functions from the articles "Add a Filter by CLSID" and "Connect Two Filters" are also used. I rewrote the most identical, but the code does not work.
I indicated the location of the error with many "!".
Project Project1.exe raised exception class AEccessViolation with message 'Access violation at address 0045AAA8 in module 'Project1.exe'. Read of address 00000000'. Process stopped. Use step or Run to continue.
In general, I have the following code:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, DirectShow9,ActiveX,BaseClass, DirectInput,
StdCtrls,DirectSound, DirectSetup, DirectPlay8, DirectMusic,
Dialogs;
type
TForm1 = class(TForm)
Button1: TButton;
ListBox2: TListBox;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
function AddFilterByCLSID(pGraphA: IGraphBuilder; clsid: TGUID; wazName: PWideChar; ppF: IBaseFilter): HRESULT;
function ConnectFilter( pGraph: IGraphBuilder; pSrc: IBaseFilter; pdest: IBaseFilter): HRESULT;
function GetUnconnectedPin(pFilter: IBaseFilter; PinDir: PIN_DIRECTION; ppPin: IPin): HRESULT;
function ConnectFilterPin( pGraph: IGraphBuilder; pOut: IPin; pdest: IBaseFilter): HRESULT;
end;
var
PropertyName:IPropertyBag;
pSrc, pWaveDest, pWriter: IBaseFilter;
pSink: IFileSinkFilter;
pGraph: IGraphBuilder;
FMediaControl: IMediaControl;
pDevEnum: ICreateDevEnum;
pEnum: IEnumMoniker;
pMoniker: IMoniker;
MArray1,MArray2: array of IMoniker;
hr: HRESULT;
DeviceName:OleVariant;
FAudioCaptureFilter: IBaseFilter;
const
CLSID_WavDest : TGUID = '{3C78B8E2-6C4D-11d1-ADE2-0000F8754B99}';
CLSID_CRleFilter: TGUID = '{BEBCF0A3-2673-42A7-82F2-5D4FC3126171}'; //My Filter.
IID_ICRleFilter: TGUID = '{35C0AC80-C3E4-4EEA-A1F5-049401E29400}'; //Myfilter
var
Form1: TForm1;
implementation
{$R *.dfm}
function TForm1.AddFilterByCLSID(pGraphA: IGraphBuilder; clsid: TCLSID;
wazName: PWideChar; ppF: IBaseFilter): HRESULT;
var
pF: IBaseFilter;
begin
CoCreateInstance(clsid, nil, CLSCTX_INPROC_SERVER, IID_IBaseFilter, pF);
hr:=pGraph.AddFilter(pF, WazName);
if hr<> S_OK then
begin
ShowMessage('фильтр вавдеста не добавился');
end;
PPf:= pF;
// pF._Release;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
pOut: IPin;
begin
HR:= CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, pGraph);
if hr<> S_OK then
begin
ShowMessage('Граф не создался');
end;
HR:= CoCreateInstance(CLSID_SystemDeviceEnum, NIL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, pDevEnum);
if hr<> S_OK then
begin
ShowMessage('перечеслитель не создался');
Exit;
end;
HR:=pDevEnum.CreateClassEnumerator(CLSID_AudioInputDeviceCategory, pEnum, 0);
if HR<>S_OK then EXIT;
//Обнуляем массив в списке моникеров
setlength(MArray2,0);
//Пускаем массив по списку устройств
while (S_OK=pEnum.Next(1,pMoniker,Nil)) do
begin
setlength(MArray2,length(MArray2)+1); //Увеличиваем массив на единицу
MArray2[length(MArray2)-1]:=pMoniker; //Запоминаем моникер в масиве
HR:=pMoniker.BindToStorage(NIL, NIL, IPropertyBag, PropertyName); //Линкуем моникер устройства к формату хранения IPropertyBag
if FAILED(HR) then Continue;
HR:=PropertyName.Read('FriendlyName', DeviceName, NIL); //Получаем имя устройства
if FAILED(HR) then Continue;
//Добавляем имя устройства в списки
Listbox2.Items.Add(DeviceName);
end;
Listbox2.ItemIndex:=0;
MArray2[Listbox2.ItemIndex].BindToObject(NIL, NIL, IID_IBaseFilter, FAudioCaptureFilter);
//добавляем устройство в граф фильтров
Pgraph.AddFilter(FAudioCaptureFilter, 'AudioCaptureFilter');
// pGraph.AddFilter(pSrc, 'Capture');
AddfilterByCLSID(pGraph, CLSID_CRleFilter, '_CRleFilter', pWaveDest);
ConnectFilter(pGraph, pWaveDest, pWriter); // This is where the mistakes start !!!!!!!!!!!!!!!!!
pGraph.QueryInterface(IID_IMediaControl, FMediaControl);
FMediaControl.Run();
end;
{
There is no function overloading in Delphi, so I named the functions differently
}
function TForm1.ConnectFilterPin(pGraph: IGraphBuilder; pOut: IPin;
pdest: IBaseFilter): HRESULT;
var
pIn : IPin;
begin
pIn:= nil;
GetUnconnectedPin(pdest, PINDIR_OUTPUT, pIn);
pGraph.Connect(pOut, pin);
end;
function TForm1.ConnectFilter(pGraph: IGraphBuilder; pSrc: IBaseFilter;
pdest: IBaseFilter): HRESULT;
var
pOut: IPin;
begin
//pOut:= 0;
GetUnconnectedPin(pSrc, PINDIR_OUTPUT, pOut);
ConnectFilterPin(pGraph, pOut, pdest);
end;
function TForm1.GetUnconnectedPin(pFilter: IBaseFilter;
PinDir: PIN_DIRECTION; ppPin: IPin): HRESULT;
var
pEnum: IEnumPins;
pPin: IPin;
hr: HRESULT;
ThisPinDir : PIN_DIRECTION;
pTmp: IPin;
begin
pTmp:=nil;
ppPin:= nil;
// pEnum:= nil;
pPin:= nil;
hr:= pFilter.EnumPins(pEnum); // This is where the error occurs !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if hr<> S_OK then
begin
ShowMessage('перечесление пинов: не равно S_OK');
end;
while pEnum.Next(1, pPin, nil) = S_OK do
begin
pPin.QueryDirection(ThisPinDir);
if ThisPinDir = PinDir then
begin
hr:= pPin.ConnectedTo(pTmp);
if Succeeded(hr) then
begin
pTmp._Release;
end else
begin
pEnum._Release;
ppPin:= pPin;
Result := S_OK;
Exit;
end;
end;
end;
pPin._Release;
ShowMessage('ошибка: не правильный код');
Result:= E_FAIL;
// ShowMessage('ошибка: не правильный код');
end;
end.
I was hoping that the error was caused by pointers, or rather their absence. I tried to put them in absolutely all combinations, but this did not lead to the desired result. Besides, everywhere in Delphi pointers are not used at all. Perhaps somewhere the parameters in the functions are not correctly passed. I reviewed all the functions 5 times, tried to find errors, but this did not work. Using pointers didn't work either.
I know the error is small and easy to fix, but I can't figure out where it is.
The error was not in the pointers. The purpose of the
Connect Filterfunction is to connect two filters. The structure looks like thisConnectFilter(Graph, Filter 1, Filter 2);. I added only one filter to the project. As a result, nothing was sent to the function instead of the second filter. There was an address reading error that was very hard to catch. Perhaps it would be easy to identify the error if I used all sorts of checks. Due to the fact that C ++ uses pointers, but Delphi does not, I thought that the error was in pointers, because I did not use them. But the fix turned out to be simpler: you need to add a second filter, and send it as the third parameter. From these errors we can conclude:nilto new variables, Delphi does it on its own.Releaseyourself.I rewrote the code with the correction of all the errors I noticed. I'll leave it below: