Implementation uvc extension unit function to control C8209DM

2024-08-07

The Extension Unit is a method provided by the UVC specification to add vendor-specific building blocks to the specification.The USB Video Class specification defines a mechanism to extend the functionality of devices that comply with that specification and describes the behavior of Extension Units. Independent hardware vendors (IHVs) can enhance the value of their devices by adding functionality that goes beyond that described in the specification.

This extension mechanism requires operating system support and some user-mode plug-ins so that applications can work with these extensions. The USB Video Class driver architecture provides such a mechanism so that IHVs can expose extended device functionality as COM APIs. This documentation describes the steps required to create and register such a plug-in.

C8209DM has integrated XU control unit, the user can use it to control the brightness of the led lights, query version number, etc.

Here is an example of how to write a pc program to communicate with the C8209DM.

Basic information

  • GUID,:{DD880F8A-1CBA-4954-8A25-F7875967F0F7}
  • bUnitID:8
  • KSP_NODE NodeId:3
  • CS select:1
  • CS data length:32

Include files

#include "stdafx.h"
#include <mfapi.h>
#include <mfplay.h>
#include <mfreadwrite.h>
#include <vector>
#include <string>
#include <ks.h>
#include <ksproxy.h>
#include <vidcap.h>

Get camera devices

HRESULT GetVideoDevices()
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
MFStartup(MF_VERSION);
// Create an attribute store to specify the enumeration parameters.
HRESULT hr = MFCreateAttributes(&pVideoConfig, 1);
CHECK_HR_RESULT(hr, "Create attribute store");
// Source type: video capture devices
hr = pVideoConfig->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
);
CHECK_HR_RESULT(hr, "Video capture device SetGUID");
// Enumerate devices.
hr = MFEnumDeviceSources(pVideoConfig, &ppVideoDevices, &noOfVideoDevices);
CHECK_HR_RESULT(hr, "Device enumeration");
done:
return hr;
}

Get device GUID

HRESULT GetVideoDeviceGUIDs(int deviceIndex)
{
// Get the the device friendly name.
UINT32 cchName;
HRESULT hr =
ppVideoDevices[deviceIndex]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SY
MBOLIC_LINK,&szFriendlyGUID, &cchName);
CHECK_HR_RESULT(hr, "Get video device GUID");
done:
  return hr;
}

Init device

HRESULT InitVideoDevice(int deviceIndex)
{
HRESULT hr = ppVideoDevices[deviceIndex]->ActivateObject(IID_PPV_ARGS(&pVideoSource));
CHECK_HR_RESULT(hr, "Activating video device");
// Create a source reader.
hr = MFCreateSourceReaderFromMediaSource(pVideoSource, pVideoConfig, &pVideoReader);
CHECK_HR_RESULT(hr, "Creating video source reader");
done:
return hr;
}

SetGetExtensionUnit

HRESULT SetGetExtensionUnit(GUID xuGuid, DWORD dwExtensionNode, ULONG xuPropertyId, ULONG
flags, void* data, int len, ULONG* readCount)
{
GUID pNodeType;
IUnknown* unKnown;
IKsControl* ks_control = NULL;
IKsTopologyInfo* pKsTopologyInfo = NULL;
KSP_NODE kspNode;
HRESULT hr = pVideoSource->QueryInterface(__uuidof(IKsTopologyInfo),
(void**)&pKsTopologyInfo);
CHECK_HR_RESULT(hr, "IMFMediaSource::QueryInterface(IKsTopologyInfo)");
hr = pKsTopologyInfo->get_NodeType(dwExtensionNode, &pNodeType);
CHECK_HR_RESULT(hr, "IKsTopologyInfo->get_NodeType(...)");
hr = pKsTopologyInfo->CreateNodeInstance(dwExtensionNode, IID_IUnknown,
(LPVOID*)&unKnown);
CHECK_HR_RESULT(hr, "ks_topology_info->CreateNodeInstance(...)");
hr = unKnown->QueryInterface(__uuidof(IKsControl), (void**)&ks_control);
CHECK_HR_RESULT(hr, "ks_topology_info->QueryInterface(...)");
kspNode.Property.Set = xuGuid; // XU GUID
kspNode.NodeId = (ULONG)dwExtensionNode; // XU Node ID
kspNode.Property.Id = xuPropertyId; // XU control ID
kspNode.Property.Flags = flags; // Set/Get request
hr = ks_control->KsProperty((PKSPROPERTY)&kspNode, sizeof(kspNode), (PVOID)data, len,
readCount);
CHECK_HR_RESULT(hr, "ks_control->KsProperty(...)");
done:
SafeRelease(&ks_control);
return hr;
}
//To get 0x300A
static const GUID xuGuid =
{ 0xDD880F8A, 0x1CBA, 0x4954,{ 0x8a, 0x25, 0xf7, 0x87, 0x59, 0x67, 0xf0, 0xf7 } };
BYTE rd[32] = { 0x06, 0x30,0x0A,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
SetGetExtensionUnit(xuGuid, 3, 1, flags, (void*)rd, 32, &readCount);
flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
SetGetExtensionUnit(xuGuid, 3, 1, flags, (void*)rd, 32, &readCount);

For C8209DL/ C8209DP
It will return
{0x69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
So 0X300A = 0x69