トップ回答者
Windows Media Player

質問
-
OS: Vista Home VS2008 C#
1つのFormに4つのWMPがあります。1つのMP4またはAVIファイルを同時に再生させようとしていますが、
微妙に時間がずれます。同時に再生させる、なにかいい方法はないでしょうか?
今は、URLにファイルを指定し、以下のように再生させてるだけです。
axWindowsMediaPlayer1.Ctlcontrols.play();
axWindowsMediaPlayer2.Ctlcontrols.play();
axWindowsMediaPlayer3.Ctlcontrols.play();
axWindowsMediaPlayer4.Ctlcontrols.play();
回答
-
>私の知識でできるかわかりませんが、一度、試してみます。
ちょっと環境が無いので動作するかもわかりませんが、以下のような感じではどうですか。
※ちょろっと書いただけなんで動作保証はできません、参考として・・・(汗
/// <summary> /// 再生する /// </summary> private void button1_Click(object sender, EventArgs e) { // 同時実行時間を決める DateTime execTime = DateTime.Now.AddSeconds(1); // 別スレッドで同時実行する System.Threading.Thread t1 = new System.Threading.Thread(PlaySound); System.Threading.Thread t2 = new System.Threading.Thread(PlaySound); System.Threading.Thread t3 = new System.Threading.Thread(PlaySound); System.Threading.Thread t4 = new System.Threading.Thread(PlaySound); t1.Start(new ThreadArg(this.axWindowsMediaPlayer1, execTime)); t2.Start(new ThreadArg(this.axWindowsMediaPlayer2, execTime)); t3.Start(new ThreadArg(this.axWindowsMediaPlayer3, execTime)); t4.Start(new ThreadArg(this.axWindowsMediaPlayer4, execTime)); } /// <summary> /// スレッド引数クラス /// </summary> private class ThreadArg { public AxWMPLib.AxWindowsMediaPlayer wmp; public DateTime execTime; public ThreadArg(AxWMPLib.AxWindowsMediaPlayer arg1, DateTime arg2) { wmp = arg1; execTime = arg2; } } /// <summary>デリゲート</summary> delegate void PlaySoundDelegate(); /// <summary>再生メソッド</summary> private void PlaySound(object arg) { ThreadArg threadArg = (ThreadArg)arg; // 実行時刻になったら再生 while(true) { if (DateTime.Now >= threadArg.execTime) { Invoke(new PlaySoundDelegate(threadArg.wmp.Ctlcontrols.play)); Console.WriteLine(threadArg.wmp.ToString()); break; } } }
- 回答としてマーク co-lab 2010年8月26日 6:17
-
ここは発想を変えて以下の方法もありだと思います。
1.WPF と Windows Froms の相互運用で、WPF のコントロールを作り Form に貼りつける。
2.メディアの再生は WPF の MediaElement を使用する。
3. MediaElement は一つだけ使い、後は ViaualBrush を使って MediaElement の再生状況を描画する。これでほぼ同期が取れます。(正確に言えば見せかけているだけ)
WPF と WindowsForms の相互運用に関しては以下を参考にしてください。http://d.hatena.ne.jp/hilapon/20100603/1275583609
ViaualBrush の使い方に関しては、エッセンシャル WPF を参考にしています。
以下 サンプルコード、4つのコントロール(MediaElement ×1 、Rectangle × 3) で一つのメディアを同期再生しています。
xaml
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="260" Width="430"> <Grid> <MediaElement Height="100" Width="140" HorizontalAlignment="Left" Name="MediaElement1" VerticalAlignment="Top" LoadedBehavior="Manual" UnloadedBehavior="Manual" Source="C:\WINDOWS\Help\Tours\WindowsMediaPlayer\Video\copycd.wmv" /> <Button Content="Button" Height="30" HorizontalAlignment="Left" Margin="313,0,0,0" Name="Button1" VerticalAlignment="Top" Width="90" /> <Rectangle Height="100" HorizontalAlignment="Left" Margin="0,114,0,0" Name="Rectangle1" Stroke="Black" VerticalAlignment="Top" Width="140"> <Rectangle.Fill> <VisualBrush TileMode="None" Visual="{Binding ElementName=MediaElement1}" /> </Rectangle.Fill> </Rectangle> <Rectangle Height="100" HorizontalAlignment="Left" Margin="162,0,0,0" Name="Rectangle2" Stroke="Black" VerticalAlignment="Top" Width="140"> <Rectangle.Fill> <VisualBrush TileMode="None" Visual="{Binding ElementName=MediaElement1}" /> </Rectangle.Fill> </Rectangle> <Rectangle Height="100" HorizontalAlignment="Left" Margin="162,114,0,0" Name="Rectangle3" Stroke="Black" VerticalAlignment="Top" Width="140"> <Rectangle.Fill> <VisualBrush TileMode="None" Visual="{Binding ElementName=MediaElement1}" /> </Rectangle.Fill> </Rectangle> </Grid> </Window>
vb (C# でなくてすみませんが・・)Public Class MainWindow Private Sub Button1_Click( ByVal sender As Object, ByVal e As RoutedEventArgs) Handles Button1.Click MediaElement1.Play() End Sub End Class
ひらぽん http://d.hatena.ne.jp/hilapon/- 回答としてマーク 山本春海 2010年8月27日 5:58
すべての返信
-
>私の知識でできるかわかりませんが、一度、試してみます。
ちょっと環境が無いので動作するかもわかりませんが、以下のような感じではどうですか。
※ちょろっと書いただけなんで動作保証はできません、参考として・・・(汗
/// <summary> /// 再生する /// </summary> private void button1_Click(object sender, EventArgs e) { // 同時実行時間を決める DateTime execTime = DateTime.Now.AddSeconds(1); // 別スレッドで同時実行する System.Threading.Thread t1 = new System.Threading.Thread(PlaySound); System.Threading.Thread t2 = new System.Threading.Thread(PlaySound); System.Threading.Thread t3 = new System.Threading.Thread(PlaySound); System.Threading.Thread t4 = new System.Threading.Thread(PlaySound); t1.Start(new ThreadArg(this.axWindowsMediaPlayer1, execTime)); t2.Start(new ThreadArg(this.axWindowsMediaPlayer2, execTime)); t3.Start(new ThreadArg(this.axWindowsMediaPlayer3, execTime)); t4.Start(new ThreadArg(this.axWindowsMediaPlayer4, execTime)); } /// <summary> /// スレッド引数クラス /// </summary> private class ThreadArg { public AxWMPLib.AxWindowsMediaPlayer wmp; public DateTime execTime; public ThreadArg(AxWMPLib.AxWindowsMediaPlayer arg1, DateTime arg2) { wmp = arg1; execTime = arg2; } } /// <summary>デリゲート</summary> delegate void PlaySoundDelegate(); /// <summary>再生メソッド</summary> private void PlaySound(object arg) { ThreadArg threadArg = (ThreadArg)arg; // 実行時刻になったら再生 while(true) { if (DateTime.Now >= threadArg.execTime) { Invoke(new PlaySoundDelegate(threadArg.wmp.Ctlcontrols.play)); Console.WriteLine(threadArg.wmp.ToString()); break; } } }
- 回答としてマーク co-lab 2010年8月26日 6:17
-
そもそも、同期機構が無いコントロールで完全に同期させることはできないと考えるべきです
その上で可能な限り同期させようとした場合に、
わたしの記憶では使用されている WMP のライブラリが「AxWMPLib」である場合、
メディアファイルの読み込みは play メソッドを実行した際に開始されたと思ったので、
ただ単純に play メソッドを列挙しただけでは、各ファイルの読み込みにかかった時間+αずつズレが生じていきますそのため、play メソッドでファイルを読み込み後に一旦再生を停止しておき、
すべての play メソッドを実行後にスレッドを使うなりして一斉に再生を再開することで、
再生時間のズレをある程度は解消できるかもしれません -
ここは発想を変えて以下の方法もありだと思います。
1.WPF と Windows Froms の相互運用で、WPF のコントロールを作り Form に貼りつける。
2.メディアの再生は WPF の MediaElement を使用する。
3. MediaElement は一つだけ使い、後は ViaualBrush を使って MediaElement の再生状況を描画する。これでほぼ同期が取れます。(正確に言えば見せかけているだけ)
WPF と WindowsForms の相互運用に関しては以下を参考にしてください。http://d.hatena.ne.jp/hilapon/20100603/1275583609
ViaualBrush の使い方に関しては、エッセンシャル WPF を参考にしています。
以下 サンプルコード、4つのコントロール(MediaElement ×1 、Rectangle × 3) で一つのメディアを同期再生しています。
xaml
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="260" Width="430"> <Grid> <MediaElement Height="100" Width="140" HorizontalAlignment="Left" Name="MediaElement1" VerticalAlignment="Top" LoadedBehavior="Manual" UnloadedBehavior="Manual" Source="C:\WINDOWS\Help\Tours\WindowsMediaPlayer\Video\copycd.wmv" /> <Button Content="Button" Height="30" HorizontalAlignment="Left" Margin="313,0,0,0" Name="Button1" VerticalAlignment="Top" Width="90" /> <Rectangle Height="100" HorizontalAlignment="Left" Margin="0,114,0,0" Name="Rectangle1" Stroke="Black" VerticalAlignment="Top" Width="140"> <Rectangle.Fill> <VisualBrush TileMode="None" Visual="{Binding ElementName=MediaElement1}" /> </Rectangle.Fill> </Rectangle> <Rectangle Height="100" HorizontalAlignment="Left" Margin="162,0,0,0" Name="Rectangle2" Stroke="Black" VerticalAlignment="Top" Width="140"> <Rectangle.Fill> <VisualBrush TileMode="None" Visual="{Binding ElementName=MediaElement1}" /> </Rectangle.Fill> </Rectangle> <Rectangle Height="100" HorizontalAlignment="Left" Margin="162,114,0,0" Name="Rectangle3" Stroke="Black" VerticalAlignment="Top" Width="140"> <Rectangle.Fill> <VisualBrush TileMode="None" Visual="{Binding ElementName=MediaElement1}" /> </Rectangle.Fill> </Rectangle> </Grid> </Window>
vb (C# でなくてすみませんが・・)Public Class MainWindow Private Sub Button1_Click( ByVal sender As Object, ByVal e As RoutedEventArgs) Handles Button1.Click MediaElement1.Play() End Sub End Class
ひらぽん http://d.hatena.ne.jp/hilapon/- 回答としてマーク 山本春海 2010年8月27日 5:58
-
MediaElementのソース部分を書き換えたりもできるのでしょうか?
Source = "xxx"
可能です。XAML で指定してもいいですし、コードレベルでも設定可能です。コードだと
MediaElement1.Source = new System.Uri("hogehoge");
のような書き方になります。詳しくは MediaElement.Source プロパティのドキュメントを見てください。
あと、メディアの再生・停止・一時停止をマニュアルで操作したいなら MediaElement.LoadedBehavior プロパティと MediaElement.UnloadedBehavior プロパティのドキュメントも合わせて読んでおくといいかも知れません。
ひらぽん http://d.hatena.ne.jp/hilapon/