Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2018年03月28日] [更新 2018年04月07日] Delphi 一般・その他
TMediaPlayer または TWindowsMediaPlayer で動画を再生
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro
[整理番号 - 1020]







TMediaPlayer または TWindowsMediaPlayer で動画を再生


エクスプローラで音声,音楽あるいは動画ファイルをダブルクリックすると,拡張子に関連付けされたアプリケーション起動してそれらを再生できます.以下のように ShellExecute 関数を使用すれば同じように再生できます.
下図では Windows Media Player が起動して動画を再生しています.


図1
動画を再生中

リスト1
拡張子に関連付けされたアプリを起動して動画を再生
uses
  ShellAPI;

{$R *.dfm}

//=============================================================================
//  拡張子に関連付けされたプログラムを起動して動画を再生
//  ShellExecute関数の使用にはusesにShellAPIが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LMediaFile : string;
begin
  LMediaFile := 'C:\Users\Public\Videos\Sample Videos\Wildlife.wmv';
  ShellExecute(Handle, '', PChar(LMediaFile), nil, nil, SW_HIDE);
end;

//=============================================================================
//  Windows Media Player で動画を再生
//  再生するファイルのパスに空白文字があるので " 括っていることに注意
//  ShellExecute関数の使用にはusesにShellAPIが必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LExePath   : string;
  LMediaFile : string;
begin
  LExePath   := 'C:\Program Files (x86)\Windows Media Player\wmplayer.exe';
  LMediaFile := '"C:\Users\Public\Videos\Sample Videos\Wildlife.wmv"';
  ShellExecute(Handle, '', PChar(LExePath), PChar(LMediaFile), nil, SW_SHOW);
end;


本ページでは ShellExecute 関数ではなく,TMediaPlayer コンポーネントと,[コンポーネントのインポート] [ActiveX コントロールの取り込み] でインストール した TWindowsMediaPlayer コンポーネントを使用して動画ファイルを再生します.また,DSPack というコンポーネントを使用するテストの記事も掲載ています.
サンプルプログラムと言うよりは簡単な使用方法の記事になっています.
これらのコンポーネントを利用すると再生に関するいろいろな操作が可能になります.



[備考 1]
サンプルコードで使用している動画ファイルは,拡張子が .wmv (Windows Media Video) のファイルです.手元に適当なテスト用の動画ファイルがない場合,例えば以下のサイトからサンプルの動画ファイルを入手することができます.

[備考 2]
AVI ファイルは,コーデックの種類によっては TMediaPlayer では再生できないことがあります.以下の最初のリンクから Windows AVI をダウンロードして再生してみてください.この AVI ファイルであれば筆者の環境で再生できることを確認しています.
TWindowsMediaPlayer であれば,デジカメ等で撮影した AVI ファイルも再生可能です.

[備考 3]
Torry's Delphi の [Effects and MultimediaI のページにもマルチメディア関係のコンポーネントやアプリケーションが登録されています.




01_TMediaPlayer で動画を再生


[System] タブの TMediaPlayer コンポーネント を使用する例です.
TMediaPlayer コンポーネントでは,読み込みファイルの拡張子に応じたプログラムが起動して音声ファイルやビデオファイルを再生します.今回のテストに使用したビデオファイルは Windows  7 に添付されている拡張子が .wmv のファイルです.

今回のテストに使用した動画のサイズはかなり大きいので,本サンプルではサイズを縮小して再生するようにしています.また,動画を再生するウィンドウの表示位置も変更しています.ただし,ウィンドウをリサイズすると,アスペクト比 (縦横比) を維持しないでリサイズするため画像が変形します.
TMediaPlayer には,リサイズの際にアスペクト比を維持する機能はありません.



図2
動画を再生中
図3
再生中にリサイズ

[備考]
本サンプルで起動する動画再生プログラムのクラス名は MCIQTZ_Window です.Windows にインストールされている Windows Media Player のクラス名は WMP Skin Host です.



