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


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

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

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

Граф рекомпрессии avi

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

Затем сжатое видео переходит к фильтру мультиплекса AVI. Аудиопоток в этом примере не сжимается, поэтому он передается непосредственно из разделителя AVI в мультиплекс AVI. Мультиплекс AVI чередует два потока, а фильтр записи файлов записывает выходные данные на диск. Обратите внимание, что 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:

Добавление исходных фильтров и фильтров сжатия

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

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

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

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

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

фильтр графа с исходными фильтрами и фильтрами сжатия

Подключение источника к mux

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

Первые два параметра определяют, какие из контактов исходного фильтра следует подключить, определяя категорию контактов и тип носителя. Фильтр источника асинхронного файла имеет только один вывод, поэтому эти параметры должны иметь значение 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 создал выходную закрепку для звука. Чтобы подключить этот контакт, снова вызовите RenderStream:

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

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

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

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

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