Среда, 22.11.2017, 01:47
Приветствую Вас Гость

Не ошибается тот, кто ничего не делает.
Но и ничего не делать - ошибка.

Эмиль Кроткий

Меню сайта
Категории раздела
Работа с библиотеками BASS и DirectShow [14]
Статьи по написанию mp3 плеера, видеоплеера, работе с WEB камерой и т.д.
Форма входа

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0


















Тиц
Главная » Статьи » Мультимедиа » Работа с библиотеками BASS и DirectShow

Урок 3.2. Учимся работать с Web камерой в Delphi (Грабим изображение с камеры в файл).
Содержание

Урок 2.1. Пишем видеоплеер (проигрыватель видео) на Delphi с использованием технологии DirectShow.

Урок 2.2. Пишем видеоплеер (проигрыватель видео) на Delphi с использованием технологии DirectShow (продолжение).

Урок 3.1. Учимся работать с Web камерой в Delphi через архитектуру DirectShow.

Урок 3.2. Учимся работать с Web камерой в Delphi (Грабим изображение с камеры в файл).

Урок 3.2.

Учимся работать с Web камерой в Delphi.

Учимся работать с Web камерой в Delphi (Грабим изображение с камеры в файл).        На этом уроке мы научимся грабить отдельные кадры изображения с камеры , сжимать их и записывать их в файл, а затем отправлять полученное изображение по FTP протоколу на хостинг для сайта. Другими словами мы создадим простейшую программу для трансляции изображений с Web камеры на страницу сайта с использованием DirectShow.








     Создадим новое приложение в Delphi.
Затем добавим и расположим компоненты на форму как показано на рисунке:

Учимся работать с Web камерой в Delphi (Грабим изображение с камеры в файл).

      Слева вверху расположена 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 секунд) укажите свое значение.
Сохраняем и тестируем приложение.

Учимся работать с Web камерой в Delphi (Грабим изображение с камеры в файл).

На сайте:

код автоподгрузки изображения с WEB камеры на сайте:
       Весь код приведен с подробными комментариями, думаю, что разобраться с ним будет не сложно. Если возникнут вопросы, пишите в комментариях.

В статье использованы материалы из книги "Есенин С.А. DirectX и Delphi. Разработка графических и мультимедийных приложений".

Спасибо за внимание.

Скачать исходники к статье можно здесь.

      В связи с возникающими вопросами по получению изображения с камеры выкладываю исходник, который просто позволяет получить изображение и поместить его на canvas.

Скачать исходники  можно здесь.

Автор статьи xaramamburu, сайт автора http://basicsprog.ucoz.ru .




Категория: Работа с библиотеками BASS и DirectShow | Добавил: xaramamburu (30.10.2011)
Просмотров: 27678 | Комментарии: 49 | Рейтинг: 5.0/4
Всего комментариев: 491 2 »
46  
Подскажите, пожалуйста, как выводить изображение только какой-то области камеры? то есть не все целиком, а например только квадрат изображения по центру?

0
47  
Можете попробовать создать еще один объект BitMap1:Tbitmap; и в него из bitmap скопировать часть изображения с помощью функции BitMap1.Canvas.CopyRect.... , затем устанавливаете с ним связь   JpegIm.Assign(Bitmap1); ну и т.д...)

48  
Я правильно понимаю, что нет способа настроить фильтр таким образом? Мне просто нужна не одна картинка из этой области, а такое же видео. То есть Вы предлагаете убрать вывод видео на панель и просто каждые 20мсек грабить картинку, преобразовывать и вставлять в Image?

0
49  
Насколько я помню (давно это было) фильтр SampleGrabber грабит кадр целиком, а далее вы можете делать с ним то, что хотите...)

45  
Уважаемый xaramamburu, а не могли бы Вы подсказать, как направить сразувидео поток, например по протоколу MMS ? smile

44  
А как транслировать в панель видео с камеры, но отразив его по вертикали/горизонтали?

37  
Подскажите пожалуйста: в окне свойств камеры не получается установить разрешение 1280х1024, выпадает "Ошибка при подключении" - "Данный формат не доступен", хотя камера такое разрешение поддерживает и в других программах работы с видео это реализуется. В соответствии с данным примером дается картинка только 640х480. Спасибо!