リスト2
TMediaPlayer で動画を再生
動画を再生するウィンドウの位置とサイズを変更
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, MPlayer, ExtCtrls;

type
  TForm1 = class(TForm)
    MediaPlayer1: TMediaPlayer;
    Button1: TButton;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
  private
  protected
    procedure CMShowingchanged(var Message: TMessage);
      message CM_SHOWINGCHANGED;
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム表示直後の処理
//  フォームが表示されていないとフォームの位置とサイズが取得できないので
//  CM_SHOWINGCHANGEDで処理
//=============================================================================
procedure TForm1.CMShowingchanged(var Message: TMessage);
begin
  inherited;
  if not Visible then exit;

  MediaPlayer1.DeviceType := dtAutoSelect;
  MediaPlayer1.AutoRewind := True;
  MediaPlayer1.FileName   := 'C:\Users\Public\Videos\Sample Videos\Wildlife.wmv';
  MediaPlayer1.Open;

  Button1Click(nil);
end;

//=============================================================================
//  フォームを閉じる時の処理
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  MediaPlayer1.Stop;
  MediaPlayer1.Close;
end;

//=============================================================================
//  表示位置とサイズを変更
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LRect   : TRect;
  LWidth  : Integer;
  LHeight : Integer;
  LLeft   : Integer;
  LTop    : Integer;
  LhWnd   : HWND;
begin
  //デフォルトの出力デバイスにおける表示サイズを取得
  LRect   := MediaPlayer1.DisplayRect;

  LWidth  := (LRect.Right  - LRect.Left) div 3;
  LHeight := (LRect.Bottom - LRect.Top)  div 3;

  //ウィンドウのフレームのサイズとキャプションバーの高さを加算
  LWidth  := LWidth  + GetSystemMetrics(SM_CXFRAME) * 2;
  LHeight := LHeight + GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);

  LLeft := Self.Left + Self.Width - LWidth;
  LTop  := Self.Top - LHeight;

  LhWnd := FindWindow('MCIQTZ_Window', nil);
  if LhWnd <> 0 then begin
    SetWindowPos(LhWnd, 0, LLeft, LTop, LWidth, LHeight, SWP_NOZORDER);
  end;
end;

end.




02_TMediaPlayer で動画をフォーム上で再生


Display プロパティで,動画を表示する TWinControl を指定できます.
ここではフォームに配置した TPanel に表示します.別のウィンドウとして表示したい場合は別フォームを表示してそこに表示することになります.


図4
設計時の画面
図5
動画を再生中

リスト3
TMediaPlayer で動画をフォーム上の TPanel 上で再生
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, MPlayer, ExtCtrls;

type
  TForm1 = class(TForm)
    MediaPlayer1: TMediaPlayer;
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LRect   : TRect;
  LWidth  : Integer;
  LHeight : Integer;
begin

  MediaPlayer1.DeviceType := dtAutoSelect;
  MediaPlayer1.FileName   := 'C:\Users\Public\Videos\Sample Videos\Wildlife.wmv';
  MediaPlayer1.Open;

  //デフォルトの出力デバイスにおける表示サイズを取得
  LRect   := MediaPlayer1.DisplayRect;
  LWidth  := LRect.Right - LRect.Left;
  LHeight := LRect.Bottom - LRect.Top;

  MediaPlayer1.Display := Panel1;
  MediaPlayer1.DisplayRect := Rect(0, 0, LWidth div 3, LHeight div 3);
end;

//=============================================================================
//  フォームを閉じる時の処理
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if MediaPlayer1.DeviceID = 0 then exit;

  MediaPlayer1.Stop;
  MediaPlayer1.Close;
end;

end.


表示用のコントロールをリサイズしてもアスペクト比を維持して動画を再生するには,例えば以下のようなコードで可能です.
TMediaPlayer.DisplayRect プロパティの型は TRect ですが,(左端,上端,幅,高さ) という値になっているようです.


