Construction d'un lecteur multimédia de base

De RAD Studio
Aller à : navigation, rechercher

Remonter à Tutoriel : Audio-vidéo dans FireMonkey

Ce tutoriel illustre comment construire un lecteur multimédia de base en utilisant TMediaPlayer et TMediaPlayerControl avec FireMonkey. Le lecteur multimédia contient des fonctions standard (lecture, pause, suivant et précédent) et offre la possibilité de manipuler le média en cours de lecture (volume et position en cours). Ce lecteur multimédia de base permet de charger un ensemble de fichiers multimédia dans un TListBox et d'en démarrer la lecture en double-cliquant sur un élément de la liste.

Conception de la fiche

  1. Sélectionnez Fichier > Nouveau > Application multi-périphérique - Delphi > Application vide.
  2. Ajoutez un TLayout à la fiche. La disposition ayant la focalisation, dans l'inspecteur d'objets, définissez la propriété Align sur Left et la propriété Name sur MainLayout. Redimensionnez MainLayout de façon à afficher des images vidéo.
  3. Ajoutez les éléments suivants à MainLayout :
    • Un TLayout. Nommez-le ControlPlayLayout et alignez-le sur le bas du MainLayout. Cette disposition contient tous les composants qui contrôlent le fichier multimédia.
    • Un TLayout. Nommez-le TextLayout et alignez-le sur le haut du MainLayout. Cette disposition contient les libellés utilisés pour afficher le nom et la durée du média en cours de lecture.
    • Un TMediaPlayerControl. Définissez sa propriété Align sur Client.
  4. Ajoutez les éléments suivants à ControlPlayLayout :
    • Cinq objets TButton, un pour chaque fonction standard d'un lecteur multimédia. Remplacez le nom des boutons par PreviousButton, PlayButton, PauseButton, StopButton et NextButton.
    • Deux objets TTrackBar : un pour contrôler le volume, l'autre pour contrôler la position en cours de lecture. Remplacez le nom des barres graduées par VolumeTrackBar et PositionTrackBar. Alignez PositionTrackBar sur le haut de ControlPlayLayout.
    • Un TCheckBox et nommez-le ShuffleCheckBox.
  5. Ajoutez deux objets TLabel à TextLayout : un pour afficher le nom du média en cours de lecture et l'autre pour afficher la durée totale des fichiers en cours de lecture en minutes et en secondes. Nommez les deux libellés NameLabel et DurationLabel. Définissez DurationLabel de façon à ce qu'il soit aligné sur la droite et définissez sa propriété AutoSize sur True. Définissez la propriété de Align de NameLabel sur Client et spécifiez que le texte sera affiché au centre en définissant sa propriété TextAlign sur Center.
  6. Ajoutez un autre TLayout à la fiche, définissez sa propriété Align sur Client et renommez-le PlayListLayout.
  7. Ajoutez les éléments suivants à PlayListLayout :
    • Un TLayout pour regrouper les boutons permettant de manipuler la sélection (playlist). Alignez la disposition nouvellement ajoutée sur le bas de son parent et renommez-la ControlPlayListLayout.
    • Un TListBox. Nommez-le PlayListBox et définissez sa propriété Align sur Client.
  8. Ajoutez trois objets TButton à PlayListLayout. Nommez-les LoadFileButton, ClearAllButton et ClearButton. Alignez les trois boutons sur la gauche de leur parent.
  9. Ajoutez les éléments suivants à la fiche :
    La fiche doit ressembler à ceci :
    Basic Media Player Form.png

Implémentation

L'implémentation peut être divisée en plusieurs étapes :

  1. Associer des actions standard à des contrôles standard
  2. Construire et manipuler la sélection
  3. Implémenter les fonctions de base d'un lecteur multimédia
  4. Implémenter les méthodes et classes utiles
  5. Personnaliser le fichier multimédia en cours de lecture

Associer des actions standard à des contrôles standard

