Поделиться через


QueryAccept (upstream)

[Функция, связанная с этой страницей, DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngineи аудио и видеозахват в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать новый код MediaPlayer, IMFMediaEngine и аудио-видеозахват в Media Foundation вместо DirectShowпо возможности. Корпорация Майкрософт предлагает, что существующий код, использующий устаревшие API, будет перезаписан для использования новых API, если это возможно.]

Этот механизм позволяет пин-коду ввода предложить изменение формата для его вышестоящего однорангового узла. Нижестоящий фильтр должен подключить тип носителя к образцу, который будет получен в следующем вызове фильтра IMemAllocator::GetBuffer. Однако для этого нижестоящий фильтр должен предоставить пользовательский распределитель для подключения. Этот распределитель должен реализовать частный метод, который может использовать нижестоящий фильтр для задания типа носителя в следующем примере.

Ниже приведены действия.

  1. Нижестоящий фильтр проверяет, используется ли подключение пин-кода настраиваемого распределителя фильтра. Если вышестоящий фильтр владеет распределителем, подчиненный фильтр не может изменить формат.
  2. Подчиненный фильтр вызывает IPin::QueryAccept на вышестоящем выходном пин-коде (см. рисунок, шаг A).
  3. Если QueryAccept возвращает S_OK, то подчиненный фильтр вызывает частный метод на его распределителе, чтобы задать тип носителя. В рамках этого закрытого метода распределитель вызывает IMediaSample::SetMediaType в следующем доступном примере (B).
  4. Исходящий фильтр вызывает GetBuffer, чтобы получить новый пример (C) и IMediaSample::GetMediaType, чтобы получить тип носителя (D).
  5. Когда вышестоящий фильтр доставляет образец, он должен оставить тип носителя присоединенным к данному образцу. Таким образом, нижестоящий фильтр может подтвердить, что тип носителя изменился (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);
    }
}