Вот такой граф создается когда открываю файл.
Вопрос в том как управлять аудио потоками?(т.е. как сделать, чтобы при нажатии кнопки переключать аудио дорожки)
Когда граф запускается проигрывается и первая и вторая, возможно ли сделать так, чтобы при запуске громкость второй дорожки была 0.
Граф строится примерно так:
procedure TForm1.VideoPlay;
var
pSourceFilter : IBaseFilter;
I : Integer;
begin
FilterGraph.Active := True;
FilterGraph.ClearGraph;
CoCreateInstance(CLSID_MKVSource, nil,CLSCTX_INPROC, IID_IBASEFilter, pSourceFilter);
(FilterGraph as IGraphBuilder).AddFilter(pSourceFilter, StringToOleStr(FFileName));
(pSourceFilter as IFileSourceFilter).Load(StringToOleStr(FFileName),nil);
with TPinList.Create(pSourceFilter) do
try
for I := 0 to Count - 1 do
if PinInfo[I].dir = PINDIR_OUTPUT then
(FilterGraph as IGraphBuilder).Render(Items[I])
finally
Free;
end;
FilterGraph.Play;
end;
Здравствуйте, Аноним, Вы писали:
А>А можно узнать — что за исходный файл ?
Если вы про фильтр, то Haali Simple Media Splitter, а файл фильм в формате MKV.
Здравствуйте, D. Mon, Вы писали:
DM>Я бы получил у аудио рендереров интерфейсы IBasicAudio и дергал бы put_Volume. Это теоретически, сам не пробовал.
Спасибо буду пробовать.
Здравствуйте, D. Mon, Вы писали:
DM>Я бы получил у аудио рендереров интерфейсы IBasicAudio и дергал бы put_Volume. Это теоретически, сам не пробовал.
А как мне найти аудио рендереры в графе? Есть функция FindAudioRenderer, но как ее использовать, чтобы узнать количество аудио рендереров?
Я пока еще учусь и буду рад примеру или помощи
Здравствуйте, XoSteL, Вы писали:
XSL>А как мне найти аудио рендереры в графе?
Сразу после построения цепочки фильтров для данного пина пройдите по ней до конца (придется написать вспомогательную функцию, которая у выходного пина будет узнавать к кому он подсоединен, а у фильтров будет узнавать выходной пин). Так будет ясно, какой рендерер к какому пину относится. Потому что другой вариант — через EnumFilters — такой информации не даст.
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, XoSteL, Вы писали:
XSL>>А как мне найти аудио рендереры в графе?
DM>Так будет ясно, какой рендерер к какому пину относится. Потому что другой вариант — через EnumFilters — такой информации не даст.
но ведь можно через EnumFilters, пробежаться по каждому фильтру и проверить его на наличие IBasicAudio
Вот Функции:
function FindRenderer, function FindAudioRenderer, function FindVideoRenderer, function CountFilterPins.
function FindRenderer(pGB: IGraphBuilder; const mediatype: PGUID; out ppFilter: IBaseFilter): HRESULT;
var
Enum : IEnumFilters;
Filter: IBaseFilter;
Pin : IPin;
Fetched,
InPins,
OutPins: Cardinal;
Found: Boolean;
MediaType_: TAMMediaType;
begin
Found := False;
// Verify graph builder interfaceif not Assigned(pGB) then
begin
Result := E_NOINTERFACE;
Exit;
end;
// Verify that a media type was passedif not Assigned(mediatype) then
begin
Result := E_POINTER;
Exit;
end;
// Clear the filter pointer in case there is no matchif Assigned(@ppFilter) then ppFilter := nil;
// Get filter enumerator
Result := pGB.EnumFilters(Enum);
if FAILED(Result) then Exit;
Enum.Reset;
// Enumerate all filters in the graphwhile((not Found) and (Enum.Next(1, Filter, @Fetched) = S_OK)) do
begin// Find a filter with one input and no output pins
Result := CountFilterPins(Filter, InPins, OutPins);
if FAILED(Result) then break;
if ((InPins = 1) and (OutPins = 0)) then
begin// Get the first pin on the filter
Pin := nil;
Pin := GetInPin(Filter, 0);
// Read this pin's major media type
Result := Pin.ConnectionMediaType(MediaType_);
if FAILED(Result) then break;
// Is this pin's media type the requested type?
// If so, then this is the renderer for which we are searching.
// Copy the interface pointer and return.if IsEqualGUID(MediaType_.majortype,mediatype^) then
begin// Found our filter
ppFilter := Filter;
Found := True;
end else
begin// This is not the renderer, so release the interface.
Filter := nil;
end;
// Delete memory allocated by ConnectionMediaType()
UtilFreeMediaType(@MediaType_);
end else
begin// No match, so release the interface
Filter := nil;
end;
end;
Enum := nil;
end;
function FindAudioRenderer(pGB: IGraphBuilder; out ppFilter: IBaseFilter): HRESULT;
begin
Result := FindRenderer(pGB, @MEDIATYPE_Audio, ppFilter);
end;
function FindVideoRenderer(pGB: IGraphBuilder; out ppFilter: IBaseFilter): HRESULT;
begin
Result := FindRenderer(pGB, @MEDIATYPE_Video, ppFilter);
end;
function CountFilterPins(pFilter: IBaseFilter; out pulInPins: Cardinal; out pulOutPins: Cardinal): HRESULT;
var
Enum: IEnumPins;
Found: Cardinal;
Pin: IPin;
PinDir: TPinDirection;
begin// Verify inputif (not Assigned(pFilter) or not Assigned(@pulInPins) or not Assigned(@pulOutPins)) then
begin
Result := E_POINTER;
Exit;
end;
// Clear number of pins found
pulInPins := 0;
pulOutPins := 0;
// Get pin enumerator
Result := pFilter.EnumPins(Enum);
if FAILED(Result) then Exit;
Enum.Reset;
// Count every pin on the filterwhile(S_OK = Enum.Next(1, Pin, @Found)) do
begin
Result := Pin.QueryDirection(PinDir);
if (PinDir = PINDIR_INPUT) then inc(pulInPins)
else inc(pulOutPins);
Pin := nil;
end;
Enum := nil;
end;
Здравствуйте, XoSteL, Вы писали:
XSL>Как использовать функцию FindAudioRenderer?
Выбросить в помойку. Она возвращает первый попавшийся фильтр, принимающий аудио. Иногда в самых простых случаях это рендерер, но легко может быть и кодек или какой-нибудь конвертер. В общем, не рекомендую ее использовать.
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, dabeat_bf, Вы писали:
_>>но ведь можно через EnumFilters, пробежаться по каждому фильтру и проверить его на наличие IBasicAudio
DM>А как узнать какой рендерер к какому потоку звука относится?
хм... дилемма, как-то не обратил на это внимание... нет конечно можно теоретически рендерить пин запускать функцию поиска нового рендерера... но это так идея, чтоб ну совсем не хоронить мою прошлую идею
Здравствуйте, D. Mon, Вы писали:
DM>Я бы получил у аудио рендереров интерфейсы IBasicAudio и дергал бы put_Volume. Это теоретически, сам не пробовал.
Рендереры я нашел, теперь вопрос как ими управлять??? (т.е как можно изменять громкость каждого рендерера отдельно)
procedure TForm1.btASwitchClick(Sender: TObject);
var
i : integer;
FilterList : TFIlterList;
ClassID : TGUID;
begin
try
FilterList := TFilterList.Create(FilterGraph as IFilterGraph);
for I := 0 to FilterList.Count - 1 do
begin
FilterList.Items[i].GetClassID(ClassID);
if (IsEqualGUID(ClassID, CLSID_AudioRender)= True) or
(IsEqualGUID(ClassID, CLSID_DSoundRender)= True) then
begin//как здесь получить интерфейсы IBasicAudio и управлять ими????end;
end;
finally
FilterList.Free;
end;
end;
Здравствуйте, XoSteL, Вы писали:
XSL>Здравствуйте, D. Mon, Вы писали:
DM>>Я бы получил у аудио рендереров интерфейсы IBasicAudio и дергал бы put_Volume. Это теоретически, сам не пробовал. XSL>Рендереры я нашел, теперь вопрос как ими управлять??? (т.е как можно изменять громкость каждого рендерера отдельно)
XSL>
XSL>procedure TForm1.btASwitchClick(Sender: TObject);
XSL>var
XSL>i : integer;
XSL>FilterList : TFIlterList;
XSL>ClassID : TGUID;
XSL>begin
XSL> try
XSL> FilterList := TFilterList.Create(FilterGraph as IFilterGraph);
XSL> for I := 0 to FilterList.Count - 1 do
XSL> begin
XSL> FilterList.Items[i].GetClassID(ClassID);
XSL> if (IsEqualGUID(ClassID, CLSID_AudioRender)= True) or
XSL> (IsEqualGUID(ClassID, CLSID_DSoundRender)= True) then
XSL> begin
XSL> //как здесь получить интерфейсы IBasicAudio и управлять ими????
XSL> end;
XSL> end;
XSL> finally
XSL> FilterList.Free;
XSL> end;
XSL>end;
XSL>
у тебя есть объект, фильтр, который ты получил (с гуидом CLSID_DSoundRender).
Так, только нужно не забыть зарелизить полученный интерфейс. В С++ лучше использовать CComPtr и CComQIPtr, тогда их деструкторы об этом позаботятся. Как в Дельфи — не в курсе.
В>у тебя есть объект, фильтр, который ты получил (с гуидом CLSID_DSoundRender).
В>IBasicAudio * m_pBasicAudio = NULL;
В>HRESULT hr = фильтр->QueryInterface(IID_IBasicAudio, (void **)&m_pBasicAudio);
В>if(SUCCEEDED(hr) && m_pBasicAudio) В>{ В> long lVolume = 10;
В> m_pBasicAudio->put_Volume(lVolume); В>}
В>по моему так. Может и не прав
//Если сделать так?
FilterList.Items[i].QueryInterface(IID_IBasicAudio, pBasicAudio);
//Значит я смогу получить интерфейсы IBasicAudio для всех рендереров????
// если так , то как можно можно управлять гомкостью дорожек используя индекс рендереров???
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, XoSteL, Вы писали:
XSL>>// если так , то как можно можно управлять гомкостью дорожек используя индекс рендереров???
DM>Если угодно по индексу рендереров — сделайте массив, содержащий указатели на IBasicAudio для каждого рендерера, и по индексу к ним обращайтесь.
Вот так все работает
procedure TForm1.btASwitchClick(Sender: TObject);
var
FilterList: TDSoundFilterList;
pBasicAudio: IBasicAudio;
i : integer;
begin
i := btASwitch.Tag + 1;
FilterList := TDSoundFilterList.Create(FilterGraph as IFiltergraph);
try
if i <> FilterList.Count then
begin
FilterGraph.QueryInterface(IID_IBasicAudio, pBasicAudio);
pBasicAudio.put_Volume(-10000);
btASwitch.Tag := btASwitch.Tag + 1;
FilterList.Items[btASwitch.Tag].QueryInterface(IID_IBasicAudio, pBasicAudio);
pBasicAudio.put_Volume(0);
ShowMessage('Audio ' + IntToStr(i) + ' из ' + IntToStr(FilterList.Count));
end else
begin
FilterGraph.QueryInterface(IID_IBasicAudio, pBasicAudio);
pBasicAudio.put_Volume(-10000);
btASwitch.Tag := 0;
FilterList.Items[btASwitch.Tag].QueryInterface(IID_IBasicAudio, pBasicAudio);
pBasicAudio.put_Volume(0);
ShowMessage('Audio ' + IntToStr(i) + ' из ' + IntToStr(FilterList.Count));
end;
finally
FilterList.Free;
end;
end;
а вы кстати выбор потоков через IAMStreamSelect учитываете? там ведь один пин на выходе сплитера, один рендерер его играющий, но нескольно аудои потоков, выбирающихся этим интерфейсом внутри сплиттера, возможно даже играющих одновременно.
конкретный пример — сплиттер Matroska от Haali.
может у вас старая его версия, если вы о нем писали про кучу пинов?
вобщем основная мысль — про IAMStreamSelect забывать не следует
Здравствуйте, squid, Вы писали:
S>Здравствуйте, XoSteL, Вы писали:
S>а вы кстати выбор потоков через IAMStreamSelect учитываете? там ведь один пин на выходе сплитера, один рендерер его играющий, но нескольно аудои потоков, выбирающихся этим интерфейсом внутри сплиттера, возможно даже играющих одновременно.
Я SourceFilter в граф добавляю в ручную у него на выходе столько же пинов сколько и аудио потоков поэтому IAMStreamSelect мне не нужен. Аудио дорожки переключаются без остановки графа мгновенно и независимо от формата файла(будь то AVI или MKV).
Здравствуйте, XoSteL, Вы писали:
XSL>Здравствуйте, squid, Вы писали:
S>>Здравствуйте, XoSteL, Вы писали:
S>>а вы кстати выбор потоков через IAMStreamSelect учитываете? там ведь один пин на выходе сплитера, один рендерер его играющий, но нескольно аудои потоков, выбирающихся этим интерфейсом внутри сплиттера, возможно даже играющих одновременно.
XSL>Я SourceFilter в граф добавляю в ручную у него на выходе столько же пинов сколько и аудио потоков поэтому IAMStreamSelect мне не нужен. Аудио дорожки переключаются без остановки графа мгновенно и независимо от формата файла(будь то AVI или MKV).
есть сплиттеры которые его используют. и если вы пишите не только для себя ваш клиент может с этим столкнутся. вот и все.