Видеоплеер DirectShow - эффект хрипящего звука
|
|
BLACK_CRAFTER666 | Дата: Воскресенье, 07.07.2013, 12:50 | Сообщение # 1 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Здравствуйте. Я пишу видеоплеер с использованием DirectShow. Строю граф вручную:
Код const // глобальные константы CLSID_FfdshowVideoDecoder : TGUID = '{04FE9017-F873-410E-871E-AB91661A4EF7}'; CLSID_ffdshowAudioDecoder : TGUID = '{0F40E1E5-4F79-4988-B1A9-CC98794E6B55}'; CLSID_haaliMediaSplitter : TGUID = '{55DA30FC-F16B-49FC-BAA5-AE59FC65F82D}'; CLSID_AC3ParserFilter : TGUID = '{280A3020-86CF-11D1-ABE6-00A0C905F375}'; //mpg2splt.ax CLSID_AC3Filter : TGUID = '{A753A1EC-973E-4718-AF8E-A3F554D45C44}'; //ac3filter.ax CLSID_ElecardMPEGDemultiplexer : TGUID = '{136DCBF5-3874-4B70-AE3E-15997D6334F7}';
var // глобальные переменные pGraphBuilder : IGraphBuilder = nil; pCaptureGraphBuilder : ICaptureGraphBuilder2 = nil; pMediaControl : IMediaControl = nil; pMediaEvent : IMediaEvent = nil; pVideoWindow : IVideoWindow = nil; pMediaPosition : IMediaPosition = nil; pBasicAudio : IBasicAudio = nil; pBasicVideo : IBasicVideo = nil; fSource : IBaseFilter = nil; ffdshow_video : IBaseFilter = nil; ffdshow_audio : IBaseFilter = nil; // haali : IBaseFilter = nil; ac3filter : IBaseFilter = nil; ac3parser : IBaseFilter = nil; ElecardDemultiplexer : IBaseFilter = nil; pAudioRender : IBaseFilter = nil; pVideoRender : IBaseFilter = nil;
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;
function buildgraph: hresult; var pin : IPin; mediatype : TAMMediaType; InPin, OutPin : IPin; begin CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER , IID_IGraphBuilder, pGraphBuilder); CoCreateInstance(CLSID_CaptureGraphBuilder2, NIL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, pCaptureGraphBuilder); pCaptureGraphBuilder.SetFiltergraph(pGraphBuilder); pGraphBuilder.AddSourceFilter(StringToOleStr(FileName),'source file',fSource);
CoCreateInstance(CLSID_AudioRender, nil, CLSCTX_INPROC, IID_IBaseFilter, pAudioRender); pGraphBuilder.AddFilter(pAudioRender, 'DirectSound Audio Renderer');
CoCreateInstance(CLSID_VideoMixingRenderer9, nil, CLSCTX_INPROC, IID_IBaseFilter, pVideoRender); pGraphBuilder.AddFilter(pVideoRender, 'Video Mixing Renderer 9');
CoCreateInstance(CLSID_ElecardMPEGDemultiplexer,nil,CLSCTX_INPROC_SERVER,IID_IBaseFilter,ElecardDemultiplexer); pGraphBuilder.AddFilter(ElecardDemultiplexer,'elecard demultiplexer');
CoCreateInstance(CLSID_FfdshowVideoDecoder,nil,CLSCTX_INPROC,IID_IBaseFilter,ffdshow_video); pGraphBuilder.AddFilter(ffdshow_video,'ffdshow video decoder');
{CoCreateInstance(CLSID_ffdshowAudioDecoder,nil,CLSCTX_INPROC,IID_IBaseFilter,ffdshow_audio); pGraphBuilder.AddFilter(ffdshow_audio,'ffdshow audio decoder');}
CoCreateInstance(CLSID_AC3Filter,nil,CLSCTX_INPROC,IID_IBaseFilter,ac3filter); pGraphBuilder.AddFilter(ac3filter,'ac3filter');
{CoCreateInstance(CLSID_AC3ParserFilter,nil,CLSCTX_INPROC,IID_IBaseFilter,ac3parser); pGraphBuilder.AddFilter(ac3parser,'ac3parser');}
if not FindPin(fSource,PINDIR_OUTPUT,pin) then begin ClearGraph; Result := S_FALSE; Exit; end; pin.ConnectionMediaType(mediatype);
Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, fSource, nil ,pAudioRender); Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, fSource, nil ,pVideoRender);
MoFreeMediaType(@mediatype);
pGraphBuilder.QueryInterface(IID_IBasicAudio,pBasicAudio); pGraphBuilder.QueryInterface(IID_IBasicVideo,pBasicVideo); pGraphBuilder.QueryInterface(IID_IMediaControl,pMediaControl); pGraphBuilder.QueryInterface(IID_IMediaPosition,pMediaPosition); pGraphBuilder.QueryInterface(IID_IVideoWindow,pVideoWindow);
Большинство файлов воспроизводятся на ура. Но у некоторых файлов происходит либо рассинхрон звука, либо хрип. Особенно у тех, где звук в формате AC-3. При этом, в трее нет ни значка ac3filter (что очень странно), ни значка ffdshow audio decoder'а. Т.е. не понятно, каким фильтром обрабатывается звук. На тех файлах, где есть значки ac3filter/ffdshow, со звуком всё ок. В чем может быть прикол? Пробовал связывать фильтры через Pin'ы, но не уверен, что правильно это делал.
Сообщение отредактировал BLACK_CRAFTER666 - Воскресенье, 07.07.2013, 12:59 |
|
| |
xaramamburu | Дата: Понедельник, 08.07.2013, 11:23 | Сообщение # 2 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Цитата В чем может быть прикол? Не знаю. Можно попробовать установить последнюю версию кодеков, может, что и изменится. Цитата Т.е. не понятно, каким фильтром обрабатывается звук. Это можно узнать только посмотрев как выглядит граф с помощью GraphStudio. Но здесь есть одно но. Я уже писал, что это работает только под Windows XP и ваш граф должен быть зарегистрирован в системе (это можно сделать с помощью функции AddGraphToRot ее тело можно найти в интернете или установить пакет DSPack и подключить к проекту модуль DSUtils). По крайней мере я когда с этим копался, создавал проект на ноутбуке с Windows Vista, а потом шел включал старенький компьютер Windows XP и смотрел как выглядит граф, я понимаю, что это извращение, но по другому посмотреть что там у меня строилось не было возможности. Цитата Строю граф вручную: Судя по вашему коду это не совсем правильно. Вы вручную добавляете фильтры в граф, затем вы определяете MediaType данных за что вы огромное спасибо, я в свое время до этого не допер. А вот далее вы используете функции:
Код Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, fSource, nil ,pAudioRender); Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, fSource, nil ,pVideoRender); RenderStream - это функция интеллектуального построения графа, причем в ней вы указываете fSource (источник) и pAudioRender (рендер) а между ними nil (в место nil можно указать конкретный фильтр для кодирования или декодирования потока) , т.е. все промежуточные фильтры вы предлагаете установить самому графу. Я уже писал, что он отдает предпочтение тем фильтрам, что вы добавили в граф, но не факт, что он установит именно их. Я не знаю знаете ли вы что эта функция позволяет строит граф по частям. Например: Вам надо построить граф из нескольких фильтров и вы точно знаете, что для данного MediaType будет использоваться фильтр А - источник, фильтр В - декодер и фильтр С - рендер, а остальные фильтры вы отдаете на усмотрение графа. Тогда функцию можно задать таким образом: 1) Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, А, В , С); - строим цепь от А до С с промежуточным фильтром В. или 2) Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, А, nil ,В) ; - строим цепь от А до В промежуточные фильтры добавляет сам граф; Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, В, nil ,С); - аналогично от В до С. Да, первый вариант у меня почему то не всегда срабатывал, возможно из - за того что промежуточных фильтров было больше чем один.
|
|
| |
BLACK_CRAFTER666 | Дата: Понедельник, 08.07.2013, 15:44 | Сообщение # 3 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Цитата (xaramamburu) Можно попробовать установить последнюю версию кодеков, может, что и изменится Это, конечно, важная составляющая. Но тут дело не в этом. Цитата (xaramamburu) Я не знаю знаете ли вы что эта функция позволяет строит граф по частям. Я не знал, но в какой-то момент начал догадываться Цитата (xaramamburu) Я уже писал, что он отдает предпочтение тем фильтрам, что вы добавили в граф, но не факт, что он установит именно их. Я помню. Чтобы этого избежать, как вариант, можно рендерить стрим частями, от фильтра до фильтра. Вы об этом писали. Цитата (xaramamburu) включал старенький компьютер Windows XP и смотрел как выглядит граф, я понимаю, что это извращение, но по другому посмотреть что там у меня строилось не было возможности. Если оперативки хватает и есть место на диске, то можно просто использовать виртуальные машины Цитата (xaramamburu) 1) Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, А, В , С); - строим цепь от А до С с промежуточным фильтром В. СПАСИБО!!! Вот в этом и был прикол! Я не мог допереть, что средний nil это промежуточный фильтр и что все промежуточные фильтры подбираются системой автоматически. Поняв это, я сделал вот так:
Код Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, fSource,nil,ffdshow_video); Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, ffdshow_video,fGrabber,pVideoRender); // SampleGrabber еще никому не мешал )) Result := pCaptureGraphBuilder.RenderStream(nil, mediatype.pbFormat, fSource,ac3filter,pAudioRender); Т.е. рендеринг от фильтра до фильтра по-очереди. Таким образом, пропал тот самый хрип, а ac3filter cтал грузиться всегда. Но появились пара досадных косяков. А именно: 1) SampleGrabber начал выдавать либо шедевр Малевича, либо пустой (nil'ьный) указатель. Но я постучал по компу ногой и всё стало S_OK 2) Пропали пропорции видео при ресайзе окна. Это решилось хитрой процедурой ручного просчета размеров двух TRect'ов. 3) В записи с каналов ТВЦ со спутника Yamal 201 рендеринг звука выдает ошибку. Какую именно - в дебаггере пока не смотрел. Возможно, нужно использовать другой фильтр аудио. Опять же, сделать возможность выбора фильтров, а если ошибка - пытаться грузить другой. Это уже из вопроса подхода к созданию интерфейса. У себя в проге я это, обязательно, сделаю. А видео с ТВЦ идет нормально. 4) Тормозят файлы приблизительно вот с такими параметрами: Это HD видео. Как видно, в них есть какая-то дополнительная текстовая информация. Может, тормозит из-за нее? Может надо для текста еще какой-то фильтр подключить? Еще, при их проигрывании, сильно грузится процессор. Знаю, это тоже влияет. При полностью автоматическом рендеринге RenderFile(), у этих файлов тормозов почти нет. Если хотите потестить, могу залить на гугл-диск файлы, которые глючат. Цитата (xaramamburu) RenderStream - это функция интеллектуального построения А я называл ее ручным построением Я в терминах запутался. Если это интеллектуальное, то RenderFile() это... автоматическое? p.s. В один пост всё не вошло
Сообщение отредактировал BLACK_CRAFTER666 - Понедельник, 08.07.2013, 16:02 |
|
| |
xaramamburu | Дата: Понедельник, 08.07.2013, 18:18 | Сообщение # 4 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Цитата Если это интеллектуальное, то RenderFile() это... автоматическое? Это тоже интеллектуальное построение, когда граф сам подбирает фильтры. Руками это когда вы сами соединяете входные и выходные Pin у фильтров, но для этого нужно точно знать какие фильтры будут в цепочке графа, при этом граф строите чисто вы программно.К сожалению у меня старенький ноутбук и вряд ли потянет HD видео. Да и скорость интернета пока не позволяет скачивать фильмы в HD качестве (и такое в наше время бывает).
|
|
| |
BLACK_CRAFTER666 | Дата: Понедельник, 08.07.2013, 18:41 | Сообщение # 5 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Цитата (xaramamburu) К сожалению у меня старенький ноутбук и вряд ли потянет HD видео. Да и скорость интернета пока не позволяет скачивать фильмы в HD качестве (и такое в наше время бывает). протестируйте тогда обычных файлах
|
|
| |
|