QueryAccept (upstream)
[Функция, связанная с этой страницей, DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngineи аудио и видеозахват в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать новый код MediaPlayer, IMFMediaEngine и аудио-видеозахват в Media Foundation вместо DirectShowпо возможности. Корпорация Майкрософт предлагает, что существующий код, использующий устаревшие API, будет перезаписан для использования новых API, если это возможно.]
Этот механизм позволяет пин-коду ввода предложить изменение формата для его вышестоящего однорангового узла. Нижестоящий фильтр должен подключить тип носителя к образцу, который будет получен в следующем вызове фильтра IMemAllocator::GetBuffer. Однако для этого нижестоящий фильтр должен предоставить пользовательский распределитель для подключения. Этот распределитель должен реализовать частный метод, который может использовать нижестоящий фильтр для задания типа носителя в следующем примере.
Ниже приведены действия.
- Нижестоящий фильтр проверяет, используется ли подключение пин-кода настраиваемого распределителя фильтра. Если вышестоящий фильтр владеет распределителем, подчиненный фильтр не может изменить формат.
- Подчиненный фильтр вызывает IPin::QueryAccept на вышестоящем выходном пин-коде (см. рисунок, шаг A).
- Если
QueryAccept
возвращает S_OK, то подчиненный фильтр вызывает частный метод на его распределителе, чтобы задать тип носителя. В рамках этого закрытого метода распределитель вызывает IMediaSample::SetMediaType в следующем доступном примере (B). - Исходящий фильтр вызывает GetBuffer, чтобы получить новый пример (C) и IMediaSample::GetMediaType, чтобы получить тип носителя (D).
- Когда вышестоящий фильтр доставляет образец, он должен оставить тип носителя присоединенным к данному образцу. Таким образом, нижестоящий фильтр может подтвердить, что тип носителя изменился (E).
Если вышестоящий фильтр принимает изменение формата, он также должен иметь возможность вернуться к исходному типу носителя, как показано на следующей схеме.
queryaccept (upstream)
Основными примерами такого изменения формата являются отрисовщики видео DirectShow.
- Исходный отрисовщик видео может переключаться между типами RGB и YUV во время потоковой передачи. При подключении фильтра требуется формат RGB, соответствующий текущим параметрам дисплея. Это гарантирует, что он может вернуться к GDI, если он должен. После начала потоковой передачи, если DirectDraw доступен, средство отрисовки видео запрашивает изменение формата в тип YUV. Позже он может вернуться на RGB, если он теряет поверхность DirectDraw по какой-либо причине.
- Более новый фильтр "Средство просмотра видео" (VMR) будет подключаться к любому формату, поддерживаемому графическим оборудованием, включая типы YUV. Однако графическое оборудование может изменить шаг базовой поверхности DirectDraw для оптимизации производительности. Фильтр VMR использует
QueryAccept
для отчета о новом шаге, указанном в элементе biWidth структуры BITMAPINFOHEAD ER. Исходные и целевые прямоугольники в VIDEOINFOHEADER или VIDEOINFOHEADER2 определяют область, в которой следует декодировать видео.
Примечание о реализации
Вряд ли вы напишете фильтр, который должен запрашивать изменения вышестоящего формата, так как это в основном функция отрисовщиков видео. Однако при написании фильтра преобразования видео или декодера видео фильтр должен правильно реагировать на запросы от отрисовщика видео.
Фильтр на месте, который находится между отрисовщиком видео и декодером, должен передавать все QueryAccept
вызовы вверх. Сохраните новые сведения о формате при поступлении.
Фильтр преобразования копирования (т. е. фильтр, отличный от транс-на месте), должен реализовать одно из следующих действий:
- Передайте изменения формата вверх и сохраните новые сведения о формате при поступлении. Фильтр должен использовать пользовательский распределитель, чтобы он смог подключить формат к вышестоящему образцу.
- Выполните преобразование формата внутри фильтра. Это, вероятно, проще, чем передача изменения формата вышестоящей версии. Однако это может быть менее эффективным, чем разрешение декодирования фильтра декодировщика в правильном формате.
- В качестве последнего способа просто отклонить изменение формата. (Дополнительные сведения см. в исходном коде для метода CTransInPlaceOutputPin::CheckMediaType в библиотеке базовых классов DirectShow.) Отклонение изменения формата может снизить производительность, так как она запрещает отрисовщику видео использовать наиболее эффективный формат.
В следующем псевдокоде показано, как реализовать фильтр преобразования копирования (производный от CTransformFilter), который может переключаться между типами выходных данных YUV и RGB. В этом примере предполагается, что фильтр выполняет преобразование, а не передает вышестоящую передачу изменений формата.
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);
}
}