Virtual Webcam Driver

Franklin picture Franklin · Oct 26, 2009 · Viewed 29.6k times · Source

I want to develop a virtual webcam driver which from User mode I'll pass image to it and it will display as webcam output.

I don't want to use DirectX filter and CSourceStream etc. Because they don't work on some programs which doesn't use DirectX for capturing webcam image.

I have to write a kernel mode device driver so.

Any ideas? I tried testcap from DDK samples, but it doesn't process image from user mode and doesn't get any input, just it displays 7 colors in webcam...

Any help would be greatly appreciated. Thanks


Thank you all!

I tried code from here: http://tmhare.mvps.org/downloads.htm (find Capture Source Filter)

It worked well when I compiled it in Yahoo, MSN, but it crashed AIM, Internet Explorer Flash Webcam, Firefox Flash webcam and Skype... I got crash in QueryInterface after 8 time call to that, I found it with tracing it with a lot of tricks..

Now I know, it crashes on 8th call to HRESULT CVCamStream::QueryInterface(REFIID riid, void **ppv)

8th call when it reaches to last if, I mean: return CSourceStream::QueryInterface(riid, ppv);

It's in 17th line of Filters.cpp

Why do you think I'm getting crash??

Thank you all for guiding me to find correct solution which is DirectShow, not driver

Answer

Christopher picture Christopher · Oct 26, 2009

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.