基本的なメディア プレーヤーの作成
チュートリアル:FireMonkey のオーディオ/ビデオ機能 への移動
このチュートリアルでは、FireMonkey で TMediaPlayer と TMediaPlayerControl を使用して、基本的なメディア プレーヤーを作成する方法を具体的に説明します。このメディア プレーヤーには、標準の機能(再生、停止、次および前)が含まれているほかに、現在再生中のメディアを操作する機能(音量および現在位置)もあります。この基本のメディア プレーヤーでは、一連のメディア ファイルを TListBox に読み込み、リスト中の項目をダブルクリックして再生を開始することもできます。
目次
フォームの設計
- [ファイル|新規作成|マルチデバイス アプリケーション - Delphi|空のアプリケーション]を選択します。
- TLayout をフォームに追加します。そのレイアウトを選択した状態で、[オブジェクト インスペクタ]で Align プロパティを
Left
に、Name プロパティを「MainLayout」に設定します。MainLayout のサイズを、ビデオの映像を表示するのに必要と思われるサイズに変更します。 - MainLayout に以下を追加します。
-
- TLayout。「ControlPlayLayout」という名前を付け、MainLayout の下端に揃えて配置します。このレイアウトには、メディア ファイルを制御するすべてのコンポーネントを含めます。
- TLayout。「TextLayout」という名前を付け、MainLayout の上端に揃えて配置します。このレイアウトには、現在再生中のメディアの名前と時間を表示するためのラベルを含めます。
- TMediaPlayerControl。Align プロパティを
Client
に設定します。
-
- ControlPlayLayout に以下を追加します。
-
- メディア プレーヤーの標準機能ごとに 1 つ、合計 5 つの TButton。ボタンの名前を、「PreviousButton」、「PlayButton」、「PauseButton」、「StopButton」、「NextButton」に変更します。
- 2 つの TTrackBar オブジェクト。1 つは音量を制御するためのもの、もう 1 つは現在の再生位置を制御するためのものです。トラック バーの名前を「VolumeTrackBar」と「PositionTrackBar」に変更します。PositionTrackBar を ControlPlayLayout の上端に揃えて配置します。
- TCheckBox。「ShuffleCheckBox」という名前を付けます。
-
- 2 つの TLabel オブジェクトを TextLayout に追加します。1 つは現在再生中のメディアの名前を表示するためのもの、もう 1 つは現在再生中のファイルの総時間を分および秒で表示するためのものです。2 つのラベルに「NameLabel」および「DurationLabel」という名前を付けます。DurationLabel を右揃えで配置し、AutoSize プロパティを True に設定します。NameLabel の Align プロパティを
Client
に設定し、テキストが中央に表示されるよう TextSettings.HorzAlign プロパティをCenter
に設定します。 - フォームに TLayout をもう 1 つ追加し、その Align プロパティを
Client
に設定し、名前を「PlayListLayout」に変更します。 - PlayListLayout に以下を追加します。
- TButton オブジェクトを 3 つ PlayListLayout に追加します。名前を「LoadFileButton」、「ClearAllButton」、「ClearButton」に設定します。3 つのボタンすべてを親の左に配置します。
- フォームに以下を追加します。
実装
実装は複数のステップに分けて行うことができます。
標準アクションと標準コントロールの関連付け
TActionList をダブルクリックします。開いたアクション リスト エディタで以下を行います。
- [新規アクション|標準アクションの新規追加...]を選択します。
- Media Library 下で次のアクションを選択します。
- TMediaPlayerStop
- TMediaPlayerCurrentTime
- TMediaPlayerVolume
- [OK]をクリックすると、これらのアクションがアクション リスト コンポーネントに追加されます。
ここで、以下のコントロールの Action プロパティにこれらのアクションを構成します。
- StopButton
- PositionTrackBar
- VolumeTrackBar
プレイリストの作成と操作
- 1. LoadFileButton ボタンをダブルクリックして、OnClick イベント ハンドラをそれに追加し、PlayListBox の内容を設定できるようにします。 LoadFileButton が押されると、ファイル選択ダイアログ ウィンドウが開きます。 1 つまたは複数のファイルを選択し、ファイル選択ダイアログ ウィンドウの[開く]ボタンを押すと、ファイルがリストに追加されます。
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;
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 から項目を削除しても、リスト ボックスの項目とそれに結び付けられたオブジェクトとの間のリンクが解放されるだけで、オブジェクト自体はメモリ内に割り当てられたまま残ります。
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;
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 メンバを追加します。
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;
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 リストに追加します。
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;
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 では、現在再生中のメディアの名前と時間(分および秒)を表示します。
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;
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 はプレイリストのメディア ファイルの絶対パスをラップします。そのコンストラクタを次のように定義します。
constructor TMediaEntry.Create(FilePath: String);
begin
Path := FilePath;
end;
TMediaPlayer::TMediaPlayer(UnicodeString FilePath)
: Path(FilePath)
{
}
現在再生中のメディア ファイルのカスタマイズ
- 1. 次のメディア ファイルの再生
現在再生中のメディアが終了したときに、メディア プレーヤーに次のメディアを再生させるために、特定の間隔で TTimer を使用します。
TTimer をダブルクリックし、OnTimer イベント ハンドラを追加します。
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;
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 内での順序と同じだからです。
procedure TForm1.ShuffleCheckBoxChange(Sender: TObject);
begin
If (not ShuffleCheckBox.IsChecked) then
begin
SetLength(Played, 0);
CurrentPlayedIndex := -1;
end;
end;
void __fastcall TForm1::ShuffleCheckBoxChange(TObject *Sender) {
if (!ShuffleCheckBox->IsChecked) {
Played.resize(0);
CurrentPlayedIndex = -1;
}
}
アプリケーションの実行
- 1. プロジェクトを実行するには、F9 キーを押します。
- 2. LoadFileButton ボタンを押して、ファイルを PlayListBox に読み込みます。
- 3. PlayButton または NextButton を押すか PlayListBox 内の項目をダブルクリックして、メディアの再生を開始します。