The State of the ViKi

In my previous posting about the VideoWiki project I mentioned that I fell off the edge of the world when I tried to replicate the work I had done previously with the player emitted by Encoder.  I’m told by the team that this is very much a work in progress, so I don’t want to get bogged down in the details, but let’s take a look at some of the issues that came up and where the code sits today.

The version of Expression Encoder that I used (version 2 service pack 1, version 2.1.1216.0) created the Template solution which in turn contained four projects

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project(“{<GUID>}”) = “Template”, “Template.csproj”, “{<GUID>}”
EndProject
Project(“{<GUID>}”) = “MediaPlayer”, “MediaPlayer\MediaPlayer.csproj”, “{<GUID>}”
EndProject
Project(“{<GUID>}”) = “AdaptiveStreaming”, “AdaptiveStreaming\AdaptiveStreaming.csproj”, “{<GUID>}”
EndProject
Project(“{<GUID>}”) = “ExpressionPlayer”, “ExpressionPlayer\ExpressionPlayer.csproj”, “{<GUID>}”
EndProject

Our working project on the other hand, is, for now,  a single project solution named Viki-Start) consisting of MainPage.xaml/.cs, App.xaml/.cs and a Views directory with the default three pair of files: AboutPage.xml/.cs, ErrorWindow.xaml/.cs and HomePage.xaml/.cs as well as the usual Properties, Resources, Bin, etc. folders.

Having templated ExpressionPlayer in Blend, we copy ExpressionPlayer.dll, MediaPlayer.dll and AdaptiveStreaming.dll into the bin/debug folder of Viki-Start and add them to the references of the project and we update App.xaml in Viki-start with the template that we created in blend (that is, in Template/App.xaml) being careful about namespaces.

What You Think You Did and What You Really Did

Twenty years ago I learned a good bit of close up magic. What I really liked about it was showing a trick and then listening to the person I showed it to describe what I did to someone else. What they saw was not what I did.  For the past three days, I’ve been insisting to everyone, including myself, that in all the previous videos and tutorials, it worked perfectly fine to call MediaPlayer from within my project but now it changed with Silverlight 3. Wrong!  Going back to find the original code so that I could point out the differences, there are none. Looking at the tutorial and the videos closely, I always launched the project from the html file – which worked then and works now; it is just that now I no longer want to do that; I want to launch from within the program.

What changed was not the ExchangePlayer (well, actually, it did change, but not in a way that affects this discussion) but my requirements.  This is a lesson I have to keep learning: synchronicity is the bane of debugging. It is the error of post-hoc ergo prompter hoc (just because it broke after I moved to Silverlight 3 doesn’t mean the failure had anything to do with moving to Silverlight 3.).

My Current Hack

Sometimes, even if you know you will eventually throw it away, it is worth getting the code to work; if only to understand it in pieces. Here is how I got my code to work.  When you ask encoder to create your starter application (which you’ll remember we then templated in Blend) it emits an entire project as shown above (Template.sln).  The two files we most care about are ExpressionPlayerControl.cs and MediaPlayer.cs.

ExpressionPlayerControl is the control that we are actually templating.  Its job is to display our media clip and raise an event when our markers are hit and it does so by inheriting from MediaPlayer and by creating a custom media stream source for adaptive streaming.  In fact, the point of ExpressionPlayerControl is to extend the MediaPlayer to fully support Adaptive Streaming.

OnStartup

The idiom for feeding the source videos to a MediaPlayer (or an ExpressionPlayer) is to call OnStartup passing in the event arguments obtained from the html page that invoked the program.  Assumptions are made. For example, the initial URI is created by obtaining the URI of the html page.

Uri uriStockContent = HtmlPage.Document.DocumentUri;

That value is then modified if there is a play list (which in my case there always was) in this section

if (e.InitParams.TryGetValue("playlist", out strInitValue))
{
try
{
Playlist.Clear();
Playlist.ParseXml(HtmlPage.Document.DocumentUri, strInitValue);
}

and we’re off to the races.  The supporting code for PlayList is defined in the PlayListCollection class of MediaPLayer and PlayList itself is a dependency property defined to be of type PlayListCollection.

A key assumption built into MediaPlayer is that ParseXml expects a document to serve as the source URI of the media items – that is, the physical location of the document must be the same as the physical location of the videos.

 

When Is A MediaPlayer Not A MediaPlayer?

If you look  up ParseXml in the Silverlight documentation for MediaPlayer you won’t find it. That is because the MediaPlayer that is listed in the documentation is not a Silverlight control, it is, rather, a player to run media using Silveright in an ASP.NET Web Page and is not the MediaPlayer emitted by Encoder.  Same name, different beast. 

My Temporary WorkAround

To get the application up and running for now, I overloaded OnStartup in ExpressionPlayer and in MediaPlayer and then copied the modified DLLs (along with the unmodified DLL for AdaptiveStreaming) into Viki-Start.

  // ExpressionPlayer 
public void OnStartup()
{
base.OnStartup();
Uri whereAmI = HtmlPage.Document.DocumentUri;
string pathAsString = whereAmI.ToString();
int offset = pathAsString.IndexOf( "TestPage.html" );
string stub = pathAsString.Substring( 0, offset );
Playlist.Clear();
PlaylistItem pli = new PlaylistItem();
pli.MediaUrl = new Uri( stub + "/encoded.wmv" );
pli.IsAdaptiveStreaming = false;
pli.ThumbSource = stub + "/test.jpg";
pli.Title = "Encoded Video";
pli.Description = "Hardcoded Hypervideo";
Playlist.Add( pli );
}
// MediaPlayer
public virtual void OnStartup()
{
Playlist.Clear();
m_autoPlayCache = true;
m_autoLoadCache = true;
m_mutedCache = false;
m_stretchMode = Stretch.None;
UserBackgroundColor = new SolidColorBrush( ColorFromString( "#FF0000FF" ) );
DisplayTimeCode = false;
CaptionsVisibility = Visibility.Collapsed;
}

 

Not beautiful, but sufficient to keep the project moving.

     Previous  ViKi Version 0.0.01
 

 

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in z Silverlight Archives and tagged . Bookmark the permalink.