Monday, January 19, 2009

Dynamic Loading Expression Media Player Template and passing parameters by code

Following my previous post on How to pass parameters to the Expression MediaPlayer component by code, here is a solution that builds upon this post to Dynamicaly load the Media Player inside your app and pass parameters to it.

You can test loading of the player here. The source code can also be downloaded here.

The loading and costumization of the parameters is done like this:

// Download the Media Player using WebClient
private void downloadVideoPlayer()
{
WebClient downloader = new WebClient();
downloader.OpenReadCompleted += new OpenReadCompletedEventHandler(onDownloadVideoPlayerCompleted);
downloader.OpenReadAsync(new Uri("MediaPlayerTemplate.xap", UriKind.Relative));
lblLoadPlayer.Text = "Downloading Media Player";
}

// Once the Media Player is downloaded
private void onDownloadVideoPlayerCompleted(object sender, OpenReadCompletedEventArgs args)
{
try
{
string appManifest = new StreamReader(Application.GetResourceStream(new StreamResourceInfo(args.Result, null), new Uri("AppManifest.xaml",UriKind.Relative)).Stream).ReadToEnd();

XElement deploymentRoot = XDocument.Parse(appManifest).Root;
List<XElement> deploymentParts = (from assemblyParts in deploymentRoot.Elements().Elements()
select assemblyParts).ToList();

Assembly asm = null;
foreach (XElement xElement in deploymentParts)
{
string source = xElement.Attribute("Source").Value;
AssemblyPart asmPart = new AssemblyPart();
StreamResourceInfo streamInfo = Application.GetResourceStream(new StreamResourceInfo(args.Result, "application/binary"), new Uri(source, UriKind.Relative));
if (source == "MediaPlayerTemplate.dll")
{
asm = asmPart.Load(streamInfo.Stream);
}
else asmPart.Load(streamInfo.Stream);
}



MediaPlayerTemplate.Page myPlayer = asm.CreateInstance("MediaPlayerTemplate.Page") as MediaPlayerTemplate.Page;
Dictionary<string,string> dic = new Dictionary<string, string>();
dic.Add("autoplay", "true");
dic.Add("enablecaptions", "true");
dic.Add("muted", "false");
dic.Add("stretchmode", "0");
dic.Add("displaytimecode", "false");
dic.Add("playlist", "<playList><playListItems><playListItem title=\"\" description=\"\" mediaSource=\"silverlight.wmv\" adaptiveStreaming=\"False\" thumbSource=\"\" frameRate=\"23.9760431376968\" width=\"512\" height=\"284\" ><chapters><chapter position=\"11.256\" title=\"MYMARKER01\" /><chapter position=\"20.033\" thumbnailSource=\"silverlight_20.033.jpg\" title=\"Capitulo%201\" /><chapter position=\"45.585\" thumbnailSource=\"silverlight_45.585.jpg\" title=\"Chapter%202\" /><chapter position=\"58.646\" thumbnailSource=\"silverlight_58.646.jpg\" title=\"Chapter%203\" /><chapter position=\"72.199\" thumbnailSource=\"silverlight_72.199.jpg\" title=\"Chapter%204\" /></chapters></playListItem></playListItems></playList>");
myPlayer.StartUp(dic);

cnvMediaPlayer.Children.Add(myPlayer);
lblLoadPlayer.Text = "";
LayoutRoot.UpdateLayout();

}
catch (Exception e)
{
lblLoadPlayer.Text = "Download Error: " + e.Message;
}
}



If you download the source code you will need to create your own playlist that points to a a movie of your own and set the thumbnails and chapters as you wish. Check the following line of code inside VideoPlayerHoster, Page.xaml.cs



