Welcome to MSDN Blogs Sign in | Join | Help

TimeCode Ranges from Windows Media Metadata

As a follow up to my previous post , I have updated the code to add the ability to extract SMPTE timecode ranges. 

 

The WMMetadataReader class (in WMMetadataReader.h) now has a public method like below:

System::Collections::Generic::List<SMPTETimeCodeRange^>^ GetSMPTERanges(String^ FilePath, int StreamIndex);

 

This allows you to explicitly get the time code ranges, for a specific video stream in a WMV file. If you want all the metadata, the GetStreamMetadata() method on the same class, now also calls the above method internally, and returns the time code ranges packaged in the WMStream.TimeCodeRanges property. The SMPTETimeCodeRange type is shown below.

SMPTETimeCodeRange

 

 

Note that the RangeNumber property stores the index of the range, in case the file has multiple time code ranges. The Start and the End property are of type string, and exposes the time code in the standard “hh:mm:ss:ff” format. To manipulate these time codes, convert them to absolute times or to otherwise work with them, you can use the very excellent TimeCode class from John Deutscher.

I have uploaded a new zip with the modified code here.

Posted by jitghosh | 0 Comments

2nd Edition of our Silverlight Recipes book is now available…

SLRecipes

 

Rob and I worked hard on updating this for SL 3. If you do happen to purchase it, please let us know if you like the format, the topics and any thoughts on how we can improve. We are about to start early work on the next edition for Silverlight 4 – your feedback will be highly appreciated.

Enjoy!!

Posted by jitghosh | 0 Comments

Windows Media Metadata in Managed Code (and by extension - Silverlight)

I have encountered several inquiries about accessing the metadata embedded in Windows Media file headers from Silverlight. Unfortunately Silverlight does not expose this information out of the box. The only way you can access this is by utilizing the Windows Media Format SDK.

The Format SDK exposes its functionality in COM and requires you to write your code in C++. The nice thing about Visual C++, is that the C++ compiler allows you to author mixed mode assemblies i.e. one assembly containing both CLR types as well as code that is completely unmanaged, both authored in C++. Using this feature you could author a set of CLR targeted wrappers in C++ that interact with the Format SDK to expose select metadata to the managed world. Once you are done with that step, you can host this code in a Windows Service, a WCF service or some other form of server side component accessible over HTTP/TCP, and then have your Silverlight code interact with that service to get the metadata over the wire.

Attached is some code that I authored recently, that allows you to get started in that direction. You will find the code here.

In the rest of the post I will give you some details on the code. To better understand (and modify if necessary) the source, you may need some familiarity with authoring managed code with C++, the basics of COM in C++, and the Windows Media Format SDK.

Windows Media Files contain a lot of information in the header. The requests I have most often encountered are for the following:

  • File Level Metadata Attributes and Per Stream Metadata Attributes: A Windows Media file can contain multiple streams of different types including video streams, audio streams, text streams etc. The header may contain metadata attributes defined for the entire file, as well for each individual stream in the file.
  • Frame Rate for the video streams in the file
  • Embedded SMPTE Timecode ranges for the video streams

In the attached solution, you will find three projects – the WMShim and the WMShimManagedClasses projects produce assemblies that you will need to reference in your code to extract the metadata from the file. The third project named WMShimTestHarness contains a simple WPF application that shows you how to extract metadata using the classes in the previous two assemblies.

