Capture de la vidéo

De Appmethod Topics
Aller à : navigation, rechercher

Remonter à Tutoriel : Audio-vidéo dans FireMonkey

Ce tutoriel montre comment capturer et afficher des données vidéo et comment personnaliser l'affichage des données vidéo avec FireMonkey.

Conception de la fiche

  1. Sélectionnez Fichier > Nouveau > Application multi-périphérique - Object Pascal > Application vide.
  2. Ajoutez un TLayout sur la fiche. La disposition ayant la focalisation, dans l'inspecteur d'objets, définissez la propriété Align sur MostBottom.
  3. Ajoutez les composants suivants au TLayout :
    • Un TButton pour commencer la capture et l'affichage des données.
    • Un TComboBox pour choisir le périphérique de capture vidéo à utiliser si plusieurs périphériques vidéo sont connectés à la station de travail.
  4. Remplacez le nom du bouton par Start.
  5. Spécifiez que Start sera désactivé en définissant la propriété Enable du bouton sur False.
  6. Ajoutez un TImage qui sera utilisé comme support pour l'affichage des données capturées. Définissez la propriété Align de l'image sur Center afin que les données vidéo soient affichées au centre de la fiche.
    La fiche doit ressembler à ceci :
    Video capturing Form Design.png

Implémentation

1. Incluez l'unité FMX.Media :
Object Pascal :
// Delphi version of the implementation
uses
 FMX.Media;
Appmethod C++ :
// C++ version of the implementation
#include <FMX.Media.hpp>
2. Déclarez un membre public TVideoCaptureDevice nommé VideoCamera à la classe TForm1 :
Object Pascal :
type
  TForm1 = class(TForm)
   // ...............
  public
    VideoCamera: TVideoCaptureDevice;
Appmethod C++ :
class TForm1 : public TForm
// ...............
public:
  TVideoCaptureDevice* VideoCamera;
3. Pour que les données capturées puissent s'afficher dans l'image, ajoutez les procédures SampleBufferReady et SampleBufferSync à TForm1 en tant que membres publics. SampleBufferReady est le gestionnaire d'événement associé à l'événement OnSampleBufferReady du périphérique de capture. Il appelle Synchronize pour garantir que l'affichage des données vidéo sur l'image est exécuté en utilisant le thread principal, ce qui évite les conflits multithread. SampleBufferSync effectue explicitement la mise en mémoire tampon des données vidéo sur l'image.
Voici les implémentations pour ces deux fonctions :
Object Pascal :
//Declaration 
  TForm1 = class(TForm)
   //.........
  public
    //........
    procedure SampleBufferSync;
    procedure SampleBufferReady(Sender: TObject; const ATime: TMediaTime);
  end;

// Implementation 
procedure TForm1.SampleBufferReady(Sender: TObject; const ATime: TMediaTime);
begin
  TThread.Synchronize(TThread.CurrentThread, SampleBufferSync);
  //Resize the image so that the video is buffered in its original size
  Image1.Width:=Image1.Bitmap.Width;
  Image1.Height:=Image1.Bitmap.Height;
end;

procedure TForm1.SampleBufferSync;
begin
  VideoCamera.SampleBufferToBitmap(Image1.Bitmap, true);
end;
Appmethod C++ :
// Declaration
class TForm1 : public TForm
//.........
public:
  //.........
  void __fastcall SampleBufferSync();
  void __fastcall SampleBufferReady(TObject *Sender, const TMediaTime ATime);

// Implementation
void __fastcall TForm1::SampleBufferReady(TObject *Sender, const TMediaTime ATime) {
  TThread::Synchronize(TThread::CurrentThread, (TThreadMethod)&SampleBufferSync);
  // Resize the image so that the video is buffered in its original size
  Image1->Width = Image1->Bitmap->Width;
  Image1->Height = Image1->Bitmap->Height;
}

void __fastcall TForm1::SampleBufferSync() {
  VideoCamera->SampleBufferToBitmap(Image1->Bitmap, true);
}
4. Remplissez la zone de liste déroulante de l'événement OnCreate de la fiche avec la liste de tous les périphériques vidéo connectés à la station de travail. Pour cela, utilisez la méthode GetDevicesByMediaType. Accédez à la méthode via la propriété Current du gestionnaire du périphérique de capture. Voici l'implémentation :
Object Pascal :
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;
Appmethod C++ :
void __fastcall TForm1::FormCreate(TObject *Sender) {
  TCaptureDeviceList DeviceList;
  int i;

  DeviceList = TCaptureDeviceManager::Current->GetDevicesByMediaType
	(TMediaType::Video);
  for (i = 0; i < DeviceList->Count; i++) {
    ComboBox1->Items->Add(DeviceList->Items[i]->Name);
  }
}
5. Sur l'événement OnChange de la zone de liste déroulante, initialisez VideoCamera en effectuant une identification du périphérique vidéo par son nom.
Object Pascal :
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  VideoCamera := TVideoCaptureDevice
    (TCaptureDeviceManager.Current.GetDevicesByName(ComboBox1.Selected.Text));
  if (VideoCamera <> nil) then
  begin
    StartButton.Enabled := true;
  end;
