Sample implementations of different Microsoft Media Foundation components
- Anton Polinger, Developing Microsoft Media Foundation Applications, ISBN: 978-0-7356-5659-8
- MSDN, Media Foundation Architecture, [http://msdn.microsoft.com/en-us/library/windows/desktop/ms696219(v=vs.85).aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/ms696219(v=vs.85\).aspx)
- MSDN, Windows 8.1 Media extension sample, http://code.msdn.microsoft.com/windowsapps/media-extensions-sample-7b466096
- tenouk.com, DLLs and linking, http://www.tenouk.com/ModuleBB.html
- MSDN, Windows Runtime C++ Template Library (WRL), http://msdn.microsoft.com/en-us/library/vstudio/hh438466.aspx
- MSDN, Walkthrough: Creating a Windows Store app using WRL and Media Foundation, http://msdn.microsoft.com/en-us/library/jj872764.aspx
An architectural overview of the Media Foundation Architecture:
Two different programming models:
- Media pipeline - Contains Media Source, MFT and Media Sink objects. Any object can be implemented by the application.
- Source reader & Sink writer
- [http://msdn.microsoft.com/en-us/library/windows/desktop/dd940436(v=vs.85).aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/dd940436(v=vs.85\).aspx)
- [http://msdn.microsoft.com/en-us/library/windows/desktop/ff819461(v=vs.85).aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/ff819461(v=vs.85\).aspx)
See github projects:
https://github.com/joekickass/media-foundation-samples
As usual when it comes to creating components that should fit into a complex framework (e.g. MF) there are some plumbing involved. With plumbing I mean all the bulk code that has to be written to hande the packaging of the component as well as to fulfill interfaces that allows the component to be loaded by the framework. In the case of MF , below is a short list:
- WRL
- DLLs, linking and exporting
- MIDL and MIDLRT
In most situations, it is recommended to use C++/CX to interact with the Windows Runtime. But in the case of hybrid components that implement both COM and Windows Runtime interfaces, such as Media Foundation objects, this is not possible. C++/CX can only create Windows Runtime objects. So, for hybrid objects it is recommended that you use WRL to interact with the Windows Runtime. Be aware that Windows Runtime C++ Template Library has limited support for implementing COM interfaces.
- http://msdn.microsoft.com/en-us/library/vstudio/hh438466.aspx
- http://channel9.msdn.com/Events/Windows-Camp/Developing-Windows-8-Metro-style-apps-in-Cpp/The-Windows-Runtime-Library-WRL-
An MF extension is usually implemented as a DLL. The following few steps are a common procedure:
-
Create a Win (Phone) 8.x DLL project
-
Add a definition file (*.def) that defines all exported functions of the shared library (the export list)
*.def:
EXPORTS DllGetActivationFactory PRIVATE DllCanUnloadNow PRIVATE DllGetClassObject PRIVATE
Note: The *.def file needs to be referenced in project settings under:
Setting Value Linker -> Input -> Definition File mydefinitionfile.def -
dllmain.cpp defines the entry point of the DLL;
DllMain()
. Let it also implement the exported functions using some WRL magic:dllmain.cpp:
#include "pch.h" // pch.h should include <wrl/module.h> using namespace Microsoft::WRL; BOOL APIENTRY DllMain(HMODULE hInstance, DWORD ul_reason_for_call, LPVOID) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInstance); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } HRESULT WINAPI DllGetActivationFactory(HSTRING activatibleClassId, IActivationFactory** factory) { return Module<InProc>::GetModule().GetActivationFactory(activatibleClassId, factory); } HRESULT WINAPI DllCanUnloadNow() { return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE; } STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv) { return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv); }
More info on DLLs and linking can be found on http://www.tenouk.com/ModuleBB.html
The Microsoft Interface Description Language is used to describe the interface exposed through the windows runtime. The following MSDN project template summarizes the steps needed to do this:
http://msdn.microsoft.com/en-us/library/vstudio/hh973463.aspx
- An .idl file that declares the MIDL attributes for a basic interface and its class implementation
- A .cpp file that defines the class implementation.
- A file that defines the library exports
DllMain()
,DllCanUnloadNow()
,DllGetActivationFactory()
, andDllGetClassObject()
.
In addition to this, the MIDLRT compiler needs to be set up to generate a .winmd file for the DLL. Without it the library won't be exposed throught the Windows Runtime and thus cannot be used as a reference in managed code. More info:
[http://msdn.microsoft.com/en-us/library/windows/desktop/hh869900(v=vs.85).aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/hh869900(v=vs.85\).aspx)
An example *.idl file for a custom MFT:
import "Windows.Media.idl";
#include <sdkddkver.h>
namespace Transform
{
[version(NTDDI_WIN8)]
runtimeclass Effect
{
[default] interface Windows.Media.IMediaExtension;
}
}
Right clicking on the idl file and selecting Properties is a shortcut to the project properties for MIDL. To genereate a .winmd file, add the following settings.
Setting | Value |
---|---|
MIDL -> General -> Enable Windows Runtime | Yes (/winrt) |
MIDL -> Output -> Metadata File | $(OutDir)%(RootNamespace).winmd |
MIDL -> Output -> Header File | %(RootNamespace)_h.h |
Note that the generated .winmd file needs to be modified in order to work properly. See StackOverflow for more info:
This means adding the following build step under project settings:
Setting | Value |
---|---|
Custom Build Step -> General -> Command Line | mdmerge -v -i "$(OutDir)." -o "$(OutDir)Output" -partial -metadata_dir "$(WindowsSDK_MetadataPath)" && copy /y "$(OutDir)Output*" "$(OutDir)" |
Custom Build Step -> General -> Output | $(OutDir)%(RootNamespace).winmd |
Custom Build Step -> General -> Execute After | Midl |
Finally, the generated header file (_%(RootNamespace)h.h) needs to be referenced in the class definition file (*.cpp) as shown in the generic example below. Notice the InspectableClass using a string definition from the header, and the ActivatableClass section.
#include "pch.h"
#include "RootNamespace_h.h"
#include <wrl.h>
using namespace Microsoft::WRL;
using namespace Windows::Foundation;
namespace ABI
{
namespace RootNamespace
{
class WinRTClass: public RuntimeClass<IWinRTClass>
{
InspectableClass(RuntimeClass_RootNamespace_ClassName, BaseTrust)
public:
WinRTClass(){}
};
ActivatableClass(WinRTClass);
}
}
A few libraries need to be referenced when creating an Effect MFT:
- mf.lib
- mfuuid.lib
- mfplat.lib
Add them to Linker -> Input -> Additional Dependencies.
In managed code (e.g. the C# application where the MFT library is referenced), the class needs to be activated using the following section added to the Package.appxmanifest file:
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>EffectTransform.dll</Path>
<ActivatableClass ActivatableClassId="EffectTransform.Effect" ThreadingModel="both" />
</InProcessServer>
</Extension>
</Extensions>
MF is a free-threaded system, which means that COM interface methods can be invoked from arbitrary threads. Therefore, when calling CoInitializeEx(), you must initialize COM with the apartment-threaded object concurrency by passing in the COINIT_APARTMENTTHREADED parameter. Your objects might also need to use synchronization primitives, such as locks, to control access to internal variables by concurrently running threads.
See also [http://msdn.microsoft.com/en-us/library/windows/desktop/ee892371(v=vs.85).aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/ee892371(v=vs.85\).aspx)