2
Vote

SeekWhileScrubbing not working as expected

description

Repro : I've enabled SeekWhileScrubbing in my player. Despite that, if I try to seek using the timeline, the video will not move until I release the timeline (ie I release the left mouse button).
 
Expected : When SeekWhileScrubbing is true, the currently displayed frame should change when the user moves the timeline.
 
Workaround : I've implemented the 'proper' behavior by overriding all three scrubbing events, here the relevant code:
 
protected override void OnScrubbingStarted(TimeSpan scrubbingPosition)
{
// Save current state
_bufferingTimeBeforeScrubbing = ActiveMediaPlugin.BufferingTime;
_wasPausedBeforeScrubbing = (PlayState == MediaPluginState.Paused);
 
base.OnScrubbingStarted(scrubbingPosition);
}
 
protected override void OnScrubbing(TimeSpan scrubbingPosition)
{
// Avoid spamming when no change.
if (scrubbingPosition.Equals(PlaybackPosition))
    return;
 
if (SeekWhileScrubbing)
{
    // Override default behavior to fix 'seek while scrubbing' behavior.
    Pause();
    ActiveMediaPlugin.BufferingTime = TimeSpan.FromTicks(1);        // Try to reduce lag. Not very effective, but no negative impact (buffering occurs when resuming playback in any case).
    ActiveMediaPlugin.Position = scrubbingPosition;
}
 
base.OnScrubbing(scrubbingPosition);
}
 
protected override void OnScrubbingCompleted(TimeSpan scrubbingPosition)
{
// Restore state.
if (!_wasPausedBeforeScrubbing)
    Play();
ActiveMediaPlugin.BufferingTime = _bufferingTimeBeforeScrubbing;
 
base.OnScrubbingCompleted(scrubbingPosition);
}
 
Fix in SMF source : maybe modifying OnScrubbing to replace PlaybackPosition = scrubbingPosition; by SeekToPosition(scrubbingPosition) would work. But I haven't tried this, and have my doubts about the pausing of the video while scrubbing is taking place.

comments

Birbilis wrote Mar 25, 2015 at 2:23 PM

if you don't care about the buffering lag, then just overriding OnScrubbing and calling SeekToPosition(scrubbingPosition) seems to work, as long as you don't call "base.OnScrubbing". This might break though any scrubbing plugins that show thumbs while scrubbing etc. So indeed most probably a SeekToPosition is missing from that method implementation

Birbilis wrote Mar 25, 2015 at 2:31 PM

btw, at restore state better first restore the BufferingTime, then Play

at first I wondered why you used Pause while scrubbing, but indeed that saves you from hearing audio hickups - when you release the scrubbing knob it does resume playback, so all is fine (and you don't lose the thumb handle as it would happen if you paused scrubbing and it kept playing)

Birbilis wrote Mar 25, 2015 at 2:37 PM

here is the modified version of this code I'm just adding to my MediaPlayer class that is descending from SMF (Client/Media/MediaPlayer.Silverlight project at http://clipflair.codeplex.com):
#region "Scrubbing (fix - see https://smf.codeplex.com/workitem/21952)

protected override void OnScrubbingStarted(TimeSpan scrubbingPosition)
{
  // Save current state
  _bufferingTimeBeforeScrubbing = ActiveMediaPlugin.BufferingTime;
  _wasPausedBeforeScrubbing = (PlayState == MediaPluginState.Paused);

  Pause(); //pause playback while scrubbing to avoid audio hickups and losing the holding of the knob when pausing dragging and time keeps on flowing - when knob is released it will resume playback if it was playing
  ActiveMediaPlugin.BufferingTime = TimeSpan.FromTicks(1); // Try to reduce lag. Not very effective, but no negative impact (buffering occurs when resuming playback in any case).

  base.OnScrubbingStarted(scrubbingPosition);
}

protected override void OnScrubbing(TimeSpan scrubbingPosition)
{
  // Override default behavior to fix 'seek while scrubbing'
  if (!scrubbingPosition.Equals(PlaybackPosition) && SeekWhileScrubbing)
    ActiveMediaPlugin.Position = scrubbingPosition;

  base.OnScrubbing(scrubbingPosition);
}

protected override void OnScrubbingCompleted(TimeSpan scrubbingPosition)
{
  //Restore state
  ActiveMediaPlugin.BufferingTime = _bufferingTimeBeforeScrubbing;
  if (!_wasPausedBeforeScrubbing)
    Play();

  base.OnScrubbingCompleted(scrubbingPosition);
}

#endregion