Screen recording using Desktop Duplication API and hardware H.264 encoder

The application takes advantage of three powerful Windows APIs at a time:

MediaFoundationDesktopRecorder initializes a desktop duplication session and sends obtained desktop images to H.264 video encoder producing a standard MP4 recording. Optionally, it can add an audio track capturing data from one of the standard inputs.

The best performance is achieved when used with hardware H.264 encoder: not only the performance of hardware encoder is better, but additionally desktop images are transferred to the encoder efficiently, without being copied through system memory. With respective hardware, recording is pretty efficient.

There are certain limitations: duplication API is Windows 8+, encoder availability depends on hardware and OS versions. The application let API pick encoder automatically and in worth case scenario falls back to software encoder, which is typically a performance hit.

MediaFoundationDesktopRecorder UI

When started, the application prints initial information, esp. regarding availability of devices, and appends as actions and events take place.

The application uses configuration file with the same name and location as the application, and .INI extension. Changes to the configuration file take effect when the application is restarted.

The application registers Win+F5, Win+F8 hotkeys globally to start/stop recording when the application is in background (that is, when user interacts with another application).

The application generates .MP4 files in the directory of its own location. There will be a video track, and optionally one additional audio track – depending on settings. Video is taken from one of the monitors, and audio – from one of the available standard audio input devices.

The application also generates log files at one the locations:

  • C:\ProgramData\MediaFoundationDesktopRecorder.log
  • C:\Users\$(UserName)\AppData\Local\MediaFoundationDesktopRecorder.log (in case the first path above is inaccessible, esp. due to insufficient permissions)

Configuration

The configuration .INI file might contain a few settings that set up and alter the behavoir of the application:

[Input]
;Video Adapter Description=NVIDIA GeForce GTX 750
Video Output Device Name=\\.\DISPLAY2
;Audio Friendly Name=Stereo Mix (Realtek High Definition Audio)

When started, the application enumerates (“found video…”, “found audio…”) available video and audio inputs. These discoveries are compared against configuration file settings in order to identify monitor for recording, and possibly audio input device.

Default behavior is to take first available monitor, which happens when settings do not instruct otherwise. By default, no audio is recorded. Audio is recorded and added to resulting file if input device is provided explicitly.

The application also prints which devices are taken for further recording (“using adapter…”).

[Format]
;Video Frame Rate=30000
;Video Frame Rate Denominator=1001
Video Bitrate=4096000
Video Texture Pool Capacity=24
Video Throttle=70
Audio Bitrate=192000

Default behavior is to identify monitor’s refresh rate and produce output file with video at the same frame rate. Video Frame Rate and Video Frame Rate Denominator settings offer an override to target file frame rate. With the former value only, it is the frame rate. With both values they define a ratio, e.g. values of 30000 and 1001 result in 29.97 fps file.

Frame rate reduction is a good way to reduce encoding complexity and overall graphics subsystem load.

Bitrate values define respective bitrates for the encoded content.

Details

As recording goes, the application grabs new desktop snapshots and sends them to encoder. There are no specific expectations about frame rate stability and reduction in case of overload of graphics subsystem. When the complexity is excessive, it is expected that some frames might be lost without breaking the entire playability of the output file.

The application provides additional information when it creates a file, for example:

Using Direct3D 11 at feature level D3D_FEATURE_LEVEL_11_0
Using Desktop Duplication mode: Resolution 1680 x 1050, Refresh Rate 59954/1000, Format DXGI_FORMAT_B8G8R8A8_UNORM
Using path “D:\Projects\...\Output\20160707-070707.mp4”
Using video transform Direct3D 11 Aware, Category MFT_CATEGORY_VIDEO_PROCESSOR, Input MFVideoFormat_ARGB32, Output MFVideoFormat_NV12
Using video transform NVIDIA H.264 Encoder MFT, Direct3D 11 Aware, Category MFT_CATEGORY_VIDEO_ENCODER, Input MFVideoFormat_NV12, Output MFVideoFormat_H264
Started writing…
PPP frames written (QQQ frame timeouts, RRR early frame skips, SSS late frame skips)
Stopped writing
Output file size is TTT bytes

