Compartilhar via


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) とプログレスバーが配置されているとします。

image

コードビハインドは以下のようになります。キモは赤字にした 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;
  }
}