My team members have been working on a entirely new version of the VisitMIX site for the past couple of months. There's going to be some very interesting activity around this site.
MIX Online is a community site for web designers and developers who are building and believe in the innovative web. In the past, the site has given a varied perspective of what is happening on the web, a view into our conference called MIX, and interviews with amazing people with incredible ideas and stories on how designers and developers can take advantage of the web. MIX Online has always been a year-round companion to the event. [more...]
I was asked to help out with a demo, my assignment was to capture some video from a WebCam that was to be used for the Cirque du Soleil demo for MIX08. There were a few ways to do this, none which were obviously attractive. There are many 3rd party tools that capture video and output to a file, but none I found were extendable and usable from within an application. Another thought was to use the DirectX API’s to do the capture, but this required some fairly involved interop. Windows Media Encoder was not an obvious choice, but to my delight ended up being perfect for the job. I was satisfied with the results. Windows Media Encoder Series 9 has type libraries that expose its COM API’s and can be added to a Visual Studio project directly as references. Visual Studio automatically generates Runtime Callable Wrappers for them.
This is a not a production quality sample, but I thought it still lhad some value getting it out there, since I spent quite some time finding out how to go about this.
A few things to mention up front
· The Windows Media Encoder Series 9 (WME9 from here on) has a bug on Windows Vista that requires a hotfix to be installed. It needs to be installed as an Administrator of the machine. You can run it as a non-Admin, but the hotfix will not install properly and will not report errors. If you find that anytime you access WME9 code (on Vista) and the application crashes without error, you can be sure that the hotfix is not installed properly.
· This sample shows at a basic level how to access audio level information via a Managed DirectX API (Microsoft.DirectX.DirectSound is the DLL referenced) and so requires installing some managed DLL’s. I happened to find these DLLs in the Microsoft LifeCam install, so that’s how I installed them, instead of installing the entire Managed DirectX SDK. There may be a faster/better way to install these DLL’s but I haven’t taken the time to look around for it. If you decide not to install this software, you will need to comment the relevant code.
· You will need a WebCam that functions on your PC to run this sample. This means that you need to install your WebCam’s software and ensure that it works outside of the context of this sample. I myself used the a Microsoft Vx6000 LifeCam, but I’ve tested this app with two other WebCams without issue. The application detects and lists the WebCam in a ComboBox on application launch.
· This application was built in Visual Studio 2008, and will also open properly in Expression Blend 2.0 Beta (February). A DesignTimeHelper class has been added to make it easier to see some of the application elements in the designer at design-time.
· To run this project in Visaul Studio you will need to uncheck the “Loader Lock” thrown checkbox due to the audio level code. To get to this dialog choose Debug -> Exceptions from the Visual Studio menu and expand the “Managed Debugging Assistants” node.