When started the application might experience a condition when certain hardware resource is no longer available, e.g. the desktop itself is locked by user. The application will close the file, and attempt to automatically restart recording into new file. The attempts keep going until user explicitly stops recording.

The application does NOT do the following (among things it could):

  • the application is limited to record from one monitor only; to record from two at a time it is possible to start several instances however the produced result will not be synchronized
  • the application does not provide options to record single window image, to cut a section of monitor image or to scale image down
  • the application does not offer choices for video encoders (e.g. there are two or more hardware H.264 encoders), it will always use encoder picked by the system
  • the application only offers bitrate setting for video encoding
  • the application does not provide flexibility in audio encoding settings, it also expects that audio device is available throughout the entire recording session (esp. is not unplugged as recording goes)

References (Informational)

Download links

Build Incrementing for Visual Studio C++ Projects

Over long time I used an automatic build incrementer add-in for Visual Studio and C++ projects, which proved to be helpful. Having increments in file information, the binaries were easy to identify. It was easy to find a matching symbol information etc. Long story short, a tool like this has been a must.

The add-in has problems or downsides though. It kept patching the .RC source and touched it when no other changes existed in the build, touching source code forced rebuilds on its own and reloaded resource-related files opened in Visual Studio editors. I was annoying even though more or less acceptable.

Visual Studio 2015 Community Edition does not support add-ins because of 2015 or because it’s Community Edition. Either way it was time to update the incrementer ot make things nicer overall.

This time I preferred to change things a bit. No longer source code patching: the incrementer can be attached as a post-build event and patch VERSIONINFO resource on the built binary. This requires that current build number is kept somewhere but not in the .RC text, so I am using an additional .INI file. The good thing is that this file can still be included in version control system and the version history can be tracked relatively easily. No longer source code modification which makes code base dirty and forces another rebuild.

Command line syntax:

C:\>IncrementBuild-Win32
Syntax: IncrementBuild-Win32.exe argument [argument...]

Arguments:
  help - displays syntax
  configuration <path> - path to .INI file holding configuration information (mandatory)
  binary <path> - path to binary to be patched with file version update (mandatory)
  string <name> <value> - add, update or remove specific version information string (optional; multiple arguments possible)
  dump - print version information data block dump before and after update

Additional feature is that incrementer can attach additional version strings (see example below – it adds build configuration as a version information string).

Setting up is easy. First, the project should have a version information resource, so that the binary has data to patch in first place.

Then, there should be an .INI file which tracks version numbers. The binary will be build with .RC numbers and then incrementer will apply the least significant number from the .INI file incrementing it along the way.

[General]

[VersionInformation]
;Language=133 ;MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)
;Version String Format=%d.%d.%d.%d
Current Build Number=4

Next thing, project post-build event needs a command for patching:

Post-Build Event in VS for C++ Project

"$(AlaxInfo_Common)\..\Utilities\IncrementBuild\_Bin\IncrementBuild-$(PlatformName).exe" configuration "$(ProjectDir)Module.ini" binary "$(TargetPath)" string "ConfigurationName" "$(ConfigurationName)" 

The command takes Module.ini from the projects directory for configuration file, patches build output and also attaches build configuration as an additional version information string.

Build output looks like this:

—— Rebuild All started: Project: EnumerateTransforms, Configuration: Release Win32 ——
stdafx.cpp
Application.cpp
Generating code
Finished generating code
EnumerateTransforms.vcxproj -> D:\Projects…_Bin\Win32\Release\EnumerateTransforms.exe
EnumerateTransforms.vcxproj -> D:\Projects…_Bin\Win32\Release\EnumerateTransforms.pdb (Full PDB)
Configuration Path: D:\Projects…\Module.ini
Binary Path: D:\Projects…_Bin\Win32\Release\EnumerateTransforms.exe
Incrementing build number, product version 1.0.0.1, file version 1.0.0.4
Applying version information string, name “ConfigurationName”, value “Release”

Presumably, it is not necessary to use same bitness tool for a binary, since version information patching API should be able to patch resources of mismatching build, but I normally use a matching tool anyway, why not?

Download links

Understanding Your DirectShow Filter Graph