図6
アスペクト比を維持したリサイズ
  • Panel1 の色を clBlack にしている

//=============================================================================
//  フォーム生成時の処理
//  FVideoWidth, FVideoHeightはInteger型のグローバル変数
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LVideoRect : TRect;
begin
  MediaPlayer1.DeviceType := dtAutoSelect;
  MediaPlayer1.FileName   := 'C:\Users\Public\Videos\Sample Videos\Wildlife.wmv';
  MediaPlayer1.Open;

  MediaPlayer1.Display := Panel1;

  //オリジナルのサイズを取得しておく
  LVideoRect   := MediaPlayer1.DisplayRect;
  FVideoWidth  := LVideoRect.Right  - LVideoRect.Left;
  FVideoHeight := LVideoRect.Bottom - LVideoRect.Top;

  Panel1Resize(nil);
end;

//=============================================================================
//  フォームを閉じる時の処理
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if MediaPlayer1.DeviceID = 0 then exit;

  MediaPlayer1.Stop;
  MediaPlayer1.Close;
end;

//=============================================================================
//  Panel1のOnResizeイベント処理
//=============================================================================
procedure TForm1.Panel1Resize(Sender: TObject);
var
  LVideoRatio : Double;
  LDispRatio  : Double;
  LDispLeft   : Integer;
  LDispTop    : Integer;
  LDispWidth  : Integer;
  LDispHeight : Integer;
begin
  if MediaPlayer1.DeviceID = 0 then exit;
  if FVideoWidth = 0 then exit;

  LVideoRatio := FVideoHeight / FVideoWidth;
  LDispRatio  := Panel1.Height / Panel1.Width;

  if LDispRatio > LVideoRatio then begin
    LDispLeft   := 0;
    LDispWidth  := Panel1.Width;
    LDispHeight := Round(LDispWidth * LVideoRatio);
    LDispTop    := Abs((Panel1.Height - LDispHeight) div 2);
  end else begin
    LDispTop    := 0;
    LDispHeight := Panel1.Height;
    LDispWidth  := Round(LDispHeight / LVideoRatio);
    LDispLeft   := (Panel1.Width - LDispWidth) div 2;
  end;

  //DisplayRect要素の値はTRect本来の定義とは違うようだ
  MediaPlayer1.DisplayRect := Rect(LDispLeft, LDispTop, LDispWidth, LDispHeight);
end;




03_TWindowsMediaPlayer で動画を再生


Windows Media Player はコンポーネントにしてフォームに直接配置して使用することができます.
それには下図のように,[コンポーネントのインストール] [コンポーネントのインポート] [ActiveX コントロールの取り込み] で [Windows Media Player] を取り込みます.

下図は Delphi XE5(UP2) Pro における操作画像ですが,Delphi XE(UP1) Pro でも同じです.今回は新規にパッケージを作成して,そこにコンポーネント類をインストールしています.



[備考]
ActiveX コントロールを使用した EXE は,実行環境に元となる DLL, OCX 等がシステム的にパスの通った場所に存在するかインストールされていないと動作しません.TWindowsMediaPlayer の場合は,実行環境で Windows Media Player が使用可能な状態でないと動作しません.
Windows Media Player は,Windows 2000 以降の環境であれば標準搭載されているはずです.



図7
ActiveX コントロールの取り込み
図8
インストールされたコンポーネント類

[ActiveX の取り込み] でインストールされたコンポーネントの内,今回のテストで使用したのはそのものズバリの TWindowsMediaPlayer だけです.下図はそのコンポーネントをフォームに配置している例です.黒い部分とその下のコントロール類がそれです.
この TWindowsMediaPlayer は TMediaPlayer よりも機能が豊富です.



図9
設計時の画面
図10
プロパティの設定
  • コントロールをダブルクリックすると現れる
  • [モードの選択] で Full (Default) を選択
  • [ウィンドウに合わせる] をチェック
