Posts Tagged with TimeLineMarker

Asynchronous loading of TimelineMarkers for Silverlight Video Player

As part of the ongoing evolution of our Open Source Silverlight Video Player on CodePlex, I added the ability to asynchronously load a set of TimeLineMarkers from an XML document.  The goal was to allow users a choice between encoding there video with markers or defining those markers in an external xml file.  What I thought would be a pretty trivial task, proved to be an interesting challenge. Here is a snapshot of the Xml format.

marker_1


The first step in implementing this functionality was to download the marker Xml.  In the event that this marker file was quite large in size I decided to make the download asynchronous.  Downloading a file asynchronously required that the path to the file is absolute.  Since I have no real control over my initParams I decided to support both an absolute or relative Uri.  In the event that the path to the Xml document is relative, I make a reasonable assumption that it is located in the same location as the XAP.  As a result ,I can define my Uri with “Host.Source” as the baseUri of the Xml document.  To Download the file, I simply make a WebRequest and define an AsyncCallback to be fired when the file has completed downloading. 

Threading Considerations

In Silverlight 2 Beta 2 there was a significant change in the concurrency model used for asynchronous communications.  In Beta 1 these type of requests returned on the UI thread.  In Beta 2, when you choose to use the BeginGetResponse of the WebRequest you are telling Silverlight to use a worker thread that comes from a thread pool.  As a result, you can NOT update any user interface elements on the UI thread.  Initially I thought I would be able to use “Application.Current.RootVisual.Dispatcher” as a way to execute a delegate on the UIThread.  Unfortunately this throws a Cross Thread exception.  After explored a few options I realized that I could simply call Dispatcher.BeginInvoke(MyMethod) from within my AsyncCallback.  here is what that looked like.

void OpenStreamCompleted(IAsyncResult ar)
{
    HttpWebRequest request = ar.AsyncState as HttpWebRequest
    WebResponse response = request.EndGetResponse(ar)
 
    // Read the response into a Stream object.
    Stream responseStream = response.GetResponseStream()
 
    // Create a new StreamReader instance using the specified Stream object.
    using (StreamReader streamreader = new StreamReader(responseStream))
    {
        XElement document = XElement.Load(streamreader) 
        _externalMarkerData = (from el in document.Elements() select GetMarkerData(el)).ToList()
    }
    Dispatcher.BeginInvoke(ProcessParsedMarkerCollection)
}

As you can see above, once I have the Xml downloaded I parse it from Xml into a collection. For this I thought it would be cool to use Linq for XML.  I am always amazed at how few a lines of code I need to write to parse an Xml document with Linq.  The end product of the parse is a List<> containing a very simple custom object called “MarkerData”.  If I had chosen to move this parsing back to the UIThread I could have just created a collection of TimelineMarkers, but I thought there was no harm in having my own object to expand over time.

To get the latest source visit the project at http://www.codeplex.com/sl2videoplayer

Silverlight 2 – Media Player with Marker support

Back in April I created a very simple Video Player in Silverlight 2 Beta 1 which Tim Heuer took to a whole new level. In his first pass he added dynamic resizing and initParams to load the video source. Then back a few weeks ago Tim brought it up to speed for Beta 2 and integrated the "VisualStateManager" to get the ToggleButton to function correctly. I love how it turned out.

One thing that I really wanted to include in my first version was control for TimelineMarkers. Unfortunately in Beta 1 I had some issues with dynamic markers, and decided to hold off until Beta 2 was released. Microsoft Expression Encoder 2 is a great tool and makes it very easy to insert markers that fire events during video playback. Markers are very simple, they define a TimeSpan of when to fire the "MarkerReached" event, and define some text that describes the marker.   In my example I will use this text as the copy for my Marker Popup.  Here is how I chose to visualize my markers in the video player.

videoplayer_c2

To achieve this effect, I created a custom UserControl called "Marker.xaml". This control contains a single animation which will fade in the text, and fade it out again after a predefined amount of time.  The control is comprised of a TextBlock and a “Arrow” path that can be moved left and right within the second row of a Grid control.  This gives me the ability to control where the Arrow visualizes in relation to my Timeline Slider control.

Based on the number of markers encoded in the video an equal number of markers will be placed in the “MediaControl”.  There position on the slider time line is determined by calculating the following:

videoplayer_c3


The position is not absolute, but close enough to where the “Thumb” in the slider control will exist at that moment the marker should popup.   Once I have placed a marker into the appropriate Grid on my MediaControl I store it in a generic Dictionary keyed off of the time it should be displayed. This allows me to very quickly find the UserControl when the Media.MarkerReached event fires or the player goes into fullscreen mode.   In the event that the user wants to play the video in fullscreen, I must reposition my markers relative to the new ActualWidth of the  sliderTimeline. 

videoplayer_c4


Here is how it all turned out. 

Code: VideoPlayerMarkers.zip