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


Создание графа повторного сжатия

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

Типичный граф фильтров для повторного сжатия AVI-файла выглядит следующим образом:

граф повторного сжатия avi

Фильтр разделения AVI AVI извлекает данные из фильтра источника файлов (Async) и преобразует их в видео- и аудиопотоки. Декомпрессор видео декодирует сжатое видео, где оно повторно сжимается видеокомпрессором. Выбор декомпрессоров зависит от исходного файла; он будет автоматически обрабатываться Intelligent Connect. Приложение должно выбрать компрессор, как правило, путем представления списка пользователю. (См. Выбор фильтра сжатия.)

Сжатое видео затем переходит в фильтр AVI Mux . Аудиопоток в этом примере не сжимается, поэтому он переходит непосредственно из разделителя AVI на AVI Mux. AVI Mux пересекает два потока, а фильтр записи файлов записывает выходные данные на диск. Обратите внимание, что AVI Mux требуется, даже если исходный файл не имеет аудиопотока.

Самый простой способ построить этот граф фильтров — использовать построитель графов захвата, который является компонентом DirectShow для создания графов захвата и других настраиваемых графов фильтров.

Начните с вызова функции CoCreateInstance для того, чтобы создать построитель графов захвата.

ICaptureGraphBuilder2 *pBuild = NULL;
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, 
                        NULL, CLSCTX_INPROC_SERVER,
    IID_ICaptureGraphBuilder2, (void **)&pBuild);

Затем используйте построитель графов записи для создания графа фильтров:

  1. Создайте раздел вывода графа, который включает фильтр AVI Mux и файл записи .
  2. Добавьте исходный фильтр и фильтр сжатия в граф.
  3. Подключите исходный фильтр к фильтру MUX. Построитель графов захвата вставляет необходимые фильтры для разбиения и декодирования, чтобы анализировать исходный файл. Он также может направлять видео и аудиопотоки через фильтры сжатия.

В следующих разделах описаны все эти действия.

Создать раздел рендеринга

Чтобы создать раздел отрисовки графа, вызовите метод ICaptureGraphBuilder2::SetOutputFileName. Этот метод принимает входные параметры, указывающие подтип носителя для выходных данных и имя выходного файла. Он возвращает указатели на фильтр MUX и модуль записи файлов. Фильтр MUX необходим для следующего этапа построения графа. Указатель на запись в файл не нужен для этого примера, так что параметр можно сделать NULL:

IBaseFilter *pMux = NULL;
hr = pBuild->SetOutputFileName(
        &MEDIASUBTYPE_Avi, // File type. 
        wszOutputFile,     // File name, as a wide-character string.
        &pMux,             // Receives a pointer to the multiplexer.
        NULL);             // Receives a pointer to the file writer. 

Когда метод возвращается, фильтр MUX имеет выдающееся число ссылок, поэтому не забудьте освободить указатель позже.

На следующей схеме показан граф фильтра на этом этапе.

раздел отрисовки графа фильтра

Фильтр MUX предоставляет два интерфейса для управления форматом AVI:

Добавление фильтров источника и сжатия

Следующим шагом является добавление фильтров источника и сжатия в граф фильтров. Построитель графа захвата автоматически создает экземпляр управляющего графом фильтров при вызове SetOutputFileName. Получите указатель на него, вызвав метод ICaptureGraphBuilder2::GetFiltergraph:

IGraphBuilder *pGraph = NULL;
hr = pBuild->GetFiltergraph(&pGraph);

Теперь вызовите метод IGraphBuilder::AddSourceFilter, чтобы добавить фильтр источника файла Async и метод IFilterGraph::AddFilter, чтобы добавить видеокомпрессор:

IBaseFilter *pSrc = NULL;
hr = pGraph->AddSourceFilter(wszInputFile, L"Source Filter", &pSrc);
hr = pGraph->AddFilter(pVComp, L"Compressor");

На этом этапе исходный фильтр и фильтр сжатия не подключены ни к чему другому в графе, как показано на следующем рисунке:

граф фильтрации с помощью фильтров источника и сжатия

Подключите источник к мультиплексору

Последним шагом является подключение исходного фильтра к фильтру AVI Mux через видеокомпрессор. Используйте метод ICaptureGraphBuilder2::RenderStream, который соединяет выходной вывод исходного фильтра с указанным фильтром приемника, опционально через фильтр сжатия.

Первые два параметра указывают, какие из контактов исходного фильтра необходимо подключить, указав категорию контакта и тип медиа. Фильтр источника файла Async имеет только один выходной пин-код, поэтому эти параметры должны быть null. Следующие три параметра указывают исходный фильтр, фильтр сжатия (при наличии) и фильтр Mux.

В следующем примере кода видеопоток отображается через видеокомпрессор:

hr = pBuild->RenderStream(
        NULL,       // Output pin category
        NULL,       // Media type
        pSrc,       // Source filter
        pVComp,     // Compression filter
        pMux);      // Sink filter (the AVI Mux)

На следующей схеме показан граф фильтра.

рендеренный видеопоток

Если исходный файл имеет звуковой поток, фильтр AVI Splitter создал выходной пин-код для звука. Чтобы подключить этот пин-код, снова вызовите RenderStream:

hr = pBuild->RenderStream(NULL, NULL, pSrc, NULL, pMux);

Здесь фильтр сжатия не указан. Выходной контакт исходного фильтра уже подключен, поэтому метод "RenderStream" ищет неподключенный выходной контакт в фильтре-разветвителе. Он находит звуковой пин-код и подключает его непосредственно к фильтру MUX. Если исходный файл не имеет аудиопотока, второй вызов RenderStream завершится ошибкой. Это ожидаемое поведение. График завершается после первого вызова RenderStream, поэтому сбой во втором вызове является безвредным.

В этом примере порядок двух вызовов RenderStream важен. Так как второй вызов не указывает компрессор, он подключит любой несоединённый пин из разделителя AVI. Если вы выполняете этот вызов перед другим, это может привести к подключению видеопотока к AVI Mux в обход вашего видеокомпрессора. Поэтому сначала должен произойти более конкретный вызов (с фильтром сжатия).

В предыдущем обсуждении предполагается, что исходный файл является файлом AVI. Однако этот метод также работает с другими типами файлов, такими как MPEG-файлы. Результирующий граф фильтров будет несколько отличаться.

повторное сжатие файла AVI