如何在捕获过滤器上的 DirectShow put_Enable 调用期间调试未指定的错误 ($80004005)?
我有一个使用 DSPACK 组件库用 Delphi 6 编写的 DirectShow 应用程序。我在启用过滤器上的输入行时遇到一个奇怪的问题。我搜索引脚,直到找到输入线(在本例中名为“麦克风”),并在过滤器图处于活动状态时对其调用 put_Enable(true)。当我这样做时,我得到一个 $80004005“未指定错误”作为 HRESULT。
我在启用输入线之前设置过滤器的输出音频媒体类型,但有些东西无法正常工作。我用来创建应用程序的原始 DirectShow 示例运行良好。我相信我正在按照完全相同的步骤构建过滤器图,当然我可能错过了一些东西。有谁对我可以尝试解决此问题有任何提示或想法吗?下面的代码片段部分显示了我正在做的事情,但并不是导致它的所有步骤,因为它们非常冗长。我用于测试的捕获设备是一个 VOIP 耳机,带有一条名为“麦克风”的单输入线。
// The function I call to find an enable the first input line I find in the filter.
function findAndEnableFirstInputLineFound(intfBaseFilter: IBaseFilter; out strInputLineUsed: string): boolean;
var
thePinList: TPinList;
i: integer;
ABool: LongBool;
begin
strInputLineUsed := '';
if not Assigned(intfBaseFilter) then
raise Exception.Create('(findAndEnableFirstInputLineFound) The base filter interface object is unassigned.');
// Now enable the first input source we can find.
Result := false;
thePinList := TPinList.Create(intfBaseFilter);
try
if thePinList.Count > 0 then
begin
// Scan the pin list looking for an input pin.
i := 0;
while (i < thePinList.Count) and (not Result) do
begin
if thePinList.PinInfo[i].dir = PINDIR_INPUT then
begin
// Found one. Enable it.
with thePinList.Items[i] as IAMAudioInputMixer do
begin
CheckDSEror(put_Enable(true)); // $80004005 error occurs here.
// Return the name of the input line used.
strInputLineUsed := thePinList.PinInfo[i].achName;
end; // with thePinList.Items[i] as IAMAudioInputMixer do
Result := true;
break; // Stop looping.
end; // if thePinList.PinInfo[i].dir = PINDIR_INPUT then
Inc(i);
end; // while()
end; // if thePinList.Count > 0 then
finally
thePinList.Free;
end; // try
end;
// The initialization procedure that calls the function above. It is run after the
// the Filter Graph is activated but before it is played.
procedure TDXChain_wavaudio.initializeCaptureFilter;
var
theMediaType: TMediaType;
intfCapturePin: IPin;
aryEnabledInputLines: TDynamicStringArray;
begin
theMediaType := nil;
intfCapturePin := nil;
aryEnabledInputLines := nil;
if not FFilterGraph.Active then
raise Exception.Create('(TDXChain_wavaudio.Create::initializeCaptureFilter) The Filter Graph is INACTIVE.');
if Assigned(FCaptureFilter) then
begin
// Make sure the Capture Filter's output pins supports the
// configured WAV format.
with FOwner.ati_WaveFormatEx do
begin
// if not Assigned(findAudioMediaTypeByFormat(FCaptureFilter_mediatypes, nSamplesPerSec, wBitsPerSample, nChannels)) then
theMediaType := findAudioMediaTypeExt_outputs(FCaptureFilter as IBaseFilter, nSamplesPerSec, wBitsPerSample, nChannels);
if not Assigned(theMediaType) then
// The capture device does not directly support the desired
// WAV format. This is not allowed currently.
raise Exception.Create('(TDXChain_wavaudio.Create::initializeCaptureFilter) The audio input device''s output pins does not support the given WAV format: '
+ CRLF
+ Format('(Device name: %s, Sample Rate: %d, Bits Per Sample: %d, Number of Channels: %d)',
[FOwner.FCaptureFilterConfigInfo.filterName, nSamplesPerSec, wBitsPerSample, nChannels])
);
// -------------- SET OUTPUT PINS TO MEDIA TYPE -------------
// Set the output pins to the desired format.
setPinAudMediaType_outputs(FCaptureFilter, theMediaType.AMMediaType);
// Don't need the media type anymore.
FreeAndNil(theMediaType);
end; // with FOwner.ati_WaveFormatEx do
// Enable at least one input line.
if FOwner.FCaptureFilterConfigInfo.inputPinName = '' then
begin
// No input name was specified so use the first one found.
if not findAndEnableFirstInputLineFound(FCaptureFilter as IBaseFilter, FOwner.FInputLineUsed) then
raise Exception.Create(
'(TDXChain_wavaudio.Create::initializeCaptureFilter) Unable to find a suitable input line for the audio input device named: '
+ FOwner.FCaptureFilterConfigInfo.filterName);
end
else
begin
// Now find the desired available input line and enable it.
if not findAndEnableInputLineByName(FOwner.FCaptureFilterConfigInfo.inputPinName, FCaptureFilter as IBaseFilter, FOwner.FInputLineUsed) then
raise Exception.Create(
'(TDXChain_wavaudio.Create::initializeCaptureFilter) Unable to find the input line named ('
+ FOwner.FCaptureFilterConfigInfo.inputPinName
+ ') for the audio input device named: '
+ FOwner.FCaptureFilterConfigInfo.filterName);
end; // else - if FOwner.FCaptureFilterConfigInfo.inputPinName = '' then
aryEnabledInputLines := getEnabledInputLineNames(FCaptureFilter as IBaseFilter);
if Length(aryEnabledInputLines) < 1 then
raise Exception.Create('(TDXChain_wavaudio.Create::initializeCaptureFilter) No input lines are enabled..');
// ------------------ BUFFER LATENCY --------------------
// Get a reference to the output pin for audio the capture device.
with FCaptureFilter as IBaseFilter do
CheckDSError(findPin(StringToOleStr('Capture'), intfCapturePin));
if not Assigned(intfCapturePin) then
raise Exception.Create('(TDXChain_wavaudio.Create::initializeCaptureFilter) Unable to find the audio input device''s Capture output pin.');
// Set the capture device buffer to 50 ms worth of audio data to
// reduce latency. NOTE: This will fail if the device does not
// support the latency you desire so make sure you watch out for that.
setBufferLatency(intfCapturePin as IAMBufferNegotiation, FOwner.ati_BufferLatency_ms, FOwner.FMediaType);
end; // if Assigned(FCaptureFilter) then
end;
I have a DirectShow application written in Delphi 6 using the DSPACK component library. I am having a strange problem enabling an input line on a Filter. I search the pins until I find the input line, in this case named 'Microphone', and call put_Enable(true) on it while the Filter Graph is active. When I do this I get an $80004005 "unspecified error" as the HRESULT.
I am setting the output audio media type for the Filter before enabling the input line, yet something is not working right. The original DirectShow sample I worked off of to create my application works fine. I believe I am following the exact same steps building my Filter Graph, and it is possible I missed something of course. Does anyone have any tips or ideas for things I can try to fix this problem? the code snippet below shows partially what I am doing, but not all the steps leading up to it since they are extremely lengthy. The capture device I am using for testing is a VOIP headset with a single input line named 'Microphone'.
// The function I call to find an enable the first input line I find in the filter.
function findAndEnableFirstInputLineFound(intfBaseFilter: IBaseFilter; out strInputLineUsed: string): boolean;
var
thePinList: TPinList;
i: integer;
ABool: LongBool;
begin
strInputLineUsed := '';
if not Assigned(intfBaseFilter) then
raise Exception.Create('(findAndEnableFirstInputLineFound) The base filter interface object is unassigned.');
// Now enable the first input source we can find.
Result := false;
thePinList := TPinList.Create(intfBaseFilter);
try
if thePinList.Count > 0 then
begin
// Scan the pin list looking for an input pin.
i := 0;
while (i < thePinList.Count) and (not Result) do
begin
if thePinList.PinInfo[i].dir = PINDIR_INPUT then
begin
// Found one. Enable it.
with thePinList.Items[i] as IAMAudioInputMixer do
begin
CheckDSEror(put_Enable(true)); // $80004005 error occurs here.
// Return the name of the input line used.
strInputLineUsed := thePinList.PinInfo[i].achName;
end; // with thePinList.Items[i] as IAMAudioInputMixer do
Result := true;
break; // Stop looping.
end; // if thePinList.PinInfo[i].dir = PINDIR_INPUT then
Inc(i);
end; // while()
end; // if thePinList.Count > 0 then
finally
thePinList.Free;
end; // try
end;
// The initialization procedure that calls the function above. It is run after the
// the Filter Graph is activated but before it is played.
procedure TDXChain_wavaudio.initializeCaptureFilter;
var
theMediaType: TMediaType;
intfCapturePin: IPin;
aryEnabledInputLines: TDynamicStringArray;
begin
theMediaType := nil;
intfCapturePin := nil;
aryEnabledInputLines := nil;
if not FFilterGraph.Active then
raise Exception.Create('(TDXChain_wavaudio.Create::initializeCaptureFilter) The Filter Graph is INACTIVE.');
if Assigned(FCaptureFilter) then
begin
// Make sure the Capture Filter's output pins supports the
// configured WAV format.
with FOwner.ati_WaveFormatEx do
begin
// if not Assigned(findAudioMediaTypeByFormat(FCaptureFilter_mediatypes, nSamplesPerSec, wBitsPerSample, nChannels)) then
theMediaType := findAudioMediaTypeExt_outputs(FCaptureFilter as IBaseFilter, nSamplesPerSec, wBitsPerSample, nChannels);
if not Assigned(theMediaType) then
// The capture device does not directly support the desired
// WAV format. This is not allowed currently.
raise Exception.Create('(TDXChain_wavaudio.Create::initializeCaptureFilter) The audio input device''s output pins does not support the given WAV format: '
+ CRLF
+ Format('(Device name: %s, Sample Rate: %d, Bits Per Sample: %d, Number of Channels: %d)',
[FOwner.FCaptureFilterConfigInfo.filterName, nSamplesPerSec, wBitsPerSample, nChannels])
);
// -------------- SET OUTPUT PINS TO MEDIA TYPE -------------
// Set the output pins to the desired format.
setPinAudMediaType_outputs(FCaptureFilter, theMediaType.AMMediaType);
// Don't need the media type anymore.
FreeAndNil(theMediaType);
end; // with FOwner.ati_WaveFormatEx do
// Enable at least one input line.
if FOwner.FCaptureFilterConfigInfo.inputPinName = '' then
begin
// No input name was specified so use the first one found.
if not findAndEnableFirstInputLineFound(FCaptureFilter as IBaseFilter, FOwner.FInputLineUsed) then
raise Exception.Create(
'(TDXChain_wavaudio.Create::initializeCaptureFilter) Unable to find a suitable input line for the audio input device named: '
+ FOwner.FCaptureFilterConfigInfo.filterName);
end
else
begin
// Now find the desired available input line and enable it.
if not findAndEnableInputLineByName(FOwner.FCaptureFilterConfigInfo.inputPinName, FCaptureFilter as IBaseFilter, FOwner.FInputLineUsed) then
raise Exception.Create(
'(TDXChain_wavaudio.Create::initializeCaptureFilter) Unable to find the input line named ('
+ FOwner.FCaptureFilterConfigInfo.inputPinName
+ ') for the audio input device named: '
+ FOwner.FCaptureFilterConfigInfo.filterName);
end; // else - if FOwner.FCaptureFilterConfigInfo.inputPinName = '' then
aryEnabledInputLines := getEnabledInputLineNames(FCaptureFilter as IBaseFilter);
if Length(aryEnabledInputLines) < 1 then
raise Exception.Create('(TDXChain_wavaudio.Create::initializeCaptureFilter) No input lines are enabled..');
// ------------------ BUFFER LATENCY --------------------
// Get a reference to the output pin for audio the capture device.
with FCaptureFilter as IBaseFilter do
CheckDSError(findPin(StringToOleStr('Capture'), intfCapturePin));
if not Assigned(intfCapturePin) then
raise Exception.Create('(TDXChain_wavaudio.Create::initializeCaptureFilter) Unable to find the audio input device''s Capture output pin.');
// Set the capture device buffer to 50 ms worth of audio data to
// reduce latency. NOTE: This will fail if the device does not
// support the latency you desire so make sure you watch out for that.
setBufferLatency(intfCapturePin as IAMBufferNegotiation, FOwner.ati_BufferLatency_ms, FOwner.FMediaType);
end; // if Assigned(FCaptureFilter) then
end;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为音频捕获过滤器在尝试启用某些引脚以混合到录音中时依赖于底层硬件和驱动程序。如果底层因错误而失败,则会将此错误转发给您。
据猜测,当您尝试在另一个引脚已启用的情况下启用一个引脚时,捕获硬件可能会指示错误,即它实际上无法混合两者。
I would suppose that
Audio Capture Filter
relies on underlying hardware and driver when trying to enable certain pin for mixing into recording. If the underlying layer fails with an error, you have this error forwarded to you.As a guess, capture hardware might be indicating an error when you are trying to enable a pin when another pin is already enabled, that is it is actually unable to do mixing of the two.