Hi,
I'm trying to play video clips, back to back, inside a canvas.
My first approach was to hold two mediaelements in the canvas, and switch their visibility, loading the data in each element while the other was playing.
This turned out to be unusable, as for some strange reason, the second element would consistently drop a lot of frames. I got this behavior even when the project was reduced to the bare minimum. If anyone has any idea why this is so, please don't hesitate to share the knowledge (using June CTP).
I then tried to switch from direct MediaElement manipulation (Source, Play, Stop etc.), to the mediatimeline/mediaclock approach. This turned out to be very tricky, but after a lot of voodoo work (e.g, explicitly assigning null to a clock before assigning a new clock), I got to a point where the media elements played back to back smoothly...BUT:
Every once in a while, an element just gets stuck. I added a mousedown handler that simply issues a seek() command to the clock's controller. This works, so there is no problem with the media or the mediaelement. It just gets stuck, sometimes after 5 iterations, other times after 15. Seek() is used just to speed up debugging, the problem persists when I use Begin().
The full code is appended below. To run this, you just need two movies called "6.wmv" and "7.wmv" next to your binary.
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace MyTimeline
{
public partial class Window1 : Window
{
MediaElement me1, me2;
MediaElement mCurrentElement;
Canvas mCanvas;
public Window1()
{
mCurrentElement = null;
InitializeComponent();
Loaded += new RoutedEventHandler(Window1_Loaded);
}
void Window1_Loaded(object s, RoutedEventArgs args)
{
// create canvas
mCanvas = new Canvas();
mCanvas.Background = Brushes.Azure;
Content = mCanvas;
// create media elements
me1 = new MediaElement();
mCanvas.Children.Add(me1);
me1.MediaOpened += new RoutedEventHandler(me_MediaOpened);
me1.LoadedBehavior = MediaState.Manual;
me1.UnloadedBehavior = MediaState.Manual;
me1.Visibility = Visibility.Hidden;
me1.Name = "me1"; // for debugging
me2 = new MediaElement();
mCanvas.Children.Add(me2);
me2.MediaOpened += new RoutedEventHandler(me_MediaOpened);
me2.LoadedBehavior = MediaState.Manual;
me2.UnloadedBehavior = MediaState.Manual;
me2.Visibility = Visibility.Hidden;
me2.Name = "me2";
// load first movie
LoadMovie("6.wmv", me1);
me1.MouseDown += new MouseButtonEventHandler(me_MouseDown);
me2.MouseDown += new MouseButtonEventHandler(me_MouseDown);
}
// click handler to 'restart' stuck video
void me_MouseDown(object sender, MouseButtonEventArgs e)
{
MediaElement elem = (MediaElement)sender;
elem.Clock.Controller.Seek(TimeSpan.FromSeconds(25), TimeSeekOrigin.BeginTime);
}
void me_MediaOpened(object sender, RoutedEventArgs e)
{
MediaElement me = (MediaElement)sender;
MediaTimeline tl = (MediaTimeline)me.Clock.Timeline;
if (mCurrentElement == null) // for the first load event, play the movie
{
PlayMovie(me);
}
}
// get a callback when the timeline starts running
void mtl_invalidated(object sender, EventArgs args)
{
MediaClock clock = (MediaClock)sender;
clock.CurrentTimeInvalidated -= new EventHandler(mtl_invalidated); // don't need more events
MediaElement nextElement = null;
MediaTimeline tl = (MediaTimeline)clock.Timeline;
string nextSource = null;
switch (tl.Source.ToString())
{
case "6.wmv":
nextElement = me2;
nextSource = "7.wmv";
break;
case "7.wmv":
nextElement = me1;
nextSource = "6.wmv";
break;
}
// load the next movie, so that it's ready when this timeline completes
LoadMovie(nextSource, nextElement);
}
void PlayMovie(MediaElement me)
{
mCurrentElement = me;
me.Visibility = Visibility.Visible;
me.Clock.CurrentTimeInvalidated +=new EventHandler(mtl_invalidated);
me.Clock.Controller.Seek(TimeSpan.FromSeconds(25), TimeSeekOrigin.BeginTime); // make debugging faster
}
// for debugging
void me_MediaEnded(object sender, RoutedEventArgs e)
{
}
private void LoadMovie(string src, MediaElement newElement)
{
Uri newSource = new Uri(src, UriKind.RelativeOrAbsolute);
MediaTimeline mtl = new MediaTimeline();
mtl.Source = newSource;
mtl.FillBehavior = FillBehavior.Stop;
mtl.Completed += new EventHandler(mtl_Completed);
MediaClock cl = mtl.CreateClock();
cl.Controller.Stop();
newElement.Clock = cl;
}
// timeline completed, play next movie
void mtl_Completed(object sender, EventArgs args)
{
MediaClock clock = (MediaClock)sender;
MediaTimeline mtl = (MediaTimeline)clock.Timeline;
string src = mtl.Source.ToString();
MediaElement newElement = null;
switch (src)
{
case "7.wmv":
newElement = me1;
break;
case "6.wmv":
newElement = me2;
break;
}
MediaElement me = mCurrentElement;
me.Close();
me.Clock = null;
me.Visibility = Visibility.Hidden;
PlayMovie(newElement);
}
}
}