Double-cliquez sur votre TActionList puis, sur l'éditeur de liste d'actions qui s'ouvre :

  1. Sélectionnez Nouveau > Nouvelle action standard.
  2. Sous Bibliothèque multimédia, sélectionnez les actions suivantes :
    • TMediaPlayerStop
    • TMediaPlayerCurrentTime
    • TMediaPlayerVolume
  3. Cliquez sur OK pour ajouter ces actions à votre composant liste d'actions.

A présent, configurez ces actions sur la propriété Action des contrôles suivants :

  • StopButton
  • PositionTrackBar
  • VolumeTrackBar

Construire et manipuler la sélection

1 Double-cliquez sur le bouton LoadFileButton pour lui attacher les gestionnaires d'événement OnClick et remplir la PlayListBox. L'appui sur LoadFileButton provoque l'ouverture de la boîte de dialogue Ouvrir. Sélectionnez un ou plusieurs fichiers devant être ajoutés à la liste lorsque l'utilisateur appuie sur le bouton OK de la boîte de dialogue Ouvrir.
Delphi :
procedure TForm1.LoadFileButtonClick(Sender: TObject);
var
  Files: TStrings;
  I: integer;
  MediaEntry: TMediaEntry;
begin
  // Sets the Filter so only the supported files to be displayed
  OpenDialog1.Filter := TMediaCodecManager.GetFilterString;
  if (OpenDialog1.Execute) then
  begin
    Files := OpenDialog1.Files;
    for I := 0 to Files.Count - 1 do
    begin
      MediaEntry := TMediaEntry.Create(Files[I]);
      PlayListBox.Items.AddObject(extractFileName(Files[I]), MediaEntry);
    end;
  end;
end;
C++Builder :
void __fastcall TForm1::LoadFileButtonClick(TObject *Sender) {
  int i;
  TMedia *Media;
  TStrings *Files = new TStringList();

  // Sets the Filter so only the supported files to be displayed
  OpenDialog1->Filter = TMediaCodecManager::GetFilterString();

  if (OpenDialog1->Execute()) {
    Files = OpenDialog1->Files;
    for (i = 0; i < Files->Count; i++) {
      Media = TMediaCodecManager::CreateFromFile(Files->operator[](i));
      PlayListBox->Items->AddObject
      (ExtractFileName((UnicodeString)Files->operator[](i)), Media);
    }
  }
}
2. Double-cliquez sur les boutons ClearAllButton et ClearButton pour leur attacher les gestionnaires d'événement OnClick.
ClearAllButton ClearButton
Delphi :
procedure TForm1.ClearAllButtonClick(Sender: TObject);
var
  I: integer;
begin
  if (PlayListBox.Count > 0) then
  begin
    for I := 0 to PlayListBox.Count - 1 do
      PlayListBox.Items.Objects[I].Free;
    PlayListBox.Clear;
    PlayListBox.ItemIndex := -1;
    SetLength(Played, 0);
    CurrentPlayedIndex := -1;
    MediaPlayer1.Clear;
    NameLabel.Text := '';
    DurationLabel.Text := '';
  end;
end;
C++Builder :
void __fastcall TForm1::ClearAllButtonClick(TObject *Sender) {
  int i;
  if (PlayListBox->Count > 0) {
    for (i = 0; i < PlayListBox->Count; i++) {
      PlayListBox->Items->Objects[i]->Free();
    }

    PlayListBox->Clear();
    PlayListBox->ItemIndex = -1;
    Played.resize(0);
    CurrentPlayedIndex = -1;
    MediaPlayer1->Clear();
    NameLabel->Text = "";
    DurationLabel->Text = "";
  }
}
Delphi :
procedure TForm1.ClearButtonClick(Sender: TObject);
var
  I, J: integer;
begin
  if PlayListBox.Count < 0 then
    Exit;
  PlayListBox.Items.Objects[PlayListBox.ItemIndex].Free;
  PlayListBox.Items.Delete(PlayListBox.ItemIndex);
  J := 0;
  // Makes sure that the deleted media is not on the Playlist
  while J < Length(Played) - 1 do
  begin
    if (Played[J] = PlayListBox.ItemIndex) then
    begin
      for I := J to Length(Played) - 1 do
        Played[I] := Played[I + 1];
      SetLength(Played, Length(Played) - 1);
    end;
    J := J + 1;
  end;
