基本的なメディア プレーヤーの作成

提供: RAD Studio
移動先: 案内検索

チュートリアル:FireMonkey のオーディオ/ビデオ機能 への移動

このチュートリアルでは、FireMonkey で TMediaPlayerTMediaPlayerControl を使用して、基本的なメディア プレーヤーを作成する方法を具体的に説明します。このメディア プレーヤーには、標準の機能(再生、停止、次および前)が含まれているほかに、現在再生中のメディアを操作する機能(音量および現在位置)もあります。この基本のメディア プレーヤーでは、一連のメディア ファイルを TListBox に読み込み、リスト中の項目をダブルクリックして再生を開始することもできます。

フォームの設計

  1. [ファイル|新規作成|マルチデバイス アプリケーション - Delphi|空のアプリケーションを選択します。
  2. TLayout をフォームに追加します。そのレイアウトを選択した状態で、[オブジェクト インスペクタ]Align プロパティを Left に、Name プロパティを「MainLayout」に設定します。MainLayout のサイズを、ビデオの映像を表示するのに必要と思われるサイズに変更します。
  3. MainLayout に以下を追加します。
    • TLayout。「ControlPlayLayout」という名前を付け、MainLayout の下端に揃えて配置します。このレイアウトには、メディア ファイルを制御するすべてのコンポーネントを含めます。
    • TLayout。「TextLayout」という名前を付け、MainLayout の上端に揃えて配置します。このレイアウトには、現在再生中のメディアの名前と時間を表示するためのラベルを含めます。
    • TMediaPlayerControlAlign プロパティを Client に設定します。
  4. ControlPlayLayout に以下を追加します。
    • メディア プレーヤーの標準機能ごとに 1 つ、合計 5 つの TButton。ボタンの名前を、「PreviousButton」、「PlayButton」、「PauseButton」、「StopButton」、「NextButton」に変更します。
    • 2 つの TTrackBar オブジェクト。1 つは音量を制御するためのもの、もう 1 つは現在の再生位置を制御するためのものです。トラック バーの名前を「VolumeTrackBar」と「PositionTrackBar」に変更します。PositionTrackBarControlPlayLayout の上端に揃えて配置します。
    • TCheckBox。「ShuffleCheckBox」という名前を付けます。
  5. 2 つの TLabel オブジェクトを TextLayout に追加します。1 つは現在再生中のメディアの名前を表示するためのもの、もう 1 つは現在再生中のファイルの総時間を分および秒で表示するためのものです。2 つのラベルに「NameLabel」および「DurationLabel」という名前を付けます。DurationLabel を右揃えで配置し、AutoSize プロパティを True に設定します。NameLabelAlign プロパティを Client に設定し、テキストが中央に表示されるよう TextSettings.HorzAlign プロパティを Center に設定します。
  6. フォームに TLayout をもう 1 つ追加し、その Align プロパティを Client に設定し、名前を「PlayListLayout」に変更します。
  7. PlayListLayout に以下を追加します。
    • プレイリストの操作に使用するボタンをまとめるための TLayout。追加したこのレイアウトを親の下端に揃えて配置し、名前を「ControlPlayListLayout」に変更します。
    • TListBox。名前を「PlayListBox」に、Align プロパティを Client に設定します。
  8. TButton オブジェクトを 3 つ PlayListLayout に追加します。名前を「LoadFileButton」、「ClearAllButton」、「ClearButton」に設定します。3 つのボタンすべてを親の左に配置します。
  9. フォームに以下を追加します。
    フォームは次のようになります。
    Basic Media Player Form.png

実装

実装は複数のステップに分けて行うことができます。

  1. 標準アクションと標準コントロールの関連付け
  2. プレイリストの作成と操作
  3. メディア プレーヤーの基本機能の実装
  4. 有用なメソッドとクラスの実装
  5. 現在再生中のメディア ファイルのカスタマイズ

標準アクションと標準コントロールの関連付け

TActionList をダブルクリックします。開いたアクション リスト エディタで以下を行います。

  1. [新規アクション|標準アクションの新規追加...]を選択します。
  2. Media Library 下で次のアクションを選択します。
    • TMediaPlayerStop
    • TMediaPlayerCurrentTime
    • TMediaPlayerVolume
  3. [OK]をクリックすると、これらのアクションがアクション リスト コンポーネントに追加されます。

ここで、以下のコントロールの Action プロパティにこれらのアクションを構成します。

  • StopButton
  • PositionTrackBar
  • VolumeTrackBar

プレイリストの作成と操作

1. LoadFileButton ボタンをダブルクリックして、OnClick イベント ハンドラをそれに追加し、PlayListBox の内容を設定できるようにします。 LoadFileButton が押されると、ファイル選択ダイアログ ウィンドウが開きます。 1 つまたは複数のファイルを選択し、ファイル選択ダイアログ ウィンドウの[開く]ボタンを押すと、ファイルがリストに追加されます。
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. ClearAllButton ボタンおよび ClearButton ボタンをダブルクリックして、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. もう使用しないメモリ オブジェクトを保持し続けることがないよう、PlayListBox に追加されたどのオブジェクトも必ず解放されるようにしてください。PlayListBox から項目を削除しても、リスト ボックスの項目とそれに結び付けられたオブジェクトとの間のリンクが解放されるだけで、オブジェクト自体はメモリ内に割り当てられたまま残ります。
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();
    }
  }
}