38  
Я не совсем понял, камера у вас совсем не работает в этой программе, или только при разрешении 1280х1024, а во всех других разрешениях работает? Вообще конечно, что бы сказать конкретнее, нужно иметь у себя вашу камеру, а то у меня две одна на ноуте 1.3 Мpix, а другая переносная 0.3 Mpix, обе без проблем работаю во всех режимах. Обычно ошибка которую вы указываете "Данный формат не доступен" возникает не из-за разрешения, а из-за формата цветопередачи (RGB24, YUY2 или других). Данный пример проверялся только для камер с RGB24 и как он будет работать если у камеры другой тип цветопередачи я не знаю, просто у меня нет таких камер. Возможно в этом случае нужно по другому строить граф фильтров. Попробуйте по экспериментировать с программой GraphStudio, посмотреть какой граф строит она для вашей камеры.)))

39  
Не работает только при разрешении 1280х1024, точнее работает только при разрешении 640х480, с меньшим разрешением тоже не хочет. В выпадающем списке "Цветовое пространство и сжатие" два варианта: YUY2 и MJPG. Спасибо за ответ!

40  
Как я и предполагал у вашей камеры совершенно другой вариант цветового пространства, поэтому скорее всего придется либо с помощью GraphStudio посмотреть какой граф нужно строить для вашей камеры ну и соответственно подправить код урока или пробовать определить тип медиаданных на выходе видеокамеры и использовать интеллектуальный режим построения графа начиная с выходного Pin видеокамеры.)))

33  
При попытке вызвать окно свойств fMpeg2, функция OleCreatePropertyFrame возвращает ошибку E_POINTER, хотя ничего не равно nil;
В вашем коде не видно, как вы задаёте имя файла для записи?
Я делаю так:
Код

  FileName := IncludeSlash(gettext(edit_RecPath1))+
  formatdatetime(cfg.RecordNameFormat,now);
pCaptureGraphBuilder.SetOutputFileName(CLSID_CMPEG2EncoderDS,StringToOleStr(FileN ame), fMpeg,pSink);
  SetVideoParams; // ставлю 15 fps

Затем:
Код

  fMpeg.QueryInterface(IID_ICodecAPI,pCodecAPI);
  bitrate := 100; //в каких единицах? я пробовал 6000000 (6 мегабит)
  Result := pCodecAPI.SetValue(CODECAPI_AVEncCommonMeanBitRate,bitrate);
  case Result of
  S_FALSE:
  t := 'S_FALSE';
  E_INVALIDARG:
  T := 'E_INVALIDARG';
  end;

Возвращает E_INVALIDARG. Справка по результатам тут: http://msdn.microsoft.com/en-us/library/windows/desktop/dd311966%28v=vs.85%29.aspx
То есть, толи GUID не правильный, толи значение.

34  
Наконец мне удалось подрубить фильтр MPEG2EncoderDS, и страница свойств фильтра перестала вызываться, хотя ошибок ни каких не выдается.


Цитата
В вашем коде не видно, как вы задаёте имя файла для записи?

Я все делаю аналогично вашему:
Result:=FCaptureGraphBuilder.SetOutputFileName(CLSID_CMPEG2EncoderDS, PWideChar(FileName), FMpeg, FSink);
if FAILED(Result) then EXIT;
 
Цитата
bitrate := 100; //в каких единицах? я пробовал 6000000 (6 мегабит)

Судя по всему в бит/с.

И наконец у меня получилось его изменить, делаю так:

//Получаю битрейт по умолчанию
Result:=FcodecAPI.GetDefaultValue(CODECAPI_AVEncCommonMeanBitRate, fvalue);
if FAILED(Result) then EXIT;

// Изменяю значение
Tvardata(fvalue).VLongWord:=120000;

//ну и задаю его фильтру
Result:=FcodecAPI.setValue(CODECAPI_AVEncCommonMeanBitRate, fvalue);
if FAILED(Result) then EXIT;

//А так можно узнать диапазон возможных значений где a, b, c: OleVariant смотрите справку msdn
Result:=FcodecAPI.GetParameterRange(CODECAPI_AVEncCommonMeanBitRate, a,b,c);
if FAILED(Result) then EXIT;
ShowMessage(string(a));
ShowMessage(string(b));

Вроде все работает, битрейт изменяется, но я писал без звука (микрофон не подключен), поэтому, что там будет со звуком сказать не могу.)))
Да, может тему на форум вынести, а то в комментариях как то не удобно?

35  
Спасибо! Битрейт изменился. Где вы это нашли?
Но теперь возникла другая проблема и другой вопрос, который, вы правы, лучше перенести на форум.
Сейчас это пока не важно. Работаю над статьёй про пины, которую обещал.

36  
Справка msdn и все тот же пример на C++, ссылку на который я вам давал выше. Единственная проблема была у меня, я ни как не мог передать новое значение битрейта фильтру, пока не до тумкал получить значение по умолчанию, определить его тип, а  потом его изменить. Иначе без значения по умолчанию и явному указанию типа, он никак не хочет его задавать.)))

25  
я сделал вот так:
Код

const
  CLSID_CMPEG2EncoderDS : TGUID = '{5F5AFF4A-2F7F-4279-88C2-CD88EB39D144}';
begin
  Result:=CoCreateInstance(CLSID_FilterGraph, NIL, CLSCTX_INPROC_SERVER,
  IID_IGraphBuilder, pGraphBuilder);
  Result:=CoCreateInstance(CLSID_CaptureGraphBuilder2, NIL, CLSCTX_INPROC_SERVER,
  IID_ICaptureGraphBuilder2, pCaptureGraphBuilder);
  pCaptureGraphBuilder.SetFiltergraph(pGraphBuilder);
  MArray1[ListBox1.ItemIndex].BindToObject(NIL, NIL, IID_IBaseFilter, fCap);
  pGraphBuilder.AddFilter(fCap, 'VideoCaptureFilter');
  pCaptureGraphBuilder.RenderStream(@pin_category_preview,@mediatype_video,
  fCap,nil,nil);
  fn := 'c:\2.mpg';
  pCaptureGraphBuilder.SetOutputFileName(CLSID_CMPEG2EncoderDS,StringToOleStr(fn),
  fWriter,pSink);
  pCaptureGraphBuilder.RenderStream(@pin_category_capture,@mediatype_video,
  fCap,fWriter,nil);

Запись пошла в MPEG со следующими параметрами: 640x480, 12 mbps, 30 fps
Теперь не пойму, через какой интерфейс можно настроить параметры записи? Например, как самому установить битрейт?

26  
Смотри комментарии 4 и 15 к этому уроку, функции были рабочие (правда я изменял только разрешение, все остальное не пробовал. И код для кнопки Buttun1 (параметры и разрешение камеры) в исходнике для этого урока, плюс код для кнопки
Button4 ( Вызов страницы свойств устройства работы с видео) из предыдущего урока.)))

27  
Код из поста 15 действительно меняет частоту кадров, но не влияет на размер файла. То есть, сколько бы кадров я ни поставил, видео пишется с 30 fps, просто делая задержку между кадрами. Получается, что код для меня бесполезен, так как размер файла записи не зависит от выставленной частоты кадров. Разрешение тоже изменить не удалось (но мне и не надо). Как еще можно изменить битрейт / fps? Чтобы писалось с реально выставленным fps. Но главное - битрейт.
Кстати, программа валится на строчке CoTaskMemFree(mt^.pbFormat); Если ее убрать, то работает. Что именно освобождает эта строчка? Без нее будет утечка памяти?
И еще:
Как смуксовать потоки, чтобы звук и видео писались в один файл MPG / TS? По-идее, нужно что-то типа MPEG-MUXER'а. Но ничего похожего я найти не могу. Есть только AVI Muxer, но для mpeg он не подходит.
Сейчас я беру с камеры изображение+звук и пишу их в отдельные файлы. А как писать в один? Пример из статьи не подходит, так как он для AVI.

28  
Со звуком разобрался. Надо просто прорендерить: pCaptureGraphBuilder.RenderStream(@pin_category_capture,@mediatype_audio,
FAudioCaptureFilter,fMpeg,nil);
.
Но заметил глюк. Записанное видео идет либо ускорено, либо замедлено. В чем дело?