Many questions in DirectShow development are caused by lack of developer’s understanding what topology his code effectively built. Intelligent Connect and RenderXxx methods help adding and connecting filters and in the end a developer does not have a faintest idea what the pipeline looks like.

DirectShow API provides methods to enumerate filters, pins, connection and obtained detailed information about the filter graph. The API is well-documented. Then Windows SDK is shipped with GraphEdit which helps building graphs interactively. Ability to publish a graph on ROT and review it from GraphEdit is nothing but powerful. And then we have GraphStudioNext which makes everything even more convenient.

This does not seem sufficient and clear as many new questions and misunderstanding show that developers have false assumptions on graphs their applications use.

DirectShowSpy goes one step further with debugging options. With DirectShowSpy one can embed reviewing UI right into the developed application and either generate detailed textual description of filters, connections, media types as well as pass filter graph to GraphEdit/GraphStudioNext for interactive review with visualized topology. No excuses left any longer for misunderstanding built topologies.

Steps below explain in detail how to visualize your application DirectShow filter graph and generate a textual report on graph details.

1. For starters, one needs to intall DirectShowSpy in target system. Standard installation is mentioned in original post.

  • It is necessary that DirectShowSpy of correct/matching bitness is installed. 32-bit applications use 32-bit DirectShowSpy and 64-bit applications – 64-bit DirectShowSpy. .NET applications built as “Any CPU” are effectively either 32 or 64 bit processes and respectively need a matching spy as well.
  • To cut long story short, simply download DirectShow*.* from Toolbox and use DirectShowSpy-Win32-reg-ui.bat or DirectShowSpy-x64-reg-ui.bat to pop up registration UI. You need local administrator privileges for the registration step (or spy is usable through COM otherwise but it’s beyond scope of this post).

2. DirectShowSpy’s FilterGraphHelper object (already mentioned earlier) offers DoPropertyFrameModal method to pop up diagnostic UI. The helper needs prior initialization with either graph, filter or pin interface. C++ code snippet:

#import "libid:B9EC374B-834B-4DA9-BFB5-C1872CE736FF" raw_interfaces_only // AlaxInfoDirectShowSpy
// ...
CComPtr<IFilterGraph2> pFilterGraph;
// ...
CComPtr<AlaxInfoDirectShowSpy::IFilterGraphHelper> pFilterGraphHelper;
ATLENSURE_SUCCEEDED(pFilterGraphHelper.CoCreateInstance(__uuidof(AlaxInfoDirectShowSpy::FilterGraphHelper)));
ATLENSURE_SUCCEEDED(pFilterGraphHelper->put_FilterGraph(pFilterGraph));
ATLENSURE_SUCCEEDED(pFilterGraphHelper->DoPropertyFrameModal(NULL));

C# code snippet:

IFilterGraph2 graph = new FilterGraph() as IFilterGraph2;
// ...
FilterGraphHelper helper = new FilterGraphHelper();
helper.FilterGraph = graph;
helper.DoPropertyFrameModal(0);

