Frame stepping with the MediaUriElement

Aug 28, 2009 at 11:03 AM


When using the MediaUriElement I want to be able to step back/forward from frame to frame. I set the PreferedPositionFormat to Frame, and then step like this:

private void NextButton_Click(object sender, RoutedEventArgs e) { long duration = mediaPlayer.MediaDuration; long position = mediaPlayer.MediaPosition; mediaPlayer.MediaPosition = Math.Min(duration, position + 1); }

Simliar code for PrevButton_Click. What I see when pressing Prev/Next is that the display updates only every second time I step. This also happens if I increase to stepping two or three frames for each click. Tried using InvalidateVisual to make the display update, but to no avail...

Any hints on how to make this work?



Aug 28, 2009 at 5:57 PM
After the media file is opened, what is the CurrentPositionFormat?  Not all dshow filters support seeking by frames.
Aug 31, 2009 at 8:56 AM

Hi Jer

When I do not set any PreferedPositionFormat I get MediaTime as default. Did some more testing with this:

My mpeg-loop has a duration of 1.59 seconds, and contains 32 frames. I.e. a frame rate of about 20FPS. I now step with 0.05 second intervals as follows:

mediaPlayer.MediaPosition = Math.Min(duration, position + 500000);

This shows exactly the same behavior as when stepping with position format Frame. The display is updated only for every second step. I also tried to double the increment to 1000000. I can see that this doubles the length of the steps, but still the display is only updated once for every two steps.

When using the same DirectShow filters with MediaElement/MediaTimeline I have seen that I can do Seek with an increment/decrement of 0.05 seconds and get a display update for every single step. This indicates that the filters are not the problem here. Renderer is different though - with the MediaUriElement code I get VideoMixingRenderer9, while MediaElement gives me Enhanced Video Renderer. I tried to check if this was the problem by changing renderer for the MediaUriElement:

m_renderer = AddFilterByName(m_graph, FilterCategory.LegacyAmFilterCategory, "Video Renderer");

This works (display in separate window though), and gives the same behavior regarding stepping - only updates for every second step. Attempting to create "Enhanced Video Renderer" the same way did not work, so I cannot really say for sure whether or not the renderer is the problem.

Any clues to how I can solve this / what more I can test to figure out where the problem is?



Aug 31, 2009 at 11:49 AM


Frame length for some files can vary. It can be 39, 40 or 41 ms. That's why stepping frame-by-frame (with frame length calculated from the file duration) can skip one frame every second time. Does anyone know how to fix this?



Aug 31, 2009 at 1:22 PM

Hi Andrew

I had thought of this as a possible explanation for my problem. That is why I also tried frame stepping with two or three frames increment, and time stepping with twice the calculated frame interval. In both cases I still saw just the same as before - the display is updated only once for every two steps. Uneven frame intervals cannot explain this.

Also: MediaElement steps nicely when using the calculated frame interval, so the frames are there - they are just not displayed correctly when stepping with the MediaUriElement...


Sep 1, 2009 at 12:02 PM

Found the problem:

There is a member variable in the MediaSeekingElement class called m_ignorePropertyChangedCallback. As far as I understand this is used to avoid loops where a property update causes a new property update etc. This seems to work as intended when looping, but not when stepping. I see that for every second step the variable is set to true, and then setting of the new position is ignored.

I did a fix in MediaSeekingElement.OnMediaPositionChanged that seems to work:

/* If the change came from within our class,
  * ignore this callback */
  if (IsPlaying && m_ignorePropertyChangedCallback)

With the test on IsPlaying the variable will be disregarded when not playing. This causes MediaSeekingPlayer.MediaPosition to be set every time I step, and update works as expected.