図11
動画再生中
  • ダブルクリックで全画面表示
  • 戻るのは [ESC]
図12
再生中にリサイズ
  • アスペクト比 (縦横比) は変化しない

リスト4
TWindowsMediaPlayer コントロールで動画を再生
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, OleCtrls, WMPLib_TLB;

type
  TForm1 = class(TForm)
    WindowsMediaPlayer1: TWindowsMediaPlayer;
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  WindowsMediaPlayer1.Align := alClient;

  WindowsMediaPlayer1.URL := 'C:\Users\Public\Videos\Sample Videos\Wildlife.wmv';
end;

end.


上の図のプロパティの設定ダイアログにある [ウィンドウに合わせる] という項目は stretchToFit プロパティの設定です.stretch (ストレッチ) となっていますが,TCanvas.StretchDraw, Tmage.Stretch の Stretch とは違い,描画領域全体に描画するわけではありません.アスペクト比 (縦横比あるいは横縦比) を維持した描画です.

上の実行結果の図は,TWindowsMediaPlayerコントロールのサイズよりも大きい動画の画像を描画する場合です.一方,下図は TWindowsMediaPlayer コントロールのサイズより小さい画像サイズの動画の時に stretchToFit の値を True または False にして再生した時の結果です.



図13
stretchToFit の値は True
図14
stretchToFit の値は False
  • これが実際の動画の画像サイズになる

リスト5
TWindowsMediaPlayer.stretchToFit プロパティの動作確認用サンプル
//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
 WindowsMediaPlayer1.Align := alClient;

  WindowsMediaPlayer1.URL := 'bongo1.wmv';
  WindowsMediaPlayer1.stretchToFit := True;
end;




04_TWindowsMediaPlayer のリサイズと再生サイズの問題


これまでのテストはページの先頭に記載している Delphi XE(UP1) での結果です.
Delphi のバージョンによっては stretchToFit プロパティが実装されていないことがあるようです (未定義のエラーとなる).また TWindowsMediaPlayer コントロールのリサイズにも問題があるようです.そこで Delphi 6(UP2) でテストしてみました.

筆者の Windows 7 U64(SP1) の Delphi 6 (UP2) Pro では,ActiveX コントロールの取り込みでインストールした結果,コンポーネントは TWindowsMediaPlayer しかインストールされませんでした.
TWindowsMediaPlayer.stretchToFit プロパティは実装されていません.前項のダイアログの [ウィンドウに合わせる] で設定すれば機能としては動作しました.
Delphi 6(UP2) で作成した EXE では下図のように TWindowsMediaPlayerコントロールの Align の値を alClient にしてもフォームのリサイズに反応しませんでした.



図15
EXE 実行開始時の画面
図16
フォームをリサイズ
  • TWindowsMediaPlayer コントロールのサイズは変化しない

前項の最後のコードを使用してテスト可能な環境で調べた結果が下の表です.この表以外の Delphi のバージョンはテスト可能な環境がありません.
Delphi 5 は Windows 7 (32 bit),Delphi 7 は Windows 8.1 (32 bit) の環境での結果です.


Delphi のバージョン インストールされたコンポーネント stretchToFit Align
Delphi 5 Pro TWindowsMediaPlayer のみ 実装されている 無効
Delphi 6(UP2) Pro TWindowsMediaPlayer のみ 未実装 無効
Delphi 7 Pro TWindowsMediaPlayer のみ 実装されている 無効
Delphi XE(UP1) Pro 前項の図を参照 実装されている 有効
Delph XE5(UP2) Pro Delphi XE と同じ 実装されている 有効
Delphi XE7 Pro Delphi XE と同じ 実装されている 有効
Delphi 10.2 Starter Delphi XE と同じ 実装されている 有効


リサイズの現象は,インプレースオブジェクト (埋め込みオブジェクト) の表示位置やサイズ等の処理を受け持つ IOleInPlaceObject インターフェイスの処理に問題があるようです (IOleInPlaceObject の実装コードは AxCtrls.pas の TActiveXControl).
下に示すコードはこの現象を回避する方法の例です.