Downloadable sample projects (FilterGraphHelperDialog for C# and FilterGraphHelperDialog2 for C++) are available in Subversion repository or Trac.

3. DoPropertyFrameModal methods opens a window (it’s argument is parent window handle, optional) with details about the graph, including copyable diagnostic text, filters and their property pages all gathered in single window.

FilterGraphHelper.DoPropertyFrameModal UI

NOTE: With root tree element “Filters” selected, the right-side pane contains the text that provides filter graph description (see image above)!

4. Additionally, it is possible to launch GraphEdit/GraphStudioNext with a hotkey and open – through ROT – the graph visually.

FilterGraphHelper.DoPropertyFrameModal UI (Actions)

Remote Graph in GraphStudioNext

This requires that Windows SDK proppage.dll is available. It is normally registered with Windows SDK, and otherwise can be copied from SDK into target system and COM-registered using regsvr32. Or copied into the folder of DirectShowSpy in which case DirectShowSpy-Win32-reg-ui.bat (see item 1 above) file will see it and offer additional property page for registration.

5. When no longer needed, DirectShowSpy can be removed from system using the batch file mentioned above in item 1.

Whatever debugging you do with DirectShow filter graph, you need a complete understanding what filter graph you deal with. If you want to provide additional information to certain DirectShow related question, a copy/pasted diagnostic information needs to be attached to such question so that others understand what you are dealing with exactly.

DeckLinkCapabilities: A Printout of Capabilities of Blackmagic Design/DeckLink Hardware

The tool provides a user- (well, actually a developer-) friendly printout of capabilities accessible via Blackmagic Design DeckLink SDK for DeckLink series of hardware. This covers features of DeckLink and Intensity series of hardware for video/audio capture, accessible via vendor’s SDK. The data is printed out in Markdown format, easy to read on its own and even nicer on Markdown Pad.

Alax.Info DeckLinkCapabilities

Alax.Info DeckLinkCapabilities Output on MarkdownPad

The hardware is good, and the SDK is designed nicely as well, however the product range is wide and capabilities vary. So do driver and SDK versions, and the tool is handy to quick check the information out. One might want to use SDK for many reasons, including the following ideas I am sharing off the top of my head:

  • wanting to leverage the full feature set of the hardware
  • operate at minimal overhead
  • user a simpler API compared to generic media APIs
  • being unsatisfied with DirectShow interface provided by Blackmagic Design

Continue reading →

Resource Tools: Custom Resource Types

This update for Resource Tools adds an option to access custom resource types, such as FILE, TYPELIB, REGISTRY etc. It lets enumerate the resource, and load/save them. The COM interafce adds new Items property; the code snippet below accesses type library of image2.dll and saves it into external tyle library file image2.tlb:

image = new ActiveXObject("AlaxInfo.ResourceTools.Image");
image.Initialize("C:\\Windows\\syswow64\\imapi2.dll");
image.Items("TYPELIB").Item(1).SaveToFile(null, "imapi2.tlb");

Additionally, image.EndUpdate(false) call makes the object close all references to the underlying file so that it can be available for other operations (e.g. overwrite), and the COM object might be further re-initialized and reused.

Download links:

GPS Location/Coordinate Converter: Fractional Seconds, More Shortcuts

This adds a small update to the recently published GPS Location/Coordinate Converter utility:

  • Seconds in Degrees, Minutes & Seconds notation are shown and are accepted as floating point numbers
  • More shortcuts to popular online map services (note that only Google Maps and Yandex Maps are still accepted as input via clipboard):
    • Bing Maps
    • Yahoo Maps
    • Open Street Map
    • WikiMapia

The latter makes the tool an easy to use converted between the services for a GPS POI.

A binary [Win32] and partial Visual C++ .NET 2010 partial source code are available from SVN.

Utility Clearance: GPS Location/Coordinate Converter

This tool came up as a result of mess around GPS coordinate formatting and variety of popular formats and notations. Some use latitude and longitude degrees, some prefer degrees and minutes with fractional part. this does not take into account choices for datum and file formats.

For instance, both Google Maps and Yandex Maps accept latitude and longitude as ll= URL parameter with the value of latitude and longitude in degrees, however Google uses latitude coming first, while Yandex prefers the opposite.

Recently, a rally road book contained the following formatting of track points:

Having to put a stop to the madness, this utility comes up as a handy assistant to convert and format GPS coordinates into reasonable presentation and separators.

The utility runs on background and monitors clipboard, and once it recognizes one of the following:

  • GPS Point in Degrees
  • GPS Point in Degrees and Minutes
  • GPS Point in Degrees, Minutes and Seconds
  • Google Maps URL
  • Yandex Maps URL

it flashes and updates its UI providing the choices of track point formatting:

The utility is trying hard to accept various separators and formats, just one thing is important to keep in mind: if you are using minutes without seconds, the fractional part of minutes should be separated by decimal point (.).

The utility also responds to hotkeys Ctrl+Shift+F1, Ctrl+Shift+F2 etc. and copies the formatted point location back into clipboard so that one could quickly re-format editable text in another application through clipboard updates. Alternatively, it is possible to click the formatted value and place it into clipboard.

The utility also provides clickable hyperlinks to open Google Maps and Yandex Maps into the point of interest.

A binary [Win32] and partial Visual C++ .NET 2010 partial source code are available from SVN.

Note: you might need to run the tool “As Administrator” elevating UAC privileges in Vista/7 operating systems.

Bonus links on the topic: