TWindowsMediaPlayerでメディアの長さや幅、高さなどを取得するタイミングの考察。
※このページはDelphi標準のTMediaPlayerではなく、ActiveXの取り込みで取り込んだTWindowsMediaPlayerのタイミングを考察しているページです。
TMediaPlayerコンポーネントはFileNameプロパティにファイル名をセットしてOpenすればメディアの長さや大きさを取得できます。
ところがTWindowsMediaPlayerではそうはいきません。
どうやらTMediaPlayerとは違って、URLプロパティにファイルをセットしてplayメソッドを呼んだ後にイベントの中でパラメータを見て処理を行うというやり方をするようです。
そこで関連すると思われるOpenStateChangeイベントとPlayStateChangeイベントの発生状況と順序を調べてみようというのがこのページの趣旨です。
実行結果です。
なにやら色々とイベントが発生しているようです。
数字だけでは分かりづらいのでマイクロソフトのリファレンス(openStateとplayState)と照らし合わせて表にしてみました。
値 | 状態 | 説明 | |
---|---|---|---|
(1) | WindowsMediaPlayer1.URL := FileName; | ||
Open | 1 | PlaylistChanging | 新しい再生リストが読み込まれようとしています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 7 | PlaylistChanged | 新しい再生リストが currentPlaylist に割り当てられました。 (ここでcurrnetMediaに値が入る) (これ以前にcurrentMediaにアクセスするとエラーになる) |
Open | 6 | PlaylistOpenNoMedia | 再生リストは開いています。 |
Play | 10 | Ready | 再生を開始する準備ができています。 |
(2) | URLへの代入から戻る。 WindowsMediaPlayer1.controls.play; |
||
Open | 21 | OpeningUnknownURL | 不明な種類の URL を開いています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 12 | MediaOpening | メディアは取得済みで、現在開いているところです。 |
(3) | controls.playから戻る。 | ||
Open | 13 | MediaOpen | メディアは現在開いています。 (ここで長さや幅などがセットされ、ようやく値を取得できる) |
Play | 3 | Playing | 現在のメディア クリップは再生中です。 (再生が始まる) |
--- 再生中 --- | |||
Play | 8 | MediaEnded | メディアの再生が完了し、最後の位置にあります。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Play | 1 | Stopped | 現在のメディア クリップの再生が停止されています。 |
かえって分かりづらい説明もありますが、ここで重要なのはOpenStateChangeの13,
MediaOpenです。このパラメータが来た後であれば長さや大きさの取得が可能になります。
残念なことにこのイベントが起きるのはplayメソッドを呼んで戻ってきた更にその後です。したがって
とやっても'00:00'が表示されるだけです。
URLにファイルを代入して戻った時点で分かるようになっていれば素直で分かりやすいのですがそうはなっていません。
結局上の例でいえばButton1Clickとは別のところで長さや大きさを取得するしかないのでちょっと見通しが悪くなってしまいますがそういうものなのだと納得するのが肝要です。
ちなみにOpenStateとPlayState定数名ですがリファレンスの「状態」名称の頭にOpenStateならwmposをPlayStateならwmppsをつけます。
次にリストにあるファイルを連続再生する場合を考えてみます。
同じ曲を連続再生する時はPlayStateChangeイベントでwmppsStoppedをつかまえてplayメソッドを加えるだけでいけます。
Play | 3 | Playing | 現在のメディア クリップは再生中です。 |
Play | 8 | MediaEnded | メディアの再生が完了し、最後の位置にあります。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Play | 1 | Stopped | 現在のメディア クリップの再生が停止されています。 |
Play | 3 | Playing | 現在のメディア クリップは再生中です。 |
Play | 8 | MediaEnded | メディアの再生が完了し、最後の位置にあります。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Play | 1 | Stopped | 現在のメディア クリップの再生が停止されています。 |
--- 以下同じことの繰り返し --- |
ところが違う曲を連続再生させようとするとこれではうまくいきません。なぜか二曲目を読み込んだ後、再生することなく次の曲を読み込みんだ挙句途中で再生せずに処理が止まってしまいます。
値 | 状態 | 説明 | |
---|---|---|---|
(1) | WindowsMediaPlayer1.URL := ListBox1.Items[0]; | ||
Open | 1 | PlaylistChanging | 新しい再生リストが読み込まれようとしています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 8 | MediaChanging | 新しいメディアが読み込まれようとしています。 |
Open | 6 | PlaylistOpenNoMedia | 再生リストは開いています。 |
Play | 10 | Ready | 再生を開始する準備ができています。 |
(2) | WindowsMediaPlayer1.controls.play; | ||
Open | 21 | OpeningUnknownURL | 不明な種類の URL を開いています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 12 | MediaOpening | メディアは取得済みで、現在開いているところです。 |
(3) | controls.playから戻る。 | ||
Open | 13 | MediaOpen | メディアは現在開いています。 |
Play | 3 | Playing | 現在のメディア クリップは再生中です。 |
--- 再生中 --- | |||
Play | 8 | MediaEnded | メディアの再生が完了し、最後の位置にあります。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Play | 1 | Stopped | 現在のメディア クリップの再生が停止されています。 |
(1) | 二曲目読み込み WindowsMediaPlayer1.URL := ListBox1.Items[1]; |
||
Open | 1 | PlaylistChanging | 新しい再生リストが読み込まれようとしています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 8 | MediaChanging | 新しいメディアが読み込まれようとしています。 |
Open | 6 | PlaylistOpenNoMedia | 再生リストは開いています。 |
Play | 10 | Ready | 再生を開始する準備ができています。 |
Open | 7 | PlaylistChanged | 新しい再生リストが currentPlaylist に割り当てられました。 |
Open | 6 | PlaylistOpenNoMedia | 再生リストは開いています。 |
(2) | WindowsMediaPlayer1.controls.play; | ||
Open | 21 | OpeningUnknownURL | 不明な種類の URL を開いています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 12 | MediaOpening | メディアは取得済みで、現在開いているところです。 |
(3) | controls.playから戻る。 | ||
Open | 13 | MediaOpen | メディアは現在開いています。 |
Play | 1 | Stopped | 現在のメディア クリップの再生が停止されています。 |
(1) | 三曲目読み込み WindowsMediaPlayer1.URL := ListBox1.Items[3]; |
||
Open | 1 | PlaylistChanging | 新しい再生リストが読み込まれようとしています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 7 | PlaylistChanged | 新しい再生リストが currentPlaylist に割り当てられました。 |
Open | 6 | PlaylistOpenNoMedia | 再生リストは開いています。 |
Play | 10 | Ready | 再生を開始する準備ができています。 |
(2) | WindowsMediaPlayer1.controls.play; | ||
(3) | controls.playから戻る。 | ||
Open | 8 | MediaChanging | 新しいメディアが読み込まれようとしています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 6 | PlaylistOpenNoMedia | 再生リストは開いています。 |
--- ここで止まる --- |
これではどうにもうまくないので色々試してみてメディアの終わりに来た時点で次の曲を読み込ませるようにしました。
PlayStateChangeイベントでwmppsMediaEndedをつかまえます。
値 | 状態 | 説明 | |
---|---|---|---|
(1) | WindowsMediaPlayer1.URL := ListBox1.Items[0]; | ||
Open | 1 | PlaylistChanging | 新しい再生リストが読み込まれようとしています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 7 | PlaylistChanged | 新しい再生リストが currentPlaylist に割り当てられました。 |
Open | 6 | PlaylistOpenNoMedia | 再生リストは開いています。 |
Play | 10 | Ready | 再生を開始する準備ができています。 |
(2) | WindowsMediaPlayer1.controls.play; | ||
Open | 21 | OpeningUnknownURL | 不明な種類の URL を開いています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 12 | MediaOpening | メディアは取得済みで、現在開いているところです。 |
(3) | controls.playから戻る。 | ||
Open | 13 | MediaOpen | メディアは現在開いています。 |
Play | 3 | Playing | 現在のメディア クリップは再生中です。 |
--- 再生中 --- | |||
Play | 8 | MediaEnded | メディアの再生が完了し、最後の位置にあります。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Play | 1 | Stopped | 現在のメディア クリップの再生が停止されています。 |
(1) | WindowsMediaPlayer1.URL := ListBox1.Items[1]; | ||
Open | 1 | PlaylistChanging | 新しい再生リストが読み込まれようとしています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 8 | MediaChanging | 新しいメディアが読み込まれようとしています。 (二回目以降なので8) |
Open | 6 | PlaylistOpenNoMedia | 再生リストは開いています。 |
Play | 10 | Ready | 再生を開始する準備ができています。 |
Open | 7 | PlaylistChanged | 新しい再生リストが currentPlaylist に割り当てられました。 |
Open | 6 | PlaylistOpenNoMedia | 再生リストは開いています。 |
(2) | WindowsMediaPlayer1.controls.play; | ||
Open | 21 | OpeningUnknownURL | 不明な種類の URL を開いています。 |
Play | 9 | Transitioning | 新しいメディアを準備中です。 |
Open | 12 | MediaOpening | メディアは取得済みで、現在開いているところです。 |
(3) | controls.playから戻る。 | ||
Play | 10 | Ready | 再生を開始する準備ができています。 |
--- ここで止まる --- |
結局途中で止まってしまうのですが二度読みすることはないのでまだましかと。
後は色々フラグを立てたりしてやってみたのですが、タイマーを使って逐一状態を監視して再生させてしまうというのが一番確実でいいようです。
その後。
Readyで止まるのならばwmppsReadyをつかまえて、そこへplayメソッドを追加すれば良いのではと思い至りました。
ところがたんにplayメソッドを付け加えただけでは連続再生はできるもののエラーが出てしまいます。
色々やってみた結果currentMediaが有効であればplayするようにしたらエラーも出ず連続再生もOKとなりました。
再びその後。
この方法ではうまくいかない場合もあるようでした。
私のやり方だと*.cdaが連続再生されませんでした。
ということでOnPlayStateChangeイベントだけでなくOnOpenStateChangeイベントでも止まるところに逐一controls.palyを仕込んでいってみたのですが、環境によって動いたり動かなかったりという状況のようでした。
で、(おなじみの)「真琴」さんと「春子」さんのかけあいでアドバイスしていただいたようにPostMessageを使ってみたところだいぶ良い感じに仕上がりました。
ただ提示してもらったコードだとStopボタンを押しても止まらないのと、うちの環境だと*.flvファイルが無限ループに陥りハングアップしてしまいます。
ということでフラグを使って書き換えてみた結果です。
まず停止ボタンを押しても止まらずに次の曲の再生が始まってしまうことへ対処します。
wmppsMediaEndedを通ったかどうかのフラグを加えます。
これによりユーザーが停止ボタンを押して途中で再生をやめようとしたのかそれともメディアの最後まできたのでwmppsStoppedにきたのか判断できるようになります。
これでユーザーが「Stop」ボタンを押した場合wmppsMediaEndedは通らないのでPostMessageの処理には入らずに再生は停止します。
次に*.flvファイルが無限ループに陥ることへ対処します。
その前に、実はwmppsMediaStoppedでPostMessageを行った場合、今まで連続再生させようとしてもwmppsReadyで止まっていたものが止まらずにちゃんと再生されるようになりました。
ということで*.cdaや*.wma、*.mp3、*.wmvなどの再生であれば上記のコードでOKです。
しかし*.flvなどはOnMediaErrorイベントが起きてwmppsReadyで止まります。
そこでwmppsReadyでもwmppsStoppedと同じようにPostMessageを行うと、URLにファイルをセットしなおすためか再生が始まらずそれどころか無限ループに陥りハングアップします。
PostMessageの処理でwmppsStoppedから呼ばれた場合とwmppsReadyから呼ばれた場合で処理を分けwmppsReadyからのときはURLにファイルをセットせずcontrols.playだけ行うようにすればちゃんと再生できるようにはなります。
とはいえ終了時にエラーが出てしまったりしてあまりいい感じではありません。
ということでwmppsReadyではPostMessageではなく単純にcontrols.playとするだけの方が良いような感じです。
これだけで充分な気もするのですが、フォルダ中のファイルリストを取得してListBox1のItemsにセットして再生させてみたところサムネイルファイルのThumbs.dbを読み込んだところでハングアップしてしまいました。
他にも*.iniや*.txtなど、再生できないファイルはハングアップします。
ということでそれらのファイルへ対処するためにF_iErrorCountというフラグを使います。
またメディアエラーを捕まえるためOnMediaErrorイベントを利用します。
F_iErrorCountが1のときだけcontrols.playを呼ぶようにしています。
*.flvなどであれば最初のメディアエラーでcontrols.playを呼べば再生が始まります。
それ以外の*.txtファイルなどはcontrols.playを呼んでも再生が始まりません。
2回目のエラーではcontrols.playは呼ばれないのでそのまま再生は停止します。
2009-03-19: アドバイスに従いPostMessageを使ったものに書き換え。
2008-11-12: wmppsReadyにcontrols.playを追加で連続再生OKを追加。