There are several APIs from Microsoft which provide access to image data.
- Twain: Used for single image capture from scanners, etc.
 
- WIA: This seems to have degenerated to a single image codec library.
 
- VfW: A very old (Win16) API which really works only Video-File encoding/decoding, but has support for some video acquisition.
 
- DirectShow: previously part in the DirectX SDK, currently in the Platform SDK. This is the place to go for current (general) streaming solutions.
 
- Windows Media/Media Foundation: This seems more to be geared at video playback/reencoding.
 
- Manufacturer Specific Libraries: Pylon/Halcon/Imaging Control/...
 
DirectShow specific :
To create image acquisition devices under windows, you have to provide either a device (driver) which implements the streamclasses interfaces (or newer Avstream) or you have to write a usermode COM object which has to be added to the VideoInputCategory enumerator.
The Avstream sample provides everything for a real image acquisition device. Only the lower layer for the actual device really is missing.
If you can design a device, you should either create it DCAM or UVC compatible. For both there are built-in drivers supplied by windows.
How to write a software source device :
You have to create a DirectShow filter which provides at least one output pin and register this under the VideoInputCategory. There may be several interfaces certain applications require from a capture application, but these depend on the application itself. Simple applications to try out filters are GraphEdit and AMCap which are supplied in the Plattform SDK.
Some code :
#include <InitGuid.h>
#include <streams.h>
const AMOVIESETUP_MEDIATYPE s_VideoPinType =
{
    &MEDIATYPE_Video,   // Major type
    &MEDIATYPE_NULL     // Minor type
};
const AMOVIESETUP_PIN s_VideoOutputPin =
{
    L"Output",              // Pin string name
    FALSE,                  // Is it rendered
    TRUE,                   // Is it an output
    FALSE,                  // Can we have none
    FALSE,                  // Can we have many
    &CLSID_NULL,            // Connects to filter
    NULL,                   // Connects to pin
    1,                      // Number of types
    &s_VideoPinType         // Pin details
};
const AMOVIESETUP_FILTER s_Filter =
{
    &CLSID_MyFilter,        // Filter CLSID
    L"bla",         // String name
    MERIT_DO_NOT_USE,               // Filter merit
    1,                              // Number pins
    &s_VideoOutputPin               // Pin details
};
    REGFILTER2 rf2;
    rf2.dwVersion = 1;
    rf2.dwMerit = MERIT_DO_NOT_USE;
    rf2.cPins = 1;
    rf2.rgPins = s_Filter.lpPin;
    HRESULT hr = pFilterMapper->RegisterFilter( CLSID_MyFilter, _FriendlyName.c_str(), 0, 
        &CLSID_VideoInputDeviceCategory, _InstanceID.c_str(), &rf2 );
    if( FAILED( hr ) )
    {
        return false;
    }
    std::wstring inputCat = GUIDToWString( CLSID_VideoInputDeviceCategory );
    std::wstring regPath = L"CLSID\\" + inputCat + L"\\Instance";
    win32_utils::CRegKey hKeyInstancesDir;
    LONG rval = openKey( HKEY_CLASSES_ROOT, regPath, KEY_WRITE, hKeyInstancesDir );
    if( rval == ERROR_SUCCESS )
    {
        win32_utils::CRegKey hKeyInstance;
        rval = createKey( hKeyInstancesDir, _InstanceID, KEY_WRITE, hKeyInstance );
        ....
_InstanceID is a GUID created for this 'virtual device' entry.