stretchToFit は IWMPPlayer4 インターフェイスにあります.そこで,IWMPPlayer4 のインスタンスを取得するわけですが,TWindowsMediaPlayer は Delphi のコンポーネントであって,インターフェイスのオブジェクトではありません.したがって QueryInterface メソッドがありません.そこで,以下のコードでは TWindowsMediaPlayer の DefaultInterface を取得してその QueryInterface メソッドを使用して取得します.
描画位置とサイズの設定は,問題となっている IOleInPlaceObject インターフェイスを使用します.方法,手順は stretchToFit と同じです.



リスト6
Windows Media Player 関係のインターフェイスオブジェクトを使用した描画サイズに関する設定
(IID_IWMPPlayer4, LWMPPlayer4) の部分は (IWMPPlayer4, LWMPPlayer4) でも同じ
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OleCtrls, WMPLib_TLB;

type
  TForm1 = class(TForm)
    WindowsMediaPlayer1: TWindowsMediaPlayer;
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  ShlObj,
  ActiveX;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LWMPCore    : IWMPCore;
  LWMPPlayer4 : IWMPPlayer4;
begin
  //DefaultInterfaceのインスタンスを取得
  LWMPCore := WindowsMediaPlayer1.DefaultInterface;

  //IWMPPlayer4インターフェイスのインスタンスを取得
  if LWMPCore.QueryInterface(IID_IWMPPlayer4, LWMPPlayer4) = S_OK then begin
    LWMPPlayer4.stretchToFit := False;
  end;

  //動画ファイルの指定
  WindowsMediaPlayer1.URL := 'bongo1.wmv';
end;

//=============================================================================
//  フォームをリサイズした時の処理
//=============================================================================
procedure TForm1.FormResize(Sender: TObject);
var
  LWMPCore   : IWMPCore;
  LOleObject : IOleInPlaceObject;
  LCtrlRect  : TRect;
begin
  //DefaultInterfaceのインスタンスを取得
  LWMPCore := WindowsMediaPlayer1.DefaultInterface;

  //IOleInPlaceObjectインターフェイスのインスタンスを取得して
  //そのSetObjectRectsメソッドでInPlaceObjectの描画位置とサイズを設定
  if LWMPCore.QueryInterface(IOleInPlaceObject, LOleObject) = S_OK then begin
    SetRect(LCtrlRect, 0, 0, Self.ClientWidth, Self.ClientHeight);
    LOleObject.SetObjectRects(LCtrlRect, LCtrlRect);
  end;
end;

end.


上のコードは Delphi XE でも動作しますが,Delphi XE では IWMPPlayer4 が DefaultInterface なので以下のコードでも同じです.
既に確認したように,Delphi XE ではこのような処理は必要ありません.



//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LWMPPlayer4 : IWMPPlayer4;
begin
  //テストなので
  WindowsMediaPlayer1.Align := alNone;

  //LWMPPlayer4のインスタンスを取得
  //Delphi XEではIWMPPlayer4がDefaultInterface
  LWMPPlayer4 := WindowsMediaPlayer1.DefaultInterface;
  LWMPPlayer4.stretchToFit := True;

  //動画ファイルの指定
  WindowsMediaPlayer1.URL := 'bongo1.wmv';
end;

//=============================================================================
//  フォームをリサイズした時の処理
//=============================================================================
procedure TForm1.FormResize(Sender: TObject);
var
  LWMPPlayer4 : IWMPPlayer4;
  LOleObject  : IOleInPlaceObject;
  LCtrlRect   : TRect;
