Recently I’ve been asked to build a proof of concept of an application involving the use of a webcam and a microphone to record some streams and elaborate them after.

At first I’ve tried with the new Silverlight support for webcam and microphone...it’s extremely easy to obtain the raw streams of data from both the devices...but after that you’re left to yourself: no support for whatsoever compression or multiplexing algorithm (I looked around and found nothing suitable to my needs) and due to the short time available I had to give up on Silverlight.

I started to look at what I could use on a WPF/C# solution, we have more options here:

  • Wrapper libraries over the good old (and complex to use) DirectShow
  • Windows Media Encoder 9
  • Microsoft Expression Encoder

All these 3 technologies do the job, but DirectShow and WME (which actually have the richest set of features) are no more supported (or will be dropped soon), they also aren’t managed assemblies.

So I decided to go for the ‘new’ Expression Encoder (also a new version should be out in the next months); it turns out that it’s quite simple to use...from my 2 days of experiments it turns out that it have 2 big problems:

  1. The lack of a good documentation and samples...what you have on MSDN is quite frankly poor compared to the standard documentation we’re used to have from Microsoft
  2. Although it’s very ‘easy’ to use it still lack some of the features WME have...but I hope they will be integrated in the future release.

Enough talking, I’ll just post you some snippets from the demo application I’m building, here’s the class I started with to access and encode the streams coming from the webcam and the microphone:

public class EncodingService : IDisposable
{
   readonly LiveJob _job = new LiveJob();

   // enumerating the devices is a breeze, the LiveJob class does it for you.
   public ReadOnlyCollection<LiveDevice> VideoDevices { get { return _job.VideoDevices; } }

   public ReadOnlyCollection<LiveDevice> AudioDevices { get { return _job.AudioDevices; } }

   public PreviewWindow PreviewWindow { get; set; }

   public bool IsCapturing
   {
       get { return _job.IsCapturing; }
   }

   public void StartCapture(LiveDevice video, LiveDevice audio, string outputFile)
   {
       // first off: add a device source specifying video and audio device you'll be using
       var source = _job.AddDeviceSource(video, audio);
       // choose an output name
       _job.OutputFileName = outputFile;
       // activate the source
       _job.ActivateSource(source);
       // specify a preview window (something with a Handle - any winform control or a WPF window)
       if (_job.OutputPreviewWindow == null && PreviewWindow != null)
           _job.OutputPreviewWindow = PreviewWindow;
       // start the job (this activates the preview too)
       _job.StartEncoding();
   }

   public void StopCapture()
   {
       _job.StopEncoding();
       // remove the source after the stop
       _job.RemoveDeviceSource(_job.DeviceSources[0]);
   }

   public void Dispose()
   {
       try
       {
           if (_job != null)
               _job.Dispose();
       }
       catch
       {
           // sometimes I get a COM exception when disposing the job...it need further investigation
       }
   }
}

The code is well commented and self explanatory: you select the LiveDevice you wanna use, add them to a LiveDeviceSource, activate it and in the end you ask the LiveJob to start the process...simple (I’ve skipped the device configuration, it will be shown in another post).

The biggest problem is the ‘PreviewWindow’...it turns out that to instantiate this class you need an Handle to something it will use to render the video stream (good old pre-WPF code here :) )...in a WPF the application the only thing that has an handle is the Window class, thus if you want your application to be fully written using WPF you need to have a floating preview window.

If you want to integrate it in a box in your main application you can use a WindowsFormsHost control and a Panel (got the idea from the Expression Encoder forum), like this:

private void CreatePreviewBox()
{
    WindowsFormsHost host = new WindowsFormsHost();
    var panel = new System.Windows.Forms.Panel();
    panel.Width = (int)PreviewRect.ActualWidth;
    panel.Height = (int)PreviewRect.ActualHeight;
    host.Child = panel;
    PreviewRect.Content = host;
    HandleRef windowHandle = new HandleRef(panel, panel.Handle);
    _vm.PreviewWindow = new PreviewWindow(windowHandle);
}

Enough for today, see you next.

Related Content