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


QueryAccept (вышестоящий)

[Функция, связанная с этой страницей 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 (вышестоящий)

В main примерах такого изменения формата используются отрисовщики видео DirectShow.

  • Исходный фильтр отрисовщика видео может переключаться между типами RGB и YUV во время потоковой передачи. При подключении фильтра требуется формат RGB, соответствующий текущим параметрам отображения. Это гарантирует, что он может отступить от GDI, если это необходимо. После начала потоковой передачи, если directDraw доступен, отрисовщик видео запрашивает изменение формата на тип YUV. Позже он может переключиться обратно на RGB, если по какой-либо причине потеряет поверхность DirectDraw.
  • Новый фильтр отрисовщика видео микширования (VMR) будет подключаться к любому формату, поддерживаемому графическим оборудованием, включая типы YUV. Однако графическое оборудование может изменить ход базовой поверхности DirectDraw, чтобы оптимизировать производительность. Фильтр VMR использует для QueryAccept сообщения о новом шаге, который указан в элементе biWidth структуры BITMAPINFOHEADER . Исходный и целевой прямоугольники в структуре 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);
    }
}