メディア プレーヤーの基本機能の実装

プレーヤーを開始するには、PlayButton または NextButton を押すか、プレイリスト内の項目をダブルクリックします。OnDblClick イベント ハンドラを PlayListBox に追加します。 ControlPlayLayout のボタンそれぞれをダブルクリックして、OnClick イベント ハンドラを追加し、メディア プレーヤーの基本機能を実装します。

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;
    }
}

有用なメソッドとクラスの実装

1. TForm1 クラスに次の public メンバを追加します。
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. Played 配列は、メディア プレーヤーがシャッフル モードで実行されたとき(ShuffleChekBox がオンのとき)に、PlayListBox 内における再生中のメディア ファイルのインデックスを保持するためのものです。前または次の再生メディアを取得できるよう、再生されたメディアが保存されます。CurrentPlayedIndex には、Played 内における現在再生中のメディアのインデックスが保持されます。AddToPlayedList メソッドでは、指定されたメディアを 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. FindAndPlay メソッドでは、PlayListBox 内におけるインデックスを使用して、再生するメディアを特定します。そして、PlayNext では、再生するメディアのインデックスを取得し、FindAndPlay を呼び出して、計算したインデックスのメディアを特定し再生します。
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 では、現在再生中のメディアの名前と時間(分および秒)を表示します。
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. TListBox では TObject サブクラスのインスタンスと各リストボックス項目を格納するため、TMediaEntry はプレイリストのメディア ファイルの絶対パスをラップします。そのコンストラクタを次のように定義します。
Delphi の場合:
constructor TMediaEntry.Create(FilePath: String);
begin
  Path := FilePath;
end;
C++Builder の場合:
TMediaPlayer::TMediaPlayer(UnicodeString FilePath)
: Path(FilePath)
{
}

現在再生中のメディア ファイルのカスタマイズ

1. 次のメディア ファイルの再生

現在再生中のメディアが終了したときに、メディア プレーヤーに次のメディアを再生させるために、特定の間隔で TTimer を使用します。

TTimer をダブルクリックし、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. シャッフルのオン/オフ

ShuffleCheckBox がオフの場合には、次に再生するメディアは PlayListBox 内の次のメディアです。オンの場合には、次に再生するメディアは PlayListBox 内のランダムなメディアです。メディア プレーヤーがシャッフル モードに設定されていない場合には、Played ベクトルを使用する必要はありません。再生順序は 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;
  }
}

アプリケーションの実行

1. プロジェクトを実行するには、F9 キーを押します。
2. LoadFileButton ボタンを押して、ファイルを PlayListBox に読み込みます。
3. PlayButton または NextButton を押すか PlayListBox 内の項目をダブルクリックして、メディアの再生を開始します。

前のトピック

関連項目