mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1474 lines
37 KiB
1474 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1994 - 1995 Microsoft Corporation. All Rights Reserved.
|
|
|
|
Module Name:
|
|
|
|
imp.c
|
|
|
|
Abstract:
|
|
|
|
This file defines the internal functions for the MPEG API DLL.
|
|
|
|
Author:
|
|
|
|
Yi SUN (t-yisun) 08-23-1994
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <winioctl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "trace.h"
|
|
|
|
#define IN_MPEGAPI_DLL
|
|
|
|
#include "mpegapi.h"
|
|
|
|
#include "imp.h"
|
|
#include "ddmpeg.h"
|
|
|
|
|
|
#define NT_MPEG_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Mpeg")
|
|
#define WIN95_MPEG_KEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Mpeg")
|
|
|
|
//
|
|
// NNNN\
|
|
// Capabilities
|
|
// Description
|
|
// InstallDate
|
|
// Manufacturer
|
|
// ProductName
|
|
// ServiceName
|
|
// Title
|
|
// Attributes\
|
|
// Audio\
|
|
// Bass\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Channel\
|
|
// Current=n
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Mode\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// VolumeLeft\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// VolumeRight\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Video\
|
|
// Brightness\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Channel\
|
|
// Current=n
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Contrast\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Hue\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Mode\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Saturation\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Tint\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// AGC\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Clamp\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Coring\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Gain\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// GenLock\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// Sharpness\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
// SignalType\
|
|
// Minimum=n
|
|
// Maximum=n
|
|
// Step=n
|
|
// Channel0=n
|
|
// Channel1=n
|
|
// Channeln=n
|
|
|
|
typedef struct _MPEG_REGISTRY_LIST {
|
|
MPEG_ATTRIBUTE eAttribute;
|
|
LPTSTR pszKeyName;
|
|
} MPEG_REGISTRY_LIST, *PMPEG_REGISTRY_LIST;
|
|
|
|
MPEG_REGISTRY_LIST AttributeList[] =
|
|
{
|
|
{ MpegAttrAudioBass, TEXT("Attributes\\Audio\\Bass") },
|
|
{ MpegAttrAudioChannel, TEXT("Attributes\\Audio\\Channel") },
|
|
{ MpegAttrAudioMode, TEXT("Attributes\\Audio\\Mode") },
|
|
{ MpegAttrAudioTreble, TEXT("Attributes\\Audio\\Treble") },
|
|
{ MpegAttrAudioVolumeLeft, TEXT("Attributes\\Audio\\VolumeLeft") },
|
|
{ MpegAttrAudioVolumeRight, TEXT("Attributes\\Audio\\VolumeRight") },
|
|
|
|
{ MpegAttrVideoBrightness, TEXT("Attributes\\Video\\Brightness") },
|
|
{ MpegAttrVideoChannel, TEXT("Attributes\\Video\\Channel") },
|
|
{ MpegAttrVideoContrast, TEXT("Attributes\\Video\\Contrast") },
|
|
{ MpegAttrVideoHue, TEXT("Attributes\\Video\\Hue") },
|
|
{ MpegAttrVideoMode, TEXT("Attributes\\Video\\Mode") },
|
|
{ MpegAttrVideoSaturation, TEXT("Attributes\\Video\\Saturation") },
|
|
{ MpegAttrVideoAGC, TEXT("Attributes\\Video\\AGC") },
|
|
{ MpegAttrVideoClamp, TEXT("Attributes\\Video\\Clamp") },
|
|
{ MpegAttrVideoCoring, TEXT("Attributes\\Video\\Coring") },
|
|
{ MpegAttrVideoGain, TEXT("Attributes\\Video\\Gain") },
|
|
{ MpegAttrVideoGenLock, TEXT("Attributes\\Video\\GenLock") },
|
|
{ MpegAttrVideoSharpness, TEXT("Attributes\\Video\\Sharpness") },
|
|
{ MpegAttrVideoSignalType, TEXT("Attributes\\Video\\SignalType") },
|
|
|
|
{ MpegAttrOverlayXOffset, TEXT("Attributes\\Overlay\\DestinationXOffset") },
|
|
{ MpegAttrOverlayYOffset, TEXT("Attributes\\Overlay\\DestinationYOffset") },
|
|
};
|
|
|
|
#define NUMBER_MPEG_ATTRIBUTES \
|
|
(sizeof(AttributeList) / sizeof(AttributeList[0]))
|
|
|
|
// define an MPEG device control block for each MPEG device in the system
|
|
|
|
#define MAX_MPEG_DEVICES 4
|
|
|
|
int nMpegAdapters = 0;
|
|
|
|
MPEG_DEVICE_CONTROL_BLOCK MpegDcbs[MAX_MPEG_DEVICES];
|
|
|
|
// {
|
|
// "ReelMagic",
|
|
// "SIGMA DESIGNS ReelMagic",
|
|
// NULL, // pseudo handle
|
|
// 0x0017, // capabilities to indicate it supports audio, video,
|
|
// // separate streams and video overlay, nothing else
|
|
// 0, // sequence number
|
|
// { // abstract devices
|
|
// { FALSE, NULL, "Combined", NULL },
|
|
// { TRUE, "\\\\.\\MPEGAudio0", "Audio", NULL },
|
|
// { TRUE, "\\\\.\\MPEGVideo0", "Video", NULL },
|
|
// { TRUE, "\\\\.\\VideoOverlay", "Overlay", NULL }
|
|
// },
|
|
// { // attribute ranges
|
|
// { (ULONG)0, (ULONG)0, (ULONG)0 },
|
|
// { (ULONG)0, (ULONG)0, (ULONG)0 },
|
|
// { (ULONG)0, (ULONG)0xFFFF, (ULONG)1 }, // left volume
|
|
// { (ULONG)0, (ULONG)0xFFFF, (ULONG)1 }, // right volume
|
|
// { (ULONG)0, (ULONG)0xFFFF, (ULONG)1 }, // both volumes
|
|
// { (ULONG)0, (ULONG)0, (ULONG)0 },
|
|
// { (ULONG)0, (ULONG)0, (ULONG)0 },
|
|
// { (ULONG)0, (ULONG)0, (ULONG)0 }
|
|
// }
|
|
// };
|
|
|
|
// extern int __cdecl atoi(char *);
|
|
|
|
|
|
// Unicode support for converting strings to integers
|
|
|
|
#ifdef UNICODE
|
|
int
|
|
atoiW(LPCWSTR strW)
|
|
{
|
|
CHAR strA[128];
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, strW, -1, strA,
|
|
sizeof strA, NULL, NULL);
|
|
|
|
return atoi(strA);
|
|
}
|
|
#define ATOI(str) atoiW(str)
|
|
#else
|
|
#define ATOI(str) atoi(str)
|
|
#endif
|
|
|
|
int
|
|
ReadRegistry()
|
|
{
|
|
OSVERSIONINFO OsVersionInfo;
|
|
LONG lResult;
|
|
HKEY hMpegKey;
|
|
HKEY hDeviceKey;
|
|
FILETIME ftLastWrite;
|
|
TCHAR szSubKeyName[256];
|
|
DWORD dwSubKeySize;
|
|
DWORD dwType;
|
|
HKEY hAttributeKey;
|
|
union
|
|
{
|
|
DWORD dwBinary;
|
|
TCHAR szString[80];
|
|
} regValue;
|
|
DWORD dwValueSize;
|
|
int idxDevice;
|
|
int iDeviceNumber;
|
|
int nAttributes;
|
|
PABSTRACT_DEVICE_CONTROL_BLOCK pADcb;
|
|
int i;
|
|
int j;
|
|
|
|
OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
|
|
|
|
GetVersionEx(&OsVersionInfo);
|
|
|
|
lResult = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ?
|
|
NT_MPEG_KEY : WIN95_MPEG_KEY,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hMpegKey);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for (idxDevice = 0; idxDevice < MAX_MPEG_DEVICES; idxDevice++)
|
|
{
|
|
dwSubKeySize = sizeof(szSubKeyName);
|
|
|
|
lResult = RegEnumKeyEx(
|
|
hMpegKey, idxDevice, &szSubKeyName[0], &dwSubKeySize,
|
|
NULL, NULL, NULL, &ftLastWrite);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
iDeviceNumber = ATOI(szSubKeyName);
|
|
|
|
lResult = RegOpenKeyEx(
|
|
hMpegKey, szSubKeyName, 0, KEY_ALL_ACCESS, &hDeviceKey);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
MpegDcbs[idxDevice].nDevice = iDeviceNumber;
|
|
|
|
dwValueSize = sizeof(regValue);
|
|
|
|
lResult = RegQueryValueEx(
|
|
hDeviceKey, TEXT("Capabilities"), 0,
|
|
&dwType, (PUCHAR)®Value, &dwValueSize);
|
|
|
|
if (lResult == ERROR_SUCCESS && dwType == REG_DWORD)
|
|
{
|
|
MpegDcbs[idxDevice].ulCapabilities = regValue.dwBinary;
|
|
}
|
|
else
|
|
{
|
|
MpegDcbs[idxDevice].ulCapabilities = 0;
|
|
}
|
|
|
|
dwValueSize = sizeof(regValue);
|
|
|
|
lResult = RegQueryValueEx(
|
|
hDeviceKey, TEXT("Description"), 0,
|
|
&dwType, (PUCHAR)®Value, &dwValueSize);
|
|
|
|
if (lResult == ERROR_SUCCESS && dwType == REG_SZ)
|
|
{
|
|
lstrcpy(MpegDcbs[idxDevice].szDescription, regValue.szString);
|
|
}
|
|
else
|
|
{
|
|
MpegDcbs[idxDevice].szDescription[0] = '\0';
|
|
}
|
|
|
|
dwValueSize = sizeof(regValue);
|
|
|
|
lResult = RegQueryValueEx(
|
|
hDeviceKey, TEXT("AttributesLocked"), 0,
|
|
&dwType, (PUCHAR)®Value, &dwValueSize);
|
|
|
|
if (lResult == ERROR_SUCCESS && dwType == REG_DWORD)
|
|
{
|
|
MpegDcbs[idxDevice].bAttributesLocked = regValue.dwBinary;
|
|
}
|
|
else
|
|
{
|
|
MpegDcbs[idxDevice].bAttributesLocked = FALSE;
|
|
}
|
|
|
|
nAttributes = 0;
|
|
|
|
for (i = 0; i < NUMBER_MPEG_ATTRIBUTES; i++)
|
|
{
|
|
lResult = RegOpenKeyEx(
|
|
hDeviceKey,
|
|
AttributeList[i].pszKeyName,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hAttributeKey);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].eAttribute =
|
|
AttributeList[i].eAttribute;
|
|
|
|
dwValueSize = sizeof(regValue);
|
|
|
|
lResult = RegQueryValueEx(
|
|
hAttributeKey, TEXT("Minimum"), 0,
|
|
&dwType, (PUCHAR)®Value, &dwValueSize);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
switch (dwType)
|
|
{
|
|
case REG_DWORD:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMinimum =
|
|
regValue.dwBinary;
|
|
break;
|
|
|
|
case REG_SZ:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMinimum =
|
|
ATOI(regValue.szString);
|
|
break;
|
|
|
|
default:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMinimum = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMinimum = 0;
|
|
}
|
|
|
|
dwValueSize = sizeof(regValue);
|
|
|
|
lResult = RegQueryValueEx(
|
|
hAttributeKey, TEXT("Maximum"), 0,
|
|
&dwType, (PUCHAR)®Value, &dwValueSize);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
switch (dwType)
|
|
{
|
|
case REG_DWORD:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMaximum = regValue.dwBinary;
|
|
break;
|
|
|
|
case REG_SZ:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMaximum =
|
|
ATOI(regValue.szString);
|
|
break;
|
|
|
|
default:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMaximum =
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMinimum;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMaximum =
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lMinimum;
|
|
}
|
|
|
|
dwValueSize = sizeof(regValue);
|
|
|
|
lResult = RegQueryValueEx(
|
|
hAttributeKey, TEXT("Step"), 0,
|
|
&dwType, (PUCHAR)®Value, &dwValueSize);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
switch (dwType)
|
|
{
|
|
case REG_DWORD:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lStep =
|
|
regValue.dwBinary;
|
|
break;
|
|
|
|
case REG_SZ:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lStep =
|
|
ATOI(regValue.szString);
|
|
break;
|
|
|
|
default:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lStep = 1;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lStep = 1;
|
|
}
|
|
|
|
for (j = 0; j < MAX_CHANNELS; j++)
|
|
{
|
|
TCHAR szValueName[40];
|
|
|
|
wsprintf(szValueName, TEXT("CurrentValue%d"), j);
|
|
|
|
dwValueSize = sizeof(regValue);
|
|
|
|
lResult = RegQueryValueEx(
|
|
hAttributeKey, szValueName, 0,
|
|
&dwType, (PUCHAR)®Value, &dwValueSize);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].eValueStatus[j] =
|
|
AttrValueUpdated;
|
|
|
|
switch (dwType)
|
|
{
|
|
case REG_DWORD:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lCurrentValue[j] =
|
|
|
|
regValue.dwBinary;
|
|
break;
|
|
|
|
case REG_SZ:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].lCurrentValue[j] =
|
|
ATOI(regValue.szString);
|
|
break;
|
|
|
|
default:
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].eValueStatus[j] =
|
|
AttrValueUnset;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MpegDcbs[idxDevice].Attributes[nAttributes].eValueStatus[j] =
|
|
AttrValueUnset;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hAttributeKey);
|
|
|
|
nAttributes++;
|
|
}
|
|
|
|
MpegDcbs[idxDevice].nAttributes = nAttributes;
|
|
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
//
|
|
// Init abstract devices
|
|
//
|
|
|
|
// We don't support any combined devices yet
|
|
MpegDcbs[idxDevice].eAbstractDevices[MpegCombined].bIsAvailable = FALSE;
|
|
|
|
// Audio Device
|
|
pADcb = &MpegDcbs[idxDevice].eAbstractDevices[MpegAudio];
|
|
pADcb->bIsAvailable = TRUE;
|
|
pADcb->nCurrentChannel = 0;
|
|
wsprintf(pADcb->szId, TEXT("\\\\.\\MpegAudio%d"), iDeviceNumber);
|
|
pADcb->hAD = NULL;
|
|
|
|
// Video Device
|
|
pADcb = &MpegDcbs[idxDevice].eAbstractDevices[MpegVideo];
|
|
pADcb->bIsAvailable = TRUE;
|
|
pADcb->nCurrentChannel = 0;
|
|
wsprintf(pADcb->szId, TEXT("\\\\.\\MpegVideo%d"), iDeviceNumber);
|
|
pADcb->hAD = NULL;
|
|
|
|
// Overlay Device
|
|
pADcb = &MpegDcbs[idxDevice].eAbstractDevices[MpegOverlay];
|
|
pADcb->bIsAvailable = TRUE;
|
|
wsprintf(pADcb->szId, TEXT("\\\\.\\MpegOverlay%d"), iDeviceNumber);
|
|
pADcb->hAD = NULL;
|
|
}
|
|
|
|
RegCloseKey(hMpegKey);
|
|
|
|
return idxDevice;
|
|
}
|
|
|
|
int
|
|
WriteRegistry(USHORT idxDevice)
|
|
{
|
|
OSVERSIONINFO OsVersionInfo;
|
|
LONG lResult;
|
|
HKEY hMpegKey;
|
|
HKEY hDeviceKey;
|
|
TCHAR szSubKeyName[256];
|
|
HKEY hAttributeKey;
|
|
int nAttribute;
|
|
int i;
|
|
int j;
|
|
|
|
OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
|
|
|
|
GetVersionEx(&OsVersionInfo);
|
|
|
|
lResult = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ?
|
|
NT_MPEG_KEY : WIN95_MPEG_KEY,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hMpegKey);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
wsprintf(szSubKeyName, TEXT("%d"), MpegDcbs[idxDevice].nDevice);
|
|
|
|
lResult = RegOpenKeyEx(
|
|
hMpegKey, szSubKeyName, 0, KEY_ALL_ACCESS, &hDeviceKey);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
nAttribute = 0;
|
|
|
|
for (i = 0; i < NUMBER_MPEG_ATTRIBUTES; i++)
|
|
{
|
|
PMPEG_ATTRIBUTE_INFO pAttributeInfo;
|
|
|
|
|
|
if (nAttribute >= MpegDcbs[idxDevice].nAttributes)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pAttributeInfo = &MpegDcbs[idxDevice].Attributes[nAttribute];
|
|
|
|
if (AttributeList[i].eAttribute != pAttributeInfo->eAttribute)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
lResult = RegOpenKeyEx(
|
|
hDeviceKey,
|
|
AttributeList[i].pszKeyName,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hAttributeKey);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (j = 0; j < MAX_CHANNELS; j++)
|
|
{
|
|
TCHAR szValueName[40];
|
|
|
|
if (pAttributeInfo->eValueStatus[j] == AttrValueUnwritten)
|
|
{
|
|
wsprintf(szValueName, TEXT("CurrentValue%d"), j);
|
|
|
|
lResult = RegSetValueEx(
|
|
hAttributeKey, szValueName, 0, REG_DWORD,
|
|
(PUCHAR)&pAttributeInfo->lCurrentValue[j], sizeof(DWORD));
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
// Should do something here
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hAttributeKey);
|
|
|
|
nAttribute++;
|
|
}
|
|
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
RegCloseKey(hMpegKey);
|
|
|
|
return idxDevice;
|
|
}
|
|
|
|
HMPEG_DEVICE
|
|
MpegADHandle(
|
|
IN USHORT usIndex,
|
|
IN MPEG_ABSTRACT_DEVICE_INDEX eIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
returns the handle of the specified abstract device
|
|
|
|
Auguments:
|
|
|
|
usIndex -- the index of the MPEG device
|
|
eIndex -- the index of the abstract device
|
|
|
|
Return Value:
|
|
|
|
the handle
|
|
|
|
--*/
|
|
{
|
|
return MpegDcbs[usIndex].eAbstractDevices[eIndex].hAD;
|
|
}
|
|
|
|
LPTSTR
|
|
MpegDeviceDescription(
|
|
IN USHORT usIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
returns the device ID of the Mpeg device
|
|
|
|
Auguments:
|
|
|
|
usIndex -- the index of the MPEG device
|
|
|
|
Return Value:
|
|
|
|
the device description
|
|
|
|
--*/
|
|
{
|
|
return (LPTSTR)MpegDcbs[usIndex].szDescription;
|
|
}
|
|
|
|
MPEG_STATUS
|
|
CreateMpegHandle(
|
|
IN USHORT usIndex,
|
|
OUT PHMPEG_DEVICE phDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
opens the MPEG device and generates a handle for it
|
|
|
|
Auguments:
|
|
|
|
usIndex -- the index of the MPEG device
|
|
phDevice -- pointer to an HMPEG_DEVICE to be set to the
|
|
generated handle
|
|
|
|
Return Value:
|
|
|
|
MpegStatusSuccess -- the call completed successfully
|
|
MpegStatusBusy -- the iAdapterIndex supplied doesn't
|
|
correspond to a valid adapter
|
|
MpegStatusHardwareFailure -- the size of description buffer is too small
|
|
|
|
--*/
|
|
{
|
|
MPEG_STATUS mpegStatus;
|
|
USHORT i;
|
|
ULONG sn;
|
|
PABSTRACT_DEVICE_CONTROL_BLOCK pADcb;
|
|
|
|
// NOTE: for the time being, the flags are hard-coded
|
|
DWORD flags[] = {0, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
FILE_ATTRIBUTE_NORMAL};
|
|
|
|
// check to see if the MPEG device is already in use
|
|
if (MpegDcbs[usIndex].usSequenceNumber & 1) {
|
|
return MpegStatusBusy;
|
|
}
|
|
|
|
//ISSUE: open device with no abstract sub devices
|
|
|
|
for (i = 0; i < MAX_ABSTRACT_DEVICES; i++) {
|
|
pADcb = MpegDcbs[usIndex].eAbstractDevices + i;
|
|
if (pADcb->bIsAvailable) {
|
|
ULONG Cookie;
|
|
|
|
TraceSynchronousIoctlStart (&Cookie, 0, IOCTL_MPEG_PSEUDO_CREATE_FILE, NULL, NULL);
|
|
pADcb->hAD = CreateFile(pADcb->szId, GENERIC_READ | GENERIC_WRITE,
|
|
0, NULL, OPEN_EXISTING, flags[i], NULL);
|
|
if (pADcb->hAD == INVALID_HANDLE_VALUE) {
|
|
TraceSynchronousIoctlEnd (Cookie, GetLastError ());
|
|
return MpegStatusHardwareFailure;
|
|
}
|
|
TraceSynchronousIoctlEnd (Cookie, ERROR_SUCCESS);
|
|
}
|
|
}
|
|
|
|
// increase the sequence no
|
|
sn = ++MpegDcbs[usIndex].usSequenceNumber;
|
|
|
|
// the higher 16 bits corresponds to the seq no; the lower does to the index
|
|
*phDevice = (HMPEG_DEVICE)((sn << 16) | usIndex);
|
|
|
|
MpegQueryAttribute(
|
|
*phDevice, MpegAttrAudioChannel,
|
|
&MpegDcbs[usIndex].eAbstractDevices[MpegAudio].nCurrentChannel);
|
|
|
|
MpegQueryAttribute(
|
|
*phDevice, MpegAttrVideoChannel,
|
|
&MpegDcbs[usIndex].eAbstractDevices[MpegVideo].nCurrentChannel);
|
|
|
|
if ((mpegStatus = UpdateAttributes(usIndex, MpegAudio)) != MpegStatusSuccess ||
|
|
(mpegStatus = UpdateAttributes(usIndex, MpegVideo)) != MpegStatusSuccess ||
|
|
(mpegStatus = UpdateAttributes(usIndex, MpegOverlay)) != MpegStatusSuccess)
|
|
{
|
|
return mpegStatus;
|
|
}
|
|
|
|
return MpegStatusSuccess;
|
|
}
|
|
|
|
|
|
MPEG_STATUS
|
|
CreateMpegPseudoHandle(
|
|
IN USHORT usIndex,
|
|
OUT PHMPEG_DEVICE phDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
retrieves the pseudo handle of the MPEG device
|
|
|
|
Auguments:
|
|
|
|
usIndex -- index to the MPEG device
|
|
phDevice -- pointer to an HMPEG_DEVICE
|
|
|
|
Return Value:
|
|
|
|
MpegStatusSuccess -- the call completed successfully
|
|
|
|
--*/
|
|
{
|
|
*phDevice = (HMPEG_DEVICE) (0xFFFF0000 | usIndex);
|
|
|
|
return MpegStatusSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
HandleIsValid(
|
|
IN HMPEG_DEVICE hDevice,
|
|
OUT PUSHORT pusIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
checks whether the handle is valid and returns the index in pusIndex
|
|
|
|
Auguments:
|
|
|
|
hDevice -- handle representing the MPEG device
|
|
pusIndex -- pointer to the index
|
|
|
|
Return Value:
|
|
|
|
TRUE if valid; otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
USHORT index;
|
|
|
|
index = (USHORT) (((ULONG)hDevice) & 0x0000FFFF);
|
|
|
|
if ((index < 0) || (index >= nMpegAdapters)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (MpegDcbs[index].usSequenceNumber != (USHORT) (((ULONG)hDevice) >> 16)) {
|
|
return FALSE;
|
|
}
|
|
|
|
*pusIndex = index;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
PseudoHandleIsValid(
|
|
IN HMPEG_DEVICE hDevice,
|
|
OUT PUSHORT pusIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
checks whether the pseudo handle is valid and returns the index in pusIndex
|
|
|
|
Auguments:
|
|
|
|
hDevice -- pseudo handle representing the MPEG device
|
|
pusIndex -- pointer to the index
|
|
|
|
Return Value:
|
|
|
|
TRUE if valid; otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
USHORT index;
|
|
|
|
index = (USHORT) (((ULONG)hDevice) & 0x0000FFFFU);
|
|
|
|
if ((index < 0) || (index >= nMpegAdapters)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (((DWORD)hDevice & 0xFFFF0000U) != 0xFFFF0000U) {
|
|
return FALSE;
|
|
}
|
|
|
|
*pusIndex = index;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
MPEG_STATUS
|
|
CloseMpegHandle(
|
|
USHORT usIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
close the handle
|
|
|
|
Auguments:
|
|
|
|
usIndex -- index of the MPEG device
|
|
|
|
Return Value:
|
|
|
|
MpegStatusSuccess -- the call completed successfully
|
|
|
|
--*/
|
|
{
|
|
USHORT i;
|
|
PABSTRACT_DEVICE_CONTROL_BLOCK pADcb;
|
|
|
|
// close abstract devices
|
|
for (i = 0; i < MAX_ABSTRACT_DEVICES; i++) {
|
|
pADcb = MpegDcbs[usIndex].eAbstractDevices + i;
|
|
if (pADcb->bIsAvailable) {
|
|
ULONG Cookie;
|
|
|
|
TraceSynchronousIoctlStart (&Cookie, 0, IOCTL_MPEG_PSEUDO_CLOSE_HANDLE, NULL, NULL);
|
|
if (CloseHandle(pADcb->hAD)) {
|
|
TraceSynchronousIoctlEnd (Cookie, ERROR_SUCCESS);
|
|
} else {
|
|
TraceSynchronousIoctlEnd (Cookie, GetLastError ());
|
|
}
|
|
pADcb->hAD = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write out updated attributes
|
|
//
|
|
|
|
if (!MpegDcbs[usIndex].bAttributesLocked)
|
|
{
|
|
WriteRegistry(usIndex);
|
|
}
|
|
|
|
// increase the sequence no
|
|
++MpegDcbs[usIndex].usSequenceNumber;
|
|
|
|
return MpegStatusSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DeviceSupportCap(
|
|
IN USHORT usIndex,
|
|
IN MPEG_CAPABILITY eCapability
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
checks whether the MPEG device has the specified capability
|
|
|
|
Auguments:
|
|
|
|
usIndex -- index of the MPEG device
|
|
eCapability -- indicates the interested capability
|
|
|
|
Return Value:
|
|
|
|
TRUE if it does; otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
if (eCapability >= MpegCapMaximumCapability) {
|
|
return FALSE;
|
|
}
|
|
|
|
return (MpegDcbs[usIndex].ulCapabilities & (1 << eCapability));
|
|
}
|
|
|
|
BOOL
|
|
DeviceSupportStream(
|
|
IN USHORT usIndex,
|
|
IN MPEG_STREAM_TYPE eStreamType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
checks whether the MPEG device supports the specified stream type
|
|
|
|
Auguments:
|
|
|
|
usIndex -- index of the MPEG device
|
|
eStreamType -- indicates the interested stream type
|
|
|
|
Return Value:
|
|
|
|
TRUE if it does; otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
if (eStreamType != MpegSystemStream &&
|
|
!DeviceSupportCap(usIndex, MpegCapSeparateStreams))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (eStreamType) {
|
|
case MpegSystemStream:
|
|
return DeviceSupportCap(usIndex, MpegCapCombinedStreams);
|
|
case MpegAudioStream:
|
|
return DeviceSupportCap(usIndex, MpegCapAudioDevice);
|
|
case MpegVideoStream:
|
|
return DeviceSupportCap(usIndex, MpegCapVideoDevice);
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
DeviceSupportDevice(
|
|
IN USHORT usIndex,
|
|
IN MPEG_DEVICE_TYPE eDeviceType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
checks whether the MPEG device supports the specified stream type;
|
|
when eDeviceType is MpegCombinedDevice, checks whether the device
|
|
supports both audio and video
|
|
|
|
Auguments:
|
|
|
|
usIndex -- index of the MPEG device
|
|
eDeviceType -- indicates the interested device type
|
|
|
|
Return Value:
|
|
|
|
TRUE if it does; otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
switch (eDeviceType)
|
|
{
|
|
case MpegCombinedDevice:
|
|
return (DeviceSupportCap(usIndex, MpegCapAudioDevice) &&
|
|
DeviceSupportCap(usIndex, MpegCapVideoDevice));
|
|
case MpegAudioDevice:
|
|
return DeviceSupportCap(usIndex, MpegCapAudioDevice);
|
|
case MpegVideoDevice:
|
|
return DeviceSupportCap(usIndex, MpegCapVideoDevice);
|
|
case MpegOverlayDevice:
|
|
return (DeviceSupportCap(usIndex, MpegCapBitmaskOverlay) ||
|
|
DeviceSupportCap(usIndex, MpegCapChromaKeyOverlay));
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
MPEG_STATUS
|
|
GetAttributeRange(
|
|
IN USHORT usIndex,
|
|
IN MPEG_ATTRIBUTE eAttribute,
|
|
OUT PLONG plMinimum,
|
|
OUT PLONG plMaximum,
|
|
OUT PLONG plStep
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
retrieves the attribute range for the specified attr.
|
|
|
|
Auguments:
|
|
|
|
usIndex -- index of the MPEG device
|
|
eAttribute -- indicates the interested attribute
|
|
plMinimum -- pointer to a LONG to be set to the minimum
|
|
plMaximum -- pointer to a LONG to be set to the maximum
|
|
plStep -- pointer to a LONG to be set to the step
|
|
|
|
Return Value:
|
|
|
|
MpegStatusSuccess -- the call completed successfully
|
|
MpegStatusInvalidParameter -- the size of description buffer is too small
|
|
|
|
--*/
|
|
{
|
|
PMPEG_DEVICE_CONTROL_BLOCK pDcb;
|
|
int idxAttribute;
|
|
|
|
pDcb = &MpegDcbs[usIndex];
|
|
|
|
for (idxAttribute = 0; idxAttribute < pDcb->nAttributes; idxAttribute++)
|
|
{
|
|
if (pDcb->Attributes[idxAttribute].eAttribute == eAttribute)
|
|
{
|
|
*plMinimum = pDcb->Attributes[idxAttribute].lMinimum;
|
|
*plMaximum = pDcb->Attributes[idxAttribute].lMaximum;
|
|
*plStep = pDcb->Attributes[idxAttribute].lStep;
|
|
return MpegStatusSuccess;
|
|
}
|
|
}
|
|
|
|
return MpegStatusUnsupported;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DeviceIoControlSync(
|
|
HMPEG_DEVICE hDevice,
|
|
DWORD dwIoControlCode,
|
|
LPVOID lpInBuffer,
|
|
DWORD nInBufferSize,
|
|
LPVOID lpOutBuffer,
|
|
DWORD nOutBufferSize,
|
|
LPDWORD lpBytesReturned
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
simulate a synchronous IOCTL command
|
|
|
|
Auguments:
|
|
|
|
hDevice -- handle representing the device
|
|
dwIoControlCode -- control code of operation to perform
|
|
lpInBuffer -- address of buffer for input data
|
|
nInBufferSize -- size of input buffer
|
|
lpOutBuffer -- address of buffer for output data
|
|
nOutBufferSize -- size of output buffer
|
|
lpBytesReturned -- address of actual bytes of output
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function succeeds; otherwise FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
OVERLAPPED overlapped;
|
|
BOOL fResult;
|
|
DWORD dwSavedError;
|
|
DWORD dwBytesRet;
|
|
|
|
//Create an overlapped structure needed to perform an asynchronous operation
|
|
overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
// Send the IOCTL asynchronously to the device
|
|
|
|
switch (dwIoControlCode) {
|
|
case IOCTL_MPEG_AUDIO_END_OF_STREAM:
|
|
case IOCTL_MPEG_AUDIO_WRITE_PACKETS:
|
|
case IOCTL_MPEG_VIDEO_END_OF_STREAM:
|
|
case IOCTL_MPEG_VIDEO_WRITE_PACKETS:
|
|
TracePacketsStart ((DWORD)hDevice,
|
|
dwIoControlCode,
|
|
&overlapped,
|
|
lpInBuffer,
|
|
nInBufferSize / (sizeof (MPEG_PACKET_LIST)));
|
|
break;
|
|
default:
|
|
TraceIoctlStart ((DWORD)hDevice, dwIoControlCode, &overlapped, lpInBuffer, lpOutBuffer);
|
|
break;
|
|
}
|
|
fResult = DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer,
|
|
nInBufferSize, lpOutBuffer, nOutBufferSize,
|
|
lpBytesReturned, (LPOVERLAPPED)&overlapped);
|
|
|
|
// If the operation did not complete, then block until it has finished
|
|
if (!fResult && GetLastError() == ERROR_IO_PENDING) {
|
|
fResult = GetOverlappedResult(hDevice, (LPOVERLAPPED)&overlapped,
|
|
&dwBytesRet, TRUE);
|
|
|
|
// dwBytesRet is what DeviceIoControl() would have
|
|
// returned in lpBytesReturned
|
|
// if it had completed synchronously.
|
|
|
|
if (lpBytesReturned)
|
|
*lpBytesReturned = dwBytesRet;
|
|
}
|
|
|
|
dwSavedError = GetLastError();
|
|
|
|
if (fResult) {
|
|
TraceIoctlEnd (&overlapped, ERROR_SUCCESS);
|
|
} else {
|
|
TraceIoctlEnd (&overlapped, dwSavedError);
|
|
}
|
|
|
|
CloseHandle(overlapped.hEvent);
|
|
|
|
SetLastError(dwSavedError);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
MPEG_STATUS
|
|
MpegTranslateWin32Error(
|
|
DWORD dwWin32Error
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Translate a WIN32 error code into an equivalent MPEG status code.
|
|
|
|
Auguments:
|
|
|
|
dwWin32Error -- WIN32 error code to be translated.
|
|
|
|
Return Value:
|
|
|
|
MPEG status code.
|
|
|
|
--*/
|
|
{
|
|
switch (dwWin32Error)
|
|
{
|
|
case NO_ERROR:
|
|
return MpegStatusSuccess;
|
|
|
|
case ERROR_INVALID_FUNCTION: // STATUS_NOT_IMPLEMENTED
|
|
return MpegStatusUnsupported;
|
|
|
|
case ERROR_INVALID_PARAMETER: // STATUS_INVALID_PARAMETER
|
|
return MpegStatusInvalidParameter;
|
|
|
|
case ERROR_OPERATION_ABORTED:
|
|
return MpegStatusCancelled;
|
|
|
|
case ERROR_REVISION_MISMATCH: // STATUS_REVISION_MISMATCH
|
|
return MpegStatusHardwareFailure;
|
|
|
|
default:
|
|
// Fall Thru for now
|
|
|
|
case ERROR_IO_DEVICE: // STATUS_IO_DEVICE_ERROR
|
|
case ERROR_GEN_FAILURE: // STATUS_UNSUCCESSFUL
|
|
return MpegStatusHardwareFailure;
|
|
}
|
|
}
|
|
|
|
MPEG_STATUS
|
|
SetCurrentChannel(
|
|
IN USHORT usIndex,
|
|
IN MPEG_DEVICE_TYPE eDeviceType,
|
|
IN INT nChannel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the current channel for the given abstract device.
|
|
|
|
Auguments:
|
|
|
|
usIndex -- Index of miniport
|
|
eDeviceType -- Index of abstract device
|
|
nChannel -- New channel
|
|
|
|
Return Value:
|
|
|
|
MPEG status code.
|
|
|
|
--*/
|
|
{
|
|
MpegDcbs[usIndex].eAbstractDevices[eDeviceType].nCurrentChannel = nChannel;
|
|
|
|
return UpdateAttributes(usIndex, eDeviceType);
|
|
}
|
|
|
|
MPEG_STATUS
|
|
GetCurrentChannel(
|
|
IN USHORT usIndex,
|
|
IN MPEG_DEVICE_TYPE eDeviceType,
|
|
OUT PINT pnChannel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the current channel for the given abstract device.
|
|
|
|
Auguments:
|
|
|
|
usIndex -- Index of miniport
|
|
eDeviceType -- Index of abstract device
|
|
pnChannel -- Address to place current channel
|
|
|
|
Return Value:
|
|
|
|
MPEG status code.
|
|
|
|
--*/
|
|
{
|
|
*pnChannel = MpegDcbs[usIndex].eAbstractDevices[eDeviceType].nCurrentChannel;
|
|
return MpegStatusSuccess;
|
|
}
|
|
|
|
MPEG_STATUS
|
|
SetCurrentAttributeValue(
|
|
IN USHORT usIndex,
|
|
IN MPEG_DEVICE_TYPE eDeviceType,
|
|
IN MPEG_ATTRIBUTE eAttribute,
|
|
IN LONG lValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the current value for the given attribute based on the current
|
|
channel for the given abstract device.
|
|
|
|
Auguments:
|
|
|
|
usIndex -- Index of miniport
|
|
eDeviceType -- Index of abstract device
|
|
eAttribute -- Attribute to set
|
|
lValue -- New value for the attribute
|
|
|
|
Return Value:
|
|
|
|
MPEG status code.
|
|
|
|
--*/
|
|
{
|
|
PMPEG_DEVICE_CONTROL_BLOCK pDcb;
|
|
PMPEG_ATTRIBUTE_INFO pAttributeInfo;
|
|
int nCurrentChannel;
|
|
|
|
pDcb = &MpegDcbs[usIndex];
|
|
nCurrentChannel = pDcb->eAbstractDevices[ eDeviceType ].nCurrentChannel;
|
|
|
|
for (pAttributeInfo = &pDcb->Attributes[0];
|
|
pAttributeInfo < &pDcb->Attributes[ pDcb->nAttributes ];
|
|
pAttributeInfo++)
|
|
{
|
|
if (pAttributeInfo->eAttribute == eAttribute)
|
|
{
|
|
pAttributeInfo->lCurrentValue[ nCurrentChannel ] = lValue;
|
|
pAttributeInfo->eValueStatus[ nCurrentChannel ] = AttrValueUnwritten;
|
|
return MpegStatusSuccess;
|
|
}
|
|
}
|
|
|
|
return MpegStatusUnsupported;
|
|
}
|
|
|
|
MPEG_STATUS
|
|
UpdateAttributes(
|
|
IN USHORT usIndex,
|
|
IN MPEG_DEVICE_TYPE eDeviceType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the attribute values for the given abstract device.
|
|
|
|
Auguments:
|
|
|
|
usIndex -- Index of miniport
|
|
eDeviceType -- Index of abstract device
|
|
|
|
Return Value:
|
|
|
|
MPEG status code.
|
|
|
|
--*/
|
|
{
|
|
PMPEG_DEVICE_CONTROL_BLOCK pDcb;
|
|
PMPEG_ATTRIBUTE_INFO pAttributeInfo;
|
|
HMPEG_DEVICE hAD;
|
|
DWORD dwIoctlCode;
|
|
DWORD cbReturn;
|
|
MPEG_ATTRIBUTE_PARAMS attribute;
|
|
int nCurrentChannel;
|
|
|
|
if (eDeviceType == MpegAudio)
|
|
{
|
|
dwIoctlCode = IOCTL_MPEG_AUDIO_SET_ATTRIBUTE;
|
|
}
|
|
else if (eDeviceType == MpegVideo)
|
|
{
|
|
dwIoctlCode = IOCTL_MPEG_VIDEO_SET_ATTRIBUTE;
|
|
}
|
|
else if (eDeviceType == MpegOverlay)
|
|
{
|
|
dwIoctlCode = IOCTL_MPEG_OVERLAY_SET_ATTRIBUTE;
|
|
}
|
|
else
|
|
{
|
|
return MpegStatusUnsupported;
|
|
}
|
|
|
|
hAD = MpegADHandle(usIndex, eDeviceType);
|
|
pDcb = &MpegDcbs[usIndex];
|
|
nCurrentChannel = pDcb->eAbstractDevices[eDeviceType].nCurrentChannel;
|
|
|
|
// Set each updated value
|
|
|
|
for (pAttributeInfo = pDcb->Attributes;
|
|
pAttributeInfo < &pDcb->Attributes[ pDcb->nAttributes ];
|
|
pAttributeInfo++)
|
|
{
|
|
if (pAttributeInfo->eValueStatus[nCurrentChannel] != AttrValueUpdated)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (pAttributeInfo->eAttribute < MpegAttrMaximumAudioAttribute)
|
|
{
|
|
if (eDeviceType != MpegAudio)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (pAttributeInfo->eAttribute < MpegAttrMaximumVideoAttribute)
|
|
{
|
|
if (eDeviceType != MpegVideo)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (eDeviceType != MpegOverlay)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
attribute.Attribute = pAttributeInfo->eAttribute;
|
|
attribute.Value = pAttributeInfo->lCurrentValue[nCurrentChannel];
|
|
|
|
if (!DeviceIoControlSync(
|
|
hAD, dwIoctlCode,
|
|
&attribute, sizeof(attribute),
|
|
NULL, 0, &cbReturn))
|
|
{
|
|
return MpegTranslateWin32Error(GetLastError());
|
|
}
|
|
|
|
pAttributeInfo->eValueStatus[nCurrentChannel] = AttrValueUnset;
|
|
}
|
|
|
|
return MpegStatusSuccess;
|
|
}
|