На этот раз речь пойдет о DirectShow. Для чего нам может понадобиться DirectShow?
DirectShow — это архитектура для воспроизведения, перехвата и обработки потоков мультимедиа. Звучит туманно? Поясняю — c помощью этого API можно:
проигрывать мультимедийные файлы различного формата, такие как MPEG (Motion Picture Experts Group), AVI (Audio-Video Interleaved), MP3 (MPEG Audio Layer-3), DVD и конечно WAV;
перехватывать видео-поток с различного рода TV-карт, видеокамер и т.п.;
создавать нестандартные обработчики мультимедиа-потоков и свои собственные форматы файлов (что, впрочем, вряд ли понадобится простым смертным);
обращаться непосредственно к видео и аудио потокам, чтобы выводить их на Surface DirectDraw (что для нас как раз интересно).
Звучит заманчиво. Но для чего это может понадобиться, спросите Вы, вспоминая родной и привычный MediaPlayer. Представьте себе, что Вы запрограммировали трехмерный мир, с анимированными спрайтами, трехмерными объектами и т.п.
Как запустить любую игру ,требующую direct X 11 на directX 10.
И в отсвете выстрелов очередной «бродилки-стрелялки», пораженный пользователь нового шедевра, видит видео клип, воспроизводимый прямо на костях очередного пораженного монстра. 🙂 Каково? Убедил? Тогда продолжим.
Кстати, раз уж упомянули DirectDraw — DirectShow интегрирован с DirectX так, что использует DirectDraw и DirectSound для вывода изображения и звука, и, при наличии аппаратного ускорения, автоматически им воспользуется.
Для работы с DirectShow Вам понадобятся:
иметь некоторое представление о технологии COM (Component Object Model) — хотя быть знатоком этой технологии вовсе не обязательно — просто достаточно знать, что для получения COM-интерфейса нужно вызвать QueryInterface;
скачать заголовочные файлы DirectShow API, переведенные на Delphi в рамках проекта JEDI — (http://www.delphi-jedi.org/DelphiGraphics/DirectX/DX5Media.zip) и либо поместить их в каталог DelphiLib либо добавить путь к каталогу, в котором они находятся в установках Delphi Library Path.
DirectShow скорее всего уже установлен на Вашем компьютере — он входит в стандартную поставку Windows 9x, Windows NT 4 (Service Pack 3 и выше), Windows 2000 (если Вы программируете для UNIX или DOS — то я вообще не понимаю зачем Вы читаете эту статью).
Основы DirectShow
В концепции DirectShow мультимедийные данные — это поток, который проходит через несколько обрабатывающих блоков. Блоки, обрабатывающие поток данных, передают данные по цепочке друг другу, таким образом можно представить себе несколько «устройств», каждое из которых выполняет какую-то обработку данных и передает их соседнему «устройству». Эти «устройства» или «блоки обработки» данных называют фильтрами. Цепочка, по которой передаются данные, содержит несколько фильтров, связанных определенным образом.
В DirectShow имеются готовые фильтры, из которых, словно из детских кубиков, программист может выстроить ту или иную цепочку обработку данных, кроме того, конечно, можно создать свои, нестандартные фильтры.
Что такое Directx
Для создания такой «цепочки обработки» (которая, кстати, официально называются Filter Graph — «граф фильтров» или, в несколько вольном переводе — «схема соединения фильтров»), так вот для создания схемы соединения фильтров, предназначен самый базовый и лежащий в основе всех основ компонет DirectShow, под названием Filter Graph Manager — Менеджер Графа Фильтров.
Например, программа показывающая видео из AVI-файла может построить такой граф фильтров:
В этом примере пять фильтров, первый (File Source) просто читает данные с диска, второй фильтр (AVI Splitter) разделяет данные на кадры и передает упакованные видео данные фильтру AVI Decompressor, который их распаковывает и передает фильтру Default DirectSound Device, выводящему звук. AVI Decompressor передает распакованные данные фильтру Video Renderer, который выводит кадры видео на экран.
Фильтры делятся на три типа:
Фильтры-источники (Source filters) — эти фильтры просто получают данные из какого-то источника, с диска (как фильтр File Source (Async) на рисунке), с CD или DVD дисковода или с TV- карты или карты, к которой подключена цифровая видеокамера.
Фильтры-преобразователи (Transform filters) — эти фильтры как видно из названия преобразуют поток данных, проходящий через них каким-либо образом, например — разделяет поток данных на кадры, производят декомпрессию и т.п. На нашем рисунке к таким фильтрам относятся AVI Splitter и AVI Decompressor.
Фильтры вывода (Renderer filters) — фильтры, которые получают полностью обработанные данные и выводят их на монитор, звуковую карту, пишут на диск или выводят на еще какое-нибудь устройство.
Итак из фильтров-кубиков можно высстраивать граф. Делается это с помощью интерфейса IGraphBuilder. Создать объект типа IGraphBuilder можно так:
CoCreateInstance(CLSID_FilterGraph,nil,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,MyGraphBuilder);
Здесь переменная MyGraphBuilder имеет тип IGraphBuilder; идентификатор класса CLSID_FilterGraph и IID_IGraphBuilder обьявлены в файле DShow.pas, поэтому не забудьте добавить
uses DShow.pas
Итак, интерфейс IGraphBuilder получен. Можно построить граф фильтров, такой, какой нам нужно. Впрочем, все не так сложно, IGraphBuilder достаточно интеллектуален, он может сам, автоматически, построить граф, в зависимости от того какие файлы мы собираемся воспроизводить. Интерфейс IGraphBuilder имеет метод RenderFile, который получает имя файла в качестве параметра и, в зависимости от типа файла (которое определяется по расширению и по специальным сигнатурам в файле), сканирует реестр, в поисках необходимой для построения графа информации, создает необходимые фильтры и строит граф, предназначенный для воспроизведения файлов этого типа (WAV, AVI, MP3, MPG и т.д.).
После построения графа DirectShow готов к воспроизведению. Для управления потоком данных через граф обработки предназначен интерфейс IMediaControl — он имеет методы Run, Pause и Stop (названия говорят сами за себя)
Давайте попробуем все это на примере:
CoCreateInstance ( CLSID_FilterGraph, nil ,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,MyGraphBuilder ) ;
MyGraphBuilder. RenderFile ( ‘cool.avi’ , nil ) ;
MyGraphBuilder. QueryInterface ( IID_IMediaControl,MyMediaControl ) ;
ShowMessage ( ‘Нажмите OК’ ) ;
Если Вы не поленитесь скопировать этот кусок кода в Delphi и запустить его то заметите, что avi-файл проигрывается в отдельном окошке, которое не принадлежит нашему приложению. Для управления окошком, в котором воспроизводится видео предназначен специальный интерфейс IVideoWindow. Получить этот интерфейс можно из экземпляра IGraphBuilder, вызвав QueryInterface и передав в качестве идентификатора интерфейса константу IID_IvideoWindow.
Интерфейс IVideoWindow содержит методы для управления заголовком, стилем, местоположением и размерами окошка в котором проигрывается видео.
Давайте попробуем переделать наш пример так, чтобы видео выводилось не в отдельном окошке, а, скажем на компоненте TPanel, расположенном в нашей форме. Добавьте на форму компонет TPanel, пусть он называется Panel1.
procedure TForm1. Button1Click ( Sender: TObject ) ;
CoCreateInstance ( CLSID_FilterGraph, nil ,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,MyGraphBuilder ) ;
MyGraphBuilder. RenderFile ( ‘C:Program FilesBorlandDelphi5DemosCoolstufcool.avi’ , nil ) ;
MyGraphBuilder. QueryInterface ( IID_IMediaControl,MyMediaControl ) ;
MyGraphBuilder. QueryInterface ( IID_IVideoWindow,VideoWindow ) ;
VideoWindow. Set_Owner ( Self . Panel1 . Handle ) ;
VideoWindow. Set_WindowStyle ( WS_CHILD OR WS_CLIPSIBLINGS ) ;
VideoWindow. SetWindowPosition ( 0 , 0 ,Panel1. ClientRect . Right ,Panel1. ClientRect . Bottom ) ;
ShowMessage ( ‘Нажмите OК’ ) ;
Надеюсь это проще, чем Вы ожидали?
DirectShow и DirectX
Для того, чтобы использовать DirectShow совместно с DirectShow нужно разобраться с понятием Multimedia Streaming (потоки мультимедиа).
Multimedia Streaming — это архитектура, используемая в DirectShow для облегчения жизни программиста. Эта архитектура позволяет работать с мультимедиа данными, как с абстрактным потоком, не вдаваясь в подробности форматов хранения мультимедиа-файлов или специфику устройств-источников мультимедиа. Используя эту архитектуру, программист концентрируется не на расшифровке и преобразовании данных, а на управлении потоком данных, кадрами видео или аудио семплами.
На рисунке изображена иерархия объектов Multimedia Streaming
На вершине иерархии находится базовый объект Multimedia Stream, который является контейнером для объектов Media Stream. Объект Multimedia Stream может содержать один или несколько объектов Media Stream. В то время как каждый объект типа Media Stream предназначен для работы с данными какого-то одного типа (видео, аудио и т.п.) — Multimedia Stream — просто содержит методы для обращения к содержащимся в нем объектам Media Stream и не зависит от типа данных.
Объект типа Stream Sample, доступ к которому можно получить из Media Stream — позволяет управлять непосредственно элементами мультимедийного потока (для видео каждый Sample — это кадр видеоизображения, для аудио он может содержать несколько семплов звука).
Однако хватит теории. Давайте перейдем к делу. Попробуем создать необходимые объекты, чтобы вывести видео на Surface DirectX. Для этого нам понадобится обращаться к кадрам видео изображения (т.е. к обьекту типа Stream Sample). Значит, придется пройтись по всей цепочке иерархии, чтобы добраться до обьектов StreamSample. Вообще цепочка обьектов, которую предстоит создать выглядит так:
IAMMultiMediaStream
+ IDirectDrawMediaStream
+ IDirectDrawStreamSample
Сравните это с нашим рисунком. Как видите на вершине находится объект типа MultiMediaStream, который будет содержать MediaStream конкретного, нужного нам типа (IDirectDrawMediaStream), а уж с помощью него мы получим доступ к конкретным видео кадрам через интерфейс IDirectDrawStreamSample.
Итак сейчас мы создадим объект типа IAMMultiMediaStream. Этот интерфейс унаследован от IMultimediaStream и содержит, кроме прочего, функцию OpenFile, которая автоматически строит граф фильтров для воспроизведения файла.
CoCreateInstance(CLSID_AMMultiMediaStream, nil, CLSCTX_INPROC_SERVER, IID_IAMMultiMediaStream, AMStream);
Здесь переменная AMStream имеет тип IAMMultiMediaStream.
Мы создали контейнер для мультимедийных потоков. Сверяемся с рисунком — мы на верхнем уровне иерархии. У нас есть объект типа IMultimediaStream — теперь в этот контейнер нужно проинициализировать и добавить один или несколько мультимедиа потоков, нужного нам типа. Сначала инициализация:
AMStream.Initialize(STREAMTYPE_READ,
AMMSF_NOGRAPHTHREAD, nil);
При инициализации указываем, что будут создаваться мультимедиа потоки для чтения, передав значение STREAMTYPE_READ (другие варианты STREAMTYPE_WRITE, STREAMTYPE_TRANSFORM).
Создадим теперь мультимедиа потоки для видео и звука:
AMStream.AddMediaStream(DDraw, MSPID_PrimaryVideo, 0, NewMediaStremVideo);
AMStream.AddMediaStream(nil, MSPID_PrimaryAudio, AMMSF_ADDDEFAULTRENDERER, NewMediaStremAudio);
Вызываем метод OpenFile — файл загружается, и автоматически строится граф фильтов:
AMStream.OpenFile(‘cool.avi’, 0);
Осталось направить видео поток мультимедиа поток на Surface. Вот процедура, которая делает это:
procedure TForm1. RenderStreamToSurface ( Surface : IDirectDrawSurface; MMStream : IMultiMediaStream ) ;
MMStream. GetMediaStream ( MSPID_PrimaryVideo, PrimaryVidStream ) ;
PrimaryVidStream. QueryInterface ( IID_IDirectDrawMediaStream, DDStream ) ;
ddsd. dwSize := sizeof ( ddsd ) ;
DDStream. GetFormat ( ddsd, Palitra, ddsd, Z ) ;
rect . top := ( 480 -ddsd. dwHeight ) div 2 ; rect . left := ( 640 — ddsd. dwWidth ) div 2 ;
rect . bottom := rect . top +ddsd. dwHeight ; rect . right := rect . left +ddsd. dwWidth ;
DDStream. CreateSample ( Surface, Rect , 0 , Sample ) ;
MMStream. SetState ( STREAMSTATE_RUN ) ;
Как видите, в этой процедуре сначала получаем интерфейс типа IDirectDrawMediaStream (соответствующий второму уровню иерархии на нашем рисунке), потом из него получаем объект типа IDirectDrawStreamSample (переменная Sample), который соответствует третьему уровню иерархии нашего рисунка.
Теперь остается вызывать в цикле (в демо-программе это делается по таймеру — здесь для простоты опускаем):
hr:=Sample. Update ( 0 , 0 , nil , 0 ) ;
MMStream. Seek ( 0 ) ;
Метод IDirectDrawStreamSample.Update выводит очередной кадр на Surface. При достижении конца потока он вернет ошибку с кодом $40003 (MS_S_ENDOFSTREAM), я в этом случае просто перематываю поток к началу, методом Seek.
Полностью программу, фрагменты кода из которой здесь приведены можно скачать здесь >.
В этой программе инициализируется DirectDraw, создается Surface , а затем на него выводится видео из avi-файла.
Пока все о DirectDraw — надеюсь эта информация послужит для Вас отправной точкой в написании чего-то потрясающего! 🙂
Источник: www.delphisite.ru
Общие сведения о DirectShow
Microsoft® DirectShow ® — это архитектура потокового мультимедиа на платформе Microsoft Windows ®. DirectShow обеспечивает высококачественное захват и воспроизведение мультимедийных потоков. Он поддерживает широкий спектр форматов, включая расширенный формат систем (ASF), группу экспертов по кинофильмам (MPEG), Audio-Video чередование (AVI), аудиоуровневый формат MPEG -3 (MP3) и звуковые файлы WAV. Он поддерживает запись с цифровых и аналоговых устройств на основе модели драйвера Windows (WDM) или видео для Windows. Он автоматически обнаруживает и использует оборудование для ускорения видео и звука при наличии, но также поддерживает системы без аппаратного ускорения.
DirectShow основана на объектной модели компонента (COM). Чтобы написать приложение или компонент DirectShow, необходимо понимать программирование клиента COM. Для большинства приложений не нужно реализовывать собственные COM-объекты. DirectShow предоставляет необходимые компоненты. Если вы хотите расширить DirectShow путем написания собственных компонентов, их необходимо реализовать как COM-объекты.
DirectShow предназначен для C++. Корпорация Майкрософт не предоставляет управляемый API для DirectShow.
DirectShow упрощает воспроизведение мультимедиа, преобразование формата и задачи записи. В то же время он предоставляет доступ к базовой архитектуре управления потоком для приложений, требующих пользовательских решений. Вы также можете создавать собственные компоненты DirectShow для поддержки новых форматов или пользовательских эффектов.
Примеры приложений, которые можно написать с помощью DirectShow включают в себя проигрыватели файлов, телевизоры и DVD-проигрыватели, приложения для редактирования видео, конвертеры форматов файлов, приложения для захвата аудио-видео, кодировщики и декодеры, цифровые обработчики сигналов и многое другое.
В этом разделе рассматриваются следующие вопросы.
- Новые возможности DirectShow
- Поддерживаемые форматы в DirectShow
- часто задаваемые вопросы DirectShow
Источник: learn.microsoft.com
Видеозапись с помощью Directshow.NET
Добрый день, уважаемые хабрапользователи. Некоторое время назад мне пришлось работать над несложным windows-приложением, в котором требовалось производить аудио- и видеозапись с различных устройств. В частности, захват аудио нужно было производить с шести каналов карты MAudio, а захват hd видео — с двух карт захвата AverMedia, сигнал на которые приходил с видеокамер по компонентному входу. Также нужно было делать скриншоты с документ-камеры, подключенной по USB-интерфейсу. Приложение было решено писать на C#, а видеозапись производить при помощи библиотеки DirectShow.NET.
По мотивам решения данной задачи возникла идея написать статью и поделиться опытом относительно видеозахвата. Может быть, кому-нибудь данная информация будет полезна. Кому интересно — прошу под кат.
Вместо предисловия.
Хотя для выполнения подобных задач сейчас все больше используется MediaFoundation, эта платформа, на мой взгляд, пока еще недостаточно распространена, даже с учетом того, что в новых версиях Windows, начиная с 8й, Microsoft постепенно отказыватся от использования и поддержки DirectShow. Существуют и различные библиотеки компьютерного зрения, поддерживающие возможность видеозаписи, такие как OpenCV или AForge, но при простом видеозахвате их мощный функционал обработки не очень требуется, да и внутри подобные библиотеки зачастую могут использовать DirectShow.
В интернете есть довольно много статей и материалов про то, что такое DirectShow и как он работает, да и на Хабре проскакивала информация в этой статье, поэтому я постараюсь не щеголять терминами, которых могу не знать и сам, а рассмотрю все с практической стороны — каким образом человек, ранее не знакомый с Directshow, сможет написать свое приложение видеозаписи на C#, с чего ему начинать и куда двигаться, а также расскажу о проблемах, с которыми пришлось столкнуться.
Для примера (см. код на GitHub) к этой статье я буду использовать простенькую usb-карту захвата EasyCap:
1. С чего начать. Требования, инструменты и информация
Инструменты, которые понадобятся, это:
1) K-Lite Codec Pack Mega и инструмент GraphStudio — для быстрого прототипирования графа видеозахвата.
2) GraphEditPlus — коммерческий аналог GraphStudio, который позволяет генерировать код. спроектированного графа на языках C++ и C#. Доступна 30-дневная триальная версия, ограничением которой является то, что сгенерированный код нельзя скопировать в буфер обмена.
3) Среда для разработки на С# — в моем случае это будет Visual Studio 12.
4) Библиотека DirectShow.net.
5) Библиотека WindowsMediaLib.
К сожалению, в интернете не получилось найти цельного и структурированного руководства по тому, как делать приложение видеозаписи, но некоторые страницы оказали поистине неоценимую помощь, это, в первую очередь:
1) Небольшая страничка, информация с которой стала катализатором всего процесса. Также там можно найти понятные описания классов и интерфейсов DirectShow.net. Очень полезная страница и огромная благодарность её автору.
2) Открытый исходный код, подобный этому, который помог разобраться с кроссбарами и прочими вопросами.
3) MSDN, в котором есть целый раздел, посвященный программированию DirectShow.
2. Фильтры, создание графа видеозаписи и визуальный редактор
Графы DirectShow строятся из фильтров, которые соединяются друг с другом входными и выходными пинами.
Более подробно об этом — здесь.
Для простейшего случая в GraphStudio можно построить граф, например, для встроенной видеокамеры следующим образом:
Но для нашей задачи требуется несколько фильтров, и граф (с учетом записи в WMV-формат) в результате должен выглядеть так:
На этом графе присутствуют фильтры:
SMI Grabber Device (группа фильтров — WDM Streaming Capture Devices) — фильтр, представляющий собой устройство захвата, именно с него мы получаем видео (а также аудио) потоки. Но в данном случае записывается не аудиопоток, поступающий c устройства захвата, а поток с микрофона (Фильтр «Микрофон. » из группы Audio Capture Sources).
SM BDA Crossbar Filter — фильтр кроссбара для устройства захвата, именно его настройка определяет коммутацию входного сигнала, поступает ли он со входа SVideo или с композитного входа.
Smart Tee — разветвитель потока, имеющий два выхода, поток с выхода Capture идет на запись в файл, а
поток с выхода Preview идет в окно предпросмотра через фильтр AVI Decompressor. Надо заметить, что цепочка
AVI Decompressor -> Video Renderer создается автоматически при выборе опции Preview -> Render Pin.
(в качестве отступления замечу, что бывают разные типы фильтров renderer, и одним из наиболее продвинутых является Enhanced Video Renderer, но в данном примере используется обычный фильтр по умолчанию)
WM ASF Writer — фильтр, обеспечивающий самый простой вариант записи видеофайла необходимого качества в формат WMV. При этом возможно менять качество записи, в том числе и на пользовательское.
Запустив данный граф, можно убедиться в корректности записи видеоисточника.
3. Библиотека DirectShow.net и перевод графа в код
3.1. Генерация кода в GraphEditPlus
Следующий шаг — перевод получившегося графа в код. В этом деле неоценимую помощь оказывает инструмент GraphEditPlus. В целом этот редактор графов более удобен, чем GraphStudio из комплекта K-Lite, но самой главной его фичей является возможность генерации кода по построенному графу:
К сожалению, данный инструмент не может кастомизировать код настройки определенных фильтров, таких как Crossbar или WM ASF Writer, но в качестве первого шага он неоценим.
3.2. Приложение видеозаписи
Повторюсь, код простого приложения, написанного специально для этой статьи можно посмотреть и скачать здесь. Заранее прошу прощения за его неоптимальность и нарушение SOLID, так как это всего лишь тестовый пример.
В данном приложении основные операции над графом (создание, уничтожение, поиск пинов, crossbar routing, запуск, остановка и прочие) определены в абстрактном классе VideoCapturebase, а классы-наследники, такие как VideoCapturePreview, VideoCaptureAsfRecord или VideoCaptureScreenshots реализуют абстрактный метод построения графа из фильтров BuildGraph() , добавляя новые фильтры в цепочку. Класс ControlVideoCommon содержит операции создания окна и привязки к нему графа, операцию остановки и уничтожения графа, а также несколько других утилитарных операций.
3.3. Не всегда очевидные моменты
3.3.1. Добавление устройств
Если существует несколько устройств одного типа (несколько одинаковых карт захвата, например),
то у них будут одинаковые guid, но разные параметры DisplayName. В этом случае необходимо найти все устройства при помощи следующего кода:
private readonly List _captures = new List(); //. //search for devices foreach (var device in DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice)) < if (device.Name.ToLower().Contains(deviceNamePart.ToLower()) < _captures.Add(device); >> //full device paths that differ var devicePath1 = _captures[0].DevicePath; var devicePath2 = _captures[1].DevicePath; //.
Далее при создании графов используются уже пути devicePath1 и devicePath2 , полученные данным методом
3.3.2. Сrossbar routing
Устройство видеозахвата может иметь или не иметь кроссбар для использования разных типов видеовходов (например, AverMedia и EasyCap из данного примера — имеют, а встроенная веб-камера или карта захвата BlackMagic — нет). Следовательно, необходимо, чтобы связывание с кроссбаром производилось автоматически.
Для этого в базовом классе определеяется метод
FixCrossbarRouting(ref IBaseFilter captureFilter, PhysicalConnectorType? physicalConnectorType) , который производит поиск и подключение кроссбара (при его наличии) с переключением на необходимый тип входа:
/// /// Configure crossbar inputs and connect crossbar to input device /// /// Filter to find and connect crossbar for /// crossbar connector type to be used /// protected int FixCrossbarRouting(ref IBaseFilter captureFilter, PhysicalConnectorType? physicalConnectorType) < object obj = null; //fixing crossbar routing int hr = CaptureGraphBuilder.FindInterface(FindDirection.UpstreamOnly, null, captureFilter, typeof(DirectShowLib.IAMCrossbar).GUID, out obj); if (hr == 0 obj != null) < //found something, check if it is a crossbar var crossbar = obj as IAMCrossbar; if (crossbar == null) throw new Exception(«Crossbar object has not been created»); int numOutPin; int numInPin; crossbar.get_PinCounts(out numOutPin, out numInPin); //for all output pins for (int iOut = 0; iOut < numOutPin; iOut++) < int pinIndexRelatedOut; PhysicalConnectorType physicalConnectorTypeOut; crossbar.get_CrossbarPinInfo(false, iOut, out pinIndexRelatedOut, out physicalConnectorTypeOut); //for all input pins for (int iIn = 0; iIn < numInPin; iIn++) < // check if we can make a connection between the input pin ->output pin hr = crossbar.CanRoute(iOut, iIn); if (hr == 0) < //it is possible, get input pin info int pinIndexRelatedIn; PhysicalConnectorType physicalConnectorTypeIn; crossbar.get_CrossbarPinInfo(true, iIn, out pinIndexRelatedIn, out physicalConnectorTypeIn); //bool indication if current input oin can be connected to output pin bool canRoute = physicalConnectorTypeIn == physicalConnectorType; //get video from composite channel (CVBS) //should output pin be connected to current input pin if (canRoute) < //connect input pin to output pin hr = crossbar.Route(iOut, iIn); if (hr != 0) throw new Exception(«Output and input pins cannot be connected»); >> //if(hr==0) > //for(iIn. ) > //for(iOut. ) > //if(hr==0 obj!=null) return hr; >
3.3.3. Освобождение ресурсов
Если не освобождать ресурсы созданного графа при его уничтожении, то создание другого экземпляра графа, использующего такие же фильтры, как и в первом, завершится ошибкой, следовательно, необходимо вызывать метод DisposeFilters() , в котором производится удаление фильтров из уничтожаемого графа. После некоторых экспериментов следующий код заработал нормально.
if (Graph == null) return; IEnumFilters ef; var f = new IBaseFilter[1]; int hr = Graph.EnumFilters(out ef); if (hr == 0) < while (0 == ef.Next(1, f, IntPtr.Zero)) < Graph.RemoveFilter(f[0]); ef.Reset(); >> Graph = null;
3.3.4. Конфигурация потока (частота кадров, разрешение, и т.д.)
Устройства видеозахвата могут выдавать разные конфигурации видеопотока, между которыми можно переключаться.
Например, hd-камера может выдавать как картинку 640 на 480 с частотой 60 кадров в секунду, так и картинку hd-качества с частотой кадров 30 кадров в секунду. Для частоты кадров существуют даже дробные цифры вроде 29.97 кадров в секунду. Для настройки подобных параметров нужно создать объект streamConfigObject при помощи метода FindInterface интерфейса CaptureGraphBuilder2 , привести его к интерфейсу IAMStreamConfig , вызвать метод GetFormat , чтобы получить объект типа AMMEdiaType , получить заголовок:
var infoHeader = (VideoInfoHeader)Marshal.PtrToStructure(mediaType.formatPtr, typeof(VideoInfoHeader));
и в дальнейшем производить операции над его параметрами
AvgTimePerFrame,
BmiHeader.Width,
BmiHeader.Height
и другими.
В коде это можно посмотреть в методах ConfigureResolution и ConfigureFramerate класса VideoCaptureAsfRecord .
3.3.5. Скриншоты
Для того, чтобы можно было делать скриншоты с видеопотока, необходимо унаследовать класс, в котором строится граф (VideoCaptureScreenshots) от ISampleGrabberCB , и переопределить два метода — BufferCB и SampleCB .
SampleCB может быть пустым, а в BufferCB производим копирование полученного массива:
if ((pBuffer != IntPtr.Zero) (bufferLen > 1000) (bufferLen
а также вызов обработчика:
_invokerControl.BeginInvoke(new CaptureDone(OnCaptureDone))
, в котором следует вызвать метод
SetCallback SamlpleGrabber ‘a
_iSampleGrabber.SetCallback(null, 0);
В методе же BuildGraph при включении фильтра SampleGrabber в цепочку следует произвести его настройку, а донастройку произвести после добавления остальных фильтров (магия, но иначе не работает). В тестовом примере за это отвечают методы ConfigureSampleGrabberInitial() и ConfigureSampleGrabberFinal() . При начальной настройке определяется AMMEdiaType , и при окончательной — установка VideoInfoHeader и вызов двух методов ISampleGrabber : SetBufferSamples(false) и SetOneShot(false) .
Первый необходим для того, чтобы отключить буферизацию проходящих черезх фильтр сэмплов, а второй — для того, чтобы обратный вызов функции снимка экрана можно было дергать несколько раз.
3.3.6. Формат wmv, файлы .prx и WindowsMediaLib
Для того, чтобы обеспечить приемлемое качество записи, необходимо переопределить настройки записи wmv-файла.
Проще всего это сделать при помощи создания пользовательского файла профиля с расширением .prx и переопределения в нем параметров, отвечающих за качество потока. Пример данного файла в коде — good.prx
Для считывания файлов профиля и создания по ним профиля в методе ConfigProfileFromFile(IBaseFilter asfWriter, string filename) был использован класс WMLib из проекта Team MediaPortal, распространяющегося под лицензией GPL. После создания профиль применяется к ASF Writer посредством метода ConfigureFilterUsingProfile(wmProfile) интерфейса IConfigAsfWriter .
Вместо послесловия или Большая Проблема, с которой пришлось столкнуться
Mpeg4Layer3, Кодеки, AVIMux и синхронизация аудио и видео
В самом начале разработки приложения была идея записывать видео в формате Mpeg4, а звук в формате Layer3, сводя все это при помощи AVI MUX в единый файл, как на следующем графе:
где на месте фильтра XVid Codec мог находиться любой фильтр из видеокомпрессоров в Mpeg-4. Были попытки использовать как xvid, так и ffdshow, и некоторые другие фильтры, однако, после нескольких попыток заставить граф записывать видео, стало понятно, что не все так просто, как кажется на первый взгляд. Возникала проблема обрыва записи спустя какое-то время после ее начала. Причина здесь, видимо, кроется в том, что при сведении видео и аудио в контейнере AVI MUX не производится автоматическая синхронизация видео и аудиодорожки, и даже с подстройкой правильной частоты граф мог остановиться в случайный момент, при этом запись обрывалась, а при воспроизведении можно было заметить, что аудио и видео выходили из синхронизации.
К сожалению, не смогу рассказать о решении данной проблемы, так как справиться с ней пришлось радикальным способом — переводом на запись в формат wmv при помощи ASF Writer.
Если эту статью читает кто-то, кто с данной проблемой сталкивался и знаком — буду рад совету.
Большое спасибо за внимание и интерес, надеюсь, данная статья не была смертельно скучной, и также надеюсь, что кому-нибудь данный материал может принести практическую пользу.
Источник: habr.com