Codec Merit
Från och med Windows 7 kan en Media Foundation-codec tilldelas ett förtjänar värde. När codecs räknas upp föredras codecs med högre meriter framför codecs med lägre meriter. Codecs med något meritvärde föredras framför codecs utan en tilldelad merit. Mer information om codec-uppräkning finns i MFTEnumEx.
Meritvärden tilldelas av Microsoft. För närvarande är endast maskinvarukodare berättigade att få ett meritvärde. Codec-leverantören utfärdas också ett digitalt certifikat som används för att verifiera codec-meritvärdet. Om du vill hämta ett certifikat skickar du en e-postbegäran till wmla@microsoft.com. Processen för att hämta ett certifikat omfattar signering av en licens och tillhandahålla en uppsättning informationsfiler till Microsoft.
Codec merit fungerar på följande sätt:
- Codec-leverantören implementerar något av följande:
- En AVStream-minidrivrutin. Media Foundation tillhandahåller en standardproxy-MFT för AVStream-drivrutiner. Det här är det rekommenderade alternativet.
- En Media Foundation-transformering (MFT) som fungerar som proxy till maskinvaran. Mer information finns i maskinvaru-MFI.
- Codec:s meritvärde lagras i registret för snabb sökning.
- Funktionen MFTEnumEx sorterar codecs i meritordning. Codecs med meritvärden visas i listan bakom lokalt registrerade codecs (se MFTRegisterLocal), men före andra codecs.
- När MFT skapas verifieras codec-värdet med hjälp av api:et Output Protection Manager (OPM).
- För en proxy-MFT implementerar codec IOPMVideoOutput--gränssnittet. För en AVStream-drivrutin implementerar codec KSPROPSETID_OPMVideoOutput egenskapsuppsättning.
Följande diagram visar hur meriter verifieras i båda fallen:
MFT för anpassad proxy
Om du anger en proxy-MFT för maskinvarukodexcen implementerar du värdet för codec merit enligt följande:
Implementera gränssnittet IOPMVideoOutput i MFT. Exempelkod visas i nästa avsnitt i det här avsnittet.
Lägg till attributet MFT_CODEC_MERIT_Attribute i registret enligt följande:
- Anropa MFCreateAttributes för att skapa ett nytt attributarkiv.
- Anropa IMFAttributes::SetUINT32 för att ange attributet MFT_CODEC_MERIT_Attribute. Värdet för attributet är codecens tilldelade förtjänst.
- Anropa MFTRegister för att registrera MFT. Skicka attributarkivet i parametern pAttributes.
Programmet anropar MFTEnumEx. Den här funktionen returnerar en matris med IMFAktivera pekare, en för varje codec som matchar uppräkningskriterierna.
Programmet anropar IMFActivate::ActivateObject för att skapa MFT.
Metoden ActivateObject anropar funktionen MFGetMFTMerit för att verifiera certifikatet och meritvärdet.
Funktionen MFGetMFTMerit anropar IOPMVideoOutput::GetInformation och skickar en OPM_GET_CODEC_INFO statusbegäran. Den här statusbegäran returnerar codec:s tilldelade meritvärde. Om det här värdet inte matchar registervärdet kan ActivateObject misslyckas.
Följande kod visar hur du lägger till meritvärdet i registret när du registrerar MFT:
// Shows how to register an MFT with a merit value.
HRESULT RegisterMFTWithMerit()
{
// The following media types would apply to an H.264 decoder,
// and are used here as an example.
MFT_REGISTER_TYPE_INFO aDecoderInputTypes[] =
{
{ MFMediaType_Video, MFVideoFormat_H264 },
};
MFT_REGISTER_TYPE_INFO aDecoderOutputTypes[] =
{
{ MFMediaType_Video, MFVideoFormat_RGB32 }
};
// Create an attribute store to hold the merit attribute.
HRESULT hr = S_OK;
IMFAttributes *pAttributes = NULL;
hr = MFCreateAttributes(&pAttributes, 1);
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(
MFT_CODEC_MERIT_Attribute,
DECODER_MERIT // Use the codec's assigned merit value.
);
}
// Register the decoder for MFTEnum(Ex).
if (SUCCEEDED(hr))
{
hr = MFTRegister(
CLSID_MPEG1SampleDecoder, // CLSID
MFT_CATEGORY_VIDEO_DECODER, // Category
const_cast<LPWSTR>(SZ_DECODER_NAME), // Friendly name
0, // Flags
ARRAYSIZE(aDecoderInputTypes), // Number of input types
aDecoderInputTypes, // Input types
ARRAYSIZE(aDecoderOutputTypes), // Number of output types
aDecoderOutputTypes, // Output types
pAttributes // Attributes
);
}
SafeRelease(&pAttributes);
return hr;
}
Implementera IOPMVideoOutput för Codec Merit
Följande kod visar hur du implementerar IOPMVideoOutput- för codec merit. En mer allmän diskussion om OPM-API:et finns i Output Protection Manager.
Not
Koden som visas här har ingen fördunkling eller andra säkerhetsmekanismer. Det är tänkt att visa den grundläggande implementeringen av OPM-handskakningen och statusbegäran.
Det här exemplet förutsätter att g_TestCert är en bytematris som innehåller codec-certifikatkedjan och g_PrivateKey är en bytematris som innehåller den privata nyckeln från certifikatet:
// Byte array that contains the codec's certificate.
const BYTE g_TestCert[] =
{
// ... (certificate not shown)
// Byte array that contains the private key from the certificate.
const BYTE g_PrivateKey[] =
{
// .... (key not shown)
I IOPMVideoOutput::StartInitialization-metoden genererar du ett slumptal för handskakningen. Returnera det här numret och certifikatet till anroparen:
STDMETHODIMP CodecMerit::StartInitialization(
OPM_RANDOM_NUMBER *prnRandomNumber,
BYTE **ppbCertificate,
ULONG *pulCertificateLength
)
{
HRESULT hr = S_OK;
DWORD cbCertificate = sizeof(g_TestCert);
const BYTE *pCertificate = g_TestCert;
// Generate the random number for the OPM handshake.
hr = BCryptGenRandom(
NULL,
(PUCHAR)&m_RandomNumber,
sizeof(m_RandomNumber),
BCRYPT_USE_SYSTEM_PREFERRED_RNG
);
// Allocate the buffer to copy the certificate.
if (SUCCEEDED(hr))
{
*ppbCertificate = (PBYTE)CoTaskMemAlloc(cbCertificate);
if (*ppbCertificate == NULL)
{
hr = E_OUTOFMEMORY;
}
}
// Copy the certificate and the random number.
if (SUCCEEDED(hr))
{
*pulCertificateLength = cbCertificate;
CopyMemory(*ppbCertificate, pCertificate, cbCertificate);
*prnRandomNumber = m_RandomNumber;
}
return hr;
}
Metoden IOPMVideoOutput::FinishInitialization slutför OPM-handskakningen:
STDMETHODIMP CodecMerit::FinishInitialization(
const OPM_ENCRYPTED_INITIALIZATION_PARAMETERS *pParameters
)
{
HRESULT hr = S_OK;
BCRYPT_ALG_HANDLE hAlg = NULL;
BCRYPT_KEY_HANDLE hKey = NULL;
BCRYPT_OAEP_PADDING_INFO paddingInfo = {0};
DWORD DecryptedLength = 0;
PBYTE pbDecryptedParams = NULL;
// The caller should pass the following structure in
// pParameters:
typedef struct {
GUID guidCOPPRandom; // Our random number.
GUID guidKDI; // AES signing key.
DWORD StatusSeqStart; // Status sequence number.
DWORD CommandSeqStart; // Command sequence number.
} InitParams;
paddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM;
// Decrypt the input using the decoder's private key.
hr = BCryptOpenAlgorithmProvider(
&hAlg,
BCRYPT_RSA_ALGORITHM,
MS_PRIMITIVE_PROVIDER,
0
);
// Import the private key.
if (SUCCEEDED(hr))
{
hr = BCryptImportKeyPair(
hAlg,
NULL,
BCRYPT_RSAPRIVATE_BLOB,
&hKey,
(PUCHAR)g_PrivateKey, //pbData,
sizeof(g_PrivateKey), //cbData,
0
);
}
// Decrypt the input data.
if (SUCCEEDED(hr))
{
hr = BCryptDecrypt(
hKey,
(PBYTE)pParameters,
OPM_ENCRYPTED_INITIALIZATION_PARAMETERS_SIZE,
&paddingInfo,
NULL,
0,
NULL,
0,
&DecryptedLength,
BCRYPT_PAD_OAEP
);
}
if (SUCCEEDED(hr))
{
pbDecryptedParams = new (std::nothrow) BYTE[DecryptedLength];
if (pbDecryptedParams == NULL)
{
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr))
{
hr = BCryptDecrypt(
hKey,
(PBYTE)pParameters,
OPM_ENCRYPTED_INITIALIZATION_PARAMETERS_SIZE,
&paddingInfo,
NULL,
0,
pbDecryptedParams,
DecryptedLength,
&DecryptedLength,
BCRYPT_PAD_OAEP
);
}
if (SUCCEEDED(hr))
{
InitParams *Params = (InitParams *)pbDecryptedParams;
// Check the random number.
if (0 != memcmp(&m_RandomNumber, &Params->guidCOPPRandom, sizeof(m_RandomNumber)))
{
hr = E_ACCESSDENIED;
}
else
{
// Save the key and the sequence numbers.
CopyMemory(m_AESKey.abRandomNumber, &Params->guidKDI, sizeof(m_AESKey));
m_StatusSequenceNumber = Params->StatusSeqStart;
m_CommandSequenceNumber = Params->CommandSeqStart;
}
}
// Clean up.
if (hKey)
{
BCryptDestroyKey(hKey);
}
if (hAlg)
{
BCryptCloseAlgorithmProvider(hAlg, 0);
}
delete [] pbDecryptedParams;
return hr;
}
I metoden IOPMVideoOutput::GetInformation implementerar du OPM_GET_CODEC_INFO statusbegäran. Indata är en OPM_GET_CODEC_INFO_PARAMETERS struktur som innehåller CLSID för din MFT. Utdata är en OPM_GET_CODEC_INFO_INFORMATION struktur som innehåller codec-meriten.
STDMETHODIMP CodecMerit::GetInformation(
const OPM_GET_INFO_PARAMETERS *Parameters,
OPM_REQUESTED_INFORMATION *pRequest
)
{
HRESULT hr = S_OK;
OPM_GET_CODEC_INFO_PARAMETERS *CodecInfoParameters;
// Check the MAC.
OPM_OMAC Tag = { 0 };
hr = ComputeOMAC(
m_AESKey,
(PBYTE)Parameters + OPM_OMAC_SIZE,
sizeof(OPM_GET_INFO_PARAMETERS) - OPM_OMAC_SIZE,
&Tag
);
if (SUCCEEDED(hr))
{
if (0 != memcmp(Tag.abOMAC, &Parameters->omac, OPM_OMAC_SIZE))
{
hr = E_ACCESSDENIED;
}
}
// Validate the status sequence number. This must be consecutive
// from the previous sequence number.
if (SUCCEEDED(hr))
{
if (Parameters->ulSequenceNumber != m_StatusSequenceNumber++)
{
hr = E_ACCESSDENIED;
}
}
// Check the status request.
if (SUCCEEDED(hr))
{
if (Parameters->guidInformation != OPM_GET_CODEC_INFO)
{
hr = E_NOTIMPL;
}
}
// Check parameters.
if (SUCCEEDED(hr))
{
CodecInfoParameters = (OPM_GET_CODEC_INFO_PARAMETERS *)Parameters->abParameters;
if (Parameters->cbParametersSize > OPM_GET_INFORMATION_PARAMETERS_SIZE ||
Parameters->cbParametersSize < sizeof(ULONG) ||
Parameters->cbParametersSize - sizeof(ULONG) != CodecInfoParameters->cbVerifier
)
{
hr = E_INVALIDARG;
}
}
// The input data should consist of the CLSID of the decoder.
if (SUCCEEDED(hr))
{
CodecInfoParameters = (OPM_GET_CODEC_INFO_PARAMETERS *)Parameters->abParameters;
if (CodecInfoParameters->cbVerifier != sizeof(CLSID) ||
0 != memcmp(&CLSID_MPEG1SampleDecoder,
CodecInfoParameters->Verifier,
CodecInfoParameters->cbVerifier))
{
hr = E_ACCESSDENIED;
}
}
if (SUCCEEDED(hr))
{
// Now return the decoder merit to the caller.
ZeroMemory(pRequest, sizeof(OPM_REQUESTED_INFORMATION));
OPM_GET_CODEC_INFO_INFORMATION *pInfo =
(OPM_GET_CODEC_INFO_INFORMATION *)pRequest->abRequestedInformation;
pInfo->Merit = DECODER_MERIT;
pInfo->rnRandomNumber = Parameters->rnRandomNumber;
pRequest->cbRequestedInformationSize = sizeof(OPM_GET_CODEC_INFO_INFORMATION);
// Sign it with the key.
hr = ComputeOMAC(
m_AESKey,
(PBYTE)pRequest + OPM_OMAC_SIZE,
sizeof(OPM_REQUESTED_INFORMATION) - OPM_OMAC_SIZE,
&pRequest->omac
);
}
return hr;
}
Metoden GetInformation måste beräkna en KOD för meddelandeautentisering (MAC) med omac-1-algoritmen. se Computing the OMAC-1 Value.
Det är inte nödvändigt att stödja andra OPM-statusbegäranden.
IOPMVideoOutput::COPPCompatibleGetInformation och IOPMVideoOutput::Konfigurera metoder krävs inte för codec merit, så dessa metoder kan returnera E_NOTIMPL.
STDMETHODIMP CodecMerit::COPPCompatibleGetInformation(
const OPM_COPP_COMPATIBLE_GET_INFO_PARAMETERS *pParameters,
OPM_REQUESTED_INFORMATION *pRequestedInformation)
{
return E_NOTIMPL;
}
STDMETHODIMP CodecMerit::Configure(
const OPM_CONFIGURE_PARAMETERS *pParameters,
ULONG ulAdditionalParametersSize,
const BYTE *pbAdditionalParameters)
{
return E_NOTIMPL;
}
Relaterade ämnen