begin
  //DefaultInterfaceのインスタンスを取得
  LWMPPlayer4 := WindowsMediaPlayer1.DefaultInterface;

  //IOleInPlaceObjectインターフェイスのインスタンスを取得して
  //そのSetObjectRectsメソッドでInPlaceObjectの描画位置とサイズを設定
  if LWMPPlayer4.QueryInterface(IOleInPlaceObject, LOleObject) = S_OK then begin
    SetRect(LCtrlRect, 0, 0, Self.ClientWidth, Self.ClientHeight);
    LOleObject.SetObjectRects(LCtrlRect, LCtrlRect);
  end;
end;




05_マルチメディア関係の関数類を使用した動画の再生


Delphi の TMediaPlayer は Windows API のマルチメディア関係の機能を使用しています.
以下のコードはそのマルチメディア関係の関数類を直接使用して動画を再生する例です.
これらの関数で動画を描画している MCIWnd ウィンドウクラスには,リサイズの際にアスペクト比を維持する機能はありません.利用者が設定することになります.



図17
動画再生中

リスト7
Windows API のマルチメディア関係の関数類を使用した動画の再生
uses に MMSystem が必要
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, MMSystem;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
    FMCIOpenParams : TMCI_Open_Parms;
    FMCIPlayParams : TMCI_Play_Parms;
    FDeviceID      : Word;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  mci関係の関数,定数名の使用にはusesにMMSystemが必要
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LMediaFile : string;
begin
  LMediaFile := 'ibutama.wmv';

  FMCIOpenParams.lpstrElementName := PChar(LMediaFile);
  mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, Integer(@FMCIOpenParams));
  FDeviceID := FMCIOpenParams.wDeviceID;

  Button1.Caption := 'Play';
  Button2.Caption := 'Stop';
end;

//=============================================================================
//  フォームを閉じる時の処理
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  mciSendCommand(FDeviceID, MCI_STOP, 0, 0);
  mciSendCommand(FDeviceID, MCI_CLOSE, 0, 0);
end;

//=============================================================================
//  Start
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  mciSendCommand(FDeviceID, MCI_PLAY, 0, Integer(@FMCIPlayParams));
end;

//=============================================================================
//  Stop
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  mciSendCommand(FDeviceID, MCI_STOP, 0, 0);
end;

end.




06_DSPack の TDSVideoWindowEx2 を使用した動画の再生


Windows Media Player は DirectShow の機能を使用しています.DSPack は その DirectShow の機能を Delphi から利用しやすいようにしたコンポーネント類です.つまり,DirectShow のラッパークラスです.
DSPack のインストール方法や DirectShow については以下のリンクの事を参考にしてください.

DSPack でビデオを再生する際,ビデオ表示用のコントロールとして多くの場合 TVideoWindow が使われているようですが,DSPack にはもう 1 つ TDSVideoWindowEx2 というコンポーネントがあります.このコンポーネントは便利なのですが,Windows Vista 以降で使用する時に少し問題があります.また,メモリリークが発生します.

Windows Vista 以降で TDSVideoWindowEx2 を使用した EXE を起動すると Aero を無効にするため一瞬,更新画面に切り替わります.終了時にも更新画面が一瞬ですが表示されます.プログラムを利用するユーザにとっては「チラつき」になります.



図18
Aero を無効にする
  • このダイアログはタスクバーのアイコンクリックで表示したもの
図19
起動した EXE の画面
  • Aero が無効になっている
  • この状態では再生中のビデオ画像はキャプチャできない
図20
メモリリーク
  • FastMM4 による検出結果

リスト8
TDSVideoWindowEx2 を使用した動画再生のテストコード
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, DSPack;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    FilterGraph1: TFilterGraph;
    Panel1: TPanel;
    DSVideoWindowEx21: TDSVideoWindowEx2;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LMediaFile : string;
begin
  LMediaFile := 'C:\Users\Public\Videos\Sample Videos\Wildlife.wmv';

  FilterGraph1.Active:= True;
  DSVideoWindowEx21.FilterGraph := FilterGraph1;
  FilterGraph1.RenderFile(LMediaFile);

  Button1.Caption := 'Play';
  Button2.Caption := 'Pause';