end;
C++Builder :
void __fastcall TForm1::ClearButtonClick(TObject *Sender) {
  unsigned int i, j;
  if (PlayListBox->Count < 0) {
    return;
  }

  PlayListBox->Items->Objects[PlayListBox->ItemIndex]->Free();
  PlayListBox->Items->Delete(PlayListBox->ItemIndex);
  j = 0;
  // Makes sure that the deleted media is not on the Playlist
  while (j < Played.size() - 1) {
    if (Played[j] == PlayListBox->ItemIndex) {
      for (i = j; i < Played.size(); i++) {
    Played[i] = Played[i + 1];
      }
      Played.resize(Played.size() - 1);
    }
    j += 1;
  }
}
3. Pour éviter de garder en mémoire des objets qui ne sont plus utilisés, assurez-vous que chaque objet ajouté à PlayListBox est libéré de la mémoire. Lorsque vous retirez un élément de PlayListBox, seul le lien existant entre l'élément de la zone de liste et l'objet attaché est libéré ; l'objet reste alloué en mémoire.
Delphi :
procedure TForm1.FormDestroy(Sender: TObject);
var
  I: integer;
begin
  if (PlayListBox.Count > 0) then
    for I := 0 to PlayListBox.Count - 1 do
      PlayListBox.Items.Objects[I].Free;
end;
C++Builder :
void __fastcall TForm1::FormDestroy(TObject *Sender) {
  int i;
  if (PlayListBox->Count > 0) {
    for (i = 0; i < PlayListBox->Count; i++) {
      PlayListBox->Items->Objects[i]->Free();
    }
  }
}

Implémenter les fonctions de base d'un lecteur multimédia

Pour démarrer le lecteur, appuyez sur PlayButton, NextButton ou double-cliquez sur un élément de la sélection (playlist). Attachez un gestionnaire d'événement OnDblClick au PlayListBox. Double-cliquez sur chacun des boutons du ControlPlayLayout pour leur attacher les gestionnaires d'événement OnClick et implémenter les fonctions de base d'un lecteur multimédia.

PlayButton

PlayListBoxDblClick

Delphi :
procedure TForm1.PlayButtonClick(Sender: TObject);
begin
  if MediaPlayer1.Media <> nil then
  begin
    if (MediaPlayer1.State = TMediaState.Stopped) and
      (MediaPlayer1.CurrentTime < MediaPlayer1.Duration) then
    begin
      MediaPlayer1.Play;
      DisplayText(extractFileName(MediaPlayer1.FileName));
    end
    else
    begin
      MediaPlayer1.CurrentTime := 0;
    end;
  end
  else
  begin
    if (PlayListBox.Count = 0) then
      Exit;
    if (PlayListBox.ItemIndex = -1) then
      PlayListBox.ItemIndex := 0;
    FindAndPlay(PlayListBox.ItemIndex);
    if (ShuffleCheckBox.IsChecked) then
      AddToPlayedList(PlayListBox.ItemIndex);
  end;
end;
C++Builder :
void __fastcall TForm1::PlaybuttonClick(TObject *Sender) {
  if (MediaPlayer1->Media != NULL) {
    if ((MediaPlayer1->State == TMediaState::Stopped) &&
     (MediaPlayer1->CurrentTime < MediaPlayer1->Duration)) {
      MediaPlayer1->Play();
      DisplayText(ExtractFileName(MediaPlayer1->FileName));
    }
    else
      MediaPlayer1->CurrentTime = 0;
  }
  else {
    if (PlayListBox->Count == 0) {
      return;
    }
    if (PlayListBox->ItemIndex == -1) {
      PlayListBox->ItemIndex = 0;
    }
    FindAndPlay(PlayListBox->ItemIndex);
    if (ShuffleCheckBox->IsChecked) {
      AddToPlayedList(PlayListBox->ItemIndex);
    }
  }
}
Delphi :
procedure TForm1.PlayListBoxDblClick(Sender: TObject);
begin
  if (PlayListBox.Count < 0) then
    Exit;
  MediaPlayer1.Clear;
  MediaPlayer1.FileName:= TMediaEntry(
    PlayListBox.Items.Objects[PlayListBox.ItemIndex]).Path;
  if MediaPlayer1.Media <> nil then
  begin
    MediaPlayer1.Play;
    DisplayText(extractFileName(MediaPlayer1.FileName));
    AddToPlayedList(PlayListBox.Items.IndexOf
      (extractFileName(MediaPlayer1.FileName)));
  end;
