Archive for the ‘C#’ Category.

Using the Expression Encoder SDK to encode lots of videos

I spent a good deal of time this weekend importing hours and hours family videos off our Mini DV cassettes.  Lots of fun, and LOTS of video!  Based on the size of these files, I was quite close to running out of room on my Windows Media Center.  So, I decided to encode the files as WMVs.  Huge size reduction with very little quality loss.

I decided to use Microsoft Expression Encoder 3 – a great tool.  The best part is that there’s an SDK and set of assemblies that you can use in your own applications.

Note: if you are using a 64-bit machine, be sure to set the platform target of your application to x86, or else you will get compilation errors from the Encoder assemblies.

Below you’ll find the application I wrote.  Let me explain my goals:

  • Multi-thread the application to encode more than one video at a time.
  • Leverage the multitude of cores in my machine.
  • Limit the number of threads (I chose the core count as a baseline).
  • Use source video and audio source to reduce quality lose.

In order to do this, I had to do two things: 1) find a way to pass in the file name into thread, and 2) keep track of the number of threads and limit them to the number of cores in the machine.

I spent a bit of time looking for a good approach.  In the end, I chose to use the delegate ParameterizedThreadStart, which takes a parameter of type object.  This way, I can create a thread using an instance of this delegate instead of just ThreadStart, and the overload to Thread.Start allows me to specify a value that is passed to this new thread.  (Be careful, though, as it only accepts a single parameter (although it can be a collection) and isn’t type-safe.)  Additionally, with this approach I was able to leverage a counter, and sleep whenever the counter is going to exceed the number of cores in my machine.

Here’s all the code.  For this to function, I imported the following assemblies (yes, you need Expression Encoder 3):

  • Microsoft.Expression.Encoder
  • Microsoft.Expression.Encoder.Types
  • Microsoft.Expression.Encoder.Utilities
  • WindowsBase
// This method is used to look-up the core the thread is using
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetCurrentProcessorNumber();
 
static string inputFolder = @"C:\temp\Videos";
static string outputFolder = @"C:\temp\OutputVideo";
static int count;
static int maxNum;
 
static void Main(string[] args)
{
    // Start the counter at zero
    count = 0;
    // Grab the processor count
    maxNum = Environment.ProcessorCount;
    // Iterate through the AVI files
    foreach (var fileName in System.IO.Directory.GetFiles(inputFolder, "*.avi"))
    {
        // Sleep/wait for a core to free up
        while (count > (maxNum - 1))
        {
            Thread.Sleep(500);
        }
        // Increment the counter
        count++;
        // Create the thread with the delegate
        Thread t = new Thread(new ParameterizedThreadStart(EncodeFile));
        // Start the thread, passing in the file name
        t.Start(fileName);
    }
}
 
public static void EncodeFile(object ofileName)
{
    string fileName = (string)ofileName;
    MediaItem mediaItem = new MediaItem(fileName);
    mediaItem.OutputFormat = new WindowsMediaOutputFormat();
    // Use source video profile if available
    if (mediaItem.SourceVideoProfile != null)
    {
        mediaItem.OutputFormat.VideoProfile = mediaItem.SourceVideoProfile;
    }
    else
    {
        mediaItem.OutputFormat.VideoProfile = new AdvancedVC1VideoProfile()
        {
            Size = mediaItem.MainMediaFile.VideoStreams[0].VideoSize,
            Bitrate = new ConstantBitrate(1000)
        };
    }
    // Use source audio profile if available
    if (mediaItem.SourceAudioProfile != null)
    {
        mediaItem.OutputFormat.AudioProfile = mediaItem.SourceAudioProfile;
    }
    else
    {
        mediaItem.OutputFormat.AudioProfile = new WmaAudioProfile();
    }
    // Create a job and the media item for the video we wish to encode.
    Job job = new Job();
    job.MediaItems.Add(mediaItem);
    // Set up the progress callback function
    job.EncodeProgress
        += new EventHandler<EncodeProgressEventArgs>(OnProgress);
    // Set up the completed callback function
    job.EncodeCompleted
        += new EventHandler<EncodeCompletedEventArgs>(job_EncodeCompleted);
    // Set the output directory and encode
    job.OutputDirectory = outputFolder;
    // Do not create a job subfolder
    job.CreateSubfolder = false;
    // Encode
    job.Encode();
}
 
static void job_EncodeCompleted(object sender, EncodeCompletedEventArgs e)
{
    // Decrement the counter
    count--;
}
 
static void OnProgress(object sender, EncodeProgressEventArgs e)
{
    // Write out information
    Console.WriteLine(
        count.ToString() + " : " +
        GetCurrentProcessorNumber().ToString() + " : " +
        System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + " : " +
        e.Progress + " : " +
        e.CurrentItem.ActualOutputFileName);
}

 

Good stuff.

I’m running it from the console, so you will have to make some modifications if you want it to run in a more sophisticated application.  Works for me, though – I just start it up at the end of the day.  Here you can see the information that’s written out to the console (note the variety of cores leveraged):

Console Output

It’s fun to see my machine working this hard.  Every core is pegged.