The class diagram below shows  the managed types that I use to define the metadata that the C++ code extracts (these types are defined in C#, in the MetadataDataContracts.cs file, in the WMShimManagedClasses project). Since the goal is to extract the metadata and have it be accessible remotely, these types are defined as data contracts to make them easily serializable.

  ClassDiagram1

The WMMetadataAttribute type defines a single metadata attribute and its value. The Name property contains the actual Windows Media metadata field name, and Label (where possible) contains a more friendly name explaining the field. The PropertyType contains string name for the CLR type that is best suited to represent the Value in managed code, and the Unit (where applicable) contains a string literal defining the unit of measurement(like bps for bitrate).

The WMStream type defines a stream, and the Attributes property returns a collection of WMMetadataAttribute instances for a specific stream or at the file level.

  • StreamType  contains one of the following values : “File”, “Video”, “Audio”, “Text”, “Script”, “Image”, “File Transfer” or “Unknown”. Each of these string literals are meant to represent a valid media type or subtype as described by the Format SDK (see http://msdn.microsoft.com/en-us/library/dd757532(VS.85).aspx ) that can be used to define a stream type. The exceptions are the values “File” used to describe file level metadata (it is not actually a stream, I just reuse the WMStream type – too lazy to build another type to represent a file) and the value “Unknown” in case there is some weird stuff going on.
  • FrameRate & TimeCodeRanges are meaningful only for video streams
  • For file level metadata BitRate, FrameRate, TimeCodeRanges are not meaningful, and StreamIndex and StreamNumber are set to 0.

The primary C++ class that is central to the extraction functionality is named WMMetadataReader, defined in WMMetadataReader.h in the WMShim project.

 

 

public ref class WMMetadataReader
  {
  public:
    WMMetadataReader(void){} 
    /** 
    Get the number of streams in a media file
    FilePath: Absolute file path 
    Return: Stream count
    **/
    unsigned int GetStreamCount(String^ MediaFilePath);
    /** 
    Get the metadata for a specific stream in a media file
    FilePath: Absolute file path
    RFCLangIdentifier: string literal for the language identifier - "en-us" etc.
    StreamIdx: 1 based Stream Index, Pass 0 for file level metadata
    Return: WMStream instance
    **/
    WMStream^ GetStreamMetadata(String^ FilePath,String^ RFCLangIdentifier, unsigned int StreamIdx);
    /** 
    Get the framerate for a video stream
    FilePath: Absolute file path 
    StreamIdx: 1 based Stream Index
    Return: Frame rate, 0 for non-video streams
    **/
    double GetFrameRate(String^ FilePath, unsigned int StreamIndex);
  }

The code above shows the public methods on WMMetadataReader- the code comments will tell you what each method does. The easiest way to extract metadata for a media file is to call the GetStreamCount() method to get the # of streams, and then call GetStreamMetadata() once for each Stream. Remember to pass a 1 based StreamIdx value for the actual streams, and pass 0 to get the file level metadata. The C# code snippet below will give you an idea – as we loop through the streams and get the metadata for each, we just add them to a List named streams, that we will use eventually else where in our code.

WMShim.WMMetadataReader rdr = new WMShim.WMMetadataReader();
int StreamCount = (int)rdr.GetStreamCount(FilePath);
List<WMStream> streams = new List<WMStream>(StreamCount + 1);
for (int idx = 0; idx <= StreamCount; idx++)
{
  streams.Add(rdr.GetStreamMetadata(ofd.FileName, "en-us", (uint)idx));
}

Below are screen shots from the WPF test harness that is also in the attached code. The above C# code snippet is actually from that app. The two screen shot shows the video stream metadata and the file level metadata from a wmv file named Dust_To_Glory.wmv.

snap1 snap2

If you look through the code you will notice that I do not supply any code to extract SMPTE Timecode ranges yet. I am still finalizing that code – I will have another post with an attachment here in a few days.

A few notes about the attached code:

- The code was built on 64 bit Windows 7 using Visual Studio 2008

- The WMShim C++ project was built targeting the x64 platform. So do make sure that you have the x64 compilers and tools for C++ installed as a part of your VS 2008 installation. If you want to retarget WMShim to a 32 bit platform instead, just change the platform to Win32 in your Project|Properties dialog and recompile.

- If you want to run the code on Windows Server, you will need to enable the “Desktop Experience” feature. This puts the necessary windows media components on the server (they are not there by default – unlike the Windows client desktop OS platforms).

 

 

 

Until the next post then !!

Posted by jitghosh | 0 Comments

IIS Media Services 3.0 Released!!

The IIS Media Services team just released the IIS Media Services 3.0 suite of technologies. This is pretty big release for us – with Live Smooth Streaming possibly being the coolest part of it. If you are watching the NBC Sunday Night Football on the web, then you have seen Live Smooth Streaming in action. You you have not – you must check it out here.

To install and try out IIS Media Services 3.0 , download it via the Web Platform Installer here.

So what’s in IIS Media Services 3.0 ?

Smooth Streaming and Live Smooth Streaming for adaptive streaming of media over HTTP

Bit Rate Throttling for controlling bandwidth spent in delivering media

Web Playlists for controlled and sequenced delivery of media

Advanced Logging for logging both on the client and the server

Application Request Routing to provide edge caching.

 

Another notable bit of software that was just put out there (albeit still in beta) is the Smooth Streaming Player Development Kit. If you are a Silverlight developer, and are looking to extend the same programming model of the Silverlight MediaElement to the world of Smooth Streaming, then the SmoothStreamingMediaElement (SSME) component contained in this kit will make your life really easy. The SSME exposes a ton of additional rich functionality to take advantage of the Smooth Streaming platform and file formats – do check it out !!

 

I will be blogging more on some of this stuff in the coming weeks – ta for now !!

Posted by jitghosh | 1 Comments

Silverlight 3 is now officially released!!

WooHoo!! Go read more about it in Scott’s blog here. I will be positing my own experiences and thoughts in the coming days.

 

Learn more and download at http://silverlight.net/GetStarted/

 

Enjoy!!

Posted by jitghosh | 0 Comments

Architect Council Webcasts

The Microsoft Patterns & Practices team, in collaboration with members of the Microsoft Developer Evangelism team (my uber team that is) is putting together a series of webcasts titled “Pragmatic Patterns for Architects” . I would vote “must attend” for these. Below are more details:

 

ARCHITECT COUNCIL | Pragmatic Patterns for Architects

“Cloud computing will supersede traditional IT”, “SOA will enable business agility”, “my way or the highway”, etc. We’ve all heard this type of proclamations before, as many look to the “next big things” in technology to exact sweeping changes and solve many issues; truth is, technologies and tools aren’t as instrumental in influencing progress, as the design and discipline in applying them to specific issues. When used appropriately, technologies and tools can be powerful enablers that bring about change.

One of the things we hear a lot working with the community is a desire for more guidance about how to use the technology instead of just talking about features and functions.  To address this, our team has put together a series of live webcasts on June 9th – 11th which will focus on guidance and patterns for some of today’s hottest topics. 

DAY 1 – June 9, 2009 at Noon PST

Patterns for Moving to the Cloud

Larry Clarkin & Wade Wegner

Everything that you read these days seems to suggest that you should be moving to the cloud. But where do you start? Which applications and services should be moving to the cloud? How do you build the bridge between on-premises and the cloud? And more importantly, what should you be looking out for along the way? In this session, learn architectural patterns and factors for moving to the cloud. Based on real-world projects, the session explores building block services, patterns for exposing applications, and challenges involving identity, data federation, and management. This session provides the tools and knowledge to determine whether cloud computing is right for you, and where to start.

DAY 2 – June 10, 2009 at Noon PST

Building Silverlight & WPF Applications with Prism

David Hill

Prism provides guidance, via design patterns, to help you build robust, flexible and modular Silverlight and WPF applications. These patterns support unit testing, separation of concerns, loose coupling and the ability to share application logic between Silverlight and WPF applications. Prism includes source code for the library itself, extensive documentation, and a sample application that shows how the patterns work together in a real-world application. It also includes a Visual Studio add-in to help you easily share code between WPF and Silverlight. This session provides an overview of Prism, and shows how you can use Prism to design and build composite Silverlight applications.

DAY 3 – June 11, 2009 at Noon PST

Patterns for Parallel Computing

David Chou

With recent advances in cloud computing, service-oriented architectures, distributed computing, server virtualization, multi-core processors; we are now seeing parallel computing techniques being implemented across the spectrum. It’s moving towards mainstream applications such as internet-scale web applications, massive data processing, graphics rendering, but the myriad of choices also present a number of questions on when and how to utilize parallel computing. This session explores the architectural patterns and trade-offs between different forms of parallel computing including: approaches for utilizing them to improve application performance, optimizing the use of existing infrastructure, and applying concurrency towards day-to-day enterprise information processing needs.

WEBCAST AGENDA

11:45 AM (PST)

Open for Dial-in

12:00 PM (PST)

Day’s Content

12:50 PM (PST)

Q&A

01:00 PM (PST)

Raffle and Close

REGISTER

To register, please click on the link below for each day:

 

Title

Event ID

Link to Register

Day 1 6/9/09

Patterns for Moving to the Cloud

1032416875

http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032416875&EventCategory=2&culture=en-US&CountryCode=US

Day 2 6/10/09

Building Silverlight & WPF Applications with Prism

1032416983

http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032416983&EventCategory=2&culture=en-US&CountryCode=US

Day 3 6/11/09

Patterns for Parallel Computing

1032416984

http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032416984&EventCategory=2&culture=en-US&CountryCode=US

We will email you with the LIVEMEETING information and log-in detail a few days before the actual event. We will use the email address you provide in the registration. Thanks!

SPEAKER BIOS

Larry Clarkin - SR ARCHITECT EVANGELIST, Microsoft

Wade Wegner - SR ARCHITECT EVANGELIST, Microsoft

Architect in the Developer & Platform Evangelism division at Microsoft, tasked to collaborate with organizations in the advanced and emergent areas of enterprise architecture, SOA, Web 2.0, and cloud computing, as well as to support decision makers on defining technology adoption strategies. You can reach Wade at his blog http://www.architectingwith.net/ or through twitter at http://twitter.com/wadewegner.

David Hill – PRINCIPAL ARCHITECT, Microsoft Patterns & Practices Team

David Chou – ARCHITECT, Microsoft

Architect in the Developer & Platform Evangelism organization at Microsoft, focused on collaborating with enterprises and organizations in many areas such as cloud computing, SOA, Web, RIA, distributed systems, security, etc., and supporting decision makers on defining evolutionary strategies in architecture. Drawing on experiences from his previous jobs at Sun Microsystems and Accenture, David enjoys helping customers create value from using objective and pragmatic approaches to define IT strategies, roadmaps, and solution architectures.

Posted by jitghosh | 1 Comments

MTV & Silverlight 3 at NAB 2009

NAB 2009 rocked !!

It was exhausting working the booth, standing on my feet all day, talking to so many people over the course of four days, but it was so exciting at the same time. We showed many cool things at the Microsoft booth, including Silverlight 3, IIS 7 Smooth Streaming, our Fast search engine, our Advertising solutions, a ton of solutions from our partners, and last but not the least – some very interesting open source starter kits that my team built, and that I will blog about in coming posts.

But I am especially excited about a specific application I was directly involved in.

Viacom/MTV announced a web based Digital Asset Management Workflow application completely built in Silverlight 3 (of course using the beta bits for now) and .Net 3.5. This is very cool, not just because it is an early adoption of Silverlight 3, but because :

- It is a great proof point that Silverlight is not just for consumer facing scenarios on the web, but is equally suited for more rigorous applications in broadcast media workflow.

- It is one of the first production applications to use the h.264 playback capabilities being enabled in Silverlight 3. MTV creates all their proxies as QuickTime .mov files, with the essence encoded using h.264 compression, either in SD or in HD resolutions. Since QT is essentially a variant of the MP4 container structure, and SL 3 supports parsing MP4 and decoding h.264 natively, we could playback all of MTV’s QT content natively in SL3, without any further transcoding. This was a huge win-win for all involved both from a time and cost perspective.

I provided some of the necessary technology guidance to a joint team from Microsoft, Vertigo and MTV in implementing the solution.

You can read more about the general press release from Viacom CIO Joe Simon here and about the specific case study here.

Posted by jitghosh | 4 Comments

Binding an embedded image using a value converter

Recently I needed to bind some embedded images to data templates. If you look at the Image type in Silverlight 2, you will see that it exposes a Source property of type ImageSource that can be set to the URI of an image either relative to the XAP, or in its absolute form. If the URI is valid, the image stream is opened and read at runtime, an underlying BitmapImage is created around the stream and is then fed into Image.Source (BitmapImage derives from ImageSource).

However this is all great when the images are on a web site. But what about images that are packaged with my XAP ? It is actually not very hard to bind those either. Assuming you have a XAP assembly named Foo (with Foo being the default namespace), and say your image, Bar.png is stored in a project folder named Images, once you compile the assembly, the image is embedded into the assembly as a resource named Foo.Images.Bar.png. To get this done through Visual Studio mark your image  as an Embedded Resource. However to access the embedded image and create a BitmapImage out of it, you will have to write some code like this:

BitmapImage bim = new BitmapImage();
bim.SetSource(this.GetType().Assembly.GetManifestResourceStream("Foo.Images.Bar.png"));

This BitmapImage instance can then be bound directly to the Image.Source property using a traditional binding expression.

However, you may already know all of this, and in any case I wanted to make this a little more general purpose. I did not quite like the fact that the string literal representing the image (in the above case “Foo.Images.Bar.png” ) could not be directly fed to the Image element in my XAML like a URI. I had to create some sort of artificial property in some type that would instead expose a BitmapImage instance, and then bind that property to my Image.Source. In effect what I wanted to do was something like this:

<Image Source="Foo.Images.Bar.png" />

but sadly that would not work. So instead I took the approach of using a value converter. I wrote a converter that looks like this:

public class ImageResourceNameToBitmapImageConverter : IValueConverter
  {
    public object Convert(object value, Type targetType,
      object parameter, System.Globalization.CultureInfo culture)
    {
      //check to see that the parameter types are conformant
      if (!(value is string) || targetType != typeof(ImageSource) )
        return null;
      BitmapImage MenuItemImage = new BitmapImage();
      try
      {
        MenuItemImage.SetSource(this.GetType().Assembly.
          GetManifestResourceStream(value as string));
      }
      catch (Exception Ex)
      {
        return null;
      }
      return MenuItemImage;
    }
    public object ConvertBack(object value, Type targetType,
      object parameter, System.Globalization.CultureInfo culture)
    {
      throw new NotImplementedException();

    }
  }

 

Now in my XAML I can declare the converter:

 

<local:ImageResourceNameToBitmapImageConverter x:Key="REF_ImageResourceNameToBitmapImageConverter" />

and then an Image element like this:

<Image Source="{Binding Converter={StaticResource REF_ImageResourceNameToBitmapImageConverter}}" DataContext="Foo.Images.Bar.png" />

 

This does the trick. Since the Binding does not specify a path, the converter gets the DataContext (which is the qualified image resource string name) passed in as the value parameter, and all I do in the converter is use the same code as before to create and pass out the BitmapImage instance.

 

Came in pretty handy and saved me the grief of creating unnecessary CLR properties for each necessary image binding.

Posted by jitghosh | 1 Comments

Open position in our team..

Our team (Developer & Platform Evangelism for Communications, Media & Entertainment) is looking to hire a person in the role of a Platform Strategy Advisor. A PSA is a very exciting, highly visible, and influential role within the team and the company. In the words of the hiring manager, below is a description of the job role:

The PSA role is a combination of business development and technical advisory. PSA's are tasked with creating deals that will drive large scale, early adoption of Microsoft technology across key accounts. The expectation is, not only will these wins lead to PR and evidence, but will also strengthen the long-term relationship between Microsoft and the customer. As such, PSA candidates need a good mix of business and technical skills as well as knowledge of the particular industries they serve. The role focuses on Media, Entertainment and Network service providers (Telco, Cable and Satellite) with a particular interest in how they are merging into one “Converged Services and Content Distribution Industry”.

This position handles the top 20-30 customers across those industries and  is based on the east coast. The customers are located throughout the US so travel is required (about 30-40%), with most being one-two day trips. Success is measured by the number of large-scale evidence wins produced and overall strategic relationship we have with the accounts in the industry. Typical activities would include -

  • working with account teams to schedule executive level briefings
  • maintaining close, working relationships with the CTO/CIO organizations
  • working with those organizations to develop strategic projects that drive early adoption of .Net developer platforms and products
  • building mutually beneficial business terms around those projects to create evidence and PR
  • working with architects to develop the project and align it with strategic initiatives inside of Microsoft
  • securing internal funding and resources for those projects
  • managing a pipeline of strategic projects and evidence
  • ensuring that evidence and PR is created from the strategic projects
  • building relationships with key partners to assist in these projects
  • participation in Industry events
  • Provide thought leadership to the industry by way of publications, event participation and PR opportunities
  • working with other members of the team to identify strategic projects and help coordinate activates around them

We're looking for someone with at least 5 years of industry experience (Media, Telco, Cable) as well as a background in software development. They must have acumen in the areas of business development and/or management and have some experience leading a team.

If you are interested, or know someone who might and fit the profile, please send an email to Helen Axelson (helenax@microsoft.com) and  reference Job Code:247186.

Who knows ? We could have some fun together shaping the future of digital media !!

- Jit

Posted by jitghosh | 1 Comments

Back to blogging - my book and other news…

I have been inconspicuously absent on blogosphere for a while now. For my handful readers – I hope you missed me :-). I am back to blogging and hope to put out some more interesting stuff for you guys in the coming weeks.

First for exciting news. We are close, very close to finishing up Silverlight 2. The product team just made the first release candidate available, and you can download it here. You can read more about the release in Scott Guthrie’s blog post here.

We also just announced the first service pack to Expression Encoder 2. Video is very important to my work, and there are some tremendous changes to be included in the SP. H.264/AAC output – finally !!!. Read more about it in Ben’s blog post here and James’ post here.

I have also been busy finishing my book on Silverlight 2, that I have been coauthoring with my teammate Rob Cameron. You can pre-order the book here. We are in the final phases of editing, but APress is also planning to put out an e-book version in their Alpha book program that allows you to pre-purchase the book and progressively read chapters as they are being edited. You can find more details at the APress web site. Rob and I are really excited about the book, and for those of you who decide to give it a try, we hope you enjoy reading it as much as we enjoyed writing it. It was hard writing a book targeting the RTM version of a technology that was still being built while we wrote. But we are pretty proud of the end product, and if you are planning to work with Silverlight 2, we are confident you will find the book useful.

Until the next post…

Posted by jitghosh | 1 Comments

Silverlight 2 Beta 2 is now available !!

Woo - Hoo!!

Navigate over to http://silverlight.net/GetStarted/ to download the  freshly minted beta 2 bits including the runtime, the SDK, and the Visual Studio 2008 tools for Silverlight 2 development. There is also a brand new version of Blend 2.5 preview and a new version of the Deep Zoom Composer available for download as well.

I have been quite busy working on several large customer projects that involve Silverlight 2 Beta 2. In the coming weeks do visit here to find more tid-bits about SL 2 development and the changes in Beta 2.

Enjoy !!

Posted by jitghosh | 2 Comments

Broken link to attachment fixed for previous post

Sone folks pointed that the code sample attachment in my previous post on the Async Multiple File Upload Control for Silverlight 2 was broken. I have fixed it in the post as well provided a link below to the code on my Windows Live SkyDrive.

http://cid-60bb739cbf5d117b.skydrive.live.com/self.aspx/Public/MultiFileUpload/MultiFileUpload.zip

Sorry for the incovinience.

Posted by jitghosh | 2 Comments

Async Multi File Upload Control with Metadata support for Silverlight 2 (Beta 1)

By now a lot of you must be having a lot of fun of Silverlight 2 Beta 1. If you have not downloaded, installed and played with SL 2 Beta 1, I urge you do it right away - you are missing out!!! You can download SL2 here.

I have been working on a number of projects that are using the Silverlight 2 beta bits, and several of them needed file upload functionality. I looked around, and found a few controls, but while all of them did certain things admirably well, there were a few things missing.

  • A few of the controls I found allowed you to select multiple files, and upload them, but all of them did so sequentially i.e. one file at a time. Parallel uploads were a necessity for my projects, with the extent of parallelization as a controllable parameter.
  • None of them really allowed you to control how a large file gets chunked i.e. at what size boundaries. This can be an important parameterization to improve efficiency.
  • Since most of my projects are media related, it is common for me to work on applications where a user is allowed to attach metadata to the file being uploaded. And metadata could vary from application to application. I needed a control that would allow some sort of metadata architecture, that is not hard wired to the control and pluggable by design. I wanted to reuse the same control in many apps, with the consuming apps defining the metadata UI and serialization process, and wiring it to the control through a standard interface.
  • And lastly I also needed a completely templatable control.

Needless to say I could not find a combination of all of the above in one control - so I set out to do the next best thing - write one for my own. And the point of this entry is to share it with you. The code is zipped and attached.

First a little about the solution structure. You will find several projects in the solution:

  • MFUControl - This the main control project containing most of the functionality behind the control. It also contains all of the control's UI.For those of you who are just starting out with SL 2, or have not played with WPF custom controls before, the default UI for a custom control is defined as a control template that gets applied to the control through a style defined in a file called generic.xaml - this file has to be named exactly this way for the runtime to recognize it(this is similar to WPF). Also, applying a UI to a custom control by way of a control template allows the consumer of the control to later apply other templates to change the L&F.
  • ProgressBar - Since SL 2 Beta 1 does not have a ProgressBar control yet, and I needed one, I created one by extending the RangeBase control. Again a default control template is applied and can be found in the generic.xaml file in the project.
  • MFUTestApp - This the test harness for the app - standard SL 2 app that has one page with the control on it.
  • TestWeb - An ASP.Net web app that can be used to run MFUTestApp from IIS
  • UploadService - This the HTTP backend to which the files are uploaded. I have chosen to use a WCF service, using a RESTful interface (implemented using the WCF Web Programming layer), with a single operation that gets invoked using an HTTP POST accepting a file stream.

I will attempt to sparingly explain some of the key pieces of the code here. I have commented the code pretty well - so hopefully in reading through the downloaded code most of it will be obvious to you.

But first things first - below is a screen shot of the control in action, uploading some videos. By the way, if some of you are designers and other kind of creative professionals, and are snickering at the UI, you will have to forgive the paucity of my artistic skills. I can code, but let it be known - I cannot design nice UI's :-).

MFU1

So the key pieces of the code as I said :

  • The actual upload functionality - The upload piece is pretty simple. I use the HttpWebRequest type to do the upload. Initialize it properly, plug in the file name in the HTTP headers, get the request stream, write the file content to it, and POST - that's about it. On the service side, it is even simpler - open the stream, get the file name from the HTTP headers, create a new file at a known location and write it out. This goes on for every file that is being uploaded.
  • The parallelization/multi threaded upload - Unfortunately while SL 2 allows you to spin up your own threads, it does not allow making network calls from anywhere other than the UI thread(at least not yet). So I had to look for a way around. The good thing is that the network API's in SL 2 are all async, and use the standard Begin...()/End...() async invocation pattern established in .Net. In this pattern as soon as you make the egin..() call, control returns to your code and the actual unit of work initiated with the call gets automatically shifted to a background thread from the thread pool.

In my code I break up the entire list of files of chosen by the user into sublists based on the number of background threads the user desires to use (this is specified by the MaximumUploadThreads dependency property on the control) - one sublist for each thread. As an example if you had selected 14 files and specified 4 threads, the first 3 sublists each get 4 files, and the last one gets 2.

Once these lists are broken up, I loop through them, and call BeginGetRequestStream() once for the first file in each list. Control returns and only as many threads get employed as there are sublists, and upload starts. To ensure that at any point in time, no more threads get employed, I start uploading the next file in any sublist, once the previous upload for that sublist is completed i.e. initiate the next upload in the callback handler specified in the BeginGetResponseStream() method for the previous upload, which gets invoked once a response comes back from the service after the previous upload completes (or fails).

Note that upping the number of threads will allow you to achieve more parallelization, but at the cost of more background threads on the client.

  • The chunking of large files - The control has another dependency property called FileChunkBoundaryInKiloBytes. What you specify is used as the chunking size boundary. For files that are smaller in size than the size specified here are uploaded in one fell swoop, and the progress bar goes straight from 0 to 100%. This is also because the HttpWebRequest has no mechanism for reporting true progress of the network activity :-(. However for files that are larger than the chunking size, are uploaded in chunk sizes as specified. the code follows a different route for those files, and all chunks of a file get uploaded in the same background thread as being used for the sublist to which the file belonged. An internal data structure named FileChunk is used to maintain stream positions, so that successive chunk uploads can be done accurately.

Progress is reported for each chunk, so you will see the progress bar report things somewhat more realistically here. Also additional HTTP headers are passed in to the backend, for each chunk, including the chunk #, total chunks and the chunk size, to facilitate the proper appending of chunks to the file as it gets built on the server with each POST of a chunk.

Note that upping the boundary may be a lucrative option for very large file uploads to achieve faster uploads, but this is client memory, and you can soon get OutOfMemory exceptions if you are not careful.

  • The metadata piece - The assumption here is that the client (the app using the control) and the server has some well known contract for the metadata passed and expected respectively, and I needed a way for the control to facilitate the collection, packaging and uploading of that metadata, without itself being aware of any specifics of the metadata - that is the only way it would be reusable across all possible metadata requirements.

The metadata UI is supplied to the control by you defining a Data Template in your app code with the appropriate UI, and supplying it to the control through the FileMetadataTemplate dependency property.

You also need to implement a custom type to act as the data source for this data template. This type needs to implement an interface named IFileMetadataBase that I defined, and that has a single method named SerializeFileMetadata() returning a string. This method is where you supply your serialization logic (in the provided sample I use Json - but you could as easily use XML) , and as long as the serialized form is a string - we are good. This type also will typically implement the metadata elements as properties that you will bind to the appropriate portions of your metadata Data Template.

So how does all this get wired up ? At runtime if the control senses that a Data Template has been specified for metadata, it raises an event called ProvideMetadataInstance and you will need to handle this. The event arguments to this event has a single property of type IFileMetadataBase (the interface I mentioned above), and you set it to a new instance of the implementing type that you created - and voila!!. The control wires up the instance to the data template. When files are uploaded, it calls the function to serialize the metadata to a string, and passes it on as another additional, well named HTTP header, so that the backend can do whatever it wants with it.

I provide a sample of this in the code, with two metadata fields called "Comments" and "Description". Clicking the little button on each file entry, displays the data template which you can fill out.

MFU2

  • The backend - I implement this as a WCF service. But since the interface is simple (HTTP POST + Headers) - I am certain that you ASP.Net (or even other web platform) experts out there can reimplement it using other patterns.

Also the service now puts all uploaded files in a subfolder called Assets under the service directory. This is hardwired in the service code. Change it as you see fit, but do remember to change service code accordingly as well.

  • There is also remove functionality in the control - you can check the little checkboxes, a Remove button appears, and you can then remove files from the list

There are a lot of things incomplete in the control:

  • Slick UI
  • There should be a ceiling enforced on both the chunking size and max thread count to prevent inadvertent memory outage/resource outage on the client
  • The button (or whatever else) that shows the metadata, needs to be hidden when no data template is attached
  • In future revs of SL 2, as network calls and background threads become more friendly, you can take better advantage of that
  • Any other bugs/incomplete features you can find (of which there may be a ton)
  • Slick UI (Have I said that already ??)

In any case my goal was to give you all something to play with and certainly improve upon. Let me know if this helped.

Remember to uninstall any older versions of SL on your machine, download and install the runtime , the SDK and the tools, and enjoy!!!

 

Download Link : http://cid-60bb739cbf5d117b.skydrive.live.com/self.aspx/Public/MultiFileUpload/MultiFileUpload.zip

Posted by jitghosh | 15 Comments

Slides and Demos from Developer Days, March 13th in New York

I recently gave two presentations at one of our events in New York - one on WPF and one on Silverlight 2. A lot of folks asked me to make the slide decks and the code demos available. So here they are (zipped) - you can download them from my Windows Live SkyDrive below. Feel free to ping me if you have questions. Sorry for being tardy in getting this done.

Click the icon above to download

Enjoy!!

Posted by jitghosh | 3 Comments

WPF based Music CD Ripper

One of the WPF based projects I am working on right now needs some functionality to enable ripping music CD's a la Windows Media Player. I was digging into the various Windows Media SDK's as well as the Media Foundation stuff in Windows Vista to find the best way to achieve this - and it turns out the easiest is to rely on Windows Media Player itself. WMP exposes all of this via COM - so all you need to do is add a reference to the appropriate typelib, and off you go. Probably not the best solution, because of the WMP dependency, but it works nicely. I built a quick WPF prototype, and thought some of you might benefit from the code. I am attaching the Visual Studio project (zipped)- feel free to play with it.

 

Note that you will need Visual Studio 2008 and WMP 11 on your machine. There is also a way to use WMP 10 for this, but the user experience is not as nice. Also note that there are ways to rip music CD's with no dependency on WMP, but the solution will be significantly more complicated. Also be aware that depending on your settings, as soon as you pop a music CD, WMP might come up itself and start ripping. Make sure to close WMP before you try this app out.

 

Below is a screenshot. Zipped source code attached.

Enjoy!!!

CDRipper

Posted by jitghosh | 7 Comments
Attachment(s): CDRipper.zip
More Posts Next page »
 
Page view tracker