Installing and running the sample
1. Install WME9 from: http://www.microsoft.com/downloads/details.aspx?FamilyID=5691ba02-e496-465a-bba9-b2f1182cdf24&DisplayLang=en
2. [optional] Install the WME9 SDK from: http://www.microsoft.com/downloads/details.aspx?FamilyID=000a16f5-d62b-4303-bb22-f0c0861be25b&DisplayLang=en (The WME9 SDK ended up being very helpful, although I found that the samples in the “samples” directories were not as helpful as the actual content in the CHM file. There are complete samples hidden in the text of the CHM files that were enlightening.)
3. [required for Windows Vista only] Copy the WME9 hotfix locally from: http://download.microsoft.com/download/0/3/d/03d35c05-67da-40e0-9e45-3ea0ca6329a4/windowsmedia9-kb929182-intl.exe (Right-click and choose “Run as Administrator” to install)
4. Install the Microsoft LifeCam Software from: http://download.microsoft.com/download/1/9/5/195512A9-1C1E-4429-BFF0-613D8D92E122/LC14.exe
5. Copy the sample project bits from http://www.hugli.org/code/videoencoder/videoencoder.zip expand it and place the VideoEncoder directory in a directory of your choice. Typically I place content in a c:\users\public\demos directory, since this directory is accessible from all profiles without security issues.
6. Install any necessary software for your WebCam and plug it in.
7. Launch the project in Visual Studio 2008.
8. Modify the OUTPUT_PATH to be a directory that your identity has write access to. The path c:\users\public is the default and will work on Vista, however for XP you will need to modify this path.
9. Press F5. After the application launches you should see two ComboBox’s and a clickable image.
10. Choose your WebCam from the “Video Source” Combobox and use the default profile (384 Kbps.)
11. Click on the image and a video dialog will fade/animate in.
12. Press “Begin Recording.” There will be a slight delay and a video preview will appear on the video dialog. Note that there are also crosshairs, recording status and progress bars to indicate audio level that overlay the video.
13. Press the “Record” button and you will see timecode start advancing in the video overlay.
14. Press the “Save” button and the video strean will be closed and saved to disk in the directory specified in OUTPUT_PATH.
15. The video is then added to a WrapPanel as a MediaElement
16. End Sample.
How was sample done?
Now I’m going to cover the application and some of its hidden subtlties. I wrote this sample in a couple of days since the demo had to be put together in short order. If I had more time, I’d break out the audio related content into its own class and spend some time cleaning up the VideoEncoder class that wraps up all the encoding logic. Another thing that I would do is break out the VideoWindow code into its own UserControl. UserControls cannot draw outside of its own bounds so you would need to allow the UserControl to span the width/height of the entire application to allow for the video fadein animation. There are some problems in the code at present. The most troublesome is that sometimes I find that when capturing video the encoder captures only blank video, and I haven’t found the cause of it yet.
WME9 archiving
One thing that confused me about WME9 initially was that as soon as the Encoder was started the video started capturing to disk and it was only then that a a preview would show up in the preview drawing surface (both happened simultaneously). What I really wanted instead was to see the video preview *before* I began capturing the video, so that I could center my WebCam on my subject, and then and only then start the video capture to disk. Well, it turns out that when the Encoder is started, the video starts capturing (Archiving as they refer to it) immediately, by default. To change the behaviour to what I wanted, i.e. to see a preview before the video captured begins, I needed to set the Encoder.EnableAutoArchive property to false (from its default true), and then start the Encoder. At this point the preview begins displaying in the application, and then we can optionally start the video capture by clicking on the “Begin Recording” button with this call:
Encoder.Archive(WMENC_ARCHIVE_TYPE.WMENC_ARCHIVE_LOCAL, WMENC_ARCHIVE_OPERATION.WMENC_ARCHIVE_START);
Encoder.PrepareToEncode(true);
and end the video capture with this call:
Encoder.Archive(WMENC_ARCHIVE_TYPE.WMENC_ARCHIVE_LOCAL, WMENC_ARCHIVE_OPERATION.WMENC_ARCHIVE_STOP);
It’s also good to know that if you want to capture to an entirely new “archive” file, you will need to stop the encoder, redefine the capture file info and then restart the encoder.
Interop
To get the Video to display in a WPF application took some simple interop. It was interesting for me to find out that you can get a Handle from all WPF elements using IntPtr handle = ((System.Windows.Interop.HwndSource)myElement).Handle so that I could have the video draw on a specific element, but all elements returned the same Handle (the parent windows Handle.) This wasn’t very useful since the video ended up being drawn inside the entire Window no matter which element I chose. To workaround this, I instead created a WindowsFormsHost element and added it to the VisualTree. I then added a System.Windows.Forms.Panel as a child to that WindowsFormsHost (note it is important that the WindowsFormsHost has a child, since the WindowsFormHost element itself gives you the handle of the parent Window, which again is not what we want. The differentiating factor is that System.Windows.Forms controls have a Handle property which makes it very convenient to get the Handle. All System.Windows.Forms.Panel controls are Windows themselve’s. This makes it easy to grab a handle and draw within the bounds of the panel. It should be noted that having all controls be windows can lead to resource and performace problems for large numbers of children, this is not an issue in WPF. The Handle property returns a System.IntPtr which we then pass directly to the Preview.SetViewProperties method along with the video stream itself. Doing this draws on the panel.
When you draw directly on a surface using this technique, there is a side-effect in a WPF application; you no longer can see WPF elements residing on top of this drawing surface anywhere in the VisualTree. I call it a “black hole”, since it obscures or cuts a hole into any window-less elements you try to place on top of it, whether a child element or an element with a higher z-order. This is essentially because the OS can only address something with a handle (a Window in this case) and so it draws the video after all the other elements in the WPF window are drawn.
Video overlay
So how then was the video overlay done? It was accomplished by placing yet another Window on top of the video. The WPF Popup element just happens to be a Window with its own handle. There is a side-effect to this technique: if the parent window is moved, you will find that the Popup doesn’t move along with the parent. This can be remedied by subcribing to the Window.LocationChanged event and in that event modify the position of the Popup. Another side effect is that when the parent Window loses focus, the popup ends up on top of other applications. Again this can be remedied by subscribing to the proper focus events, both of these issues are beyond the scope of this writing.
Animation
Note that the video preview Grid (videoCaptureGrid which also contains the Popup) are not part of the animated videoWindow Grid. I found that trying to animate an element that contained the video rendered through interop performed poorly and drew improperly, so I simply hid videoCaptureGrid until the videoWindow Grid finished fading and animating in.
Possible Exercises
- Try to get a Thumbnail of a video. I spent some time on trying to do this and ended up falling back to having a media element display the video for lack of time. Two potential ways to do this are: Use RenderTargetBitmap or grab the Thumbnail that Windows itself generates. The code for using RenderTargetBitmap is in the project in the RasterizeVisualAt96dpi method, but is not used at present. I found that it was tricky to grab the thumb of the video since the first frame(s) of the video tend to be black. Grabbing a video thumbnail from Windows will require the use of interop. I’m not sure if this is possible or feasible.
- WME9 is able to capture the desktop of your computer. Create a WPF application that runs in your systray that captures your desktop to a WMV file.
- Calibrate the audio levels. Right now the Audio levels are cosmetic and gratuitous. They seem to be a bit delayed and levels seem higher than they should appear. Experiment to get the indicators working properly.
- Modify the Popup position when the application is moved or loses focus.
In Building a recipe application using Vista and .NET 3.0 (Part IV: ThumbnailProvider interface) I reference the DBMon.exe tool, and state that it is located in the Windows SDK, however, as of the lastest Windows SDK: Microsoft® Windows® Software Development Kit Update for Windows Vista™ (released 3/22/07), DBMon no longer ships in the SDK. I was unable to find it in any other Microsoft release.
In my search I found this tool that very nicely replaces DBMon: DebugView v4.74 (by SysInternals.) This tool has the same basic functionality, plus many, many more features, such as the abilty to connect to remote machines, persisting sessions to disk, filter entries, and capture from many debug sources.
It is available here on the Microsoft.com TechNet site: (published 11/27/07)
Although I'm certainly not a SharePoint expert, MSDN just posted an article I authored that shows how to cleanly integrate the security model between these two platforms using ASP.NET Roles. I put this together for the Office team from something that came out of a need for our team: http://msdn2.microsoft.com/en-us/library/bb892784.aspx.
I had a need to create a string “Linkify” function for a web site that I am working on; a function that takes a string, parses it for URL’s, and replaces those URL’s with HTML anchors. The end result is when the string is passed to a web client it would allow the user to browse to the URL.
I started out thinking that it could be done with some simple string manipulation, but quickly realized that finding the end of a URL was not trivial. It then occurred to me that Regular Expressions would solve the problem from my experience with Perl. Regular expressions are exceedingly powerful, but with its’ power comes complexity.
The .NET framework has a namespace dedicated to Regular Expressions: System.Text.RegularExpressions. The RegEx class has a constructor that takes a pattern and options as parameters. The RegEx.Matches(string) method takes a string as an input and returns a MatchCollection, which contains a lot of buried information. For my purposes I was able to avoid having to drill down deep into the collections contained within the object, but it’s good to know that it has the ability to capture the individual groups that a pattern returns.
The trickiest part for me, was recalling how to construct a pattern for this type of query. RegEx pattern syntax is a language of its own, that takes me time to wrap my head around every time I need to work with Regular Expressions, which is not all too often.
So how did I overcome my cerebrally-challenged problem? In searching on Live.com… incidentally in Windows Vista, by default, hit the Windows key, type your search word(s), press the down arrow and press enter… I came across a free 3rd party tool Regular Expression Designer by Rad Software, (this tool is not endorsed by Microsoft) that helped me to quickly construct and try out the pattern that I needed. It also has a handy quick reference to show the meaning of the esoteric symbols used in RegEx patterns.
Construction of the pattern
Anything within parentheses in a RegEx pattern is called a “group.” In this application want 3 groups; the first: the protocol, the second: the domain, and the third: the path. For the protocol group we want to find an occurrence of http or and ftp. The | operator indicates an Or, followed by the literal ://. The domain group is one or more matches + that do not contain a forward slash, a carriage return, a close paren, or a quote mark [^/\r\n\")], note that some are escaped by preceding backslashes, and the path group needs to have zero or more matches * that begin with a forward slash , but not a carriage return, close paren or a quote mark [^\r\n)\"], and lastly we want to find *all* matches in the string with a ?
Putting it all together we arrive at this: "(http|ftp)://([^/\r\n\")]+)(/[^\r\n\")]*)?"
We could have given the groups friendly names as in: "(?<protocol>http|ftp)://(<?<domain>[^/\r\n\")]+)(?<path>/[^\r\n\")]*)?", if we had wanted to access the individual values by name, for some other purpose. Without assigning names, by default, the groups are numbered in order of occurrence within the pattern starting with 0.
Following is a method call that wraps it all up:
using System.Text.RegularExpressions;
/// <summary>
/// This method takes a string and looks for URL’s within it.
/// If a URL is found it makes a HTML Anchor out of it and embeds it
/// in the output string. This method assumes that we are not passing
/// in HTML. This method would have to be revised to support that.
/// </summary>
/// <param name="input"></param>
/// <returns>Clickified String</returns>
public static string LinkifyString(string input)
{
Regex regex = new Regex("(http|ftp)://([^/\r\n)\"]+)(/[^\r\n)\"]*)?", RegexOptions.IgnoreCase);
MatchCollection mc = regex.Matches(input);
foreach (Match m in mc)
{
string url = m.Value;
string link = Globals.CreateAnchorTargetBlank(url, url);
input = input.Replace(url, link);
}
return input;
}
public static string CreateAnchorTargetBlank(string href, string description)
{
return string.Format("<a href=\"{0}\" target=\"_blank\">{1}</a>", href, description);
}
MSDN has some RegEx examples that may be worth taking a look at.
Be advised that this LinkifyString function will corrupt HTML if you pass an HTML’ified string to it, since we are not checking for anchor elements surrounding the URL’s. To do this one would have to add additional groups that ignore matches inside anchors. i.e. <a href=” http://www.foo.com”>http://www.foo.com</a>.
-Hans Hugli
Abstract
Becoming familiar with SharePoint 2007 web parts, CAML and implementing a custom web part that interacts with a SharePoint page’s CAML. This article also covers setting up a development environment, building, deploying, installing, and debugging a web part and includes a project linked at the bottom.
Intro
It is our teams’ goal this year to create an internal site for our Technical Evangelists to go to as a first stop resource for demos. We wanted to organize these demos so that they are easy to find, and we wanted to have the site in a blog-like format. It’s a demos’ nature to become stale with time, and so we thought that a blog format was a good fit for documenting demos. We really like the “tag clouds” concept since it surface’s keywords and their frequency of use and popularity.
We took a look at a few blogging solutions. The first was an ASP.NET sample “Blog Starter Kit.” While it’s a great example of how to code a blog server from the ground up, it proved to be too much work to get where we wanted in a short time.
I next took a look at Community Server 2.0. This is very robust and easy to use blogging software and contains a wealth of other community capabilities, but it ended up being overkill for our simple blogging needs. It also didn’t have the ability to easily customize the UI layout via its web interface; I wanted to be able to add announcements and contact information without having to manage any HTML, plus we needed to be able to add custom properties to the blog entries, such as demo storage location, which Community Server was not designed to enable without code, this meant becoming familiar with their architecture and writing custom code.
Having had some familiarity with SharePoint, and knowing its great support for being able to customize lists, I then examined SharePoint 2007’s blog capabilities, and while they are certainly not as developed as Community Servers’, they were a good starting point for our proposed solution. Out-of-the-box SharePoint 2007 has the capability of creating blog sites with ease. It creates a home page that contains a Blog Post List web part (based on ListViewWebPart.) These blogs can have multiple categories assigned to them with items from the “Category” List, and they can also have multiple comments attached with items from the “Comments” List. The homepage contains a list of all posts in a summary view layout. A second, but equally important, reason for having chosen SharePoint is that I wanted to have a better understanding of its inner workings.
From the Category List, the user can drill down into the category page which out-of-box only displays items from a single category. I found this to be too constraining for our needs, and so I set out to modify Category.aspx to allow filtering with multiple categories, plus create a way to navigate the page in a more efficient and meaningful way with a “Tag Filter” control that would look something like this:

I started out with the “Tag Cloud” web part that I found on www.codeplex.com as a starting point which was very useful, but I needed to change it dramatically to meet our requirements since they were quite different. See resources for more info on the “Tag Cloud” web parts
Definitions
Not the most exciting, but necessary never-the-less to understand later portions of this writing.
CAML – Collaborative Application Markup Language – not to be confused with the Caml programming language, is an XML based language that contains tags to define and display data. In this post we will focus on CAML’s query language and query language schema.
SharePoint Designer 2007 – A tool to edit SharePoint pages along with CAML embedded in those pages. Since the web part CAML markup is stored in SQL, opening files via UNC (e.g. \\<my share point server name>\blogs\default.aspx) from a SharePoint Server within normal editing tools, will not show the CAML markup, so it’s necessary to edit pages with SharePoint Designer 2007 to surface and edit the CAML. Incidentally here’s the trial version of SharePoint Web Designer 2007.
SharePoint Web Part – This is the fundamental unit that can access SharePoint information and display itself on a SharePoint page. With SharePoint 2007, the Office team has made it much easier to develop web parts, since they are now leveraging ASP.NET’s web part infrastructure. See resources section for required reading on web parts that will help you along with development.
Getting Started
The Blog Home page
The default.aspx SharePoint blog home page shows all blog posts that have been created. The two web parts that we will find most interesting on this page are the Category web part and the Posts web part. The Category part enumerates all categories that have been defined. For example: a category of “MyTag” would link to “/<blogsitename>/lists/categories/category.aspx?Name=MyTag”. Note that “Category” and “Tag” will sometimes be used interchangeably in this writing. The Posts part shows all Blog posts ordered by PublishedDate and ID. How do I know how the Posts are ordered? Well, I could edit the page in the browser, go into the View Settings, and look at the settings for its current view, but that won’t help us later when we are trying to dissect the category.aspx page. So let’s instead open the default.aspx page in the SharePoint Designer and take a look at the web part titled “Posts”.
CAML
The web part XML that you will find contains all the default and user-defined settings for the Posts part. A large portion of these settings are exposed through the web management UI, but the ListViewXml property is not. Instead the Web based View Settings UI manages most of the capabilities of this property.
Notice that embedded in the CAML (escaped to avoid collisions in SharePoint Designer) inside the ListViewXml property is a query node. That looks like this:
<Query>
<OrderBy>
<FieldRef Name="PublishedDate" Ascending="FALSE"/>
<FieldRef Name="ID" Ascending="FALSE"/>
</OrderBy>
</Query>
Converted to XML, it appears much more readable as:
<Query>
<OrderBy>
<FieldRef Name="PublishedDate" Ascending="FALSE"/>
<FieldRef Name="ID" Ascending="FALSE"/>
</OrderBy>
</Query>
The Category.aspx Page
So now that we know where the CAML and its Queries are serialized, we can move on to taking a look at the Category.aspx page. The Category.aspx page shows only Post items that have been tagged with a name that is passed as a parameter to the page. How does the Category.aspx page capture a request parameter? The answer lies in the CAML of the Posts web part which is also included on the category.aspx page. Inspecting the Category.aspx page with the SharePoint Designer this is how the Posts part markup appears inline. Taking a look at ListViewXml reveals this CAML XML. We find the Query node and see now that it is more complex. Looking at just the Query node again, we now see a “Where” clause that compares the “PostCategory” value with the “Name” request variable:
<Query>
<OrderBy>
<FieldRef Name="PublishedDate" Ascending="FALSE"/>
<FieldRef Name="ID" Ascending="FALSE"/>
</OrderBy>
<Where>
<Eq>
<FieldRef Name="PostCategory"/>
<Value Type="">
<GetVar Scope="Request" Name="Name"/>
</Value>
</Eq>
</Where>
</Query>
If we make some minor changes to this query, we can get some much more interesting results, for example: if I wanted to find all Posts that contain the word “Demos” and “WPF”. I could pass the following to the Category.aspx page: “Category.aspx?N1=Demos&N2=WPF” and have the following CAML embedded process the request:
<Query>
<OrderBy>
<FieldRef Name="PublishedDate" Ascending="FALSE"/>
<FieldRef Name="ID" Ascending="FALSE"/>
</OrderBy>
<Where>
<And>
<Eq>
<FieldRef Name="PostCategory"/>
<Value Type="">
<GetVar Scope="Request" Name="N1"/>
</Value>
</Eq>
<Eq>
<FieldRef Name="PostCategory"/>
<Value Type="">
<GetVar Scope="Request" Name="N2"/>
</Value>
</Eq>
</And>
</Where>
</Query>
And then taken to the extreme; we’d like to retain the original “Name” parameter, for backwards compatibility, so that pre-existing links don’t break, and we’d like to have the ability to filter up to 6 Categories deep. (Note that if values are omitted for any of the parameters, no results will be returned. The drawback to this approach, due to the AND query logic, is that we need to always pass a parameter for all request variables; otherwise the query returns no results. So, for this sample to work we need to create a common category “All” and (important for this to work) tag every single Blog Post with it. So our final query will be:
<Query>
<OrderBy>
<FieldRef Name="PublishedDate" Ascending="FALSE"/>
<FieldRef Name="ID" Ascending="FALSE"/>
</OrderBy>
<Where>
<Or>
<And>
<And>
<And>
<And>
<And>
<Eq>
<FieldRef Name="PostCategory"/>
<Value Type="">
<GetVar Scope="Request" Name="N1"/>
</Value>
</Eq>
<Eq>
<FieldRef Name="PostCategory"/>
<Value Type="">
<GetVar Scope="Request" Name="N2"/>
</Value>
</Eq>
</And>
<Eq>
<FieldRef Name="PostCategory"/>
<Value Type="">
<GetVar Scope="Request" Name="N3"/>
</Value>
</Eq>
</And>
<Eq>
<FieldRef Name="PostCategory"/>
<Value Type="">
<GetVar Scope="Request" Name="N4"/>
</Value>
</Eq>
</And>
<Eq>
<FieldRef Name="PostCategory"/>
<Value Type="">
<GetVar Scope="Request" Name="N5"/>
</Value>
</Eq>
</And>
<Eq>
<FieldRef Name="PostCategory"/>
<Value Type="">
<GetVar Scope="Request" Name="N6"/>
</Value>
</Eq>
</And