Pegged Cores

Hope someone finds this useful.  Anyone see a better way to approach this?

Getting Started with XNA Development

Starflight I love gaming.  Long before the death match 95 tournament with Windows 95 that featured Bill Gates in a trench coat, I was playing computer games.  Two of the first games I remember playing were The Ancient Art of War and Montezuma’s Revenge – simple but fun.  I soon became a Sierra devotee, and devoured games such as Kings Quest, Heroes Quest (renamed Quest for Glory), Space Quest, Police Quest, and Leisure Suit Larry (just don’t tell my dad).  However, my favorite all time game was Starflight from Binary Systems – this game had everything: space battles, exploration, great story line, and it required strategy and a lot of invested time.

As an aside, I have seen the Starflight and Starflight 2 executables, along with some of the other games I’ve mentioned, floating around the Internet for awhile.  It is possible to use DOSBox – an x86 emulator with DOS – to play these games.

The common theme to all of this, of course, is that my gaming platform was the PC – while I had a Nintendo, I never really considered it a decent gaming platform.  All of the console platforms of the day – Sega, Atari, Nintendo – paled in comparison to the PC as a gaming platform.  Even today, I prefer the PC to a console.  Despite this prejudice, I have come to love my Xbox 360 – not only is it a great gaming platform, but it’s the media hub of our entire house.

XNAFor a long time I’ve wanted to try my hand at making a game, but I’m a developer not a designer.  Additionally, I know nothing about DirectX, OpenGL, and other multimedia/gaming APIs.  While I’ve known about the XNA since it released in 2006, I never made the time to try it out. For those of you that aren’t familiar with XNA, it’s a framework with a set of tools that facilitates the development and management of computer games.  The best part is it uses C#!

Now, there’s a lot that goes into making a game.  I’m a complete noob, and I’ll try to share the things I learn on this blog as I go.  As I see it, the first step is actually getting your tools and environment setup.  It is this process that I intend to outline in this article.  The process is a bit confusing, but what I’ve been able to piece together are the following three steps:

  • Setting up your XNA account
  • Configuring your Xbox
  • Deploying your first “game”

I should also mention that my goal here is to build and deploy a “game” to the Xbox 360.  This may seem contradictory given my stated preference for the PC above, but there’s more to the Xbox 360 than just games, and eventually I’d like to build applications for the Xbox (not just games).

Setting Up Your XNA Account

The first thing to do is get your XNA account all setup.  This allows you to deploy games to your Xbox 360.  It will also cost a little $$.

1. Download XNA Game Studio 3.1.  I grabbed it via my MSDN membership, but I believe you can find it elsewhere too.  You can get it for Visual C# Express here.

2. Go to the XNA Creators Club Online and setup an account.  Note: It’s very important that you use the same account that’s associated to XBOX Live.  Review the different membership options – you will start off as Registered (after creating an account) and you want Premium.

XNA Membership Options

4. Sign up for Premium Membership.  There area  few ways to do this – if you’re lucky enough to have a Redeem Code, then use it here.

XNA Membership Types

5. After you have setup your membership, verify by selecting Creators and choose My Profile.

My Profile

6. Your membership should now be premium.

My Profile - Premium

While straightforward, I never found this process nicely spelled out and defined.

Configuring Your Xbox

The next thing to do is setup your Xbox such that you can deploy your games to it.  This one took me a bit longer to figure out because of all the various steps.

1. Go to your Xbox 360 and turn it on.

2. Log into your Xbox Live account on your Xbox 360.  Remember how you used the same Live ID in step #2 above?  This is why you did so.

3. The next step is to setup the XNA Game Studio Connect software on your Xbox .  Follow these steps:

  • Select Game Marketplace
  • Select Explore Game Content
  • Select Browse
  • Select title X
  • Select title XNA Creators Club
  • Select All Downloads
  • Select XNA Game Studio Connec
    t
  • Select Confirm Download
  • Select Play Now

4. The application will provide you a connection key that you’ll use to register your Xbox with your development environment.  Write down the key.

5. Return to your development machine.

6. Open up the XNA Game Studio Device Center.

7. Click Add Device.

Add Device

8. Select the XBOX 360 icon.

XBOX 360

9. Choose an Xbox 360 Name.

Name

10. Enter the connection key you wrote down.

Connection Key

11. When you’re complete, click Finish.  You should now see your Xbox as a listed device.

XNA Game Studio Device Center

Okay, everything’s setup.  Now to build and deploy a game.

Deploying Your First “Game”

1. Take a look at this great “Hello World!” in XNA post by Nezeeh.  Follow the steps – they are very simple.

2. Ensure that the XNA Game Studio Connect application is still running on your XBOX.

XNA Game Studio Connect

3. Deploy your application from Visual Studio.  It will push the package to the XBOX 360 and should look something like this:

Hello World!

And there you have it!  Your “game” is running.  I apologize for the poor quality pictures – I used my phone as it was easy and available.

All in all, this process shouldn’t take you more than an hour.  I spent about three hours trying to figure it all out, but I guess I’m just slow.  I hope you find this valuable.

Happy gaming!