Visualizando áudio de TV
[O recurso associado a esta página, DirectShow, é um recurso herdado. Foi substituído por MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]
Para visualizar o áudio de TV, encaminhe o pino do Decodificador de Áudio no filtro da barra cruzada para o pino do Sintonizador de Áudio. Para ativar o mudo do áudio, encaminhe o pino do Decodificador de Áudio para -1, conforme mostrado no diagrama a seguir. (Filtros de barra cruzada são descritos em Trabalhando com barras cruzadas.)
A abordagem básica é a seguinte:
- Use o método ICaptureGraphBuilder2::FindInterface para localizar o filtro de barra cruzada.
- Use o método IAMCrossbar::get_CrossbarPinInfo para enumerar os pinos de entrada e saída do filtro de barra cruzada. Pesquise um pino de saída do decodificador de áudio e um pino de entrada do sintonizador de áudio.
- Se você encontrar os pinos corretos, chame IAMCrossbar::Route para rotear os pinos. Caso contrário, procure upstream outra barra cruzada e repita o processo.
- Para ativar o mudo do áudio, encaminhe o pino do decodificador de áudio para -1.
A maioria dos sintonizadores de TV usa um único filtro de barra cruzada, mas alguns usam dois filtros de barra cruzada. Portanto, talvez seja necessário pesquisar uma segunda barra cruzada se a primeira falhar.
Observação
Ao contrário do que você pode esperar, nenhum filtro de captura de áudio ou renderizador de áudio é necessário para visualizar o áudio, pois há uma conexão física entre o sintonizador cartão e o som cartão.
O código a seguir mostra essas etapas com mais detalhes. Primeiro, aqui está uma função auxiliar que pesquisa um filtro de barra cruzada para um tipo de pino especificado:
HRESULT FindCrossbarPin(
IAMCrossbar *pXBar, // Pointer to the crossbar.
PhysicalConnectorType PhysicalType, // Pin type to match.
PIN_DIRECTION Dir, // Pin direction.
long *pIndex) // Receives the index of the pin, if found.
{
BOOL bInput = (Dir == PINDIR_INPUT ? TRUE : FALSE);
// Find out how many pins the crossbar has.
long cOut, cIn;
HRESULT hr = pXBar->get_PinCounts(&cOut, &cIn);
if (FAILED(hr)) return hr;
// Enumerate pins and look for a matching pin.
long count = (bInput ? cIn : cOut);
for (long i = 0; i < count; i++)
{
long iRelated = 0;
long ThisPhysicalType = 0;
hr = pXBar->get_CrossbarPinInfo(bInput, i, &iRelated,
&ThisPhysicalType);
if (SUCCEEDED(hr) && ThisPhysicalType == PhysicalType)
{
// Found a match, return the index.
*pIndex = i;
return S_OK;
}
}
// Did not find a matching pin.
return E_FAIL;
}
A próxima função tenta ativar ou silenciar o áudio, dependendo do valor do parâmetro bActivate . Ele pesquisa o filtro de barra cruzada especificado para os pinos necessários. Se ele não conseguir encontrá-los, retornará um código de erro.
HRESULT ConnectAudio(IAMCrossbar *pXBar, BOOL bActivate)
{
// Look for the Audio Decoder output pin.
long i = 0;
HRESULT hr = FindCrossbarPin(pXBar, PhysConn_Audio_AudioDecoder,
PINDIR_OUTPUT, &i);
if (SUCCEEDED(hr))
{
if (bActivate) // Activate the audio.
{
// Look for the Audio Tuner input pin.
long j = 0;
hr = FindCrossbarPin(pXBar, PhysConn_Audio_Tuner,
PINDIR_INPUT, &j);
if (SUCCEEDED(hr))
{
return pXBar->Route(i, j);
}
}
else // Mute the audio
{
return pXBar->Route(i, -1);
}
}
return E_FAIL;
}
A próxima função pesquisa no grafo de filtro um filtro de barra cruzada. Se encontrar um, ele tentará ativar ou silenciar o áudio (usando a função anterior). Se essa operação falhar, o método pesquisa upstream uma segunda barra cruzada e tenta novamente. Para obter uma abordagem mais generalizada para gerenciar vários filtros de barra cruzada em um grafo, consulte a classe CCrossbar no aplicativo de exemplo AmCap.
HRESULT ActivateAudio(ICaptureGraphBuilder2 *pBuild, IBaseFilter *pSrc,
BOOL bActivate)
{
// Search upstream for a crossbar.
IAMCrossbar *pXBar1 = NULL;
HRESULT hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, NULL, pSrc,
IID_IAMCrossbar, (void**)&pXBar1);
if (SUCCEEDED(hr))
{
hr = ConnectAudio(pXBar1, bActivate);
if (FAILED(hr))
{
// Look for another crossbar.
IBaseFilter *pF = NULL;
hr = pXBar1->QueryInterface(IID_IBaseFilter, (void**)&pF);
if (SUCCEEDED(hr))
{
// Search upstream for another one.
IAMCrossbar *pXBar2 = NULL;
hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, NULL, pF,
IID_IAMCrossbar, (void**)&pXBar2);
pF->Release();
if (SUCCEEDED(hr))
{
hr = ConnectAudio(pXBar2, bActivate);
pXBar2->Release();
}
}
}
pXBar1->Release();
}
return hr;
}
O código a seguir mostra como chamar essas funções:
// Build the analog TV graph (not shown).
// Activate the audio.
hr = ActivateAudio(pBuild, pCap, TRUE);
// Later, mute the audio.
hr = ActivateAudio(pBuild, pCap, FALSE);
Observe que essas funções de exemplo repetem muitas das mesmas chamadas de função. Por exemplo, eles enumeram os pinos da barra cruzada a cada vez. Em um aplicativo real, você pode armazenar em cache algumas dessas informações.
Tópicos relacionados