HRESULT MiniPlayer::findPin(IBaseFilter *pFilter, int dir, IPin **pOutPin) { IEnumPins *pEnumPins = NULL; IPin *pPin = NULL; PIN_INFO pinInfo; //FILTER_INFO filterInfo; //HRESULT hr = pFilter->QueryFilterInfo(&filterInfo); //if(hr == S_OK) //{ // ctrace(L"%s Pins:\n", filterInfo.achName); //} HRESULT hr = pFilter->EnumPins(&pEnumPins); if(FAILED(hr)) return hr; while(pEnumPins->Next(1, &pPin, NULL) == S_OK) { hr = pPin->QueryPinInfo(&pinInfo); if(FAILED(hr)) continue; if(pinInfo.dir == dir) { *pOutPin = pPin; //ctrace(L"[%s] %s\n", (dir == PINDIR_INPUT)? L"INPUT": L"OUTPUT", pinInfo.achName); return S_OK; } } pEnumPins->Release(); return -1; }
// フィルタから指定メディアのピンを検索する IPin* DirectShowUtil::GetFilterPin(IBaseFilter *pFilter, const PIN_DIRECTION dir, const AM_MEDIA_TYPE *pMediaType) { IEnumPins *pEnumPins=NULL; IPin *pPin; IPin *pRetPin=NULL; if(pFilter->EnumPins(&pEnumPins)==S_OK ){ ULONG cFetched; while(!pRetPin&&pEnumPins->Next(1,&pPin,&cFetched)==S_OK){ PIN_INFO stPin; if(pPin->QueryPinInfo(&stPin)==S_OK){ if(stPin.dir==dir){ if(!pMediaType){ // 方向さえあっていればOK pRetPin=pPin; pRetPin->AddRef(); } else { // DirectShowにまかせてピンを検索 if(pPin->QueryAccept(pMediaType)==S_OK){ pRetPin=pPin; pRetPin->AddRef(); } } } if(stPin.pFilter) stPin.pFilter->Release(); } pPin->Release(); } pEnumPins->Release(); } return pRetPin; }
IBaseFilter *DirectShowPlayerService::getConnected( IBaseFilter *filter, PIN_DIRECTION direction) const { IBaseFilter *connected = 0; IEnumPins *pins = 0; if (SUCCEEDED(filter->EnumPins(&pins))) { for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { PIN_DIRECTION dir; if (SUCCEEDED(pin->QueryDirection(&dir)) && dir == direction) { IPin *peer = 0; if (SUCCEEDED(pin->ConnectedTo(&peer))) { PIN_INFO info; if (SUCCEEDED(peer->QueryPinInfo(&info))) { if (connected) { qWarning("DirectShowPlayerService::getConnected: " "Multiple connected filters"); connected->Release(); } connected = info.pFilter; } peer->Release(); } } } pins->Release(); } return connected; }
HRESULT CDShowUtility::GetNextFilter(IBaseFilter *pFilter, PIN_DIRECTION Dir, IBaseFilter **ppNext) { if (!pFilter || !ppNext) { return E_POINTER; } IEnumPins *pEnum = NULL; IPin *pPin = 0; HRESULT hr = pFilter->EnumPins(&pEnum); if (FAILED(hr)) { return hr; } while (S_OK == pEnum->Next(1, &pPin, 0)) { // see if this pin matches the specified direction PIN_DIRECTION ThisPinDir; hr = pPin->QueryDirection(&ThisPinDir); if (FAILED(hr)) { // something strange happened hr = E_UNEXPECTED; pPin->Release(); break; } if (ThisPinDir == Dir) { // check if the pin is connected to another pin IPin *pPinNext = NULL; if (SUCCEEDED(hr)) { // get the filter that owns that pin PIN_INFO PinInfo; hr = pPinNext->QueryPinInfo(&PinInfo); pPinNext->Release(); pEnum->Release(); if (FAILED(hr) || PinInfo.pFilter == NULL) { // Something strange happened return E_UNEXPECTED; } // This is the filter we're looking for *ppNext = PinInfo.pFilter; return S_OK; } } pPin->Release(); } pEnum->Release(); return hr; }
HRESULT FindSourceFilter(IFilterGraph* filterGraph,IBaseFilter*& result) { HRESULT hr; IEnumFilters *enumFilters; hr = filterGraph->EnumFilters(&enumFilters); if (FAILED(hr)) { ErrorPrint("Get enum filters error",hr); return hr; } ComReleaser enumFilterReleaser(enumFilters); IBaseFilter* filter; while (S_OK == enumFilters->Next(1, &filter, NULL)) { ComReleaser filterReleaser(filter); IEnumPins *enumPins; hr = filter->EnumPins(&enumPins); if (FAILED(hr)) { ErrorPrint("Get enum pins error",hr); return hr; } ComReleaser enumPinsReleaser(enumPins); IPin* pin; bool isSourceFilter = true; while (S_OK == enumPins->Next(1, &pin, NULL)) { ComReleaser pinReleaser(pin); PIN_INFO pinInfo; hr = pin->QueryPinInfo(&pinInfo); if (FAILED(hr)) { ErrorPrint("Get pin info error",hr); continue; } if (pinInfo.dir == PINDIR_INPUT) //认为没有输入pin的就是source filter,这其实是有些问题的,特别是当捕获(如声卡的音频)的filter有时候有很多输入PIN { isSourceFilter = false; break; } } if (isSourceFilter) { filter->AddRef(); //存在一个资源管理的释放类,必须增加一个引用,否则会被释放掉 result = filter; return S_OK; } } return E_FAIL; }
IPin* FindDecoderSubpictureOutputPin(IBaseFilter* pFilter) { IEnumPins* pEnum = NULL; HRESULT hr = pFilter->EnumPins(&pEnum); if (hr != NOERROR) return NULL; ULONG ulFound; IPin *pPin = NULL; hr = E_FAIL; while(S_OK == pEnum->Next(1, &pPin, &ulFound)) { PIN_INFO PinInfo; // // grab this, so we can examine its name field // hr = pPin->QueryPinInfo(&PinInfo); if(SUCCEEDED(hr)) { PinInfo.pFilter->Release(); // // check direction // if (PinInfo.dir == PINDIR_OUTPUT) { // Make sure its not connected yet and its a video type. IPin* dummyPin = NULL; hr = pPin->ConnectedTo(&dummyPin); SAFE_RELEASE(dummyPin); if (hr == VFW_E_NOT_CONNECTED) { IEnumMediaTypes *mtEnum = NULL; pPin->EnumMediaTypes(&mtEnum); AM_MEDIA_TYPE *pMT = NULL; while (S_OK == mtEnum->Next(1, &pMT, NULL)) { if (pMT->majortype == MEDIATYPE_Video) { DeleteMediaType(pMT); SAFE_RELEASE(mtEnum); SAFE_RELEASE(pEnum); return pPin; } DeleteMediaType(pMT); } SAFE_RELEASE(mtEnum); } } } pPin->Release(); } SAFE_RELEASE(pEnum); return NULL; }
// Get the first upstream or downstream filter HRESULT GetNextFilter( IBaseFilter *pFilter, // Pointer to the starting filter PIN_DIRECTION Dir, // Direction to search (upstream or downstream) IBaseFilter **ppNext) // Receives a pointer to the next filter. { if (!pFilter || !ppNext) return E_POINTER; IEnumPins *pEnum = 0; IPin *pPin = 0; HRESULT hr = pFilter->EnumPins(&pEnum); if (FAILED(hr)) return hr; while (S_OK == pEnum->Next(1, &pPin, 0)) { // See if this pin matches the specified direction. PIN_DIRECTION ThisPinDir; hr = pPin->QueryDirection(&ThisPinDir); if (FAILED(hr)) { // Something strange happened. hr = E_UNEXPECTED; pPin->Release(); break; } if (ThisPinDir == Dir) { // Check if the pin is connected to another pin. IPin *pPinNext = 0; hr = pPin->ConnectedTo(&pPinNext); if (SUCCEEDED(hr)) { // Get the filter that owns that pin. PIN_INFO PinInfo; hr = pPinNext->QueryPinInfo(&PinInfo); pPinNext->Release(); pPin->Release(); pEnum->Release(); if (FAILED(hr) || (PinInfo.pFilter == NULL)) { // Something strange happened. return E_UNEXPECTED; } // This is the filter we're looking for. *ppNext = PinInfo.pFilter; // Client must release. return S_OK; } } pPin->Release(); } pEnum->Release(); // Did not find a matching filter. return E_FAIL; }
HRESULT CKTVDlg::EnumPinsOnFilter( IBaseFilter *pFilter, PIN_DIRECTION PinDir , int index) { HRESULT r; IEnumPins *pEnum = NULL; IPin *pPin = NULL; // Verify filter interface if (!pFilter) return E_NOINTERFACE; // Get pin enumerator r = pFilter->EnumPins(&pEnum); if (FAILED(r)) return r; pEnum->Reset(); // Enumerate all pins on this filter while((r = pEnum->Next(1, &pPin, 0)) == S_OK) { PIN_DIRECTION PinDirThis; r = pPin->QueryDirection(&PinDirThis); if (FAILED(r)) { pPin->Release(); continue; } // Does the pin's direction match the requested direction? if (PinDir == PinDirThis) { PIN_INFO pininfo={0}; // Direction matches, so add pin name to listbox r = pPin->QueryPinInfo(&pininfo); if (SUCCEEDED(r)) { wstring str = pininfo.achName; m_captureFilterVec[index].PinVec.push_back(str); } // The pininfo structure contains a reference to an IBaseFilter, // so you must release its reference to prevent resource a leak. pininfo.pFilter->Release(); } pPin->Release(); } pEnum->Release(); return r; }
// Find all the immediate upstream or downstream peers of a filter. HRESULT GetPeerFilters( IBaseFilter *pFilter, // Pointer to the starting filter PIN_DIRECTION Dir, // Direction to search (upstream or downstream) CFilterList &FilterList) // Collect the results in this list. { if (!pFilter) return E_POINTER; IEnumPins *pEnum = 0; IPin *pPin = 0; HRESULT hr = pFilter->EnumPins(&pEnum); if (FAILED(hr)) return hr; while (S_OK == pEnum->Next(1, &pPin, 0)) { // See if this pin matches the specified direction. PIN_DIRECTION ThisPinDir; hr = pPin->QueryDirection(&ThisPinDir); if (FAILED(hr)) { // Something strange happened. hr = E_UNEXPECTED; pPin->Release(); break; } if (ThisPinDir == Dir) { // Check if the pin is connected to another pin. IPin *pPinNext = 0; hr = pPin->ConnectedTo(&pPinNext); if (SUCCEEDED(hr)) { // Get the filter that owns that pin. PIN_INFO PinInfo; hr = pPinNext->QueryPinInfo(&PinInfo); pPinNext->Release(); if (FAILED(hr) || (PinInfo.pFilter == NULL)) { // Something strange happened. pPin->Release(); pEnum->Release(); return E_UNEXPECTED; } // Insert the filter into the list. AddFilterUnique(FilterList, PinInfo.pFilter); PinInfo.pFilter->Release(); } } pPin->Release(); } pEnum->Release(); return S_OK; }
// Tear down everything downstream of a given filter void __fastcall NukeDownstream(IBaseFilter * pf, IGraphBuilder * pGB) { IPin *pP = 0; IPin *pTo = 0; ULONG u; IEnumPins *pins = NULL; PIN_INFO pininfo; if (!pf) return; // Enumerate all filter pins HRESULT hr = pf->EnumPins(&pins); // Go to beginning of enumeration pins->Reset(); while(hr == NOERROR) { hr = pins->Next(1, &pP, &u); if(hr == S_OK && pP) { pP->ConnectedTo(&pTo); if(pTo) { hr = pTo->QueryPinInfo(&pininfo); if(hr == NOERROR) { if(pininfo.dir == PINDIR_INPUT) { NukeDownstream(pininfo.pFilter, pGB); pGB->Disconnect(pTo); pGB->Disconnect(pP); pGB->RemoveFilter(pininfo.pFilter); } pininfo.pFilter->Release(); pininfo.pFilter = NULL; } pTo->Release(); pTo = NULL; } pP->Release(); pP = NULL; } } if(pins) { pins->Release(); pins = NULL; } }
HRESULT TffdshowDecAudioInputPin::CompleteConnect(IPin* pReceivePin) { HRESULT hr = __super::CompleteConnect(pReceivePin); if (FAILED(hr)) { return hr; } m_hNotifyEvent = NULL; // Some source filters are not multithreaded, in that case we must not use the blocking mode unsigned int numstreams = filter->inpins.getNumConnectedInpins(); bool noBlock = false; for (unsigned int i = 0; i < numstreams; i++) { TffdshowDecAudioInputPin *inpin = filter->inpins[i]; if (noBlock) { inpin->m_useBlock = false; continue; } IPin *pPin = NULL; inpin->ConnectedTo(&pPin); if (!pPin) { continue; } PIN_INFO pinInfo; if (SUCCEEDED(pPin->QueryPinInfo(&pinInfo))) { CLSID clsid; if (pinInfo.pFilter && SUCCEEDED(pinInfo.pFilter->GetClassID(&clsid))) { if (clsid == CLSID_AviSplitter || clsid == CLSID_MPC_OggSplitter || clsid == CLSID_MPC_AC3DTSSourceFilter) { DPRINTF(_l("TffdshowDecAudioInputPin::CompleteConnect Use blocking mode on pin %u"), this); m_useBlock = true; } /* Damm it, Haali is monothreaded (all pins are managed in the same thread), so we cannot use the blocking mode even if another source filter needs it (DTS/AC3 source filter). This is annoying because we can't use Haali with an external AC3/DTS file (albain) */ else if (clsid == CLSID_HaaliMediaSplitter) { DPRINTF(_l("TffdshowDecAudioInputPin::CompleteConnect Disable all blocking modes, source filter is monothreaded on pin %u"), this); noBlock = true; i = 0; } } SAFE_RELEASE(pPin); SAFE_RELEASE(pinInfo.pFilter); } } return S_OK; }
BOOL GetConnectedFilter(IBaseFilter* pFilter, PIN_DIRECTION pinDir, IBaseFilter** ppFilterConnected) { if(!pFilter || !ppFilterConnected) return FALSE; IEnumPins* pEnumPin = NULL; if(FAILED(pFilter->EnumPins(&pEnumPin))) return FALSE; HRESULT hr = E_FAIL; IPin* pPin = NULL; while(S_OK == pEnumPin->Next(1,&pPin,NULL)) { PIN_DIRECTION pinDirThis; hr = pPin->QueryDirection(&pinDirThis); if(FAILED(hr)) { pPin->Release(); pEnumPin->Release(); return FALSE; } if(pinDirThis == pinDir) { IPin* pPinConnected; hr = pPin->ConnectedTo(&pPinConnected); if(SUCCEEDED(hr)) { PIN_INFO pinInfo; hr = pPinConnected->QueryPinInfo(&pinInfo); pPinConnected->Release(); pPin->Release(); pEnumPin->Release(); if(FAILED(hr) || pinInfo.pFilter == NULL) { return FALSE; } *ppFilterConnected = pinInfo.pFilter; return TRUE; } } pPin->Release(); } pEnumPin->Release(); return FALSE; }
static IPin* ds_get_pin(IBaseFilter* filter, const char* pin_name) { com_t<IEnumPins> enum_pins; IPin* pin = null; if_failed_return(filter->EnumPins(&enum_pins), null); while (enum_pins->Next(1, &pin, 0) == S_OK) { PIN_INFO pin_info = {0}; pin->QueryPinInfo(&pin_info); com_release(pin_info.pFilter); if (stricmp(pin_name, wcs2str(pin_info.achName)) == 0) { return pin; } com_release(pin); } return null; }
HRESULT FindConnectedFilter( IBaseFilter *pSrc, // Pointer to the starting filter PIN_DIRECTION PinDir, // Directtion to look (input = upstream, output = downstream) IBaseFilter **ppConnected) // Returns a pointer to the filter that is connected to pSrc { if (!pSrc || !ppConnected) return E_FAIL; *ppConnected = NULL; IEnumPins *pEnum = 0; IPin *pPin = 0; HRESULT hr = pSrc->EnumPins(&pEnum); if (FAILED(hr)) { return hr; } while (pEnum->Next(1, &pPin, NULL) == S_OK) { PIN_DIRECTION ThisPinDir; pPin->QueryDirection(&ThisPinDir); if (ThisPinDir == PinDir) { IPin *pTmp = 0; hr = pPin->ConnectedTo(&pTmp); if (SUCCEEDED(hr) && pTmp) { // Return the filter that owns this pin. PIN_INFO PinInfo; pTmp->QueryPinInfo(&PinInfo); pTmp->Release(); pEnum->Release(); if (PinInfo.pFilter == NULL) { // Inconsistent pin state. Something is wrong... return E_UNEXPECTED; } else { *ppConnected = PinInfo.pFilter; return S_OK; } } } pPin->Release(); } pEnum->Release(); return E_FAIL; }
HRESULT GetNextFilter(IBaseFilter* filter, PIN_DIRECTION dir, IBaseFilter*& nextFilter) { IEnumPins *enumPins; IPin* pin; HRESULT hr; hr = filter->EnumPins(&enumPins); if(FAILED(hr)) { ErrorPrint("Get enum pins error", hr); return hr; } ComReleaser enumPinsReleaser(enumPins); while (enumPins->Next(1, &pin, NULL) == S_OK) { ComReleaser pinReleaser(pin); PIN_DIRECTION thisDir; hr = pin->QueryDirection(&thisDir); if(FAILED(hr)) { ErrorPrint("Query direction error", hr); return hr; } if(thisDir == dir) { IPin *nextPin; hr = pin->ConnectedTo(&nextPin); if(SUCCEEDED(hr)) { ComReleaser nextPinReleaser(nextPin); PIN_INFO nextPinInfo; hr = nextPin->QueryPinInfo(&nextPinInfo); if(SUCCEEDED(hr)) { nextFilter = nextPinInfo.pFilter; return S_OK; } else { return E_UNEXPECTED; } } } } return E_FAIL; }
HRESULT MiniPlayer::findPin(IBaseFilter *pFilter, int dir, const GUID &mediaMajorType, IPin **pOutPin) { IEnumPins *pEnumPins = NULL; IEnumMediaTypes *pEnumMediaTypes = NULL; IPin *pPin = NULL; PIN_INFO pinInfo; //FILTER_INFO filterInfo; AM_MEDIA_TYPE *pMediaType = NULL; //HRESULT hr = pFilter->QueryFilterInfo(&filterInfo); //if(hr == S_OK) //{ // ctrace(L"%s Pins:\n", filterInfo.achName); //} HRESULT hr = pFilter->EnumPins(&pEnumPins); if(FAILED(hr)) return hr; while(pEnumPins->Next(1, &pPin, NULL) == S_OK) { hr = pPin->QueryPinInfo(&pinInfo); if(FAILED(hr)) continue; if(pinInfo.dir == dir) { hr = pPin->EnumMediaTypes(&pEnumMediaTypes); if(FAILED(hr))continue; while(pEnumMediaTypes->Next(1, &pMediaType, NULL) == S_OK) { if(pMediaType->majortype == mediaMajorType) { *pOutPin = pPin; return S_OK; } } pEnumMediaTypes->Release(); } } pEnumPins->Release(); return -1; }
// Tear down everything upstream of a given filter void NukeUpstream(IGraphBuilder * inGraph, IBaseFilter * inFilter) { if (inGraph && inFilter) { IEnumPins * pinEnum = 0; if (SUCCEEDED(inFilter->EnumPins(&pinEnum))) { pinEnum->Reset(); IPin * pin = 0; ULONG cFetched = 0; bool pass = true; while (pass && SUCCEEDED(pinEnum->Next(1, &pin, &cFetched))) { if (pin && cFetched) { IPin * connectedPin = 0; pin->ConnectedTo(&connectedPin); if(connectedPin) { PIN_INFO pininfo; if (SUCCEEDED(connectedPin->QueryPinInfo(&pininfo))) { if(pininfo.dir == PINDIR_OUTPUT) { NukeUpstream(inGraph, pininfo.pFilter); inGraph->Disconnect(connectedPin); inGraph->Disconnect(pin); inGraph->RemoveFilter(pininfo.pFilter); } pininfo.pFilter->Release(); } connectedPin->Release(); } pin->Release(); } else { pass = false; } } pinEnum->Release(); } } }
//取设备输出Pin IPin* CGraphBuilder::GetPin(PIN_DIRECTION PinDirection) { IPin * foundPin = NULL; if( m_pBaseFilter ) { //创建枚举 IEnumPins * pinEnum = NULL; if ( m_pBaseFilter->EnumPins(&pinEnum)==S_OK ) { //复位 pinEnum->Reset(); //循环每个PIN ULONG fetchCount = 0; IPin * pin = NULL; while ( !foundPin && S_OK==(pinEnum->Next(1, &pin, &fetchCount)) && fetchCount ) { if (pin) { //得到PIN信息 PIN_INFO pinInfo; if ( S_OK==pin->QueryPinInfo(&pinInfo) ) { //检测是否是输出PIN if (pinInfo.dir == PinDirection) { pin->AddRef(); //加一引用 foundPin = pin; //返回PIN } pinInfo.pFilter->Release(); } pin->Release(); } } pinEnum->Release(); } } if (foundPin) { foundPin->Release(); } return foundPin; }
//取设备输出Pin IPin* CCaptureDevice::GetPin(void) { IPin * foundPin = NULL; if( m_pBaseFilter ) { //创建枚举 IEnumPins * pinEnum = NULL; if (m_pBaseFilter->EnumPins(&pinEnum)==S_OK) { //复位 pinEnum->Reset(); //循环每个PIN ULONG fetchCount = 0; IPin * pin = NULL; while ( !foundPin && S_OK==(pinEnum->Next(1, &pin, &fetchCount)) && fetchCount ) { if (pin) { //得到PIN信息 PIN_INFO pinInfo; if (S_OK==pin->QueryPinInfo(&pinInfo)) { //检测是否是输出PIN if (pinInfo.dir == PINDIR_OUTPUT) { // pin->AddRef(); //加一引用 foundPin = pin; //返回PIN } pinInfo.pFilter->Release(); } pin->Release(); } } pinEnum->Release(); } } // if (foundPin) // { // foundPin->Release(); // } return foundPin; }
//----------------------------------------------------------------------------- // GetPin // Find the pin of the specified name on the given filter // This method leaves an outstanding reference on the pin if successful HRESULT CDSUtils::GetPin(IBaseFilter* pFilter, const wchar_t* pName, IPin** ppPin) { HRESULT hr = S_OK; if (pFilter && pName && ppPin) { CComPtr<IEnumPins> pIEnumPins = NULL; hr = pFilter->EnumPins(&pIEnumPins); if (SUCCEEDED(hr)) { IPin* pIPin = NULL; while (S_OK == pIEnumPins->Next(1, &pIPin, NULL)) { PIN_INFO info = {0}; hr = pIPin->QueryPinInfo(&info); if (SUCCEEDED(hr)) { SAFE_RELEASE(info.pFilter); if (0 == wcsncmp(info.achName, pName, wcslen(pName))) { // matched the pin category *ppPin = pIPin; break; } } SAFE_RELEASE(pIPin); } } if (NULL == *ppPin) { // failed to find the named pin hr = E_FAIL; } } else { hr = E_INVALIDARG; } return hr; }
void MiniPlayer::listAllPins(IBaseFilter *pFilter) { IEnumPins *pEnumPins = NULL; IEnumMediaTypes *pEnumMediaTypes = NULL; IPin *pPin = NULL; PIN_INFO pinInfo; FILTER_INFO filterInfo; AM_MEDIA_TYPE *pMediaType = NULL; HRESULT hr = pFilter->QueryFilterInfo(&filterInfo); if(hr == S_OK) { ctrace(L"%s Pins:\n", filterInfo.achName); } hr = pFilter->EnumPins(&pEnumPins); if(FAILED(hr)) return; while(pEnumPins->Next(1, &pPin, NULL) == S_OK) { hr = pPin->QueryPinInfo(&pinInfo); if(FAILED(hr)) continue; ctrace(L"\t [%s] %s: ", (pinInfo.dir == PINDIR_INPUT)? L"INPUT": L"OUTPUT", pinInfo.achName); hr = pPin->EnumMediaTypes(&pEnumMediaTypes); if(FAILED(hr))continue; while(pEnumMediaTypes->Next(1, &pMediaType, NULL) == S_OK) { if(pMediaType->majortype == MEDIATYPE_Video) ctrace("Video "); if(pMediaType->majortype == MEDIATYPE_Audio) ctrace("Audio "); } ctrace("\n"); pEnumMediaTypes->Release(); } pEnumPins->Release(); }
int DirectShowPlayerService::findStreamTypes(IBaseFilter *source) const { QVarLengthArray<IBaseFilter *, 16> filters; source->AddRef(); filters.append(source); int streamTypes = 0; while (!filters.isEmpty()) { IEnumPins *pins = 0; IBaseFilter *filter = filters[filters.size() - 1]; filters.removeLast(); if (SUCCEEDED(filter->EnumPins(&pins))) { for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { PIN_DIRECTION direction; if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) { AM_MEDIA_TYPE connectionType; if (SUCCEEDED(pin->ConnectionMediaType(&connectionType))) { IPin *peer = 0; if (connectionType.majortype == MEDIATYPE_Audio) { streamTypes |= AudioStream; } else if (connectionType.majortype == MEDIATYPE_Video) { streamTypes |= VideoStream; } else if (SUCCEEDED(pin->ConnectedTo(&peer))) { PIN_INFO peerInfo; if (SUCCEEDED(peer->QueryPinInfo(&peerInfo))) filters.append(peerInfo.pFilter); peer->Release(); } } else { streamTypes |= findStreamType(pin); } } } } filter->Release(); } return streamTypes; }
void CCaptureDevice::EnumInputList( ENUMINPUTCALLBACK EnumInputCallBack, LPVOID lp ) { char pinName[128]; if (m_pBaseFilter) { IEnumPins * pinEnum = NULL; if ( m_pBaseFilter->EnumPins(&pinEnum) == S_OK ) { pinEnum->Reset(); BOOL bCancel = FALSE; IPin * pin = NULL; ULONG fetchCount = 0; while (!bCancel && pinEnum->Next(1, &pin, &fetchCount)==S_OK && fetchCount) { if (pin) { PIN_INFO pinInfo; if ( pin->QueryPinInfo(&pinInfo)==S_OK ) { pinInfo.pFilter->Release(); if (pinInfo.dir == PINDIR_INPUT) { ::WideCharToMultiByte(CP_ACP, 0, pinInfo.achName, -1, pinName, 128, NULL, NULL); if( EnumInputCallBack( pinName, pin, lp, bCancel ) != S_OK ) bCancel = TRUE; } pin->Release(); pin = NULL; } } else { bCancel = FALSE; } } pinEnum->Release(); } } }
CLSID GetConnectedFilterCLSID(CBasePin *pPin) { CLSID clsid = GUID_NULL; if (pPin) { IPin *pConnectedPin = pPin->GetConnected(); if (pConnectedPin) { PIN_INFO pi; if (SUCCEEDED(pConnectedPin->QueryPinInfo(&pi))) { if (pi.pFilter) { pi.pFilter->GetClassID(&clsid); pi.pFilter->Release(); } } } } return clsid; }
HRESULT GetFreePin(IBaseFilter* filter, IPin*& result, PIN_DIRECTION dir) { HRESULT hr = S_OK; IEnumPins *enumPins; hr = filter->EnumPins(&enumPins); if(FAILED(hr)) { ErrorPrint("Enum pins error"); return hr; } ComReleaser enumPinsReleaser(enumPins); IPin *pin; while (S_OK == enumPins->Next(1, &pin, NULL)) { PIN_INFO pinInfo; hr = pin->QueryPinInfo(&pinInfo); if(FAILED(hr)) { ErrorPrint("Query pin info error"); pin->Release(); continue; } if(pinInfo.dir == dir) { IPin* connectedPin; pin->ConnectedTo(&connectedPin); if(connectedPin == NULL) { result = pin; return S_OK; } } pin->Release(); } return E_FAIL; }
BOOL EnumPins(void) { IEnumPins *enumpins; if (m_pFilter->EnumPins(&enumpins) != S_OK) return FALSE; enumpins->Reset(); IPin *pin; PIN_INFO pInfo; // FIXME: ffdshow has 2 input pins "In" and "In Text" // there is not way to check mediatype before connection // I think I need a list of pins and then probe for all :( while ((m_res = enumpins->Next(1, &pin, NULL)) == S_OK) { pin->QueryPinInfo(&pInfo); /* wprintf(L"Pin: %s - %s\n", pInfo.achName, (pInfo.dir == PINDIR_INPUT) ? L"Input" : L"Output"); */ if (!m_pInputPin && (pInfo.dir == PINDIR_INPUT)) m_pInputPin = pin; else if (!m_pOutputPin && (pInfo.dir == PINDIR_OUTPUT)) m_pOutputPin = pin; pin->Release(); m_pFilter->Release(); } enumpins->Release(); if (!(m_pInputPin && m_pInputPin)) return FALSE; if (m_pInputPin->QueryInterface(IID_IMemInputPin, (LPVOID *) &m_pImp) != S_OK) return FALSE; return TRUE; }
HRESULT SetVboxFrequency( JNIEnv *env, DShowCaptureInfo* pCapInfo, ULONG ulFrequency ) { HRESULT hr; DWORD dwSupported=0; IEnumPins* pEnumPin; IPin* pInputPin; ULONG ulFetched; PIN_INFO infoPin; if ( pCapInfo->pBDATuner == NULL ) return E_FAIL; if( ulFrequency == 0 ) { slog( (env,"VOX tuner skips frequency 0\r\n") ); return S_OK; } IBaseFilter* pTunerDevice = pCapInfo->pBDATuner; pTunerDevice->EnumPins(&pEnumPin); if( SUCCEEDED( hr = pEnumPin->Reset() ) ) { while((hr = pEnumPin->Next( 1, &pInputPin, &ulFetched )) == S_OK) { pInputPin->QueryPinInfo(&infoPin); // Release AddRef'd filter, we don't need it if( infoPin.pFilter != NULL ) infoPin.pFilter->Release(); if(infoPin.dir == PINDIR_INPUT) break; } if(hr != S_OK) { slog( (env,"Vbox tuner input pin query failed \r\n") ); return hr; } } else { slog( (env,"Vbox tuner reset failed \r\n") ); return E_FAIL; } IKsPropertySet *pKsPropertySet; pInputPin->QueryInterface(&pKsPropertySet); if (!pKsPropertySet) { slog( (env,"Vbox tuner input pin's QueryInterface failed \r\n") ); return E_FAIL; } KSPROPERTY_TUNER_MODE_CAPS_S ModeCaps; KSPROPERTY_TUNER_FREQUENCY_S Frequency; memset(&ModeCaps,0,sizeof(KSPROPERTY_TUNER_MODE_CAPS_S)); memset(&Frequency,0,sizeof(KSPROPERTY_TUNER_FREQUENCY_S)); ModeCaps.Mode = AMTUNER_MODE_TV; // Check either the Property is supported or not by the Tuner drivers hr = pKsPropertySet->QuerySupported(PROPSETID_TUNER, KSPROPERTY_TUNER_MODE_CAPS,&dwSupported); if(SUCCEEDED(hr) && dwSupported&KSPROPERTY_SUPPORT_GET) { DWORD cbBytes=0; hr = pKsPropertySet->Get(PROPSETID_TUNER,KSPROPERTY_TUNER_MODE_CAPS, INSTANCEDATA_OF_PROPERTY_PTR(&ModeCaps), INSTANCEDATA_OF_PROPERTY_SIZE(ModeCaps), &ModeCaps, sizeof(ModeCaps), &cbBytes); } else { SAFE_RELEASE(pKsPropertySet); slog( (env,"Vbox tuner input pin's not support GET query \r\n") ); return E_FAIL; } Frequency.Frequency=ulFrequency; // in Hz if(ModeCaps.Strategy==KS_TUNER_STRATEGY_DRIVER_TUNES) Frequency.TuningFlags=KS_TUNER_TUNING_FINE; else Frequency.TuningFlags=KS_TUNER_TUNING_EXACT; // Here the real magic starts //if(ulFrequency>=ModeCaps.MinFrequency && ulFrequency<=ModeCaps.MaxFrequency) { hr = pKsPropertySet->Set(PROPSETID_TUNER, KSPROPERTY_TUNER_FREQUENCY, INSTANCEDATA_OF_PROPERTY_PTR(&Frequency), INSTANCEDATA_OF_PROPERTY_SIZE(Frequency), &Frequency, sizeof(Frequency)); if(FAILED(hr)) { slog( (env,"Vbox tuner input pin's set frequency %d failed hr=0x%x\r\n", Frequency.Frequency, hr ) ); SAFE_RELEASE(pKsPropertySet); return E_FAIL; } } // else // { //slog( (env,"Vbox tuning frequency %d is out of range (%d %d)\r\n", // ulFrequency, ModeCaps.MinFrequency, ModeCaps.MaxFrequency ) ); // return E_FAIL; // } SAFE_RELEASE(pKsPropertySet); slog( (env,"Vbox tuner tuning overider frequency %d successful. \r\n", ulFrequency) ); return S_OK; }
HRESULT DirectShowVideoWrapper::ConnectSampleGrabber(void) { HRESULT hr = S_OK; TCHAR szErr[MAX_ERROR_TEXT_LEN]; // Register the graph in the Running Object Table (for debug purposes) AddGraphToROT(_pGraphBuilder, &dwROT); // Create the Sample Grabber which we will use // To take each frame for texture generation if(_pSampleGrabberFilter == NULL) { hr = _pSampleGrabberFilter.CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not create SampleGrabberFilter, error: " << szErr << std::endl; return hr; } } _pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, reinterpret_cast<void**>(&_pSampleGrabber)); // We have to set the 24-bit RGB desire here // So that the proper conversion filters // Are added automatically. AM_MEDIA_TYPE desiredType; memset(&desiredType, 0, sizeof(desiredType)); desiredType.majortype = MEDIATYPE_Video; //desiredType.subtype = MEDIASUBTYPE_RGB565; desiredType.subtype = MEDIASUBTYPE_RGB24; //desiredType.subtype = GUID_NULL; desiredType.formattype = GUID(); //desiredType.formattype = FORMAT_VideoInfo; _pSampleGrabber->SetMediaType(&desiredType); _pSampleGrabber->SetBufferSamples(TRUE); // A Null Renderer does not display the video // But it allows the Sample Grabber to run // And it will keep proper playback timing // Unless specified otherwise. if(_pVideoRenderer == NULL) { hr = _pVideoRenderer.CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Unable to create Null Renderer, error: " << szErr << std::endl; return hr; } } //Get Input pins to VideoRenderer IPin* _VideoRendererIntputPin; if (FAILED(hr = _pVideoRenderer->FindPin(L"In", &_VideoRendererIntputPin))) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not find VideoRenderer Intput Pin, error: " << szErr << std::endl; return hr; } IBaseFilter* pVidRenderer = NULL; hr = FindVideoRenderer(_pGraphBuilder,&pVidRenderer); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } if(pVidRenderer) { SLOG << "Removing default video renderer" << std::endl; //get input pin of video renderer IPin* ipin; hr = GetPin(pVidRenderer, PINDIR_INPUT, 0, &ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Vidio Renderer in pin, error: " << szErr << std::endl; return hr; } IPin* opin = NULL; //find out who the renderer is connected to and disconnect from them hr = ipin->ConnectedTo(&opin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } //Get the filter of the opin PIN_INFO OpinInfo; opin->QueryPinInfo(&OpinInfo); IBaseFilter* LastFilter(OpinInfo.pFilter); FILTER_INFO LastFilterInfo; LastFilter->QueryFilterInfo(&LastFilterInfo); CLSID LastFilterClassID; LastFilter->GetClassID(&LastFilterClassID); SLOG << "Last filter name: " << LastFilterInfo.achName << ", ClassID " << LastFilterClassID.Data1 << "-" << LastFilterClassID.Data2 << "-" << LastFilterClassID.Data3 << "-" << LastFilterClassID.Data4 << std::endl; LPWSTR *VendorInfo; LastFilter->QueryVendorInfo(VendorInfo); if(VendorInfo) { SLOG << "Last filter vendor: " << *VendorInfo << std::endl; } hr = ipin->Disconnect(); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } hr = opin->Disconnect(); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } //SAFE_RELEASE(ipin); //remove the default renderer from the graph hr = _pGraphBuilder->RemoveFilter(pVidRenderer); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } //SAFE_RELEASE(pVidRenderer); //see if the video renderer was originally connected to //a color space converter _pGraphBuilder->FindFilterByName(L"Color Space Converter", &_pCSCFilter); if(_pCSCFilter == NULL) { // Create the Color Space filter hr = _pCSCFilter.CoCreateInstance(CLSID_Colour, NULL, CLSCTX_INPROC_SERVER); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not create Color Space Converter Filter, error: " << szErr << std::endl; return hr; } hr = _pGraphBuilder->AddFilter(_pCSCFilter, L"Color Space Converter"); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not add Color Space Converter Filter, error: " << szErr << std::endl; return hr; } //get the output pin of the last filter hr = GetPin(LastFilter, PINDIR_OUTPUT, 0, &opin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Last filter out pin, error: " << szErr << std::endl; return hr; } //get the input pin of the Color Space Converter hr = GetPin(_pCSCFilter, PINDIR_INPUT, 0, &ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Color Space Converter In Pin, error: " << szErr << std::endl; return hr; } //connect the filter that was originally connected to the default renderer //to the Color Space Converter SLOG << "Attaching Color Space Converter Filter. " << opin << " -> " << ipin << std::endl; hr = _pGraphBuilder->Connect(opin, ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not attach Color Space Converter Filter so it won't be used, error: " << szErr << std::endl; //return hr; } else { LastFilter = _pCSCFilter; } } hr = _pGraphBuilder->AddFilter(_pSampleGrabberFilter, L"Video Sample Grabber"); //get the input pin of the Sample Grabber hr = GetPin(_pSampleGrabberFilter, PINDIR_INPUT, 0, &ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Sample Grabber In Pin, error: " << szErr << std::endl; return hr; } //get the output pin of the last filter in the graph hr = GetPin(LastFilter, PINDIR_OUTPUT, 0, &opin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Color Space Converter out pin, error: " << szErr << std::endl; return hr; } SLOG << "Attaching video sample grabber filter." << std::endl; hr = _pGraphBuilder->Connect(opin, ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } //SAFE_RELEASE(ipin); //SAFE_RELEASE(opin); //get output pin of sample grabber hr = GetPin(_pSampleGrabberFilter, PINDIR_OUTPUT, 0, &opin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Sample Grabber out pin, error: " << szErr << std::endl; return hr; } SLOG << "Attaching Video Null Renderer." << std::endl; hr = _pGraphBuilder->AddFilter(_pVideoRenderer, L"Video Null Renderer"); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Unable to add Renderer to filter graph, error: " << szErr << std::endl; return hr; } //get input pin of null renderer hr = GetPin(_pVideoRenderer, PINDIR_INPUT, 0, &ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Null Renderer in pin, error: " << szErr << std::endl; return hr; } //connect them SLOG << "Attaching null video renderer." << std::endl; hr = _pGraphBuilder->Connect(opin, ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Unable to connect Renderer to sample grabber, error: " << szErr << std::endl; return hr; } //SAFE_RELEASE(ipin); //SAFE_RELEASE(opin); } // Just a little trick so that we don't have to know // The video resolution when calling this method. bool mediaConnected = false; AM_MEDIA_TYPE connectedType; if (SUCCEEDED(hr = _pSampleGrabber->GetConnectedMediaType(&connectedType))) { if (connectedType.formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER* infoHeader = (VIDEOINFOHEADER*)connectedType.pbFormat; _VideoWidth = infoHeader->bmiHeader.biWidth; _VideoHeight = infoHeader->bmiHeader.biHeight; mediaConnected = true; } else if (connectedType.formattype == FORMAT_VideoInfo2) { VIDEOINFOHEADER* infoHeader = (VIDEOINFOHEADER*)connectedType.pbFormat; _VideoWidth = infoHeader->bmiHeader.biWidth; _VideoHeight = infoHeader->bmiHeader.biHeight; mediaConnected = true; } else { SWARNING << "Unable to get the media type connected to the sample grabber." << std::endl; } SLOG << "Video Dimensions: " << _VideoWidth << " x " << _VideoHeight << std::endl; CoTaskMemFree(connectedType.pbFormat); } else { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Unable to get connected media type, error: " << szErr << std::endl; return hr; } /*if (!mediaConnected) { uninitVideo(); return false; }*/ return hr; }
void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel) { if( !pGraph ) { return; } IEnumFilters *pFilters; DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph)); if (FAILED(pGraph->EnumFilters(&pFilters))) { DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!"))); } IBaseFilter *pFilter; ULONG n; while (pFilters->Next(1, &pFilter, &n) == S_OK) { FILTER_INFO info; if (FAILED(pFilter->QueryFilterInfo(&info))) { DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%x] -- failed QueryFilterInfo"), pFilter)); } else { QueryFilterInfoReleaseGraph(info); // !!! should QueryVendorInfo here! DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%x] '%ls'"), pFilter, info.achName)); IEnumPins *pins; if (FAILED(pFilter->EnumPins(&pins))) { DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!"))); } else { IPin *pPin; while (pins->Next(1, &pPin, &n) == S_OK) { PIN_INFO info; if (FAILED(pPin->QueryPinInfo(&info))) { DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin)); } else { QueryPinInfoReleaseFilter(info); IPin *pPinConnected = NULL; HRESULT hr = pPin->ConnectedTo(&pPinConnected); if (pPinConnected) { DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] '%ls' [%sput]") TEXT(" Connected to pin [%x]"), pPin, info.achName, info.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"), pPinConnected)); pPinConnected->Release(); // perhaps we should really dump the type both ways as a sanity // check? if (info.dir == PINDIR_OUTPUT) { AM_MEDIA_TYPE mt; hr = pPin->ConnectionMediaType(&mt); if (SUCCEEDED(hr)) { DisplayType(TEXT("Connection type"), &mt); FreeMediaType(mt); } } } else { DbgLog((LOG_TRACE,dwLevel, TEXT(" Pin [%x] '%ls' [%sput]"), pPin, info.achName, info.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"))); } } pPin->Release(); } pins->Release(); } } pFilter->Release(); } pFilters->Release(); }
void DirectShowPlayerService::doRender(QMutexLocker *locker) { m_pendingTasks |= m_executedTasks & (Play | Pause); if (IMediaControl *control = com_cast<IMediaControl>(m_graph, IID_IMediaControl)) { control->Stop(); control->Release(); } if (m_pendingTasks & SetAudioOutput) { m_graph->AddFilter(m_audioOutput, L"AudioOutput"); m_pendingTasks ^= SetAudioOutput; m_executedTasks |= SetAudioOutput; } if (m_pendingTasks & SetVideoOutput) { m_graph->AddFilter(m_videoOutput, L"VideoOutput"); m_pendingTasks ^= SetVideoOutput; m_executedTasks |= SetVideoOutput; } IFilterGraph2 *graph = m_graph; graph->AddRef(); QVarLengthArray<IBaseFilter *, 16> filters; m_source->AddRef(); filters.append(m_source); bool rendered = false; HRESULT renderHr = S_OK; while (!filters.isEmpty()) { IEnumPins *pins = 0; IBaseFilter *filter = filters[filters.size() - 1]; filters.removeLast(); if (!(m_pendingTasks & ReleaseFilters) && SUCCEEDED(filter->EnumPins(&pins))) { int outputs = 0; for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { PIN_DIRECTION direction; if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) { ++outputs; IPin *peer = 0; if (pin->ConnectedTo(&peer) == S_OK) { PIN_INFO peerInfo; if (SUCCEEDED(peer->QueryPinInfo(&peerInfo))) filters.append(peerInfo.pFilter); peer->Release(); } else { locker->unlock(); HRESULT hr; if (SUCCEEDED(hr = graph->RenderEx( pin, /*AM_RENDEREX_RENDERTOEXISTINGRENDERERS*/ 1, 0))) { rendered = true; } else if (renderHr == S_OK || renderHr == VFW_E_NO_DECOMPRESSOR){ renderHr = hr; } locker->relock(); } } } pins->Release(); if (outputs == 0) rendered = true; } filter->Release(); } if (m_audioOutput && !isConnected(m_audioOutput, PINDIR_INPUT)) { graph->RemoveFilter(m_audioOutput); m_executedTasks &= ~SetAudioOutput; } if (m_videoOutput && !isConnected(m_videoOutput, PINDIR_INPUT)) { graph->RemoveFilter(m_videoOutput); m_executedTasks &= ~SetVideoOutput; } graph->Release(); if (!(m_pendingTasks & ReleaseFilters)) { if (rendered) { if (!(m_executedTasks & FinalizeLoad)) m_pendingTasks |= FinalizeLoad; } else { m_pendingTasks = 0; m_graphStatus = InvalidMedia; if (!m_audioOutput && !m_videoOutput) { m_error = QMediaPlayer::ResourceError; m_errorString = QString(); } else { switch (renderHr) { case VFW_E_UNSUPPORTED_AUDIO: case VFW_E_UNSUPPORTED_VIDEO: case VFW_E_UNSUPPORTED_STREAM: m_error = QMediaPlayer::FormatError; m_errorString = QString(); break; default: m_error = QMediaPlayer::ResourceError; m_errorString = QString(); qWarning("DirectShowPlayerService::doRender: Unresolved error code %x", uint(renderHr)); } } QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); } m_executedTasks |= Render; } m_loop->wake(); }