Mérite du codec
à partir de Windows 7, un codec Media Foundation peut se voir attribuer une valeur mérite . Lorsque les codecs sont énumérés, les codecs avec des mérites plus élevés sont préférés par rapport aux codecs avec une valeur plus faible. Les codecs ayant n’importe quelle valeur mérite sont préférés sur les codecs sans mérite affecté. Pour plus d’informations sur l’énumération des codecs, consultez MFTEnumEx.
Les valeurs mérite sont attribuées par Microsoft. Actuellement, seuls les codecs matériels peuvent recevoir une valeur mérite. Le fournisseur du codec reçoit également un certificat numérique, qui est utilisé pour vérifier la valeur mérite du codec. Pour obtenir un certificat, envoyez une demande par courrier électronique à wmla@microsoft.com . Le processus d’obtention d’un certificat consiste à signer une licence et à fournir un ensemble de fichiers d’informations à Microsoft.
La mérite du codec fonctionne comme suit :
- Le fournisseur du codec implémente l’un des éléments suivants :
- Un mini-pilote AVStream. Media Foundation fournit une table MFT de proxy standard pour les pilotes AVStream. C'est l'option recommandée.
- Une Media Foundation transformation (MFT) qui agit comme un proxy pour le matériel. Pour plus d’informations, consultez Hardware MFTS.
- La valeur mérite du codec est stockée dans le registre pour une recherche rapide.
- La fonction MFTEnumEx trie les codecs dans l’ordre de leur mérite. Les codecs dont les valeurs méritent s’affichent dans la liste derrière les codecs inscrits localement (voir MFTRegisterLocal), mais avant les autres codecs.
- Lorsque la table MFT est créée, le mérite du codec est vérifié à l’aide de l’API de sortie Protection Manager (OPM).
- Pour une table MFT de proxy, le codec implémente l’interface IOPMVideoOutput . Pour un pilote AVStream, le codec implémente le _ jeu de propriétés KSPROPSETID OPMVideoOutput.
Le diagramme suivant montre comment la mérite est vérifiée dans les deux cas :

MFT du proxy personnalisé
Si vous fournissez une table MFT du proxy pour le codec matériel, mettez en œuvre la valeur du codec comme suit :
Implémentez l’interface IOPMVideoOutput dans la table MFT. L’exemple de code est présenté dans la section suivante de cette rubrique.
Ajoutez l' attribut _ _ _ attribut de mérite du codec MFT au registre comme suit :
- Appelez MFCreateAttributes pour créer un nouveau magasin d’attributs.
- Appelez IMFAttributes :: SetUINT32 pour définir l’attribut de _ _ mérite _ du codec MFT . La valeur de l’attribut est le mérite affecté au codec.
- Appelez MFTRegister pour inscrire la table MFT. Transmettez le magasin d’attributs dans le paramètre pAttributes .
L’application appelle MFTEnumEx. Cette fonction retourne un tableau de pointeurs IMFActivate , un pour chaque codec qui correspond aux critères d’énumération.
L’application appelle IMFActivate :: ActivateObject pour créer la table MFT.
La méthode ActivateObject appelle la fonction MFGetMFTMerit pour vérifier le certificat et la valeur mérite.
La fonction MFGetMFTMerit appelle IOPMVideoOutput :: GetInformation et envoie une demande d’état d’informations d' _ extraction de _ codec _ OPM . Cette demande d’État retourne la valeur mérite attribuée au codec. Si cette valeur ne correspond pas à la valeur de Registre, ActivateObject peut échouer.
Le code suivant montre comment ajouter la valeur mérite au registre lorsque vous inscrivez la table 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;
}
Implémentation de IOPMVideoOutput pour la mérite du codec
Le code suivant montre comment implémenter IOPMVideoOutput pour la mérite du codec. Pour une description plus générale de l’API OPM, consultez sortie Protection Manager.
Notes
Le code présenté ici n’a pas d’obscurcissement ou d’autres mécanismes de sécurité. Il est destiné à illustrer l’implémentation de base de la demande d’État et de la négociation OPM.
Cet exemple suppose que g _ TestCert est un tableau d’octets qui contient la chaîne de certificats du codec et que g _ PrivateKey est un tableau d’octets qui contient la clé privée du certificat :
// 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)
Dans la méthode IOPMVideoOutput :: StartInitialization , générez un nombre aléatoire pour le protocole de transfert. Retournez ce numéro et le certificat à l’appelant :
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;
}
La méthode IOPMVideoOutput :: FinishInitialization termine le protocole de transfert OPM :
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;
}
Dans la méthode IOPMVideoOutput :: GetInformation , implémentez la demande d’état d' informations d’extraction de _ _ codec _ OPM . Les données d’entrée sont une structure de _ _ _ _ paramètres d’extraction de codec OPM qui contient le CLSID de votre MFT. Les données de sortie sont une structure d' _ _ _ _ informations de codec OPM obten contenant la mérite du codec.
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;
}
La méthode GetInformation doit calculer un code D’AUTHENTIFICATION de message (Mac) à l’aide de l’algorithme OMAC-1 ; consultez calcul de la valeur OMAC-1.
Il n’est pas nécessaire de prendre en charge d’autres demandes d’État OPM.
Les méthodes IOPMVideoOutput :: COPPCompatibleGetInformation et IOPMVideoOutput :: configure ne sont pas requises pour la mérite du codec. elles peuvent donc retourner 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;
}