Tutorial: How to Capture and Display Video with FireMonkey FM2

By: Tim DelChiaro

Abstract: This tutorial demonstrates how to capture, display and customize on displaying video data with FireMonkey

This tutorial is part of the RAD Studio XE3 online documentation. Links in the article go to the Embarcadero Doc Wiki. 

To follow along with these steps, you can buy or download a trial of an Embarcadero developer tool with FireMonkey including Delphi, C++Builder and RAD Studio.


    Form Design

  1. Select File > New > FireMonkey Desktop Application - Delphi > HD FireMonkey Application.
  2. Add a TLayout to the form. With the the layout in focus, set in Object InspectorAlign property to alMostBotoom.
  3. To the TLayout add:
    • TButton to start capturing and displaying data.
    • TComboBox to choose the video capturing device that will be used, if there multiple video devices connected to the station work.
  4. Change the name of the button to Start.
  5. Set the Start as being disabled by setting the Enable property of the button to False.
  6. Add a TImage to be use as support for displaying the captured data. Set the Align property of the image to alCenter, so the video data to be displayed on the center of the form .
    The form should look like this:
    File:Video capturing Form Design.png

    Implementation

1. Include the FMX.Media unit in the uses section:
// Delphi version of the implementation
uses
 FMX.Media;
2.Declare a TVideoCaptureDevice public member, named VideoCamera to the TForm1 class:
type
  TForm1 = class(TForm)
   // ...............
  public
    VideoCamera: TVideoCaptureDevice;
3. To be able to display the captured data to the image add as public members SampleBufferReady and SampleBufferSync procedures to the TForm1SampleBufferReadyis the event handler associated to the OnSampleBufferReady event of the capturing device. It calls Synchronize to make sure that displaying of the video data on the image is executed using the main thread, thereby avoiding multithread conflicts. SampleBufferSync explicitly buffers the video data on the image.
There are the implementations for this two functions:
//Declaration 
  TForm1 = class(TForm)
   //.........
  public
    //........
    procedure SampleBufferSync;
    procedure SampleBufferReady(Sender: TObject; const ATime: TMediaTime);
  end;
procedure TForm1.SampleBufferReady(Sender: TObject; const ATime: TMediaTime);
begin
  TThread.Synchronize(TThread.CurrentThread, SampleBufferSync);
  //Resize the image so the video to be buffered on its original size.
  Image1.Width:=Image1.Bitmap.Width;
  Image1.Height:=Image1.Bitmap.Height;
end;
 
procedure TForm1.SampleBufferSync;
begin
  VideoCamera.SampleBufferToBitmap(Image1.Bitmap, true);
end;
4 Populate the combo box the OnCreate event of the form, with a list of all video devices connected to the station. Do this by using GetDevicesByMediaType method. Access the method trough Current property of the capturing device manager. This is the implementation:
procedure TForm1.FormCreate(Sender: TObject);
var
  DeviceList: TCaptureDeviceList;
  i: integer;
begin
  DeviceList := TCaptureDeviceManager.Current.GetDevicesByMediaType
    (TMediaType.Video);
  for i := 0 to DeviceList.Count - 1 do
  begin
    ComboBox1.Items.Add(DeviceList[i].Name);
  end;
end;
5. On the OnChange event of the combo box initialize VideoCamera by identifying the video device by name.
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  VideoCamera := TVideoCaptureDevice
    (TCaptureDeviceManager.Current.GetDevicesByName(ComboBox1.Selected.Text));
  if (VideoCamera <> nil) then
  begin
    StartButton.Enabled := true;
  end;
end;
5. Double-click the Start button to attach OnClick event handlers to it. When the capturing process s running, the Start button is used to stop the process.
procedure TForm1.StartButtonClick(Sender: TObject);
begin
  if (VideoCamera <> nil) then
  begin
    if (VideoCamera.State = TCaptureDeviceState.Stopped) then
    begin
      VideoCamera.OnSampleBufferReady := SampleBufferReady;
      VideoCamera.StartCapture;
      StartButton.Text := 'Stop';
    end
    else
    begin
      VideoCamera.StopCapture;
      StartButton.Text := 'Start';
    end;
  end
  else
  begin
    Caption := 'Video capture devices not available.';
  end;
end;
6. Make sure that the capturing device stops capturing if the form is closed when the capturing process is still working, by calling the StopCapture method when the form is destroyed.
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if VideoCamera <> nil then
    VideoCamera.StopCapture;
end;

    Run the Application

1. Run the project by pressing F9.
2. Choose a video devise from combo box.
3. Press the Start button to start capturing data. The captured data will be displayed in the middle of the form.

    Customize the captured image

In the next step, to the current form, is added the possibility to apply FireMonkey effects over the captured image.

1. In order to have the possibility to choose different effects, add an other TComboBox to the layout added above. Set the it as being disabled by setting the Enable property of the button to False. It will be enabled when the capturing device starts working.
2. Populate the added combo box with the current available FireMonkey effects using the TFilterManager. To have access to effects and filter, include FMX.Filter andFMX.Filter.Effects units.
uses
 FMX.Media,FMX.Filter,FMX.Filter.Effects ;
3. Add as public members a TImageFXEffect component named Effect and FillComboxEffect procedure. TImageFXEffect is the base class for all FireMonkey image effects andEffect is used to keep the current effect applied.
FillComboxEffect procedure :
  • gets the list of current available filters.
  • extracts the name of the filters.
  • builds the the name of the effects from filter's names (each filter has defined an effect). You can see all effects in Tool Palette under Effects Category or going toFMX.Filter.Effects unit.
  • adds the effect in the combo box list.
This is the implementation:
procedure TForm1.FillComboxEffect();
var
  i, j, pos: integer;
  FiltersCategoryList, FilterList: TStrings;
  str: string;
  filterClass: TFilterClass;
begin
  FiltersCategoryList := TStringList.Create;
  TFilterManager.FillCategory(FiltersCategoryList);
  for j := 0 to FiltersCategoryList.Count - 1 do
  begin
    FilterList := TStringList.Create;
    TFilterManager.FillFiltersInCategory(FiltersCategoryList[j], FilterList);
    i := 0;
    for i := 0 to FilterList.Count - 1 do
    begin
      str := FilterList[i];
      pos := AnsiPos('Filter', str);
      if (pos <> 0) then
        Delete(str, pos, 6);
      str := 'T' + str + 'Effect';
      ComboBox2.Items.Append(str);
    end;
    FilterList.Free;
  end;
  FiltersCategoryList.Free;
  ComboBox2.Items.Add('None');
  ComboBox2.ItemIndex:=ComboBox2.Items.IndexOf('None');
end;
4. Call FillComboxEffect from the OnCreate event handler of the form.
5. Sett the effect combo box as enable from the OnChange event handler of the first combo box (the one used to choose the video device),
6. Add an OnChange event for the effect combo box, to apply the current selected effect over the image. This is the implementation:
procedure TForm1.ComboBox2Change(Sender: TObject);
var
  filterClass: TFmxObjectClass;
begin
  if (ComboBox2.ItemIndex <> -1) then
  begin
    if Assigned(Effect) then
      Effect.Free;
    if (ComboBox2.Selected.Text <> 'None') then
    begin
      filterClass := TFmxObjectClass(FindClass(ComboBox2.Selected.Text));
      if Assigned(filterClass) then
      begin
        Effect := TImageFXEffect(filterClass.Create(self));
        Effect.Parent := Image1;
      end;
    end;
  end;
end;
7.Run the project, start capturing and observe how the effects are applied while the video data are captured and displayed.

Server Response from: ETNASC03