end;
Appmethod C++ :
void __fastcall TForm1::ComboBox1Change(TObject *Sender) {
  VideoCamera = dynamic_cast<TVideoCaptureDevice*>
	(TCaptureDeviceManager::Current->GetDevicesByName(ComboBox1->Selected->Text));
  if (VideoCamera != NULL) {
    StartButton->Enabled;
  }
}
6. Double-cliquez sur le bouton Start pour lui attacher des gestionnaires d'événement OnClick. Lorsque le processus de capture s'exécute, le bouton Start permet d'arrêter le processus.
Object Pascal :
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;
Appmethod C++ :
void __fastcall TForm1::StartButtonClick(TObject *Sender) {
  if (VideoCamera != NULL) {
    if (VideoCamera->State == TCaptureDeviceState::Stopped) {
      VideoCamera->OnSampleBufferReady = SampleBufferReady;
      VideoCamera->StartCapture();
      StartButton->Text = "Stop";
    }
    else {
      VideoCamera->StopCapture();
      StartButton->Text = "Start";
    }
  }
  else
    Caption = "Video capture devices not available.";
}
7. Assurez-vous que le périphérique de capture interrompt la capture si la fiche est fermée alors que le processus de capture continue, en appelant la méthode StopCapture à la destruction de la fiche.
Object Pascal :
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if VideoCamera <> nil then
    VideoCamera.StopCapture;
end;
Appmethod C++ :
void __fastcall TForm1::FormDestroy(TObject *Sender) {
  if (VideoCamera != NULL) {
    VideoCamera->StopCapture();
  }
}

Exécuter l'application

1. Pour exécuter le projet, appuyez sur F9.
2. Choisissez le périphérique vidéo dans la zone de liste déroulante.
3. Pour commencer la capture des données, appuyez sur le bouton Start. Les données capturées s'affichent au milieu de la fiche.

Personnaliser l'image capturée

Lors de l'étape suivante, vous pouvez appliquer les effets FireMonkey à l'image capturée dans la fiche en cours.

1. Pour pouvoir choisir différents effets, ajoutez un autre TComboBox à la disposition ajoutée précédemment. Spécifiez qu'il sera désactivé en définissant la propriété Enable du bouton sur False. Il sera activé lorsque le périphérique de capture commencera à fonctionner.
2. Remplissez la zone de liste déroulante ajoutée avec les effets FireMonkey actuellement disponibles en utilisant TFilterManager. Pour avoir accès aux effets et au filtre, incluez les unités FMX.Filter et FMX.Filter.Effects.
Object Pascal :
uses
 FMX.Media,FMX.Filter,FMX.Filter.Effects ;
Appmethod C++ :
#include <FMX.Filter.hpp>
#include <FMX.Filter.Effects.hpp>
3. Ajoutez en tant que membres publics un composant TImageFXEffect nommé Effect et une procédure FillComboxEffect. TImageFXEffect est la classe de base pour tous les effets d'image FireMonkey et Effect est utilisé pour conserver l'effet actuellement appliqué.
La procédure FillComboxEffect :
  • Obtient la liste des filtres actuellement disponibles.
  • Extrait le nom des filtres.
  • Construit le nom des effets à partir des noms de filtres (chaque filtre a défini un effet). Vous pouvez voir tous les effets dans la palette d'outils sous la catégorie Effets ou dans l'unité FMX.Filter.Effects.
  • Ajoute l'effet dans la liste de la zone de liste déroulante.
Voici l'implémentation :
Object Pascal :
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;
Appmethod C++ :
void __fastcall TForm1::FillComboxEffect() {
  int i, j, pos;
  TStrings *FiltersCategoryList, *FilterList;
  String str;
  TFilterClass filterClass;

  FiltersCategoryList = new TStringList();
  TFilterManager::FillCategory(FiltersCategoryList);
  for (j = 0; j < FiltersCategoryList->Count; j++) {
    FilterList = new TStringList();
    TFilterManager::FillFiltersInCategory
          	(FiltersCategoryList->operator[](j), FilterList);
    i = 0;
    for (i = 0; i < FilterList->Count; i++) {
      str = FilterList->operator[](i);
      pos = AnsiPos("Filter", str);
      if (pos != 0) {
	str.Delete(pos, 6);
      }
      str = "T" + str + "Effect";
      ComboBox2->Items->Append(str);
    }
    FilterList->Free();
  }
  FiltersCategoryList->Free();
  ComboBox2->Items->Add("None");
  ComboBox2->ItemIndex = ComboBox2->Items->IndexOf("None");
}
4. Appelez FillComboxEffect depuis le gestionnaire d'événement OnCreate de la fiche.
5. Définissez la zone de liste déroulante des effets comme activée depuis le gestionnaire d'événement OnChange de la première zone de liste déroulante (celle utilisée pour choisir le périphérique vidéo).
6. Ajoutez un événement OnChange pour la zone de liste déroulante des effets afin d'appliquer l'effet actuellement sélectionné sur l'image. Voici l'implémentation :
Object Pascal :
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;
Appmethod C++ :
void __fastcall TForm1::ComboBox2Change(TObject *Sender) {
  TFmxObjectClass filterClass;

  if (ComboBox2->ItemIndex != -1) {
    if (Effect != NULL) {
      Effect->Free();
    }
    if (ComboBox2->Selected->Text != "None") {
      filterClass = TFmxObjectClass(FindClass(ComboBox2->Selected->Text));
      if (filterClass != NULL) {
	Effect = dynamic_cast<TImageFXEffect *>(filterClass->InitInstance(this));
	Effect->Parent = Image1;
      }
    }
  }
}
7. Exécutez le projet, commencez la capture et observez comment les effets sont appliqués pendant la capture et l'affichage des données vidéo.

Suivant

Voir aussi