Silverlight でビデオの巻き戻し・早送り
WPF の MediaElementには SpeedRatio プロパティがあるので再生速度の変更(早送り)が可能です、また再生速度については MediaClock や MediaTimeline を見ることもできます。しかし、Silverlight の MediaElement にはそのようなプロパティがなく、再生速度の調整はできません。
しかし Silverlight の MediaElement にも Position プロパティはあるので、メディア ファイルが正しくロードされていれば、任意の位置に移動できます。任意の位置に移動するとその位置での静止画が表示されます。
Silverlight ビデオ早送りのアイデアは、DispatcherTimer で100ミリ秒ごとにコールバックを呼び出し、N倍速のときN*100ミリ秒分だけPositionを変更するというものです。つまり4倍速早送りなら4*100ミリ秒、8倍巻き戻しなら
-8*100ミリ秒だけPositionを進めるのです。
通常ビデオは30fps(33ミリ秒)なので、少しカクカクしますが、早送りなのであまり目立ちません。また、再生していないので早送り・巻き戻し中に音は出ません。
XAMLでは以下のように一連のボタンと MediaElement(myMediaElement) とプログレスバーが配置されているとします。
コードビハインドは以下のようになります。キモは赤字にした Position の変更です。
//速度レート
internal enum Speed:int
{back8=-8, back4=-4, pause= -1, stop = 0,
play=1, forward4=4, forward8=8};
internal int currentSpeedRate = (int)Speed.stop;
//タイマー
internal DispatcherTimer timer = new DispatcherTimer();
//タイマーの時間幅を100ミリ秒に設定
internal static int timerinterval = 100;
/// <summary>
/// タイマーによるコールバック
/// 倍速・巻き戻しの時、時間幅に速度レートを掛けて
/// メディアのPositionを移動
/// </summary>
private void timerCallback(object sender, EventArgs e)
{
if (currentSpeedRate < (int)Speed.pause ||
currentSpeedRate > (int)Speed.play)
{
myMediaElement1.Position +=
new TimeSpan(0, 0, 0, 0, timerinterval * currentSpeedRate);
if (myMediaElement1.Position>myMediaElement1.NaturalDuration.TimeSpan
|| myMediaElement1.Position < new TimeSpan())
{
myMediaElement1.Stop();
currentSpeedRate = (int)Speed.stop;
}
}
myProgressbar.Value = (double)myMediaElement1.Position.Ticks;
}
/// <summary>
/// メディアロード時にタイマーをスタート
/// </summary>
private void myMediaElement1_Loaded(object sender, RoutedEventArgs e)
{
timer.Tick += new EventHandler(timerCallback);
timer.Interval = new TimeSpan(0, 0, 0, 0, timerinterval);
timer.Start();
}
/// <summary>
/// 倍速・巻き戻しボタンが押された時のコールバック
/// メディアをポーズにして速度レートを設定
/// </summary>
private void Button_Click(object sender, RoutedEventArgs e)
{
myMediaElement1.Pause();
Button b = (Button)sender;
switch ((string)b.Content)
{
case "<<8":
currentSpeedRate = (int)Speed.back8;
break;
case "<<4":
currentSpeedRate = (int)Speed.back4;
break;
case "4>>":
currentSpeedRate = (int)Speed.forward4;
break;
case "8>>":
currentSpeedRate = (int)Speed.forward8;
break;
}
}