Пишем видеоплеер (проигрыватель видео) на Delphi с использованием технологии DirectShow.
Сегодня на уроке мы познакомимся с технологией DirectShow и начнем создавать простейший проигрыватель видео. Почему DirectShow спросите вы, ведь есть куча других способов создать видеоплеер. Когда я начал этим заниматься, думал точно также. И начал свою первую попытку создания плеера с компонента TMediaPlayer, который входит в Delphi и находится на вкладке System. Но уже через несколько часов работы с ним я заметил, что многие фильмы, которые без проблем работают в других проигрывателях, в TMediaPlayer отказывались на отрез запускаться. Я начал копать в сторону подключения к нему видео кодеков, но как оказалась это сделать либо в принципе невозможно или я плохо искал. Такое положение дел меня сильно не устраивало и я начал искать другие способы создания видеоплеера. Кстати, скачать мои мучения с TMediaPlayer можно здесь. Реализованы функцииPlay, Pause, Stop, время проигрывания, текущее время, ProgressBar, регулирование громкости. Может, кому пригодится. Поиск информации в Интернете обозначил несколько направлений: - BASS_DSHOW; - xVideo; - DSPack; - DirectShow.
BASS_DSHOW модуль подгружаемый к библиотеке Bass.dll. К сожалению запустить под Vista на Delphi 2010 ни его ни примеры из Demo поставляемое с ним мне не удалось.
Библиотека xVideo и примеры идущие с ней заработали без проблем, но попытки найти в Интернете хоть какую-нибудь информацию по ней, кроме справки поставляемой с ней на английском языке и форума- тоже на английском мне не удалось. Скачать BASS_DSHOW и xVideo можно здесь:
http://surodev.com/downloads/BASS_DSHOW2.4.2.zip http://surodev.com/downloads/xVideo.zip А здесь http://surodev.com находится форум по ним.
DSPack – оказался визуальным компонентом для Delphi и надстройкой над DirectShow. В Интернете нашел правленую версию DSPack для Delphi 2010 . Пакет встал нормально, примеры из демо тоже работали.
Ну и на одном из сайтов я наткнулся на статью: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=270
Которая и вдохновила меня копать в сторону DirectShow.
Теперь немножко теории.
DirectShow – это архитектура (API) для воспроизведения, перехвата и обработки потоков мультимедиа. Для работы с DirectShow Вам понадобится скачать заголовочные файлы DirectShow API c сайта http://www.clootie.ru/ или здесь и поместить их в каталог Delphi\Lib либо добавить путь к каталогу, в котором они находятся в установках Delphi Library Path. Хотя DirectShow скорее всего уже установлен на Вашем компьютере т.к. он входит в стандартную поставку Windows. Основы DirectShow.
Любой видео поток представляет собой последовательность кадров (фреймов). Аудио и видео-потоки могут быть обработаны самыми разными способами: раскодированы, скопированы, изменены. В DirectShow все эти операции реализованы в виде COM-объектов, так называемых фильтрах. Фильтр – является единицей операции в DirectShow. Каждый фильтр это программный компонент, который встраивается в поток мультимедийных данных и может выполнять определенные действия: - читать данные из файла; - получать видео непосредственно с источника; - декодировать форматы; - передавать данные на графическую или звуковую плату.
DirectShow имеются готовые фильтры, из которых, словно из детских кубиков, программист может выстроить ту или иную цепочку обработки данных, кроме того, можно создать свои, нестандартные фильтры. Такая цепочка обработки называется графом фильтров (Filter Graph). Так вот для создания схемы соединения фильтров, предназначен самый базовый и лежащий в основе всех основ компонент DirectShow, под названием Filter Graph Manager – Менеджер Графа Фильтров.
Например, программа, показывающая видео из AVI-файла может построить такой граф фильтров:
В этом примере пять фильтров, первый (File Source) просто читает данные с диска, второй фильтр (AVI Splitter) разделяет данные на кадры и передает упакованные видео данные фильтру AVI Decompressor, который их распаковывает и передает фильтру Default DirectSound Device, выводящему звук. AVI Decompressor передает распакованные данные фильтру Video Renderer, который выводит кадры видео на экран. (Этот пример и часть кода исходников ниже из книги Есенин С.А. DirectX и Delphi. Разработка графических и мультимедийных приложений.). Фильтры делятся на три типа:
Фильтры-источники (Source filters) - эти фильтры просто получают данные из какого-то источника, с диска (как фильтр File Source (Async) на рисунке), с CD или DVD дисковода или с TV- карты или карты, к которой подключена цифровая видеокамера. Фильтры-преобразователи (Transform filters) – эти фильтры как видно из названия преобразуют поток данных, проходящий через них каким-либо образом, например – разделяет поток данных на кадры, производят декомпрессию и т.п. На нашем рисунке к таким фильтрам относятся AVI Splitter и AVI Decompressor. Фильтры вывода (Renderer filters) – фильтры, которые получают полностью обработанные данные и выводят их на монитор, звуковую карту, пишут на диск или выводят на еще какое-нибудь устройство.
Итак из фильтров можно выстраивать граф. Делается это с помощью интерфейса IGraphBuilder. Создать объект типа IGraphBuilder можно так:
Здесь переменная pGraphBuilder имеет тип IGraphBuilder; идентификатор класса CLSID_FilterGraph и IID_IGraphBuilder объявлены в файле DirectShow9.pas, поэтому не забудьте добавить uses DirectShow9,ActiveX;
Если интерфейс IGraphBuilder получен, то можно построить граф фильтров в ручную или автоматически. IGraphBuilder может сам, автоматически, построить граф, в зависимости от того какие файлы мы собираемся воспроизводить. Интерфейс IGraphBuilder имеет метод RenderFile, который получает имя файла в качестве параметра и, в зависимости от типа файла (которое определяется по расширению и по специальным сигнатурам в файле), сканирует реестр, в поисках необходимой для построения графа информации, создает необходимые фильтры и строит граф, предназначенный для воспроизведения файлов этого типа (WAV, AVI, MP3, MPG и т.д.).
После построения графа DirectShow готов к воспроизведению. Для управления потоком данных через граф обработки предназначен интерфейс IMediaControl – он имеет методы Run, Pause и Stop.
И так приступим к созданию видео проигрывателя. Запустим Delphi создадим новый проект и начнем создавать интерфейс нашего плеера как показано на рисунке:
Теперь немного подробнее:
Размещаем на форме вверху компонент TPanel, два компонента TListBox из вкладки Standard и компонент TSplitter из вкладки Additional.ListBox-ы и Splitter должны быть вне Panel1. Splitter должен находиться между Panel1 и ListBox2 (смотрите рисунок). Он предназначен для изменения размеров. В нашем случае изменения размера плейлиста мышкой во время выполнения программы. Далее в низу добавляем компонент TGroupBox из вкладки Standard и размещаем на нем Panel2, ProgressBar из вкладки Win32 и Panel3. Для Panel3 устанавливаем свойство Align->alBottom, для ProgressBar1 свойство Align->alBottom и для Panel2 устанавливаем свойство Align->alBottom. Затем размещаем все остальные элементы управления как показано на рисунке:
В качестве кнопок управления использован компонент TSpeedButton из вкладки Additional.
Далее в для ListBox1 свойство Visible->False. Для ListBox2 свойство Align->alRight. Для Splitter1 свойство Align->alRight. Для Panel1 свойство Align->alClient. Затем кидаем на форму два компонента TTimer из вкладки System, компонент TOpenDialog из вкладки Dialogs и компонент TPopupMenu из вкладки Standard.
Для ListBox2 свойство PopupMenu-> PopupMenu1. Panel1 – будет служить для вывода изображения фильма. ListBox –ы будут служить плейлистом, в ListBox1 будем хранить пути к файлам проигрывания, поэтому мы его сделали скрытым, а в ListBox2 название файлов. Цвет панели для проигрывания и цвет плейлиста вы можете изменить в свойстве Color компонента, при этом не забывайте изменить цвет текста плейлиста в свойстве Font->Color. В компоненте PopupMenu1 создаем три пункта «Добавить», «Удалить», «Очистить». Свойство AutoPopup устанавливаем False. Для Timer1 свойство Interval->500, а для Timer2 свойство Interval->2000. Для TrackBar1 свойство Max->100, свойство Position->50. Картинки для кнопок управления можно взять свои или скачать здесь. Установить их можно в свойстве Glyph компонента SpeedButton. На этом настройка интерфейса закончена. Сохраняем проект. Код для обработки событий напишем на следующем уроке.
Установил Ваш видео плейер из урока Урок 2.2. Пишем видеоплеер (проигрыватель видео) на Delphi с использованием технологии DirectShow (продолжение). в windows7 всё работает великолепно, но Win10 кроме *.avi не берёт другие видео файлы. Пишет "Не удается прорендерить файл". В чём дело.
еще проблема в воспроизведении некоторых файлов, в проигрывателях таких как gomplayer, light alloy, wmp файлы открываются, а тут пишется что - Не удается прорендерить файл
//загружаем файл для проигрывания при этом граф строится автоматический hr := pGraphBuilder.RenderFile(StringToOleStr(PChar(filename)), ''); if hr<>0 then begin ShowMessage('Не удается прорендерить файл'); exit;
Ну по поводу исчезновения видео, раз оно происходит только в real-time, значит нужно искать ошибки в коде программы. Скидывайте ваш проект мне на почту попробую посмотреть, правда у меня Delphi 2010, но думаю что должно работать. По поводу воспроизведения некоторых файлов, то к сожалению те проигрыватели, которые вы перечислили, вряд ли используют автоматическое построение графа фильтров, я думаю, что в них граф строится в зависимости от типа воспроизводимого файла. Посмотрите урок 5.1, там граф строится немножко по другому, можете проверить будут ли воспроизводиться ваши файлы таким способом, работу проверял только для avi и wmv, на самом деле как я понял нужно для каждого типа файлов строить свой граф, если интеллектуальное построение выдает ошибку.)))
А как при ручном построении Графа(Дракулы) узнать, какие кодеки и фильтры нужны для конкретного файла? И как получить список кодеков/сплиттеров/фильтров DirectShow, установленных в системе? Хорошо бы про это статью забацать. Про DirectShow в интернете информации совсем мало, а что-то конкретное вообще не найти.
Честно говоря не знаю, я когда этим занимался то для просмотра графа использовал программы GraphEdit и GraphStudio, смотрел граф и добавлял соответствующие фильтры в проект. Смотрите урок 4.2 (добавление фильтра в граф: //создаем объект для построения фильтра вывода видео FVideoRender CoCreateInstance(CLSID_VideoMixingRenderer, nil, CLSCTX_INPROC, IID_IBaseFilter, FVideoRender); // Добавляем его в граф FGraphBuilder.AddFilter(FVideoRender, 'Video Renderer');), и уроки 5.1 и 5.2 (построение графа по ключевым фильтрам в зависимости от расширения: (//если расширение wmv if lowercase(ExtractFileExt(FileNameVideo))='.wmv' then begin //строим участок графа от фильтра источника fl_SrcFile до фильтра FDirectVobSub if FAILED(RenderStream(nil, @MEDIATYPE_Video, fl_SrcFile, nil , FDirectVobSub)) then Begin ShowMessage('Внимание! Произошла ошибка на участке от фильтра источника fl_SrcFile до фильтра FDirectVobSub'); Exit; End;). Для получения списка фильтров или устройств из конкретной категории используется объект перечислитель устройств. Смотрите уроки по работе с видеокамерой 3.1 и 3.2, а здесь пример получения списка видео, аудио устройств и фильтров для сжатия http://basicsprog.ucoz.ru/uroki_delphi/multimedia/urok3_1/kamera000.zip Вообще по DirectShow есть книга "DirectShow и телевидение", но примеры в ней на С. Да если необходимо соединить только конкретные заданные фильтры, то используют соединение через Pin (т.е. фильтры добавляются в граф, затем ищутся входные и выходные контакты Pin, а затем соединяются, но до этого я так и не дошел, но информацию в интернете видел). Юзайте сайт и форум "DirectShow по русский" http://directshow.wonderu.com/ .))))
Роль сервера: выводить на LCD-тв видео ролики а так же текстовую информацию разного содержания и формата. Роль клиента: отпровлять на сервер список выводимых роликов, текста, информации для отображения.
исчезновение происходит в real-time, если указать сразу настройки на форме все нормально. пока сделал криво, останавливаю видео заново привязываю к панели и и возвращаю позицию на которой остановилось. переключается секунды 3 такой вариант
Добрый день, xaramamburu. Обращаюсь к Вам, за советом. Вопрос о наложении текста(пост 8), решил отображать текст на прозрачном окне поверх окна плеера. Нужна ваша помощь в следующем : На форме имеется список файлов для проигрования, кнопки пуск и стоп , также эта форма является серверным приложением. Если я нажимаю кнопку пуск на форме в ручную т.е. мышкой , то файл воспроизводится и все ок, но если я подаю команду обработать процедуру нажатия кнопки пуск (нажать кнопку пуск) по сети с клиентского приложения то выдается сообщение с ошибкой Не удается создать граф от(ShowMessage('Не удается создать граф');). В чем разница построения графа не пойму.(соответственно все сетевые настройки и подключения работают) Могу выслать файлы проектя сервера и клиента для наглядности, только ваш е-mail не доступен для просмотра.
Тогда смотрите после какой из этих команд видео начинает пропадать, либо в свойствах формы сразу попробуйте задать полно экранный режим без бордюра, поверх окон и с максимальным разворачиванием окна. Вы первый кто обращается с такой проблемой. Короче вам надо определить какое конкретное из этих свойств приводит к исчезновению видео и как это проявляется (т.е это происходит в real-time и/или при задании настроек в ручную в свойствах формы, а уже дальше думать как решать.))))
здравствуйте! при включении полноэкранного режима если прописать BorderStyle:=bsNone; //без бордюра или FormStyle :=fsstayOnTop; //поверх окон, видео продолжает работать, но на панели перестает показываться. как с этим бороться?
спасибо за ваш пример и помощь. отлично разобрался. меня интересует еще один вопрос как можно открыть файл с определенными правами. дело в том что я пишу потоковый видеопроигрыватель для просмотра фильмов hd без скачивания. одновременно файл должен скачиваться и проигрываться. если фильм уже скачивается то его нельзя открыть. другие проигрыватели как то это делают. либо как то создать поток TMemoryStream и постоянно подгружать но тогда как открывать его?
Ну тут я вам сильно помочь не смогу, но по работе с потоками памяти в DSPack есть пример DSPack\Demos\D6-D7\Filters\Async\MemFile\, к сожалению запустить его под Delphi 2010 так и не удалось. Но как я понял он показывает как грузить и читать видео из памяти. В интернете даже видел примеры использования этого фильтра.
Всё как то сложновато. В общем используя программу GraphEdit построил интеллектуальный граф фильтров, и увидел как называются звуковые фильтра. Затем в своей программе используя функцию pGraphBuilder.FindFilterByName(StringToOleStr(PChar('AC3Filter 0002')), pFilter); и pFilter.Stop остановил один звуковой поток, таким же образом могу остановить и второй. Есть еще функция EnumFilters которая якобы как я понял из MSDN перечисляет все фильтра в графе, но как ею пользоваться я так и не понял(. может кто поможет?
На самом деле под построением графа ручками я имел ввиду, что граф можно построить каким угодно способом, но затем нужно перебрать все фильтры в графе и удалить фильтры для аудио потока, а затем построить новые. Или сразу искать нужный фильтр потока, а все другие удалить или как то отключить. Вот можете посмотреть мои попытки выбора потока и небольшой материал, который удалось нарыть в интернете. Отпишитесь если разберетесь.))))))