Re: DX и Видеозахват.
От: SZobin  
Дата: 11.09.04 12:31
Оценка:
Здравствуйте, debuger, Вы писали:

D>У меня есть карточка для виделзахвата AVerMedia EZ Capture.

D>Пишу я под Делфой(как ни прискорбно), пожалуйста, если захотели ответить куском D>кода, пусть он будет делфо-образным (не сюшным). Пасаибо

Ввод и показ видео при помощи AVerMedia EZ Capture
==================================================
Сергей Зобин * 2004 * sz@mc.carrier.kiev.ua
Полные исходники проекта доступны по запросу (AVER_Ex.zip, 60 kb)
Исходники созданы на базе анализа кода библиотечных DLL из SDK к AVER EZ Capture

*Примечание — в данной статье объясняются логически значимые части кода, полный код см. в исходниках проекта.

Глава 1. Построение графа
=========================

Для DxShow можно предварительно строить графы при помощи продукта GraphEdit — входящего в комплект MSDN раздел мультимедия размер 3Мб)
В нашем случае, когда все элементы графа уже известны, сделаем это при помощи собственной программы.


1) создаем экземпляр собственно графа

hRes:=CoCreateInstance(CLSID_FilterGraph, nil,
CLSCTX_INPROC, IID_IGraphBuilder, fGraphBuilder);
if hRes<>S_OK then begin
DoError(hRes, 'Cannot create FilterGraph!');
exit;
end;

2) Ищем фильтр, при помощи которого вводится видеоизображение, у AVerMedia EZ Capture он называется "Conexant Capture" по названию фирмы-производителя чипа Bt8x8

if not FindCaptureFilter(cCaptureFilterName, fCaptureFilter) then
exit;


3) Ищем кроссбар — это фильтр, при помощи которого переключаются входные цепи (для AVEr EZ Capture это "S-Video", "Composite"), его имя тоже известно — это "Conexant Crossbar"

if not FindCrossbarFilter(cCrossbarFilterName, fCrossbarFilter) then
exit;

4) Создаем построитель графа-захватчика видео (что является переводом CaptureGraphBuilder)

hRes:=CoCreateInstance(IID_ICaptureGraphBuilder, nil,
CLSCTX_INPROC, IID_ICaptureGraphBuilder, fCaptureGraphBuilder);
if hRes<>S_OK then begin
DoError(hRes, 'Cannot create Capture graph builder!');
exit;
end;

5) Создаем экземпляр фильтра "Pause", разработанного Aver Media специально для захвата одиночных кадров. Этот фильтр находится в файле PauseVideo.ax и устанавливается вмести с драйверами платы AVER EZ Capture

hRes:=CoCreateInstance(cGUID_PauseVideoFilter, nil,
CLSCTX_INPROC, IID_IBaseFilter, fPauseVideoFilter);
if hRes<>S_OK then begin
DoError(hRes, 'Cannot create Pause Video filter');
exit;
end;


6) Вносим в граф CaptureFilter

hRes:=fGraphBuilder.AddFilter(fCaptureFilter, nil);
if hRes<>S_OK then begin
DoError(hRes, 'AddFilter CaptureFilter is fail!');
exit;
end;

7) Вносим в граф построитель графа-захватчика видео

hRes:=fCaptureGraphBuilder.SetFiltergraph(fGraphBuilder);
if hRes<>S_OK then begin
DoError(hRes, 'Cannot give graph to builder');
exit;
end;

8) Вносим в граф фильтр "Pause"
hRes:=fGraphBuilder.AddFilter(fPauseVideoFilter, nil);
if hRes<>S_OK then begin
DoError(hRes, 'Add Pause Video Filter is fail!');
exit;
end;

9) Находим выходной пин фильтра, с которого вводим изображение. Для AVER EZ Capture — их 2 — "Просмотр" и "Запись". Первый применяется, как видно из его названия, для просмотра, второй — для записи видео. Т.к. сейчас строится граф для просмотра видео — то будет использоваться пин "Просмотр"

hRes:=fCaptureFilter.FindPin(cCaptureOutPinName, fCaptureOutPin);
if hRes<>S_OK then begin
DoError(hRes, 'Cannot find capture out pin: '+cCaptureOutPinName);
exit;
end;

11) Перечислим все поддерживаемые картой типы форматов видео (их можно использовать для дальнейшего выбора формата пользователем)

if not EnumOutMediaTypes then exit;

12) Соединяем выходной пин фильтра-источника изображения (у нас это fCaptureFilter) с входным пином фильтра паузы

hRes:=fPauseVideoFilter.FindPin('In', PauseInPin);
if hRes<>S_OK then begin
DoError(hRes, 'VideoPause.In pin not found');
exit;
end;

hRes:=fGraphBuilder.Connect(fCaptureOutPin, PauseInPin);
PauseInPin:=nil;
if hRes<>S_OK then begin
DoError(hRes, 'Connect Video Capture filter and Pause Video Filter failure!');
exit;
end;

13) Отдает построителю графа-захватчика команду достроить граф автоматически до окна отображения видео