end;
C++Builder :
void __fastcall TForm1::PlayListBoxDblClick(TObject *Sender) {
  if (PlayListBox->Count < 0) {
    return;
  }
  MediaPlayer1->Clear();
  MediaPlayer1->FileName = dynamic_cast<TMedia *>
      (PlayListBox->Items->Objects[PlayListBox->ItemIndex])->FileName;

  if (MediaPlayer1->Media != NULL) {
    MediaPlayer1->Play();
    DisplayText(ExtractFileName(MediaPlayer1->FileName));
    AddToPlayedList(PlayListBox->Items->IndexOf
        (ExtractFileName(MediaPlayer1->FileName)));
  }
}

PauseButton

NextButton

Delphi :
procedure TForm1.PauseButtonClick(Sender: TObject);
begin
  if MediaPlayer1.Media <> nil then
    MediaPlayer1.Stop;
end;
C++Builder :
void __fastcall TForm1::PauseButtonClick(TObject *Sender) {
  if (MediaPlayer1->Media != NULL) {
    MediaPlayer1->Stop();
  }
}
Delphi :
procedure TForm1.NextButtonClick(Sender: TObject);
begin
  if (PlayListBox.Count > 0) then
  begin
    PlayNext;
  end;
end;
C++Builder :
void __fastcall TForm1::NextButtonClick(TObject *Sender) {
  if (PlayListBox->Count > 0) {
    PlayNext();
  }
}

PreviousButton

Delphi :
procedure TForm1.PreviousButtonClick(Sender: TObject);
begin
  if ShuffleCheckBox.IsChecked then
  begin
    if (Length(Played) > 0) and (CurrentPlayedIndex > 0) then
    begin
      CurrentPlayedIndex := CurrentPlayedIndex - 1;
      FindAndPlay(Played[CurrentPlayedIndex]);
      PlayListBox.ItemIndex := Played[CurrentPlayedIndex];
    end;
  end
  else if (PlayListBox.ItemIndex > 0) then
  begin
    FindAndPlay(PlayListBox.ItemIndex - 1);
    PlayListBox.ItemIndex := PlayListBox.ItemIndex - 1;
  end;
end;
C++Builder :
void __fastcall TForm1::PreviousButtonClick(TObject *Sender) {
  if (ShuffleCheckBox->IsChecked) {
    if ((Played.size() > 0) && (CurrentPlayedIndex > 0)) {
      CurrentPlayedIndex = CurrentPlayedIndex - 1;
      FindAndPlay(Played[CurrentPlayedIndex]);
      PlayListBox->ItemIndex = Played[CurrentPlayedIndex];
    }
  }
  else
    if (PlayListBox->ItemIndex > 0) {
      FindAndPlay(PlayListBox->ItemIndex - 1);
      PlayListBox->ItemIndex = PlayListBox->ItemIndex - 1;
    }
}

Implémenter les méthodes et les classes utiles

1. Ajoutez les membres publics suivants à la classe TForm1 :
Delphi :
  public
    { Public declarations }
    Played: array of integer;
    CurrentPlayedIndex: integer;
    procedure AddToPlayedList(Index: integer);
    procedure DisplayText(str: string);
    procedure PlayNext();
    procedure FindAndPlay(Index: integer);
  end;

  TMediaEntry = class(TObject)
  public
    Path: String;
    constructor Create(FilePath: String);
  end;
