Aufzeichnen von Videos

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Tutorial: Audio-Video in FireMonkey

In diesem Tutorial wird gezeigt, wie Videodaten aufgezeichnet und angezeigt werden und wie die Darstellung der Videodaten mit FireMonkey angepasst wird.

Formularentwurf

  1. Wählen Sie Datei > Neu > Geräteübergreifende Anwendung - Delphi > Leere Anwendung.
  2. Fügen Sie dem Formular eine TLayout-Komponente hinzu. Setzen Sie im Objektinspektor die Eigenschaft Align der TLayout-Komponente auf MostBottom.
  3. Fügen Sie TLayout Folgendes hinzu:
    • Ein TButton-Steuerelement zum Starten der Aufzeichnung und Anzeigen der Daten.
    • Ein TComboBox-Steuerelement zum Auswählen des Video-Aufnahmegeräts, das verwendet wird, wenn mehrere Videogeräte am Computer angeschlossen sind.
  4. Ändern Sie den Namen der Schaltfläche in Start.
  5. Deaktivieren Sie Start durch Setzen der Eigenschaft Enable der Schaltfläche auf False.
  6. Fügen Sie ein TImage-Steuerelement zur Unterstützung der Anzeige der aufgezeichneten Daten hinzu. Setzen Sie die Eigenschaft Align des TImage-Steuerelements auf Center, damit die Videodaten in der Mitte des Formulars angezeigt werden.
    Das Formular sollte wie folgt aussehen:
    Video capturing Form Design.png

Implementierung

1. Fügen Sie die Unit FMX.Media hinzu:
Delphi:
// Delphi version of the implementation
uses
 FMX.Media;
C++Builder:
// C++ version of the implementation
#include <FMX.Media.hpp>
2. Deklarieren Sie in der Klasse TForm1 einen public-TVideoCaptureDevice-Member mit Namen VideoCamera:
Delphi:
type
  TForm1 = class(TForm)
   // ...............
  public
    VideoCamera: TVideoCaptureDevice;
C++Builder:
class TForm1 : public TForm
// ...............
public:
  TVideoCaptureDevice* VideoCamera;
3. Fügen Sie TForm1 die Prozeduren SampleBufferReady und SampleBufferSync als public-Member hinzu, damit die aufgezeichneten Daten in dem Bild angezeigt werden können. SampleBufferReady ist die im Ereignis OnSampleBufferReady des Aufnahmegeräts zugeordnete Ereignisbehandlungsroutine. Diese Routine ruft Synchronize auf, damit die Anzeige der Videodaten in dem Bild im Haupt-Thread ausgeführt wird, und so Multithread-Konflikte vermieden werden. SampleBufferSync puffert explizit die Videodaten für das Bild.
Die Implementierungen für diese beiden Funktionen lauten folgendermaßen:
Delphi:
//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;
C++Builder:
// 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. Füllen Sie das Kombinationsfeld im Ereignis OnCreate des Formulars mit einer Liste aller Videogeräte, die am Computer angeschlossen sind. Verwenden Sie dazu die Methode GetDevicesByMediaType. Greifen Sie auf die Methode über die Eigenschaft Current des Aufnahmegerätemanagers zu. Die Implementierung lautet folgendermaßen:
Delphi:
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;
C++Builder:
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. Initialisieren Sie VideoCamera im OnChange-Ereignis des Kombinationsfeldes mit dem Namen des Videogeräts.
Delphi:
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  VideoCamera := TVideoCaptureDevice
    (TCaptureDeviceManager.Current.GetDevicesByName(ComboBox1.Selected.Text));
  if (VideoCamera <> nil) then
  begin
    StartButton.Enabled := true;
  end;