hRes:=fPauseVideoFilter.FindPin('Out', PauseOutPin);
if hRes<>S_OK then begin
DoError(hRes, 'VideoPause.Out pin not found');
exit;
end;


hRes:=fCaptureGraphBuilder.RenderStream(nil, PauseOutPin, nil, nil);
PauseOutPin:=nil;
if hRes<>S_OK then begin
DoError(hRes, 'It is fail to render out pin of pause video filter');
exit;
end;

14) В построенном графе найдем фильтр вывода видео на экран

hRes:=fCaptureGraphBuilder.FindInterface(@PINNAME_VIDEO_PREVIEW, fCaptureFilter, IID_IVideoWindow, fVideoWindow);
if hRes<>S_OK then begin
DoError(hRes, 'VideoWindow not found in graph');
exit;
end;

15) Установим все ранее установленные пользователем настройки:

Источник видео
if not SetVideoSource(fParams.rConnector) then exit;
Видеоформат
if not SetVideoFormat(fParams.rVideoFormat) then exit;
Яркость
if not SetBrightness(fParams.rBrightness) then exit;
Контрастность
if not SetContrast(fParams.rContrast) then exit;
Цветность
if not SetHue(fParams.rHue) then exit;

16) Настроим фильтр вывода видео на экран


Для этого передадим Handle и размеры компонента, на котором будем отображать видео (на форме это может быть например TPanel или сама форма, если видео нужно изображать на всю форму)

fHandle:=aHandle;
FillChar(fViewRect, SizeOf(fViewRect), #0);
fViewRect.Right:=aWidth;
fViewRect.Bottom:=aHeight;

lWindowStyle := GetWindowLong(aHandle, GWL_STYLE);
lWindowStyleEx := GetWindowLong(aHandle, GWL_EXSTYLE);

hRes:=fVideoWindow.put_Owner(fHandle);
if hRes<>S_OK then begin
DoError(hRes, 'InitVideoWindow: put_Owner');
exit;
end;

hRes:=fVideoWindow.put_WindowStyle(lWindowStyle or WS_CHILD or WS_CLIPCHILDREN); // $4200 0000
if hRes<>S_OK then begin
DoError(hRes, 'InitVideoWindow: put_WindowStyle');
exit;
end;

hRes:=fVideoWindow.put_WindowStyleEx(lWindowStyleEx);
if hRes<>S_OK then begin
DoError(hRes, 'InitVideoWindow: put_WindowStyleEx');
exit;
end;

hRes:=fVideoWindow.put_MessageDrain(aHandle);
if hRes<>S_OK then begin
DoError(hRes, 'InitVideoWindow: put_MessageDrain');
exit;
end;

hRes:=fVideoWindow.SetWindowPosition(fViewRect.Left, fViewRect.Top, fViewRect.Right — fViewRect.Left, fViewRect.Bottom — fViewRect.Top);
if hRes<>S_OK then exit;

hRes:=fVideoWindow.put_Visible(True);
if hRes<>S_OK then exit;

17) Запустим граф в работу


hRes:=fGraphBuilder.QueryInterface(IID_IMediaControl, MediaControl);
if hRes<>S_OK then exit;

hRes:=MediaControl.Run;
MediaControl:=nil;

Итак в 17 шагов построен граф для отображения видео в окне от AVER EZ Capture

Глава 2. Ввод кадра
===================

1. Определим размеры выводимого изображения

Result:=DetectVideoSourceSize(lSize);
if not Result then exit;

2. запросим интерфейс для ввода кадра от фильтра PauseVideo. Его особенностью является то, что он вводит кадр асинхронно и прямо в процессе показа видео.

hRes:=fPauseVideoFilter.QueryInterface(cGUID_PauseIntf, PauseWaiter);
if hRes<>S_OK then exit;


3. Выделим и очистим память для изображения (хотя очищать ее не обязательно)
lBufSize:=lSize.X*lSize.Y*4;
GetMem(lDataBuf, lBufSize);
FillChar(lDataBuf^, lBufSize, #0);

gWaitFlag:=0;
hRes:=PauseWaiter.CaptureFrame(lDataBuf, @WaitPauseProc);

4. Синхронизуем работу ввода — подождем окончания ввода или истечения тайм-аута
lTime:=GetTickCount;
while (gWaitFlag=0) and
(GetTickCount — lTime<=1000) do
Sleep(1);

PauseWaiter:=nil;

5. Если тайм-аут истек — что-то не сработало
if GetTickCount — lTime>=1000 then begin
DoError(0, 'Capture Frame time-out');
exit;
end

6. Преобразуем буфер в битмапу
case fCaptureBitPerPixel of
8: ConvertBuffer8ToBitmap(lDataBuf, aOutBitmap)
15: ConvertBuffer15ToBitmap(lDataBuf, aOutBitmap)
24: ConvertBuffer24ToBitmap(lDataBuf, aOutBitmap)
32: ConvertBuffer32ToBitmap(lDataBuf, aOutBitmap)
else begin
DoError(0, 'Unsupported video format: '+IntToStr(fCaptureBitPerPixel));
end;
end;

Преобразование нужно для того, чтобы перевернуть картинку и привести ее к формату GRB24
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.