QueryAccept (upstream)
[La característica asociada a esta página, DirectShow, es una característica heredada. Se ha reemplazado por MediaPlayer, IMFMediaEngine y Captura de audio/vídeo en Media Foundation. Esas características se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer, IMFMediaEngine y Audio/Video Capture en Media Foundation en lugar de DirectShow, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.
Este mecanismo permite a un pin de entrada proponer un cambio de formato a su par ascendente. El filtro de bajada debe adjuntar un tipo de medio a la muestra que el filtro ascendente obtendrá en su siguiente llamada a IMemAllocator::GetBuffer. Sin embargo, para ello, el filtro de bajada debe proporcionar un asignador personalizado para la conexión. Este asignador debe implementar un método privado que el filtro de bajada pueda usar para establecer el tipo de medio en el ejemplo siguiente.
Tienen lugar los pasos siguientes:
- El filtro de bajada comprueba si la conexión de anclaje usa el asignador personalizado del filtro. Si el filtro ascendente posee el asignador, el filtro de bajada no puede cambiar el formato.
- El filtro de bajada llama a IPin::QueryAccept en el pin de salida ascendente (vea ilustración, paso A).
- Si
QueryAccept
devuelve S_OK, el filtro de bajada llama al método privado en su asignador para establecer el tipo de medio. Dentro de este método privado, el asignador llama a IMediaSample::SetMediaType en el siguiente ejemplo disponible (B). - El filtro ascendente llama a GetBuffer para obtener un nuevo ejemplo (C) e IMediaSample::GetMediaType para obtener el tipo de medio (D).
- Cuando el filtro ascendente entrega el ejemplo, debe dejar el tipo de medio adjunto a ese ejemplo. De este modo, el filtro de bajada puede confirmar que el tipo de medio ha cambiado (E).
Si el filtro ascendente acepta el cambio de formato, también debe poder volver al tipo de medio original, como se muestra en el diagrama siguiente.
Los principales ejemplos de este tipo de cambio de formato implican los representadores de vídeo directShow.
- El filtro original de Video Renderer puede cambiar entre los tipos RGB e YUV durante el streaming. Cuando el filtro se conecta, requiere un formato RGB que coincida con la configuración de visualización actual. Esto garantiza que puede revertirse a GDI si es necesario. Una vez que se inicia el streaming, si DirectDraw está disponible, Video Renderer solicita un cambio de formato a un tipo YUV. Más adelante, podría volver a RGB si pierde la superficie de DirectDraw por cualquier motivo.
- El filtro más reciente del representador de mezcla de vídeos (VMR) se conectará con cualquier formato compatible con el hardware gráfico, incluidos los tipos YUV. Sin embargo, el hardware gráfico podría cambiar el ritmo de la superficie de DirectDraw subyacente para optimizar el rendimiento. El filtro VMR usa
QueryAccept
para notificar el nuevo paso, que se especifica en el miembro biWidth de la estructura BITMAPINFOHEADER . Los rectángulos de origen y destino de la estructura VIDEOINFOHEADER o VIDEOINFOHEADER2 identifican la región donde se debe descodificar el vídeo.
Nota de implementación
Es poco probable que escriba un filtro que necesite solicitar cambios de formato ascendentes, ya que esto es principalmente una característica de los representadores de vídeo. Sin embargo, si escribe un filtro de transformación de vídeo o un descodificador de vídeo, el filtro debe responder correctamente a las solicitudes del representador de vídeo.
Un filtro trans-in-place que se encuentra entre el representador de vídeo y el descodificador debe pasar todas las QueryAccept
llamadas ascendentes. Almacene la nueva información de formato cuando llegue.
Un filtro de transformación de copia (es decir, un filtro no trans-in-place) debe implementar uno de los siguientes comportamientos:
- Pase los cambios de formato ascendentes y almacene la nueva información de formato cuando llegue. El filtro debe usar un asignador personalizado para que pueda adjuntar el formato al ejemplo ascendente.
- Realice la conversión de formato dentro del filtro. Esto probablemente sea más fácil que pasar el cambio de formato ascendente. Sin embargo, puede ser menos eficaz que permitir que el filtro del descodificador descodifique en el formato correcto.
- Como último recurso, simplemente rechaza el cambio de formato. (Para obtener más información, consulte el código fuente del método CTransInPlaceOutputPin::CheckMediaType en la biblioteca de clases base directShow). No obstante, rechazar un cambio de formato puede reducir el rendimiento, ya que impide que el representador de vídeo use el formato más eficaz.
El siguiente pseudocódigo muestra cómo puede implementar un filtro de transformación de copia (derivado de CTransformFilter) que puede cambiar entre los tipos de salida YUV y RGB. En este ejemplo se supone que el filtro realiza la propia conversión, en lugar de pasar el cambio de formato ascendente.
HRESULT CMyTransform::CheckInputType(const CMediaType *pmt)
{
if (pmt is a YUV type that you support) {
return S_OK;
}
else {
return VFW_E_TYPE_NOT_ACCEPTED;
}
}
HRESULT CMyTransform::CheckTransform(
const CMediaType *mtIn, const CMediaType *mtOut)
{
if (mtOut is a YUV or RGB type that you support)
{
if ((mtIn has the same video dimensions as mtOut) &&
(you support the mtIn-to-mtOut transform))
{
return S_OK;
}
}
// otherwise
return VFW_E_TYPE_NOT_ACCEPTED;
}
// GetMediaType: Return a preferred output type.
HRESULT CMyTransform::GetMediaType(int iPosition, CMediaType *pMediaType)
{
if (iPosition < 0) {
return E_INVALIDARG;
}
switch (iPosition)
{
case 0:
Copy the input type (YUV) to pMediaType
return S_OK;
case 1:
Construct an RGB type that matches the input type.
return S_OK;
default:
return VFW_S_NO_MORE_ITEMS;
}
}
// SetMediaType: Override from CTransformFilter.
HRESULT CMyTransform::SetMediaType(
PIN_DIRECTION direction, const CMediaType *pmt)
{
// Capture this information...
if (direction == PINDIR_OUTPUT)
{
m_bYuv = (pmt->subtype == MEDIASUBTYPE_UYVY);
}
return S_OK;
}
HRESULT CMyTransform::Transform(
IMediaSample *pSource, IMediaSample *pDest)
{
// Look for format changes from downstream.
CMediaType *pMT = NULL;
HRESULT hr = pDest->GetMediaType((AM_MEDIA_TYPE**)&pMT);
if (hr == S_OK)
{
hr = m_pOutput->CheckMediaType(pMT);
if(FAILED(hr))
{
DeleteMediaType(pMT);
return E_FAIL;
}
// Notify our own output pin about the new type.
m_pOutput->SetMediaType(pMT);
DeleteMediaType(pMT);
}
// Process the buffers
if (m_bYuv) {
return ProcessFrameYUV(pSource, pDest);
}
else {
return ProcessFrameRGB(pSource, pDest);
}
}