#include "precomp.h" #define MAGIC_CPU_DO_NOT_EXCEED_PERCENTAGE 50 //Don't use more than this % of the CPU for encoding (also in audiocpl.cpp) /*************************************************************************** Name : GetQOSCPULimit Purpose : Gets the total allowed CPU percentage use from QoS Parameters: None Returns : How much of the CPU can be used, in percents. 0 means failure Comment : ***************************************************************************/ ULONG GetQOSCPULimit(void) { #define MSECS_PER_SEC 900 IQoS *pQoS=NULL; LPRESOURCELIST pResourceList=NULL; ULONG ulCPUPercents=0; ULONG i; HRESULT hr=NOERROR; // create the QoS object and get the IQoS interface // CoInitialize is called in conf.cpp hr = CoCreateInstance( CLSID_QoS, NULL, CLSCTX_INPROC_SERVER, IID_IQoS, (void **) &pQoS); if (FAILED(hr) || !pQoS) { // this means that QoS was not instantiated yet. Use predefined value // ASSERT, because I want to know if this happens ASSERT(pQoS); ulCPUPercents = MSECS_PER_SEC; goto out; } // get a list of all resources from QoS hr = pQoS->GetResources(&pResourceList); if (FAILED(hr) || !pResourceList) { ERROR_OUT(("GetQoSCPULimit: GetReosurces failed")); goto out; } // find the CPU resource for (i=0; i < pResourceList->cResources; i++) { if (pResourceList->aResources[i].resourceID == RESOURCE_CPU_CYCLES) { // QoS keps the CPU units as the number of ms in a sec that the // CPU can be used. Need to divide by 10 to get percents ulCPUPercents = pResourceList->aResources[i].nUnits / 10; break; } } out: if (pResourceList) pQoS->FreeBuffer(pResourceList); if (pQoS) pQoS->Release(); return ulCPUPercents; } HRESULT CapsCtl::ComputeCapabilitySets (DWORD dwBitsPerSec) { HRESULT hr = hrSuccess; UINT nAud = 0; UINT nAudCaps = 0; UINT nVid = 0; UINT nVidCaps = 0; UINT x, y, nSets = 0; BASIC_AUDCAP_INFO *pac = NULL; BASIC_VIDCAP_INFO *pvc = NULL; MEDIA_FORMAT_ID *AdvList = NULL; int CPULimit; LPAPPCAPPIF pAudIF = NULL; LPAPPVIDCAPPIF pVidIF = NULL; if (pAudCaps) { hr = pAudCaps->QueryInterface(IID_IAppAudioCap, (void **)&pAudIF); if(!HR_SUCCEEDED(hr)) { goto ComputeDone; } } if (pVidCaps) { hr = pVidCaps->QueryInterface(IID_IAppVidCap, (void **)&pVidIF); if(!HR_SUCCEEDED(hr)) { goto ComputeDone; } } //Save away the Bandwidth dwConSpeed=dwBitsPerSec; // Create the default PTERMCAPDESCRIPTORS set // Get the number of BASIC_VIDCAP_INFO and BASIC_AUDCAP_INFO structures // available if (pVidIF) pVidIF->GetNumFormats(&nVidCaps); if (pAudIF) pAudIF->GetNumFormats(&nAudCaps); if (nAudCaps) { // Allocate some memory to hold the list in if (pac = (BASIC_AUDCAP_INFO*)MemAlloc(sizeof(BASIC_AUDCAP_INFO) * nAudCaps)) { // Get the list if ((hr = pAudIF->EnumFormats(pac, nAudCaps * sizeof (BASIC_AUDCAP_INFO), (UINT*)&nAudCaps)) != hrSuccess) goto ComputeDone; } else { hr = CAPS_E_SYSTEM_ERROR; goto ComputeDone; } } if (nVidCaps) { // Allocate some memory to hold the video list in if (pvc = (BASIC_VIDCAP_INFO*) MemAlloc(sizeof(BASIC_VIDCAP_INFO) * nVidCaps)) { // Get the list if ((hr = pVidIF->EnumFormats(pvc, nVidCaps * sizeof (BASIC_VIDCAP_INFO), (UINT*)&nVidCaps)) != hrSuccess) goto ComputeDone; } else { hr = CAPS_E_SYSTEM_ERROR; goto ComputeDone; } } //Allocate memory for the defined list of Codecs, so we can track them if (nAudCaps) { AdvList = (MEDIA_FORMAT_ID*) MemAlloc(sizeof(MEDIA_FORMAT_ID) * nAudCaps); if (!AdvList) { hr = CAPS_E_SYSTEM_ERROR; goto ComputeDone; } } if (pAdvertisedSets && pAdvertisedSets->wLength) { ResetCombinedEntries(); } // We're about to write over pSetIDs, make sure it's freed. if (pSetIDs) { MemFree(pSetIDs); pSetIDs = NULL; } //Allocate nVidCaps+1 Set Ids ASSERT(!pSetIDs); pSetIDs = (DWORD*) MemAlloc(sizeof(DWORD) * (nVidCaps + 1)); if (!pSetIDs) { hr = CAPS_E_SYSTEM_ERROR; goto ComputeDone; } // // If we can get a % limit from the QOS, then use that as the upper bound of // CPU consumption for a Codec. If it exceeds this bound, do not enable it. // CPULimit= (int) GetQOSCPULimit(); if (CPULimit == 0) CPULimit = MAGIC_CPU_DO_NOT_EXCEED_PERCENTAGE; // // Now, sort that list, according to preference // This function adds the sets to the advertised list. It sorts audio // by each video codec. // for (x=0; ((xIsFormatPublic(pvc[x].Id)) { nVid++; // Loop through the Audio codecs, checking to see if they can // fit alongside the video codec // BUGBUG - we only check the total BW and CPU because we rely on // QOS to scale back the video in favor of audio. in other words, // video can be scaled down to zero BW and CPU. for (y=0;((yIsFormatPublic(pac[y].Id))) { // going to advertise this ID in this AdvList[nAud++]=pac[y].Id; } } //Advertise this set, if we can do audio and video if (nAud) { hr = AddCombinedEntry (AdvList,nAud,&pvc[x].Id,1,&pSetIDs[nSets++]); if(!HR_SUCCEEDED(hr)) { goto ComputeDone; } } nAud = 0; } } //#if(0) // Advertising only one media type in a simcaps set is redundant. //Now, do the no-video case. If we couldn't advertise above.-- Which implies, in this iteration // A problem with all the video codecs. We don't do any "combined" compares, so we know // it's a video problem (if it's audio, well we won't have anything to advertise anyways) if (!nSets) { for (y=0;yIsFormatPublic(pac[y].Id))) { //Advertise this ID AdvList[nAud++]=pac[y].Id; } } //Advertise this set, if we can do any audio codecs alone if (nAud) { //Since the set is 0 based the nVidCaps+1th entry is nVidcaps... hr=AddCombinedEntry (AdvList,nAud,NULL,0,&pSetIDs[nSets++]); if(!HR_SUCCEEDED(hr)) { goto ComputeDone; } } } //#endif // if(0) ComputeDone: if (pVidIF) { pVidIF->Release(); } if (pAudIF) { pAudIF->Release(); } if (AdvList) { MemFree(AdvList); } if (pvc) { MemFree(pvc); } if (pac) { MemFree(pac); } return(hr); }