end;

//=============================================================================
//  フォームを閉じる時の処理
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FilterGraph1.ClearGraph;
  FilterGraph1.Active := False;
end;

//=============================================================================
//  Start
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  FilterGraph1.Play;
end;

//=============================================================================
//  Pause
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  FilterGraph1.Pause;
end;

end.




07_DSPack の TVideoWindow を使用した動画の再生
DSPack_TVideoWindow_Test.zip [582 KB] 2018年04月17日版 (EXE 同梱)


動画,ビデオの再生用コントロールして TVideoWindow を使用するテストです.
これまでのテストとは違い,TOpenDialog を使用して動画ファイルを選択できるようにしています.

最初の図は WMV ファイルを再生した結果です.上下が反転しています.次の図は MOD ファイルですが「ピンが接続されていないので,操作は実行できません」のエラーが発生して TVideoWindow に動画が表示されません.再生の際のアスペクト比も VideoWindow1.VMROptions.KeepAspectRatio の値を True にしてもアスペクト比は維持されません.AVI ファイルであれば,アスペクト比は維持されませんが正常に再生できます.



図21
WMV ファイルの場合
  • 上下が反転した状態となる
図22
MOD ファイルの場合
  • 別ウィンドウで再生される

リスト9
TVideoWindow を使用した動画再生のテストコード
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, DSPack;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    VideoWindow1: TVideoWindow;
    FilterGraph1: TFilterGraph;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    OpenDialog1: TOpenDialog;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
    FMediaFile : string;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//
//  Panel1はAlignをalTopにしてからAnchorsのakBottomをTrueにしている
//  Panel1の上にTVideoWindowを配置.AlignはalClient
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.Caption := 'Open';
  Button2.Caption := 'Play';
  Button3.Caption := 'Pause';
end;

//=============================================================================
//  フォームを閉じる時の処理
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FilterGraph1.ClearGraph;
  FilterGraph1.Active := False;
end;

//=============================================================================
//  Open
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LAction : TCloseAction;
begin
  if OpenDialog1.Execute then begin
    LAction := caNone;
    FormClose(nil, LAction);

    FMediaFile := OpenDialog1.FileName;

    FilterGraph1.Active      := True;
    VideoWindow1.FilterGraph := FilterGraph1;
    FilterGraph1.RenderFile(FMediaFile);

    Button2Click(nil);
  end;
end;

//=============================================================================
//  Play
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  FilterGraph1.Play;
end;

//=============================================================================
//  Pause
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
begin
  FilterGraph1.Pause;
end;

end.


上記の上下が反転する現象と,アスペクト比が維持されない現象を回避するには,レンダリングの方式を VMR にします.そのためには TVideoWindow コンポーネントの Mode プロパティの値を vmVMR にします.このプロパティはオブジェクト・インスペクタで設定できます.
Windows Vista 以降の Windows が動作可能な環境であれば,Mode プロパティのデフォルト値を vmVMR にしても問題ないと思われます.



図23
TVideoWindow.Mode の値を vmVMR にする
  • それ以外は変更しなくてもいいが,後のためにも変更した方がいいかも知れない

下図は,上記の変更をして動画を再生した結果です.再生の際のアスペクト比も維持されています.
筆者の環境では FLV ファイルも再生できました.
テストには上に示したコードを使用しています.



図24
WMV ファイルの例
  • Aero も有効の状態で実行されている
図25
MOD ファイルの例

下図は Windows 10.0.10586 (64 bit) での実行結果です.この Windows 10 は VMware WorkStation 12 Player で動作していて,Aero 効果が無効になっていますが,アスペクト比が維持された状態で動画が再生できることを確認しました.



図26
EXE を Windows 10 で実行した結果

下図は,DSPack に添付の \Demos\D6-D7\VMR\VMRPlayWin\VMRPlayWin.dpr を Delphi XE(UP1) Pro でコンパイルして実行した結果です.DSPack には多くのデモプログラムが添付されています.また CHM 形式のヘルプもあります.



