Видеоплеер DirectShow - ручное построение графа
|
|
BLACK_CRAFTER666 | Дата: Вторник, 02.07.2013, 11:14 | Сообщение # 1 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Здравствуйте. Основываясь на статье: http://basicsprog.ucoz.ru/publ/6-1-0-25 , написал свой видеоплеер. Но воспроизведение иногда глючит, а некоторые файлы вообще не открываются. В связи с этим, возник логичный вопрос: Как построить граф вручную в зависимости от типа/формата исходного видео-файла? Как узнать, какие сплиттеры/кодеки нужны и как правильно подключить их к Графу(Дракуле)? И как получить список сплиттеров/декодеров, установленных в системе? Дополнительный вопрос: как вытащить информацию о видео-файле? Такую, как: FourCC, битрейт аудио/видео, количество кадров в секунду (fps), и т.п.
|
|
| |
xaramamburu | Дата: Среда, 03.07.2013, 19:07 | Сообщение # 2 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Честно говоря не знаю, я когда этим занимался то для просмотра графа использовал программы 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 / .))))
|
|
| |
xaramamburu | Дата: Среда, 03.07.2013, 19:18 | Сообщение # 3 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Цитата Дополнительный вопрос: как вытащить информацию о видео-файле? Такую, как: FourCC, битрейт аудио/видео, количество кадров в секунду (fps), и т.п. Как получить битрейт аудио/видео, количество кадров в секунду (fps), разрешение видео (длину/ширину) можно посмотреть здесь http://www.cyberforum.ru/blogs/140240/blog136.html там сложного ничего нет.))))
|
|
| |
BLACK_CRAFTER666 | Дата: Четверг, 04.07.2013, 13:03 | Сообщение # 4 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Цитата (xaramamburu) GraphEdit и GraphStudio Насколько я понял, надо запустить любое видео в любом плеере, а в проге нажать "connect to remote graph"? Но это действие выдает пустой список и прога никуда не подключается. Цитата (xaramamburu) Смотрите урок 4.2(добавление фильтра в граф: Добавлять фильтры в граф я вроде как уже умею Цитата (xaramamburu) и уроки 5.1 и 5.2 (построение графа по ключевым фильтрам в зависимости от расширения: (//если расширение wmv if lowercase(ExtractFileExt(FileNameVideo))='.wmv' then begin А причем тут расширение? Расширение определяет только тип контейнера и какой нужен сплиттер. А как определить, какой для файла нужен декодер? Например, в MP4 может быть всё, что угодно. Цитата (xaramamburu) а здесь пример получения списка видео, аудио устройств и фильтров для сжатия http://basicsprog.ucoz.ru/uroki_delphi/multimedia/urok3_1/kamera000.zip Там идет получение списка фильтров для сжатия. А мне, я так понимаю, нужны фильтры для декодирования. Я не знаю, какой CLSID_* подставить, чтобы их получить. p.s. В ходе испытания "своего" плеера, заметил, что функция RenderFile() не хочет подгружать FFDShow, а всегда использует Microsoft DTV-DVD Video Decoder. Читал в MSDN, что функция RenderFile() вроде как ищет фильтры в зависимости толи от формата толи от чего-то еще по гуйдам в реестре (точно не понял). Может в реестре только стандартные форматы прописаны, такие как AVI,MPG,WMV,AVC, по-этому он другие не знает, чем открывать. Отсюда могу сделать вывод, что при таком раскладе плеер будет читать только те форматы, декодирование которых поддерживается Microsoft DTV-DVD Video Decoder'ом. Может, если насильно подгрузить FFDShow, то будут читаться и другие форматы? Понятное дело, что не все. Но, по-идее, их количество должно прибавиться? Кстати, для декодирования звука используется как-раз FFDShow audio decoder, либо AC3Filter (в зависимости от настроек приоритета). Цитата (xaramamburu) Вообще по DirectShow есть книга "DirectShow и телевидение", но примеры в ней на С. Книга это штука хорошая, но читать ее долго Цитата (xaramamburu) Да если необходимо соединить только конкретные заданные фильтры, то используют соединение через Pin (т.е. фильтры добавляются в граф, затем ищутся входные и выходные контакты Pin, а затем соединяются, Не совсем понимаю, чем отличается соединение фильтров от добавления их в граф и что это дает. Можете доступно объяснить? И еще не понимаю, что такое null_renderer и зачем он нужен и что делает. Цитата (xaramamburu) Юзайте сайт и форум "DirectShow по русский" http://directshow.wonderu.com / .)))) Дак я бы с радостью Но их форум это белая страница с надписью "It works!" Туда бы еще trollface прилепить Цитата (xaramamburu) Как получить битрейт аудио/видео, количество кадров в секунду (fps), разрешение видео (длину/ширину) можно посмотреть здесь http://www.cyberforum.ru/blogs/140240/blog136.html там сложного ничего нет.)))) Cпасибо. FPS и разрешение определились без проблем. А вот битрейт определяется либо сильно завышенным, либо вообще равным нулю.
|
|
| |
xaramamburu | Дата: Пятница, 05.07.2013, 16:53 | Сообщение # 5 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Как вы заметили сайт уже почти год не обновлялся. Все, что здесь написано было давно и я многое уже забыл. Поэтому сильно не ругайтесь.))) Цитата Насколько я понял, надо запустить любое видео в любом плеере, а в проге нажать "connect to remote graph"? Но это действие выдает пустой список и прога никуда не подключается. К сожалению на Windows Vista и 7 этот способ у меня тоже не работал, так я делал только под Windows XP. Кроме этого можно выбирать "Render Media File", он автоматом вам построит и покажет граф. Далее вы можете удалять нужные вам фильтры и добавлять другие. Одно и тоже видео можно воспроизвести с помощью разного набора фильтров. Цитата А причем тут расширение? Расширение определяет только тип контейнера и какой нужен сплиттер. А как определить, какой для файла нужен декодер? Например, в MP4 может быть всё, что угодно. Я это понимаю, но как определить не знаю. Я строил граф в GraphStudio, смотрел какие фильтры он добавлял и использовал их как ключевые в цепи построения графа.
Цитата Книга это штука хорошая, но читать ее долго Думаю, что почитать ее все равно придется, как раз в ней вы можете найти названия CLSID_* скачать ее можно здесь Книга 'DirectShow и телевидение'. Далее фильтры в граф добавляются по величине "Merit" эта такая характеристика, которая есть у каждого фильтра и чем он выше, тем больше вероятность, что данный фильтр будет добавлен в фильтр. Цитата Не совсем понимаю, чем отличается соединение фильтров от добавления их в граф и что это дает. Можете доступно объяснить? Как я понял фильтр, добавленный в граф не означает, что он будет соединен в цепь с другими фильтрами. Он может просто висеть ни к чему не подключенным. Но при этом при сборке графа отдается предпочтение фильтрам которые вы добавили и если они не подходят, то происходит поиск фильтров зарегистрированных в системе. Кроме интеллектуального построения графа, его можно строить в ручную. Добавляются необходимые фильтры в граф. Далее находятся входные и выходные контакты для этого есть (EnumPins, FindPin и т.д. интерфейсы у IBaseFilter) и проверяется попытка соединения и так по цепочке строим весь граф целиком. На практике у меня до этого дело так и не дошло, как то пробовал накидать пример тестовый пример, но сейчас найти не могу. Давно это было.((( Цитата И еще не понимаю, что такое null_renderer и зачем он нужен и что делает. Чтобы граф работал цепь должна начинаться Source (источником) и Render (приемником) фильтрами (по крайней мере я так думаю, возможно и неправ). Пока цепь графа фильтров не закончена - граф не запустится. Поэтому null_renderer - вывод в никуда используется для того, чтобы закончить цепь, например при захвате видео (изображения) с камеры, но без вывода на экран (можно написать шпиона). Цитата directshow.wonderu.com Да форум похоже действительно накрылся.((( Ищите инфу в интернете, хотя именно для Delphi ее очень мало и она разрознена по разным форумам. В основном надо искать по конкретным словам (название фильтров, интерфейсов и т.д.), просто по DirectShow выдается всякая дрянь.))))
|
|
| |
BLACK_CRAFTER666 | Дата: Суббота, 06.07.2013, 17:21 | Сообщение # 6 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Цитата (xaramamburu) Как я понял фильтр, добавленный в граф не означает, что он будет соединен в цепь с другими фильтрами. Он может просто висеть ни к чему не подключенным. Это я уже тоже понял Сегодня методом тыка и статьи 5.1 научился доставать из системы нужные фильтры по их guid Но прикол вот в чем: подключаю к графу ac3filter или ffdshow audio decoder. Если открыть mpg/ts (внутри mpeg), то граф при рендеринге звука их грузит. Если открыть FLV (внутри AAC), то выдается ошибка. Но если открыть тот же FLV-файл с помощью функции RenderFile(), т.е. используя автоматическое построение Графа(Дракулы), то в граф добавляется именно AC3FILTER. Не знаю, как это понимать а как программно узнать, что прицепилось, а что висит? Цитата (xaramamburu) Далее находятся входные и выходные контакты для этого есть (EnumPins, FindPin и т.д. интерфейсы у IBaseFilter) Т.е. нужно добавить фильтры и прицепить их друг к другу в той последовательности, в которой они идут в graphEdit'e? p.s. книга по ссылке не качается) ошибками ругается)
Добавлено (06.07.2013, 10:40) --------------------------------------------- Я нашел ошибку! надо писать
Код res := FCaptureGraphBuilder.RenderStream(nil, @MEDIATYPE_AUDIO, fl_SrcFile, nil ,FAudioRender);
вместо
Код res := FCaptureGraphBuilder.RenderStream(nil, nil, fl_SrcFile, nil ,FAudioRender);
тогда фильтры звука грузятся и звук в подопытном FLV есть Исправьте это в статье 5.1 На других контейнерах еще не пробовал. Попробую - отпишусь. А пока(липсис) - всем спасибо!
Добавлено (06.07.2013, 17:21) --------------------------------------------- но и это не правильно надо вот так: сначала строим граф и цепляем ffdshow + ac3filter (можно радиобоксы/чекбоксы сделать, что будем цеплять):
Код CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER , IID_IGraphBuilder, pGraphBuilder); CoCreateInstance(CLSID_CaptureGraphBuilder2, NIL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, pCaptureGraphBuilder); pCaptureGraphBuilder.SetFiltergraph(pGraphBuilder); //FileName := 'd:\(2013) Disney - June 13 15 43 17.mpg'; //FileName := 'c:\1.flv'; pGraphBuilder.AddSourceFilter(StringToOleStr(FileName),'source file',fSource); CoCreateInstance(CLSID_VideoMixingRenderer, nil, CLSCTX_INPROC, IID_IBaseFilter, pVideoRender); pGraphBuilder.AddFilter(pVideoRender, 'Video Mixing Renderer'); CoCreateInstance(CLSID_FfdshowVideoDecoder,nil,CLSCTX_INPROC,IID_IBaseFilter,ffdshow_video); pGraphBuilder.AddFilter(ffdshow_video,'ffdshow video decoder'); CoCreateInstance(CLSID_AC3Filter,nil,CLSCTX_INPROC_SERVER,IID_IBaseFilter,ac3filter); pGraphBuilder.AddFilter(ac3filter,'ac3filter'); CoCreateInstance(CLSID_AudioRender, nil, CLSCTX_INPROC, IID_IBaseFilter, pAudioRender); pGraphBuilder.AddFilter(pAudioRender, 'DirectSound Audio Renderer');
потом ищем MediaType фильтра-источника (fSource), предварительно найдя его Output Pin:
Код if not FindPin(fSource,PINDIR_OUTPUT,pin) then begin ClearGraph; Result := S_FALSE; Exit; end; pin.ConnectionMediaType(mediatype); функция поиска первого нужного Pin'а:
Код function FindPin(const filter: IBaseFilter; const pinDir: _PinDirection; var pinOut: IPin):Boolean; var enumPins: IEnumPins; Direction : _PinDirection; begin Result := False; enumPins := nil; filter.EnumPins(enumPins); while enumPins.Next(1,pinOut,0)=s_ok do begin pinOut.QueryDirection(Direction); if Direction=pinDir then begin Result := True; enumPins := nil; Exit; end; end; if Assigned(enumPins) then enumPins := nil; end; ежели Pin найден и MediaType определен, рендерим аудио и видео в любой последовательности:
Код Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, fSource, nil ,pVideoRender); // строим цепочку видео (подсунув сюда MediaType) Result := pCaptureGraphBuilder.RenderStream(nil, MEDIATYpe.pbFormat, fSource, nil ,pAudioRender); // строим цепочку аудио (так же подсунув сюда MediaType) MoFreeMediaType(@mediatype); // освободим MediaType
и не забываем проверять результат каждой функции на ошибки!
Вот, кажется, и всё Интерфейсы управления доставать, как обычно. Не знаю, насколько это правильно. Но теперь прога стала читать те файлы, которые раньше не читала. *Проверил на нескольких файлах. Видео и звук есть. Спасибо Харамамбуре за духовную наставку!
Сообщение отредактировал BLACK_CRAFTER666 - Суббота, 06.07.2013, 17:35 |
|
| |
xaramamburu | Дата: Суббота, 06.07.2013, 20:53 | Сообщение # 7 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| BLACK_CRAFTER666, Я смотрю вы упрямый. Респект. Выкладывайте если еще, что то накопаете, может кому пригодится.
|
|
| |
|