We've been digging in to adaptive streaming pretty deeply as of late, and it's been an interesting learning experience. Words cannot express how much I love what adaptive streaming does for video on the Internet. I have felt since I first saw it that it will change the way we all watch video online, and we're seeing that start to happen.
After working with it for just a couple of projects, I cannot see ever going back to a WMV source file. They just seem so... small. In contrast, I've been able to deliver multiple concurrent full browser 720p videos without killing the systems on which they are running. The videos start immediately, are more scalable, and just look better - this provides a much better user experience than the old "buffering" animation while you're waiting for content.
The basic process of getting adaptive streaming up and running wasn't too bad, once we figured out a hosting solution. We've had an account at Limelight for quite some time, and although they were telling us they supported adaptive streaming, when push came to shove, it turns out they really don't. It was always "just around the corner".
We did a little digging and found a local hosting provider here in Portland that fully supports adaptive streaming and is a Microsoft Gold Certified partner. We had been using them for a while for various hosting needs, and they have really stellar support - if you're looking for an inexpensive adaptive streaming solution, check out Opus Interactive. They know what they're doing and can get it set up fast!
Our early smoke tests worked out pretty well. We used some various example code we found online to access some existing smooth streaming content. The process was pretty straightforward:
1) Add a reference to the SmoothStreaming.dll in your application
2) Add
using Microsoft.Expression.Encoder.AdaptiveStreaming;
to your usings.
3) Create a new adaptive streaming source:
AdaptiveStreamingSource MainSrc =
new AdaptiveStreamingSource(MainVideo, new Uri
("http://video3.smoothhd.com/ondemand/Got_Imagination_(California).ism/Manifest"));
4) Assign the AdaptiveStreamingSource to your media element:
MainVideo.SetSource(MainSrc);
Note that in step 3, we're pointing to the base file that Encoder 2 produced, and adding "/manifest" to the URI string. There is no file called "manifest" - you're telling the server which file to use as the manifest. The file being used as the manifest is an XML file that describes the available video and audio streams.
Fire up your application and you're good to go. We were able to read test streams from smoothhd.com and also had success in placing the Big Buck Bunny demo on our own hosting provider and pointing to that.
Life is good, until....
In creating some test streams for an application we were building, we starting running into trouble. Strangely, the code had worked fine for an application we just built, but broke on the very next application we worked on. The application was tossing out errors about reading the manifest file.
We did some digging and the root cause of the problem is that with Encoder 3, the format of the manifest file has changed. We had outsourced the encoding of the videos for the earlier project, and they had obviously utilized Encoder 2, which is why the code worked the first time through.
The change in the manfiest file format is no problem at all if you are using the Silverlight template from Encoder, because the libraries were updated there. However, if you have written a custom solution, you're going to need to update your code. This is both a good thing and a bad thing. It takes a little more code to make the streams go, but there appears to be a lot more stuff you can control.
Thankfully, it turns out not to be too difficult (in hindsight) to utilize the Encoder 3 adaptive streaming output in your own code, and the new libraries are also backwards compatible with the Encoder 2 manifest file format, so any existing streams you have encoded will not need to be re-encoded.
Here's how to use adaptive streaming with files encoded with Encoder 3:
1) Start by navigating to your Encoder 3 folder with Windows Explorer. On my systems, the path is:
C:\Program Files\Microsoft Expression\Encoder 3\Templates\en
2) The template you want is called "Graphing". In that folder, you will find a Silverlight application (XAP) file called "SmoothStreaming.xap". Change the extension to .zip, and open the archive up. You want to extract both the "PlugInMssCtrl.dll", and "SmoothStreaming.dll" libraries for use in your own projects.
3) In your application, right-click the project References, and pick "Add Reference". Locate and add both libraries.
4) Add
using Microsoft.Expression.Encoder.AdaptiveStreaming;
to your usings.
5) Next (you can code these however you'd like, this way just suited my needs), create variables for your video URI and AdaptiveStreamingSource:
private string uriString = "http://video3.smoothhd.com/ondemand/Got_Imagination_(California).ism/Manifest"; private AdaptiveStreamingSource MainSrc = new AdaptiveStreamingSource();
6) Now here's where it changes a bit. The AdaptiveStreamingSource has a MediaElement property, which needs to be assigned to your MediaElement:
MainSrc.MediaElement = MainVideo;
This is flipped from how it worked before. In the earlier example, the video source was set to the AdaptiveStreamingSource. Now, the AdaptiveStreamingSource has a MediaElement associated with it.
7) The AdaptiveStreamingSource also needs the location of the manifest file:
MainSrc.ManifestUrl = new Uri(uriString);
8) Finally, you can set up an event listener for "MainSrc.MediaElement.Loaded", and play the video once it has been loaded with the following code:
MainSrc.StartPlayback();
That should get the video going for you. I've run into a few quirks using the adaptive streams. The most troublesome was a "MediaEnded" event on a particular video that was raising 10 seconds or more before my video ended. This made it impossible for me to reset the state of the application when the video I was playing finished on its own. Still, that is a relatively minor issue that is easy to work around.
If you're interested in an example that uses this code, I've placed one online that you can download.
Entries (RSS)
October 29th, 2009 at 9:20 am
Uber thankful for your help on this, it got me up and running nice and quickly. thanks again.
November 17th, 2009 at 3:13 am
Well that End event that gets raised 10 sec before the end of the video. Under a “default” encoded video 10 sec is the buffer before the playback starts. So in turn the End event in your case might get triggered by the video finishing to load and not by the use finishing to actually watch it.
November 24th, 2009 at 5:19 pm
Hi Jeff,
Great info, big thanks for posting it!
I am in the process of doing exactly this myself, as we’ve developed a custom Smooth streaming player in SL2 and Encoder 2, which I’m now looking to upgrade to SL 3/Encoder 3.
This post was extremly helpful and saved me at least a few hours of headache