GraphEdit

Автор: Валентин Вовк

Что такое GraphEdit?

Так называется утилита Microsoft, входящая в состав DirectShow SDK (сейчас эта утилита, как и заголовочные файлы DirectShow, входит в состав Windows Platform SDK. С ее помощью можно соединять установленные и зарегистрированные в системе фильтры. 

Что она может нам дать? 

Во-первых, без использования других программ и написания кода совершать различные манипуляции с медиа-файлами: конвертировать из одного формата в другой, извлекать из видеофайлов звуковые дорожки, захватывать "живое видео" и т.п. 

Во-вторых, это поможет нам быстрее понять, что такое DirectShow и ввести нас в круг его понятий - это будет полезно при чтении остальных статей.

Скачать GraphEdit

Кодеки

Они представляют фильтры, в более широком смысле - сборник фильтров (Codeck Pack). Перечислю наиболее известные:

и другие, поскольку вряд ли я в состоянии перечислить все необходимые. Смотрите также по ссылкам:

и т.д. - далее по ссылкам на этих сайтах.

Потихоньку разбираемся

Итак, запустим программу graphedt.exe - вот так должно выглядеть окно приложения:

Рис. 1. Окно GraphEdit'а

Проигрывание видеофайла

Жмем File->Render Media File ... - появляется окно с приглашением выбрать media-файл. Я выбрал файл с именем new.avi (вы можете выбрать, конечно, что угодно другое, но рекомендую тоже avi-файл) и нажимаю OK. У меня получилось вот что:

Рис. 2. Автоматически построенный граф фильтров

Давайте в общих чертах разберемся, что здесь нарисовано. Картинка состоит из синеньких прямоугольников, соединенных стрелочками. Первый прямоугольник символизирует, видимо, наш исходный файл (напомню, он называется new.avi). Далее, по ходу стрелочки, видим следующий прямоугольник, в котором написано "AVI Splitter",- судя по названию, а также по двум исходящим из него стрелкам, он предназначен для того, чтобы взять данные от первого прямоугольника и разделить их на два потока - нетрудно сообразить, что это - аудио- и видео- потоки. Входы и выходы в прямоугольнички в терминологии DirectShow представляют собой входящие и исходящие контакты (InputPin и OutputPin), а сами прямоугольники - собственно фильтры (теперь мы сможем догадаться о причине ошибки, если увидим где-то сообщение о ней вроде "Действие не может быть выполнено, поскольку контакты не подключены" - речь идет именно об этих контактах). Вся же эта схема есть так называемым графом фильтров. Дальнейший анализ нашей картинки не должен представлять трудностей. Поэтому выберем пункты меню Graph->Play и посмотрим наше видео-аудио. Насмотревшись вдоволь, остановим просмотр (Graph->Stop или красненький квадратик на панели инструментов) и немного поупражняемся в составлении графов фильтров вручную.

Для этого выберем File->New, откажемся от сохранения нашей работы в файл (впрочем, можете сохранять, авось пригодится).

Нашей следующей целью будет повторение того, что мы уже сделали, но вручную. Для этого выберем Graph->Insert Filters:

Рис. 3. Окно выбора фильтра

Нас пока будут интересовать DirectShow фильтры. Поэтому распахнем узел дерева "DirectShow Filters", найдем пункт "File Source (Async.)" и совершим на этом пункте двойной щелчок мышью (т.е. выберем этот фильтр). В появившемся окне диалога выбора медиа-файла укажем тот же, что и раньше, файл (new.avi). Появится прямоугольник с именем нашего файла. Если в той области, где находится надпись "Output" щелкнуть правой кнопкой мышки, увидим меню:

Рис. 4. Автоматическое построение графа фильтров

Заметим, что выбор пункта "Render Pin" приведет к построению графа, с которым мы уже знакомы: Рис. 2. Вы попробуйте это сделать, убедитесь, что я прав, а потом удалите ненужные элементы графа и вернитесь к этому месту. Дальше из той же категории "DirectShow Filters" выберем "Avi Splitter Filter" фильтр и соединим наши два имеющиеся в данный момент фильтра, протянув мышкой от исходящего контакта первого фильтра к входящему второго:

Рис. 5. Построение графа фильтров вручную

Остальное очевидно. Смотрим на Рис.2, выбираем соответствующие фильтры и соединяем их. Понятно, что GraphEdit, когда его просишь проиграть медиа-файл, каким-то образом узнает, какие нужны для этого фильтры и какие их контакты должны быть подключены. Разберемся с этим. Тем более, что это пригодится при написании собственных фильтров в том случае, если мы хотим сделать их доступными в процессе автоматического построения графа фильтров - утилита GraphEdit всего лишь вызывает API-функции для построения такого графа.

IGraphBuilder

Intelligent connect

Каким образом GraphEdit узнает, какие нужны фильтры для проигрывания медиа-файла? Для этого используется специальный механизм - Intelligent Connect. Он описан в справке DirectShow, а я его сейчас перескажу в меру способностей.

Intelligent connect затрагивает следующие методы интерфейсаIGraphBuilder:

Метод Render строит подсекцию графа. Он начинает обработку, начиная с первого несоединенного исходящего контакта и добавляет новые фильтры по мере необходимости. Стартовый фильтр (самый первый, т.е. - для нашего случая - File Source (Async)) уже должен быть в графе. На каждом новом шаге метод Render ищет фильтр, который можно соединить с текущим фильтром.

Для соединения каждого исходящего контакта метод Render проделывает следующие операции:

  • Если контакт поддерживает интерфейс IStreamBuilder, менеджер графа фильтра делегирует весь процесс методу контакта IStreamBuilder::Render. Предоставляя этот интерфейс, контакт принимает на себя ответственность за построения остатка графа, вплоть до собственно рендеринга. Впрочем, немногие контакты поддерживают этот интерфейс.
  • Менеджер фильтра графа пытается использовать фильтры, закешированные в памяти, если такие есть. На протяжении всего процесса "интеллектуального соединения" менеджер графа фильтра пытается использовать кешированные фильтры из предыдущих шагов процесса.
  • Если граф фильтра содержит фильтры с несоединенными входными контактами, менеджер графа фильтра попытается соединить их потом. Можно принудительно вызвать метод Render для попытки соединения с каким-то специфическим фильтром перед вызовом метода Render.
  • И последнее, менеджер графа фильтра ищет в реестре, используя метод IFilterMapper2::EnumMatchingFilters.Он пытается сопоставить исходящим контактам представленных медиа-типов медиа-типы, находящиеся в реестре.

Каждый фильтр регистрируется с неким показателем (merit), числовой величиной, показывающей предпочтение фильтра в отношении других фильтров. Метод EnumMatchingFilters возвращает фильтры в порядке их этого показателя, с минимальным значением MERIT_DO_NOT_USE + 1. Игнорируются фильтры с показателем MERIT_DO_NOT_USE или меньшим. Фильтры также группируются в категории, определяемые посредством GUID. Эти категории имеют определенные показатели, и метод EnumMatchingFilters игнорирует любые из них с показателем MERIT_DO_NOT_USE или меньше, даже если фильтры в этой категории имеют и более высокие показатели.

Короче говоря, метод Render пытается соединить фильтры следующим образом:

  • Используя IStreamBuilder.
  • Пытаясь использовать кешированные фильтры.
  • Пытаясь использовать фильтры в графе.
  • Просматривая фильтры в реестре.

Продолжим, однако, рассмотрение методов, к которым имеет отношение Intelligent Connect.

Метод AddSourceFilter добавляет фильтр источника, который может произвести рендеринг указанного файла. Он просматривает реестр и сопоставляет расширению файла соответствующий протокол или набор предопределенных проверочных байтов (check bytes), которые задают определенный шаблон. Словом, этот метод находит подходящий фильтр источника, создает экземпляр этого фильтра, добавляет его в граф и вызывает метод IFileSourceFilter::Load с соответствующим именем файла.

Метод RenderFile строит граф, отталкиваясь от имени файла. Внутри себя он использует AddSourceFilter для поиска корректного фильтра источника и Render для построения оставшейся части графа.

Метод Connect соединяет исходящие и входящие контакты. Этот метод добавляет, если необходимо, промежуточные фильтры, используя вариации алгоритма, используемого для метода Render:

  • Пытается напрямую соединить фильтры, без промежуточных фильтров.
  • Пытается использовать кешированные фильтры.
  • Пытается использовать фильтры в графе
  • Просматривает фильтры в реестре.

Конвертирование WAV <-> MP3

Попытаемся теперь решить проблему, которая меня мучила несколько лет назад - никак не мог найти программу для конвертирования файлов формата mp3 в wav (а вот наоборот - без проблем). Мы сделаем то и другое, т.е. взаимообратное конвертирование.

Итак, запускаем GraphEdit, выбираем из DirectShow фильтров фильтр FileSource (Async.), в качестве входного файла указываем ему, например, "Вход в Windows.wav", дальше выбираем фильтры Wave Parser, LAME MPEG Layer III Audio Encoder (если каких-то из предыдущих или последующих фильтров вы у себя не найдете, ищите их в наборах кодеков по ссылкам, приведенным выше) и, наконец, фильтр Dump, который используется для записи,- он предложит задать имя файла, в который предполагается произвести конвертацию. Ну вот, все сделали, картинка будет иметь приблизительно такой вид:

Рис. 6. WAV -> MP3

Запустим граф: Graph->Play. Результатом его работы должен быть наш новый mp3-файл. Обратная процедура, конвертация mp3 в wav, не должна теперь представлять для нас какой-то сложности. Рисунок графа фильтра ниже:

Рис. 7. MP3 -> WAV

На самом деле я должен вас (или, скорее, себя) разочаровать - на поверку оказалось, что полученный wav-файл плохой, негодный. Видимо, какой-то из фильтров чего-то не того делает. Вполне возможно, что нужен еще какой-то фильтр для записи, например, заголовков. Короче, я не знаю.

Правда, я качал Nimo версии 5.91-бета и видел предупреждение, что могут быть проблемы. Ну ладно, в конце концов, если мне теперь припечет что-нибудь куда-нибудь конвертировать, я буду искать уже не готовые программы, а фильтры - это немного проще. Может быть, мне даже кто-то из читателей сообщит правильное решение.

Конвертирование AVI<->MP4

Построим теперь графы фильтров для конвертирования файлов формата AVI в MPEG и наоборот.

Рис. 8. AVI -> MP4

И

Рис. 9. MP4 -> AVI

Здесь не учтен звук - это будет домашним заданием.

Захват и сохранение Real Audio/Video

Перейдем теперь к еще одному когда-то интересовавшему меня вопросу: как сохранить в файл, т.н. реал видео и аудио, а то как-то мне понравился какой-то клип, а я его смог смотреть только через интернет, поскольку ни браузер, ни медиа плеер (или что-то там такое) не давало возможности это видео-аудио сохранить.

Для этого нам понадобятся другие DirectShow-фильтры, ориентированные как раз на эту задачу. Сохранять мы будем, например, файл ... (если к моменту вашего эксперимента ссылка будет уже недействительной, поищите в интернете подобные с расширениями *.rm, *.rv, *.ram и т.п. - всех не помню).

Вот написал я это, попытался было сделать, о чем расхвастался, сходу не вышло, и стал на протяжении нескольких дней разбираться что к чему. А что было делать - RenderFile не работает, GraphEdit глючит и вообще отказывается делать что бы то ни было - слетает при попытке соединить фильтры или просто отказывается для всех подозрительных фильтров, ориентированных на проигрывание файлов из сети, устанавливать для файла нелокальное имя. Пришлось даже в форумах спрашивать. Долгие поиски дали следующее.

http://www.realnetworks.com/products/producer/index.html

Для начала давайте поэкспериментируем с локальными файлами формата Real Video. Первый вопрос - где их взять? Изначально их нет, из интернета так просто не скачаешь, поэтому, не особо мучась пока вопросом, как решить подобную проблему на все случаи жизни, я скачал программу Easy Real Conver, которую нашел по адресу http://www.share2.com/easy-real-converter/ , она платная, но первые 10 конвертаций (я конвертировал из avi) выполняет даром (а больше мне и не нужно). Она, правда, почему-то отказалась конвертировать аудиопоток, ну да бог с ним - меньше проблем. Конвертировав свой avi-файл в файл формата Real Media, я получил материал, с которым смог работать. Для обратной конвертации, кстати, пригодится программа TINRA, которую можно взять здесь http://www.divx-digest.com/software/tinra.html 

Конвертирование MOV<->AVI

Еще одна, иногда возникающая, проблема. Давайте будем расти не только как программисты, но еще и решим конкретную задачу. Помнится, я как-то не смог даже при установленном QuickTime'е конвертировать с помощью какой-то (не помню какой) программы свой mov-файл в какой-нибудь другой формат. Разгадка оказалась и простой, и даже очевидной. У QuickTime'а свой формат, свой API, а для нас важно, что есть DirectShow фильтры, позволяющие работать с этим форматом унифицированным образом. Эти фильтры входят в состав QuickTime Alternative. Если у вас их нет, советую установить (при установке, впрочем, нам будет предложено убрать настоящий QuickTime, если он установлен, иначе фильтр не устанавливается - почему так, я не понял; но я все же согласился с этим предложением и неудобств пока не чувствую; может быть, эту проблему и можно как-то обойти, но я не вникал) и продолжим.

Сначала попробуем просто проиграть mov-файл. Сразу оказывается, что для чтения файла с диска фильтр File Source (Async.) совершенно не подходит - у меня GraphEdit вообще вылетает при попытке открыть файл с его помощью. Что же, пусть это будет на совести разработчиков этой программы. Видимо, в данном случае попытка воспользоваться помощьюIntelligent Connect терпит сокрушительную неудачу, а программисты не позаботились оформить соответствующие охраняемые блоки. В свое время мы будем умнее и учтем этот факт.

Проблема решается с помощью фильтра CyberLink QuickTime Source Filter (Direct Show filters -> CyberLink QuickTime Source Filter) - он должен присутствовать в системе, если QuickTime Alternative была установлена корректно. Выбираем его, указываем наш mov-файл, а затем в появившемся прямоугольнике делаем обоим контактам "Render Pin". Результат должен выглядеть следующим образом:

Рис 10. Воспроизведение MOV-файла

Жмем Graph->Play и смотрим, все должно быть видно и слышно.

После этого уже нетрудно сообразить, как произвести конвертацию в формат avi-файла. Для этого, для начала, удалим фильтры "Video Render" и "Default DirectSound Device", затем добавим к графу фильтр AVI Mux и File Writer (последнему укажем имя - я назвал новый файл eee.avi) и можем спокойно запускать процесс:

Рис. 11. MOV -> AVI

Имейте в виду, я не отвечаю ни за размер файла, ни за синхронизацию видео и звука (ни в этом случае, ни в других). Пути решения возникающих проблем придется искать самостоятельно.

А вот обратную конвертацию, avi в mov, совершить не удалось. Кто знает, пусть поделится информацией.

Захват видео

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

Рис. 12. Отображение "живого" видео

Источник видео я выбрал из категории Video Capture Sources, видно, что у меня в системе установлено только одно устройство видеозахвата. Все, теперь можно жать кнопку Run и смотреть кино.

Передача по сети

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

Comments