Слева вверху расположена
Panel1 для вывода изображения с камеры. Справа располагается
Panel2 с размещенным на ней компонентом
TImage свойство
Proportional у
Image1 устанавливаем
True, в нем будем показывать с грабленое изображение. Под
Panel1 размещаем компонент
TListBox и кнопку
TButton (
«Параметры и разрешение камеры»). Справа от
ListBox1 размещаем восемь компонентов
TLabel и семь компонентов
TEdit. И девятый компонент
Label9 с надписью
Caption (
Трансляция изображения остановлена) размещаем под панелями. Добавляем компонент
TTimer свойство
Enable устанавливаем
False. На этом интерфейс приложения закончен.
В целом граф захвата изображения с камеры, строится также как и в предыдущем уроке. Для получения кадра из потока данных
Web камеры мы будем использовать интерфейсы
IBaseFilter и ISampleGrabber. Передавать данные по
FTP будем с помощью модуля
WinInet, а для сохранения настроек
FTP воспользуемся модулем
IniFiles.
Ниже привожу полный код приложения с комментариями:unit Unit1;interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls,
directshow9, ActiveX, Jpeg, WinInet, IniFiles; //не забудьте добавить выделенные модули
//
Скачать заголовочные файлы DirectShow можно здесь.type TForm1 = class(TForm)
ListBox1: TListBox;
Panel1: TPanel;
Button1: TButton;
Panel2: TPanel;
Image1: TImage;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit6: TEdit;
Label6: TLabel;
Label8: TLabel;
Button2: TButton;
Timer1: TTimer;
Edit5: TEdit;
Label5: TLabel;
Button3: TButton;
Label4: TLabel;
Edit4: TEdit;
Edit7: TEdit;
Label7: TLabel;
Label9: TLabel;
function CreateGraph: HResult;
function Initializ: HResult;
function CaptureBitmap: HResult;
procedure LoadIniFiles;
procedure SaveIniFiles; procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure ListBox1DblClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure SendFtp; procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var Form1: TForm1;
IniFile: TIniFile;
FileName: string;
RecMode: boolean = False;
DeviceName:OleVariant;
PropertyName:IPropertyBag;
pDevEnum:ICreateDEvEnum;
pEnum:IEnumMoniker;
pMoniker:IMoniker;
MArray1: array of IMoniker; //Это список моникеров, из которго
//мы потом будем получать необходмый моникер
//интерфейсы
FGraphBuilder: IGraphBuilder;
FCaptureGraphBuilder: ICaptureGraphBuilder2;
FMux: IBaseFilter;
FSink: IFileSinkFilter;
FMediaControl: IMediaControl;
FVideoWindow: IVideoWindow;
FVideoCaptureFilter: IBaseFilter;
FAudioCaptureFilter: IBaseFilter;
//область вывода изображения
FVideoRect: TRect;
FBaseFilter: IBaseFilter;
FSampleGrabber: ISampleGrabber;
MediaType: AM_MEDIA_TYPE;
implementation{$R *.dfm}
function TForm1.Initializ: HResult;begin
//Создаем объект для перечисления устройств
Result:=CoCreateInstance(CLSID_SystemDeviceEnum, NIL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, pDevEnum);
if Result<>S_OK then EXIT;
//Перечислитель устройств Video
Result:=pDevEnum.CreateClassEnumerator(CLSID_VideoInputDeviceCategory, pEnum, 0);
if Result<>S_OK then EXIT;
//Обнуляем массив в списке моникеров
setlength(MArray1,0);
//Пускаем массив по списку устройств
while (S_OK=pEnum.Next(1,pMoniker,Nil)) do
begin
setlength(MArray1,length(MArray1)+1); //Увеличиваем массив на единицу
MArray1[length(MArray1)-1]:=pMoniker; //Запоминаем моникер в масиве
Result:=pMoniker.BindToStorage(NIL, NIL, IPropertyBag, PropertyName); //Линкуем моникер устройства к формату хранения IPropertyBag
if FAILED(Result) then Continue;
Result:=PropertyName.Read('FriendlyName', DeviceName, NIL); //Получаем имя устройства
if FAILED(Result) then Continue;
//Добавляем имя устройства в списки
Listbox1.Items.Add(DeviceName);
end;
//Первоначальный выбор устройств для захвата видео
//Выбираем из спика камеру
if ListBox1.Count=0 then
begin
ShowMessage('Камера не обнаружена');
Result:=E_FAIL;;
Exit;
end;
Listbox1.ItemIndex:=0;
//если все ОК
Result:=S_OK;
end;
function TForm1.CreateGraph:HResult;var
pConfigMux: IConfigAviMux;
begin
//Чистим граф
FVideoCaptureFilter := NIL;
FVideoWindow := NIL;
FMediaControl := NIL;
FSampleGrabber := NIL;
FBaseFilter := NIL;
FCaptureGraphBuilder := NIL;
FGraphBuilder := NIL;
//Создаем объект для графа фильтров
Result:=CoCreateInstance(CLSID_FilterGraph, NIL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, FGraphBuilder);
if FAILED(Result) then EXIT;
// Создаем объект для граббинга
Result:=CoCreateInstance(CLSID_SampleGrabber, NIL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, FBaseFilter);
if FAILED(Result) then EXIT;
//Создаем объект для графа захвата
Result:=CoCreateInstance(CLSID_CaptureGraphBuilder2, NIL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, FCaptureGraphBuilder);
if FAILED(Result) then EXIT;
// Добавляем фильтр в граф
Result:=FGraphBuilder.AddFilter(FBaseFilter, 'GRABBER');
if FAILED(Result) then EXIT;
// Получаем интерфейс фильтра перехвата
Result:=FBaseFilter.QueryInterface(IID_ISampleGrabber, FSampleGrabber);
if FAILED(Result) then EXIT;
if FSampleGrabber <> NIL then
begin
//обнуляем память
ZeroMemory(@MediaType, sizeof(AM_MEDIA_TYPE));
// Устанавливаем формат данных для фильтра перехвата
with MediaType do
begin
majortype := MEDIATYPE_Video;
subtype := MEDIASUBTYPE_RGB24;
formattype := FORMAT_VideoInfo;
end;
FSampleGrabber.SetMediaType(MediaType);
// Данные будут записаны в буфер в том виде, в котором они
// проходят через фильтр
FSampleGrabber.SetBufferSamples(TRUE);
// Граф не будет остановлен для получения кадра
FSampleGrabber.SetOneShot(FALSE);
end;
//Задаем граф фильтров
Result:=FCaptureGraphBuilder.SetFiltergraph(FGraphBuilder);
if FAILED(Result) then EXIT;
//выбор устройств ListBox - ов
if Listbox1.ItemIndex>=0 then
begin
//получаем устройство для захвата видео из списка моникеров
MArray1[Listbox1.ItemIndex].BindToObject(NIL, NIL, IID_IBaseFilter, FVideoCaptureFilter);
//добавляем устройство в граф фильтров
FGraphBuilder.AddFilter(FVideoCaptureFilter, 'VideoCaptureFilter'); //Получаем фильтр графа захвата
end;
//Задаем, что откуда будем получать и куда оно должно выводиться
Result:=FCaptureGraphBuilder.RenderStream(@PIN_CATEGORY_PREVIEW, nil, FVideoCaptureFilter ,FBaseFilter ,nil);
if FAILED(Result) then EXIT;
//Получаем интерфейс управления окном видео
Result:=FGraphBuilder.QueryInterface(IID_IVideoWindow, FVideoWindow);
if FAILED(Result) then EXIT;
//Задаем стиль окна вывода
FVideoWindow.put_WindowStyle(WS_CHILD or WS_CLIPSIBLINGS);
//Накладываем окно вывода на Panel1
FVideoWindow.put_Owner(Panel1.Handle);
//Задаем размеры окна во всю панель
FVideoRect:=Panel1.ClientRect;
FVideoWindow.SetWindowPosition(FVideoRect.Left,FVideoRect.Top, FVideoRect.Right - FVideoRect.Left,FVideoRect.Bottom - FVideoRect.Top);
//показываем окно
FVideoWindow.put_Visible(TRUE);
//Запрашиваем интерфейс управления графом
Result:=FGraphBuilder.QueryInterface(IID_IMediaControl, FMediaControl);
if FAILED(Result) then Exit;
//Запускаем отображение просмотра с вебкамер
FMediaControl.Run();
end;
//с помощью этой функции будем грабить изображение
function TForm1.CaptureBitmap: HResult;var
bSize: integer;
pVideoHeader: TVideoInfoHeader;
MediaType: TAMMediaType;
BitmapInfo: TBitmapInfo;
Buffer: Pointer;
tmp: array of byte;
Bitmap: TBitmap;
JpegIm: TJpegImage;
begin
// Результат по умолчанию
Result := E_FAIL;
// Если отсутствует интерфейс фильтра перехвата изображения,
// то завершаем работу
if FSampleGrabber = NIL then EXIT;
// Получаем размер кадра
Result := FSampleGrabber.GetCurrentBuffer(bSize, NIL);
if (bSize <= 0) or FAILED(Result) then EXIT;
// Создаем изображение
Bitmap := TBitmap.Create;
try
//обнуляем память
ZeroMemory(@MediaType, sizeof(TAMMediaType));
// Получаем тип медиа потока на входе у фильтра перехвата
Result := FSampleGrabber.GetConnectedMediaType(MediaType);
if FAILED(Result) then EXIT;
// Копируем заголовок изображения
pVideoHeader := TVideoInfoHeader(MediaType.pbFormat^);
ZeroMemory(@BitmapInfo, sizeof(TBitmapInfo));
CopyMemory(@BitmapInfo.bmiHeader, @pVideoHeader.bmiHeader, sizeof(TBITMAPINFOHEADER));
Buffer := NIL;
// Создаем побитовое изображение
Bitmap.Handle := CreateDIBSection(0, BitmapInfo, DIB_RGB_COLORS, Buffer, 0, 0);
// Выделяем память во временном массиве
SetLength(tmp, bSize);
try
// Читаем изображение из медиа потока во временный буфер
FSampleGrabber.GetCurrentBuffer(bSize, @tmp[0]);
// Копируем данные из временного буфера в наше изображение
CopyMemory(Buffer, @tmp[0], MediaType.lSampleSize);
//если необходимо сохранить изображение в bmp файле
//Bitmap.SaveToFile('Имя файла.bmp');
// Конвертируем изображение в Jpeg
//создаем объект JpegImage
JpegIm := TJpegImage.Create;
//устанавливаем связь с объектом Bitmap
JpegIm.Assign(Bitmap);
//задаем степень сжатия
JpegIm.CompressionQuality := 30;
//сжимаем
JpegIm.Compress;
//сохраняем в файл
FileName:=Edit7.Text;
JpegIm.SaveToFile(FileName);
except
// В случае сбоя возвращаем ошибочный результат
Result := E_FAIL;
end;
finally
// Освобождаем память
SetLength(tmp, 0);
Bitmap.Free;
JpegIm.Free;
end;
end;
//процедура запускает процесс получения кадра и его переда по FTP
procedure TForm1.Button2Click(Sender: TObject);
begin
//проверяем если устройства для захвата изображения
if Listbox1.Count=0 then
Begin
ShowMessage('Внимание! Камера не обнаружена.');
Exit;
End;
//Грабим кадр и начинаем передачу изображения
if FAILED(CaptureBitmap) then
Begin
ShowMessage('Внимание! Произошла ошибка при получении изображения');
Exit;
End;
Label9.Caption:='Идет трансляция изображения';
SendFtp;
//запуск таймера с заданным интервалом
Timer1.Interval:=StrToInt(Edit6.Text)*1000;
Timer1.Enabled:=True;
end;
procedure TForm1.Button1Click(Sender: TObject);//Вызов страницы свойств Web-камеры
var
StreamConfig: IAMStreamConfig;
PropertyPages: ISpecifyPropertyPages;
Pages: CAUUID;
Begin
//если запись уже идет - выходим
If RecMode then Exit;
// Если отсутствует интерфейс работы с видео, то завершаем работу
if FVideoCaptureFilter = NIL then EXIT;
// Останавливаем работу графа
FMediaControl.Stop;
try
// Ищем интерфейс управления форматом данных выходного потока
// Если интерфейс найден, то ...
if SUCCEEDED(FCaptureGraphBuilder.FindInterface(@PIN_CATEGORY_CAPTURE,
@MEDIATYPE_Video, FVideoCaptureFilter, IID_IAMStreamConfig, StreamConfig)) then
begin
// ... пытаемся найти интерфейс управления страницами свойств ...
// ... и, если он найден, то ...
if SUCCEEDED(StreamConfig.QueryInterface(ISpecifyPropertyPages, PropertyPages)) then
begin
// ... получаем массив страниц свойств
PropertyPages.GetPages(Pages);
PropertyPages := NIL;
// Отображаем страницу свойств в виде модального диалога
OleCreatePropertyFrame(
Handle,
0,
0,
PWideChar(ListBox1.Items.Strings[listbox1.ItemIndex]),
1,
@StreamConfig,
Pages.cElems,
Pages.pElems,
0,
0,
NIL
);
// Освобождаем память
StreamConfig := NIL;
CoTaskMemFree(Pages.pElems);
end;
end;
finally
// Восстанавливаем работу графа
FMediaControl.Run;
end;
end;
//остановка передачи изображения
procedure TForm1.Button3Click(Sender: TObject);begin
Label9.Caption:='Трансляция изображения остановлена';
Timer1.Enabled:=False;
end;
procedure TForm1.FormCreate(Sender: TObject);begin
//загружаем настройки из ini файла
LoadIniFiles;
CoInitialize(nil);// инициализировать OLE COM
//вызываем процедуру поиска и инициализации устройств захвата видео и звука
if FAILED(Initializ) then
Begin
ShowMessage('Внимание! Произошла ошибка при инициализации');
Exit;
End;
//проверяем найденный список устройств
if Listbox1.Count>0 then
Begin
//если необходимые для работы устройства найдены,
//то вызываем процедуру построения графа фильтров
if FAILED(CreateGraph) then
Begin
ShowMessage('Внимание! Произошла ошибка при построении графа фильтров');
Exit;
End;
end else
Begin
ShowMessage('Внимание! Камера не обнаружена.');
//Application.Terminate;
End;
end;
procedure TForm1.FormDestroy(Sender: TObject);begin
// Освобождаем память
pEnum := NIL;
pDevEnum := NIL;
pMoniker := NIL;
PropertyName := NIL;
DeviceName:=Unassigned;
CoUninitialize;// деинициализировать OLE COM
//сохраняем настройки в inifile
SaveIniFiles;
IniFile.Free;
end;
//Выбор устройств из ListBox1
procedure TForm1.ListBox1DblClick(Sender: TObject);begin
if ListBox1.Count=0 then
Begin
ShowMessage('Камера не найдена');
Exit;
End;
//перестраиваем граф при смене камеры
if FAILED(CreateGraph) then
Begin
ShowMessage('Внимание! Произошла ошибка при построении графа фильтров');
Exit;
End;
end;
procedure TForm1.Timer1Timer(Sender: TObject);begin
//грабим кадр
if FAILED(CaptureBitmap) then
Begin
ShowMessage('Внимание! Произошла ошибка при получении изображения');
Exit;
End;
//вызываем процедуру пересылки изображения по FTP
SendFtp;
end;
//Передача файла по FTP
procedure TForm1.SendFtp;var Username,Password,Folder, Port, Server:String;
inet_open, conn_param :pointer;
begin
//Передача файла по FTP
Folder:=Edit5.Text;
Username:=Edit2.Text;
Password:=Edit3.Text;
Port:=Edit4.Text;
Server:=Edit1.Text;
FileName:=Edit7.Text;
//выводим отправляемую картинку в Image1
Image1.Picture.LoadFromFile(FileName);
//Открываем интернет соединение
inet_open:= internetopen('iexplore',INTERNET_OPEN_TYPE_DIRECT,nil,nil,0);
//подключаемся к FTP серверу
conn_param:=internetconnect(inet_open, PChar(Server), strtoint(Port), PChar(Username), PChar(Password), INTERNET_SERVICE_FTP,INTERNET_FLAG_PASSIVE,0);
//задаем директорию для копирования файла
FtpSetCurrentDirectory(conn_param, PChar(Folder));
//Передаем файл по FTP
if ftpputfile(conn_param,PChar(FileName),PChar(FileName), FTP_TRANSFER_TYPE_UNKNOWN,0)=false then
begin
ShowMessage('Ошибка. Загрузка не удалась!');
Label9.Caption:='Трансляция изображения остановлена';
Timer1.Enabled:=false;
end;
//выдаем звуковой сигнал об успешной отправке изображения
beep;
//Закрываем соединение
internetclosehandle(conn_param);
internetclosehandle(inet_open) ;
end;
//процедура загрузки данных из inifile
procedure TForm1.LoadIniFiles;begin
//создание inifile с именем Config.ini
IniFile:=TIniFile.Create(ExtractFilePath(Application.ExeName)+'config.ini');
//загрузка настроек из inifile
//положение формы и размер
Form1.Left:=IniFile.ReadInteger('Form info','Left',285);
Form1.Top:=IniFile.ReadInteger('Form info','Top',168);
//Параметры FTP сервера
Edit1.Text:=IniFile.ReadString('FTP','Host','');
Edit2.Text:=IniFile.ReadString('FTP','UserName','');
Edit3.Text:=IniFile.ReadString('FTP','Password','');
Edit4.Text:=IniFile.ReadString('FTP','Port','21');
Edit5.Text:=IniFile.ReadString('FTP','Folder','/');
Edit6.Text:=IniFile.ReadString('FTP','Interval','20');
Edit7.Text:=IniFile.ReadString('FTP','FileName','');
end;
//процедура сохранения настроек в inifile
procedure TForm1.SaveIniFiles;begin
//сохраняем настройки в inifile
//форма
IniFile.WriteInteger('Form info','Left',Left);
IniFile.WriteInteger('Form info','Top',Top);
//Параметры FTP сервера
IniFile.WriteString('FTP','Host',Edit1.Text);
IniFile.WriteString('FTP','UserName',Edit2.Text);
IniFile.WriteString('FTP','Password',Edit3.Text);
IniFile.WriteString('FTP','Port',Edit4.Text);
IniFile.WriteString('FTP','Folder',Edit5.Text);
IniFile.WriteString('FTP','Interval',Edit6.Text);
IniFile.WriteString('FTP','FileName',Edit7.Text);
end;
end.
Далее на сам сайт ставите следующий скрипт в HTML:код автоподгрузки изображения с WEB камеры на сайте:
<html>
<head><title>Play Web Camera</title>
</head>
<body><center>
<script language="JavaScript">
function go()
{
var now = new Date();
var id= parseInt(now.getTime() / 1000);
document.images.cam.src="path/image.jpg?"+id;
setTimeout("go()", 5000);
}
setTimeout("go()", 5000);
</script>
<body>
<div align="center">
<b>Тест Web камеры</b><br><br>
<img src="path/image.jpg" name="cam"><br>
</div>
</body>
</html>
Данный скрипт позволяет обновлять изображение на сайте каждые
5 секунд. В место
path/image.jpg вы должны указать свое подгружаемое изображение. Для изменения времени обновления в место
5000 (5 секунд) укажите свое значение.
Сохраняем и тестируем приложение.
На сайте:
Весь код приведен с подробными комментариями, думаю, что разобраться с
ним будет не сложно. Если возникнут вопросы, пишите в комментариях.
В статье использованы материалы из книги "Есенин С.А. DirectX и Delphi. Разработка графических и мультимедийных приложений".
Спасибо за внимание.
Скачать исходники к статье можно здесь. В связи с возникающими вопросами по получению изображения с камеры выкладываю исходник, который просто позволяет получить изображение и поместить его на canvas.
Скачать исходники можно здесь.Автор статьи
xaramamburu, сайт автора
http://basicsprog.ucoz.ru .