29  
Здесь даже посоветовать ничего не могу.(((

32  
А я вот кое в чем разобрался))
lTVideoInfoHeader.AvgTimePerFrame:= 10000000 div 15;
Это не частота кадров, как таковая, а интервал смены кадра в наносекундах.
Это не влияет на запись (у меня пишет с 30-ю fps), но влияет на скорость смены кадров при воспроизведении. Делаю вывод, что эта структура содержит информацию, которая сообщает плееру, как воспроизводить файл. Думаю, что и MediaInfo берёт часть информации из этой структуры. По-этому, информация может не совпадать с реальными данными.
Моя камера (думаю, и ваша тоже) выдаёт 15 fps. Если передать структуре значение 15 (т.е. 15 fps), то записанное видео идет нормально без ускорения. Если передать больше, то видео ускорится. Чем больше передать, тем сильнее будет ускорение. На скорость звука это не влияет.
В связи с этим, возник вопрос. Можно ли узнать частоту кадров камеры, чтобы не угадывать ее самому?
И еще такой прикол: когда останавливаю и разрушаю граф, обрезается последняя секунда записи. Может между остановкой и разрушением надо задержку делать?

30  
Значит здесь у фильтра Mpeg2Encoder есть интерфейс ICodecAPI, а у него есть свойство AVEncCommonMeanBitRate которое задает битрейт. Вот ссылка на справку http://msdn.microsoft.com/en-us.....aspx ,
а вот пример на С++  http://www.codeproject.com/Questio....encoder , но к сожалению я тут целый вечер просидел, а подрубить этот интерфейс так и не смог.((( Windows XP сейчас у меня нет, поэтому посмотреть какой граф строится не могу, а проблема в том, что он не хочет писать видео в формате mpeg2 (показывает после записи кодек: 24 бит RGB 'RV24'), возможно просто фильтр не подгружается, отсюда и проблемы.))))

31  
А где взять константы CODECAPI_*?
Я вроде нашел их список, но там всё на C, такого вида:
Код

#define STATIC_CODECAPI_AVEncCommonMeanBitRate  0xf7222374, 0x2144, 0x4815, 0xb5, 0x50, 0xa3, 0x7f, 0x8e, 0x12, 0xee, 0x52

Как это будет выглядеть в Delphi? На C++ писал только ради общего ознакомления. 0xFF это вроде некое число в HEXADEMICAL? С этим мало знаком. Как их перевести в "нормальный" вид?
И что нужно передать в функцию [b]ICodecAPI::SetValue(avenccommonmeanbitrate,???); вторым аргументом?

24  
какие фильтры нужны для записи в MPEG или WMV?
Я пытался подключать WM_ASF_WRITER, но запись пошла только с очень маленьким разрешением и битрейтом. В delphi7 не объявлены функции и константы для работы с профилями Windows Media. И в интернете их, почему-то, нет. Где их можно достать?
Но больше хочется писать в MPEG, нежели в WMV. Что нужно для записи в MPEG?

21  
а как получить список всех имеющихся в системе видеорендереров?
CLSID_AudioRendererCategory есть, а CLSID_VideoRendererCategory почему-то нет.

22  
Фильтры WMR-7 и WMR-9 относятся к CLSID_LegacyAmFilterCategory, к какой категории относится стандартный VideoRenderer я не знаю.)))

23  
спасибо)

14  
Спасибо xaramamburu за данный материал!
Работающие исходники, подробные комментарии - чего еще надо)

Исходники позволили с наскока добавить необходимую функциональность
в свою поделку, ну вообще не вдаваясь в суть происходящего (=
Однако в дальнейшем, при необходимости, открываются возможности по наращиванию
функционала за счет использования DS уже с каким-то осознанием.

зы: В win8 мелкософт уже что-то намутил негативное для DS в окружении "мЕтро".
Ну и хОр с ним, надеюсь еще долго не придется уходить с предыдущих версий осей.

12  
Если заменить
MEDIASUBTYPE_RGB24
на 
 MEDIASUBTYPE_YUY2

То при попытке сграбить картинку вылезает ошибка.

13  
Какая? sad

1-10 11-17
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск
Наш опрос
Оцените мой сайт
Всего ответов: 532
Уголок общения



Copyright MyCorp © 2017Конструктор сайтов - uCoz