図27
DSPack に添付のデモプログラムの例
図28
Brightness を変更




08_動画が再生できない時に必要な コーデック と DirectShow Splitter


本ページのテストで使用している MOD と FLV ファイルは,システムのデフォルトの状態では再生できません.該当する動画ファイルの種類に応じたコーデックをインストールする必要があります.以下のリンクの記事で確認してください.
これらのコーデックをインストールすると,Windows Media Player でもその動画ファイルを再生できるようになります.



FLV ファイルの再生には FLV 用の DirectShow Splitter が必要です.以下は代表的なダウンロードサイトの例です.Flash Video Splitter という名称になっています.
2018年04月07日現在の最新バージョンは 1.5.2.3465 - Black Edition ですが,1.0.0.5 (for Windows Vista/XP/2k/2k3) をダウンロードした方がいいでしょう.ダウンロードしたらブロックを解除してから解凍してインストールします.



この Flash Video Splitter をインストールすると,FLV ファイルを Windows Media Player でも再生できるようになります.
アンインストールは,[プログラムと機能] から [OpenSource Flash Video Splitter 1.0.xxx] を選択します.インストール,アンインストールは FLVSplitter.ax ファイルのレジストリへの登録と登録解除を行います.

K-Lite Codec Pack (Full エディション) のように,DirectShow Splitter もインストールしてくれるコーデックパックもあります.



FLV 用の DirectShow Splitter をインストールしても,IE のプラグインとしての Flash Player がインストールされていないと再生できません.IE を使用している場合,おそらく Flash Player はインストール済みのことが多いと思われます.



[備考 1]
インターネットブラウザには Flash Video のコンテンツ再生専用のプラグインがあります.一方,コンピュータに保存されている FLV ファイルの再生では,ブラウザのそのプラグインのような役割を FLV 用の DirectShow Splitter が行います.

Windows では,コンピュータに保存されている動画再生には Windows Media Player が広く利用されています.一方,インターネットブラウザでは主に Flash Player というプラグインが動画再生に使用されていますが,2016 年頃から段階的に HTML5 Video に移行中のようです.
筆者の FireFox 59.0.2 では,Flash Player で動画を再生しようとすると,[Adobe Flash を実行します] をクリックしないと再生できなくなっています.
Adobe 社における Flash Player のサポート終了は 2020年です.


[備考 2]
テストで使用している拡張子が .mod ファイルのコーデックは MPEG-2 です.
拡張子を .MPG に変更すれば TMediaPlayer でも再生できます.FLV ファイルは DirectShow Splitter をインストールしても TMediaPlayer では再生できません.

[備考 3]
拡張子が .swf (Small Web Format の略) の動画は,FLV ファイルが再生可能な状況であれば Windows Media Player で再生できます.TWindowsMediaPlayer でも再生できますが,TMediaPlayer あるいは DSPack の TVideoWindow では再生できません.
SWF の動画ファイルを再生する方法として,以下の記事にあるように,ActiveX コントロールの取り込みで TShockwaveFlash コンポーネントをインストールして利用する方法があります. IE 用のプラグインである Flash Player がインストールされていないと ActiveX の取り込みのリストに [Shockwave Flash] は表示されません.
Flash Player の動向を考えると,他の形式に変換して再生することも考えられます.

[備考 4]
以下は筆者が使用している動画再生用のアプリです.このようなアプリの仕様も開発の際には参考になるかも知れません.
MPC-BE (Media Player Classic - BE) は各種のコーデック類と DirectShow Splitter を MPC-BE 専用として自前で実装していますが,システムにインストールされているコーデック類を使用することもできます.

[備考 5]
Windows Vista ではマルチメディアを扱うための COM ベースの Media Foundation という API が新たに実装されています (実用的な実装は Windows 7 から).これらの API を Delphi で利用するためのユニット類をネットで提供されている方もいるようです.