dic.Add("playlist", "<playList>...



The Dynamic loading was implemented by looking at these 2 posts:



http://www.silverlighthack.com/post/2008/09/29/Silverlight-2-(RC0-RTM)-Dynamic-Assembly-Loading.aspx



http://silverlight.net/learn/learnvideo.aspx?video=65687



Using Expression Encoder 2 MediaPlayer Templates in your application

Microsoft Expression Encoder 2 SP1 now includes a set of Silverlight 2 Output Templates:

clip_image002

After installing SP1 you'll have a some Silverlight 2 templates in "C:\Program Files\Microsoft Expression\Encoder 2\Templates\en".

The Templates use 2 controls that implement most of the logic that we need on our media apps: MediaPlayer and ExpressionPlayer. These controls take care of all basic media handling functionalities but also Video Marker handling, Chapters and chapter thumbnails, playlists, cpations, etc.

Out-of-the-box the templates can be hosted in a html or aspx page and the parameters passed when loading the XAP. Here is the html of the page that is created when running your template:




<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="MediaPlayerTemplate.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="initparams" value='autoplay=&lt;$=TemplateParameter.AutoPlay$>,autoload=<$=TemplateParameter.AutoLoad$>,enablecaptions=<$=TemplateParameter.EnableCaptions$>,muted=<$=TemplateParameter.Muted$>,stretchmode=<$=TemplateParameter.StretchMode$>,displaytimecode=<$=TemplateParameter.DisplayTimecode$>,playlist=<$=PlayListParam(TemplateParameter.AllowedCodecs)$>' />

All customization is made via the initparams.If you want to use the MediaPlayer inside your own Silverlight application (that happens to use a media player) you need to make same changes in order to pass the parameters by code and not by the initparams of the silverlight object command in HTML as the template does.



When Silverlight loads the XAP via HTML it calls:




        public Page(object sender, StartupEventArgs e)

        {

            InitializeComponent();

            myPlayer.OnStartup(sender, e);

        }


Since you cannot create a StartupEventArgs class because it is marked as internal we need another way to pass our parameters from code.



Here are the changes:



1. In ExpressionPlayerControl.cs change the OnStartup method to receive a Dictionary<string, string> instead of StartupEventArgs:




public override void OnStartup(object sender, StartupEventArgs e)

replace by


public override void OnStartup(object sender, Dictionary<string, string> e)


2. Inside the OnStartup method replace "e.InitParams" for InitParams.



3. Since ExpressionPlayer derives from MediaPlayer and OnStartup is overrided we also need to update the OnStartup method in MediaPayer.cs:



public override void OnStartup(object sender, StartupEventArgs e)


replace by


public override void OnStartup(object sender, Dictionary<string, string> e)


4. Since you changed the method signature you also need to update the call to it on Page.xaml.cs and cast it to Dictionary<string, string>:




public Page(object sender, StartupEventArgs e)

{

    InitializeComponent();

    myPlayer.OnStartup(sender, (Dictionary<string, string>) e.InitParams);

}




5. Create a new method that will allow your code to costumize the player:



public void StartUp(Dictionary<string, string> InitParams)

{

    myPlayer.OnStartup(this, InitParams);

}


6. Now you are ready to costumize your mediaplayer from code:





   1:  MediaPlayerTemplate.Page myPlayer = asm.CreateInstance("MediaPlayerTemplate.Page") as MediaPlayerTemplate.Page;

   2:  Dictionary<string,string> dic = new Dictionary<string, string>();

   3:  dic.Add("autoplay", "true");

   4:  dic.Add("enablecaptions", "true");

   5:  dic.Add("muted", "false");

   6:  dic.Add("stretchmode", "0");

   7:  dic.Add("displaytimecode", "false");

   8:  dic.Add("playlist", "<playList><playListItems><playListItem title=\"\" description=\"\" mediaSource=\"silverlight.wmv\" adaptiveStreaming=\"False\" thumbSource=\"\" frameRate=\"23.9760431376968\" width=\"512\" height=\"284\" ><chapters><chapter  position=\"11.256\" title=\"MYMARKER01\" /><chapter  position=\"20.033\" thumbnailSource=\"silverlight_20.033.jpg\" title=\"Capitulo%201\" /><chapter  position=\"45.585\" thumbnailSource=\"silverlight_45.585.jpg\" title=\"Chapter%202\" /><chapter  position=\"58.646\" thumbnailSource=\"silverlight_58.646.jpg\" title=\"Chapter%203\" /><chapter  position=\"72.199\" thumbnailSource=\"silverlight_72.199.jpg\" title=\"Chapter%204\" /></chapters></playListItem></playListItems></playList>");

   9:   

  10:  myPlayer.StartUp(dic);





(assuming myPlayer was defined in your Xaml)

Saturday, December 13, 2008

Host Deep Zoom project on Silverlight Streaming

It is possible to host a Deep Zoom project with all it's images on silverlight.live.com
It doesn't seem possible at first because the interface asks you to upload only the xap file. So ... where do we put the images ? You just need to do some "magic" as explained here

Here is a sample project hosted there.

Unexpected browser crash with Silverlight 2

I'm developing a Silverlight application that uses the MultiScaleImage control and also some text overlays that i'm scaling according to the Deep Zoom scale. Very often the browser (Internet Explorer, Firefox and Chrome) crashes.

It seems there is an issue mixing ScaleTransform and MultiScaleImage control as also posted on the Silverlight Forums

The Application that has this problem is this one when you enable the checkbox useScaleTransform, but with a different Deep Zoom output. with the one shown here does not seem to reproduce the problem :(

Here is the entry on the event viewer:

Faulting application IEXPLORE.EXE, version 7.0.6000.16764, time stamp 0x48f6a2ed, faulting module ntdll.dll, version 6.0.6000.16386, time stamp 0x4549bdf8, exception code 0xc0000029, fault offset 0x000675fc, process id 0xf18, application start time 0x01c95d5ad4de2d60.

Tuesday, October 14, 2008

UX Week with Peter Morville

Due to the incresing importance of the user experience and the way information is organized in a site, Fullsix invited Peter Morville to present a series of workshops about: User Experience, Information Architecture and Findability.


These workshops will happen in November in Lisbon:

- 3rd Nov - User Experience Strategy: Public Talk at Microsoft Portugal.

- 4,5th Nov - User Experience Workshop (2 days)
- 6th Nov - Information Architecture & Search Workshop (1 day)


More information can be found at http://www.fullsix.pt/uxweek/




Technorati :

Thursday, October 09, 2008

Classic Mistakes

Eight years ago I read the book Radid Development by Steve McConnell. In this book Steve presents the classic mistakes in software development and I found it "very funny" to notice that my company was doing exactly the same mistakes that Steve pointed out like: Feature Creep, Gold-Plating, Adding people to a late project, etc.

Today I came across a interesting whitepaper where Construx updates these classic mistakes after surveing 500 Software Practicioners. They introduce some new classic mistakes like Confusing estimates with targets or Excessive multi-tasking among others.

Thursday, August 28, 2008

Quick Start to Sprint Backlog template

I started using Mitch Lacey's Sprint Backlog Templates in our scrum projects. Here is a small guide to help someone new to it quickly start using it.




A. Preparing the ground ­ - The initial tasks you need to do to prepare the template for your project:


1. Fill in the team roster. The Alias will be used in the other sheets (Driver column in the Sprint Sheet). The alias should not changed after the other sheets are filled (unless you change sprint data - Column Sprint!$F).


Fill in any extra information about the team. All information besides the alias will be purely informational.


Also in this sheet, you should fill in the Sprint Vision (Team Roster!$C$4) so it is clear for all members of the team.



2. Set the sprint start date in Capacity!$E$3


If your dates are not in US format you need to manually change the week days in column D because formula for I6 expects English week days.



3. Specify your options for the project in the Analysis!E40:E47:


a. SkipWeekends (Analysis!E40) - (0=30 calendar days; 1=30 working days). Set to 1 to have dates skip over weekends (30 working day sprint, >30 calendar day sprint). Do not switch after Sprint has started or data will be stored under wrong days.


b. DailyScrumDateModifier (Analysis!E41) -Number of days added to or subtracted from today's date to ensure the highlighted date column in the sprint worksheet corresponds to the day of the current daily Scrum meeting. In the Spint worksheet, Today's day will be highlighted. This value adjusts the day that is highlighted. Negative number to go back from today's date; positive number to go forward from today's date.



Do not change the Workbook-Wide Constants These are constants for the formulas used elsewhere.



4. Define your functional areas in Project Specific Reports!A9:A24. If you need to change the number of columns you will need to adjust the Data validation of columns B of the Sprint Worksheet by going to Data, and then Data Validation menu.



5. Fill in the Sprint Backlog items


a. Worktype - select between Feature, Tax, Precondition or spike


i. Feature - describes functionality that will be valuable to either a user or purchaser of a system or software.


ii. Tax - A tax is the cost of doing business


iii. Precondition - Preconditions are items that must happen at the completion


iv. Spike - Brief experiment to learn more about an area of application. Timeboxed, which allows the spike to be estimated.


b. Deliverable Area - You can select from the functional areas of your project that you defined in step 4. This will allow you to get a report based on the functional areas.


c. Product Backlog Item or Group -


d. Work Item ID - The Id of the work item.


e. Sprint Work item Description - Description of the work to be done.


f. Driver - Who will be responsible to drive this work item.


g. Status - it is automatic set for "Complete";"In progress" and "pending". You can manually add "Postponed" and "Cancelled", so it shows up in the reports.


h. Pri - Priority of the Work item


i. Initial - The initial estimate for this work item.




B. Daily updates - The daily information to be updated on the template.


On the end of the day or the morning of the next day each person of the team needs to update the time spent with each work item and re-estimate the remaining time to complete the task.


Go to the correspondent Day of the iteration and fill :


1. Spent - Time spent during that day with that work item


2. Left - The remaining time to complete the work item. It can be higher then the previous Left value due to new knowledge you acquired during that day.



C. Analysis - Checking the flow of the sprint


On the Analysis worksheet you can see the burndown chart per items and hours and several other overall indicators that are self explanatory.