C++Builder :
public:   // User declarations
  std::vector<int> Played;
  unsigned int CurrentPlayedIndex;
  void __fastcall AddToPlayedList(int index);
  void __fastcall DisplayText(String s);
  void __fastcall PlayNext();
  void __fastcall FindAndPlay(int index);
};

class TMediaEntry : public TObject
{
public:
  TMediaEntry(UnicodeString FilePath);
  UnicodeString Path;
};
2. Le tableau Played est utilisé pour garder les index des fichiers multimédia lus dans PlayListBox lorsque le lecteur multimédia fonctionne en mode Shuffle (ShuffleChekBox est activé). Le fichier multimédia en cours de lecture est enregistré de façon à obtenir le média précédent ou suivant. CurrentPlayedIndex conserve l'index du média en cours de lecture dans Played. La méthode AddToPlayedList ajoute un média spécifié à la liste Played.
Delphi :
procedure TForm1.AddToPlayedList(Index: integer);
var
  Len: integer;
begin
  Len := Length(Played);
  SetLength(Played, Len + 1);
  Played[Len] := Index;
  CurrentPlayedIndex := Len;
  PlayListBox.ItemIndex := index;
end;
C++Builder :
void __fastcall TForm1::AddToPlayedList(int index) {
  int len;

  len = Played.size();
  Played.resize(len + 1);
  Played[len] = index;
  CurrentPlayedIndex = len;
  PlayListBox->ItemIndex = index;
}
3. La méthode FindAndPlay identifie le média à lire grâce à l'index contenu dans PlayListBox. PlayNext obtient ensuite l'index du média à lire puis appelle FindAndPlay pour identifier et lire le média avec l'index calculé.
FindAndPlay PlayNext
Delphi :
procedure TForm1.FindAndPlay(Index: integer);
begin
  MediaPlayer1.Clear;
  PositionTrackBar.Value := PositionTrackBar.Min;
  if Index >= PlayListBox.Items.Count then
    Index := 0;
  MediaPlayer1.FileName := TMediaEntry(PlayListBox.Items.Objects[Index]).Path;
  if MediaPlayer1.Media <> nil then
  begin
    MediaPlayer1.Play;
    DisplayText(extractFileName(MediaPlayer1.FileName));
  end;
end;
C++Builder :
void __fastcall TForm1::FindAndPlay(int index) {
  MediaPlayer1->Clear();
  PositionTrackBar->Value = PositionTrackBar->Min;
  MediaPlayer1->FileName = dynamic_cast<TMedia*>
          (PlayListBox->Items->Objects[index])->FileName;
  if (MediaPlayer1->Media != NULL) {
    MediaPlayer1->Play();
    DisplayText(ExtractFileName(MediaPlayer1->FileName));
  }
}
Delphi :
procedure TForm1.PlayNext();
var
  Index: integer;
begin
  if (ShuffleCheckBox.IsChecked) then
  begin
    if (CurrentPlayedIndex < Length(Played) - 1) then
    begin
      CurrentPlayedIndex := CurrentPlayedIndex + 1;
      FindAndPlay(Played[CurrentPlayedIndex]);
    end
    else
    begin
      Index := Random(PlayListBox.Count - 1);
      FindAndPlay(Index);
      AddToPlayedList(Index);
    end;
    PlayListBox.ItemIndex := Played[CurrentPlayedIndex];
  end
  else
  begin
    FindAndPlay(PlayListBox.ItemIndex + 1);
    PlayListBox.ItemIndex := PlayListBox.ItemIndex + 1;
  end;
end;
C++Builder :
void __fastcall TForm1::PlayNext() {
  unsigned int index;

  if (ShuffleCheckBox->IsChecked) {
    if (CurrentPlayedIndex < Played.size() - 1) {
      CurrentPlayedIndex = CurrentPlayedIndex + 1;
      FindAndPlay(Played[CurrentPlayedIndex]);
    }
    else {
      index = Random(PlayListBox->Count - 1);
      FindAndPlay(index);
      AddToPlayedList(index);
    }
    PlayListBox->ItemIndex = Played[CurrentPlayedIndex];
  }
  else {
    FindAndPlay(PlayListBox->ItemIndex + 1);
    PlayListBox->ItemIndex = PlayListBox->ItemIndex + 1;
  }
}
4. DisplayText affiche le nom et la durée (en minutes et secondes) du média en cours de lecture.
Delphi :
procedure TForm1.DisplayText(str: string);
var
  DurationMin, DurationSec: integer;