Back to back video playback: problems + inconsistent behavior
wirwin
According to Graphedt, The decoder is Sorenson MPEG video decoder.
I'd be grateful if you could explain to me why WPF fails to play the video, given that the decoder is available on the machine and WMP plays the file correctly.
Thanx,
David
Stewart Engelman
The first issue with the dropped frames sounds like a bug that has since been fixed.
The second issue may be the same thing - just that all the frames are getting dropped. Could you tell me if you continue to hear audio when the video gets stuck If so, I think it's the same bug.
BinFolder
Sometimes a movie loads with no error, but "plays" blank. Other times, I get OnMediaFailed with ErrorException {"Exception from HRESULT: 0xC00D3E85"} System.Exception {System.Runtime.InteropServices.COMException}
http://tinyurl.com/g8afz (7 meg)
http://tinyurl.com/h6tb4 (34 meg)
pmanisekaran
Speakafreaka
Is the bugfix available in the July CTP
Jerry Lew
You can see my list of codecs installed on my machine here .
In any case, I don't understand why WMP plays the files on my computer, while WPF doesn't. Perhaps I need a primer on how WPF handles video. A link would be welcome.
XNA Rockstar
I also discovered that every once in a while, the end of the timeline generates a mediaended call from the mediaelement, rather than timelinecompleted from the timeline.
Any comment on this from ms people would be great, as for now we seriously think about switching to ocx based video playback.
tibballs
Thanks for the info. WPF should be able to play any file that WMP plays. The most likely reason this is failing is that we use a different video renderer than WMP uses. I suspect the video renderer I use (EVR, or Enhanced Video Renderer) isn't playing nice with the Sorensen codec. I'll update you when I know more.
Could you confirm that you are running on XP And is your version of WMP 10 or 11
Ragnarok
While on the subject of WPF video, can any1 tell me what is the purpose of UnloadedBehavior and how I should use it
Peter Huber
Can you point me to one of the videos that fails in Avalon
UnloadedBehavior specifies how MediaElement behaves when the element is unloaded. For video, you usually want to leave this at the default of Close (we used to have a default of Unset, but we've changed that). When the element is unloaded you won't normally be able to see the video and closing the element reclaims a lot of system resources. For audio (or perhaps video that includes an audio stream too), you may want to continue to hear the audio even when the element is unloaded, so you may want to change the UnloadedBehavior. I hope that answers your question.
Catalin Zima
Jamie Thomson
zproxy
Hello,
Are you sure it was "Sorenson MPEG video decoder "
Any chance you have Sorenson Media's "Sorenson Squeeze" product installed If so, can you tell us what the version number of Squeeze it is
-Ben Waggoner
irl-barse