end;
C++Builder:
void __fastcall TForm1::ComboBox1Change(TObject *Sender) {
  VideoCamera = dynamic_cast<TVideoCaptureDevice*>
	(TCaptureDeviceManager::Current->GetDevicesByName(ComboBox1->Selected->Text));
  if (VideoCamera != NULL) {
    StartButton->Enabled;
  }
}
6. Doppelklicken Sie auf die Schaltfläche Start, um OnClick-Ereignisbehandlungsroutinen hinzuzufügen. Bei Ausführung der Aufzeichnung wird mit der Schaltfläche Start die Aufzeichnung angehalten.
Delphi:
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;
C++Builder:
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. Stellen Sie sicher, dass das Aufnahmegerät die Aufzeichnung anhält, wenn das Formular geschlossen wird, indem die Methode StopCapture bei Freigabe des Formulars aufgerufen wird.
Delphi:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if VideoCamera <> nil then
    VideoCamera.StopCapture;
end;
C++Builder:
void __fastcall TForm1::FormDestroy(TObject *Sender) {
  if (VideoCamera != NULL) {
    VideoCamera->StopCapture();
  }
}

Ausführen der Anwendung

1. Drücken Sie F9, um das Projekt auszuführen.
2. Wählen Sie aus dem Kombinationsfeld ein Videogerät aus.
3. Drücken Sie die Schaltfläche Start, um die Datenaufzeichnung zu beginnen. Die aufgezeichneten Daten werden in der Mitte des Formulars angezeigt.

Anpassen des aufgezeichneten Bildes

Im nächsten Schritt können Sie für das aufgezeichnete Bild im aktuellen Formular FireMonkey-Effekte anwenden.

1. Fügen Sie dem oben hinzugefügten Layout ein weiteres TComboBox-Steuerelement hinzu, damit verschiedene Effekte ausgewählt werden können. Deaktivieren Sie das TComboBox-Steuerelement durch Setzen der Eigenschaft Enable auf False. Es wird aktiviert, wenn das Gerät mit der Aufnahme beginnt.
2. Füllen Sie das hinzugefügte Kombinationsfeld mit den aktuell verfügbaren FireMonkey-Effekten mithilfe von TFilterManager. Beziehen Sie die Units FMX.Filter und FMX.Filter.Effects ein, damit auf die Effekte und Filter zugegriffen werden kann.
Delphi:
uses
 FMX.Media,FMX.Filter,FMX.Filter.Effects ;
C++Builder:
#include <FMX.Filter.hpp>
#include <FMX.Filter.Effects.hpp>
3. Fügen Sie eine TImageFXEffect-Komponente mit dem Namen Effect und eine FillComboxEffect-Prozedur als public-Member hinzu. TImageFXEffect ist die Basisklasse für alle FireMonkey-Bildeffekte, und mit Effect wird der aktuell angewendete Effekt beibehalten.
Die Prozedur FillComboxEffect:
  • Ruft die Liste der aktuell verfügbaren Filter ab.
  • Extrahiert die Namen der Filter.
  • Erstellt die Namen der Effekte aus den Namen der Filter (für jeden Filter ist ein Effekt definiert). Alle Effekte befinden sich in der Tool-Palette in der Kategorie Effekte oder in der Unit FMX.Filter.Effects.
  • Fügt der Liste des Kombinationsfeldes den Effekt hinzu.
Die Implementierung lautet folgendermaßen:
Delphi:
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;
C++Builder:
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. Rufen Sie FillComboxEffect aus der Ereignisbehandlungsroutine OnCreate des Formulars auf.
5. Aktivieren Sie das Effekt-Kombinationsfeld in der Ereignisbehandlungsroutine OnChange des ersten Kombinationsfeldes (dasjenige für die Auswahl des Videogeräts).
6. Fügen Sie für das Effekt-Kombinationsfeld ein OnChange-Ereignis hinzu, um den aktuell ausgewählten Effekt auf das Bild anzuwenden. Die Implementierung lautet folgendermaßen:
Delphi:
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;
C++Builder:
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. Führen Sie das Projekt aus, beginnen Sie die Aufzeichnung und beobachten Sie, wie die Effekte bei der Aufnahme und Anzeige der Videodaten angewendet werden.

Weiter

Siehe auch