begin
  NameLabel.Text := str;
  DurationMin := MediaPlayer1.Duration div 10000 div 60000;
  DurationSec := MediaPlayer1.Duration div 10000 mod 60000 div 1000;
  DurationLabel.Text := IntToStr(DurationMin) + ':' + IntToStr(DurationSec);
end;
C++Builder :
void __fastcall TForm1::DisplayText(String s) {
  int DurationMin, DurationSec;
  NameLabel->Text = s;
  DurationMin = MediaPlayer1->Duration / 10000 / 60000;
  DurationSec = MediaPlayer1->Duration / 10000 % 60000 / 1000;
  DurationLabel->Text = IntToStr(DurationMin) + ':' + IntToStr(DurationSec);
}
5. TMediaEntry encapsule le chemin d'accès absolu d'un fichier multimédia à partir de la sélection, TListBox permettant de stocker une instance de sous-classe TObject en même temps que chaque entrée de la zone de liste. Définissez son constructeur comme suit :
Delphi :
constructor TMediaEntry.Create(FilePath: String);
begin
  Path := FilePath;
end;
C++Builder :
TMediaPlayer::TMediaPlayer(UnicodeString FilePath)
: Path(FilePath)
{
}

Personnaliser le fichier multimédia en cours de lecture

1. Lire le fichier multimédia suivant

Pour que le lecteur multimédia lise le fichier multimédia suivant à la fin de la lecture du fichier en cours, utilisez le TTimer sur un certain intervalle.

Double-cliquez sur le TTimer pour lui attacher les gestionnaires d'événement OnTimer.

Delphi :
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  // When the current media ends the player starts playing
  // the next media in playlist
  if (MediaPlayer1.State = TMediaState.Playing) and
    (MediaPlayer1.CurrentTime = MediaPlayer1.Duration) then
    PlayNext;
end;
C++Builder :
void __fastcall TForm1::Timer1Timer(TObject *Sender) {
  PositionTrackBar->Tag = 1;
  PositionTrackBar->Value = MediaPlayer1->CurrentTime;
  PositionTrackBar->Tag = 0;
  // When the current media ends the player starts playing
  // the next media in playlist
  if ((MediaPlayer1->State == TMediaState::Playing) &&
        (MediaPlayer1->CurrentTime == MediaPlayer1->Duration)) {
    PlayNext();
  }
}
2. Activer/désactiver le mode shuffle (mode aléatoire)

Si ShuffleCheckBox n'est pas activée, le prochain fichier multimédia devant être lu est le média suivant dans PlayListBox. Si la case à cocher est activée, le prochain fichier multimédia à être lu sera un média aléatoire dans PlayListBox. Si le lecteur multimédia n'est pas configuré en mode shuffle, il n'est pas nécessaire d'utiliser le vecteur Played, car l'ordre de lecture est le même que l'ordre défini dans PlayListBox.

Delphi :
procedure TForm1.ShuffleCheckBoxChange(Sender: TObject);
begin
  If (not ShuffleCheckBox.IsChecked) then
  begin
    SetLength(Played, 0);
    CurrentPlayedIndex := -1;
  end;
end;
C++Builder :
void __fastcall TForm1::ShuffleCheckBoxChange(TObject *Sender) {
  if (!ShuffleCheckBox->IsChecked) {
    Played.resize(0);
    CurrentPlayedIndex = -1;
  }
}

Exécuter l'application

1. Pour exécuter le projet, appuyez sur F9.
2. Chargez les fichiers dans PlayListBox en appuyant sur le bouton LoadFileButton.
3. Démarrez le lecteur multimédia en appuyant sur PlayButton ou NextButton ou en double-cliquant sur un élément de PlayListBox.

Précédent

Voir aussi