Beispiel #1
0
// 指定フィルタ経由してピン接続を行う(主に入力=1/出力=1の経由型フィルタ接続用)
// Filter指定版
//
// lpwszFilterName は NULL でも良い。
// ppCurrentOutputPin が上流に接続された有効なピンであるのが前提。
// ppCurrentOutputPin は正常終了なら解放され、フィルタの出力ピンが*ppNewOutputPinになる。
// ppNewOutputPin==NULL の場合、フィルタの出力ピンが*ppCurrentOutputPinになる。元の*ppCurrentOutputPinは解放される
//
HRESULT DirectShowUtil::AppendFilterAndConnect(IGraphBuilder *pFilterGraph,
				IBaseFilter *pFilter,LPCWSTR lpwszFilterName,
				IPin **ppCurrentOutputPin,IPin **ppNewOutputPin,bool fDirect)
{
	HRESULT hr;

	// ポインタチェック
	if (!pFilterGraph || !pFilter || !ppCurrentOutputPin)
		return E_INVALIDARG;
	// 同じピンアドレスなら New==NULL で入力されたのと同義
	if (ppCurrentOutputPin==ppNewOutputPin)
		ppNewOutputPin = NULL;
	if (!lpwszFilterName)
		lpwszFilterName = L"No Name";
	hr = pFilterGraph->AddFilter(pFilter, lpwszFilterName);
	if (FAILED(hr)) {
		// フィルタに追加失敗
		return hr;
	}
	IPin *pInput = GetFilterPin(pFilter, PINDIR_INPUT);
	if (!pInput) {
		// 入力ピンが見つからない
		pFilterGraph->RemoveFilter(pFilter);
		return E_FAIL;
	}
	// 接続
	if (fDirect)
		hr = pFilterGraph->ConnectDirect(*ppCurrentOutputPin,pInput,NULL);
	else
		hr = pFilterGraph->Connect(*ppCurrentOutputPin,pInput);
	if (FAILED(hr)) {
		// 接続できない
		SAFE_RELEASE(pInput);
		pFilterGraph->RemoveFilter(pFilter);
		return hr;
	}
	// 接続に使ったピン解放
	SAFE_RELEASE(*ppCurrentOutputPin);
	SAFE_RELEASE(pInput);
	// 次フィルタへの出力ピンを探す(出力ピンが無くても処理は続行)
	IPin *pNewOutput = GetFilterPin(pFilter, PINDIR_OUTPUT);
	if (ppNewOutputPin) {
		// 新出力ピンに出力
		// 元の出力ピンは既に解放済み
		*ppNewOutputPin = pNewOutput;
	} else {
		// 出力ピンを更新(ppCurrentOutputPin==ppNewOutputPinの場合でも実体が上書きだから更新となる)
		// 元の出力ピンは既に解放済み
		*ppCurrentOutputPin = pNewOutput;
	}
#ifdef _DEBUG
	LONG refCount = GetRefCount(pFilter);
#endif
	return S_OK;
}
static bool EnumVideoDevice(std::vector<VideoDevice> &devices,
		IBaseFilter *filter,
		const wchar_t *deviceName,
		const wchar_t *devicePath)
{
	ComPtr<IPin>        pin;
	ComPtr<IPin>        audioPin;
	ComPtr<IBaseFilter> audioFilter;
	VideoDevice   info;

	if (wcsstr(deviceName, L"C875") != nullptr ||
	    wcsstr(deviceName, L"Prif Streambox") != nullptr ||
	    wcsstr(deviceName, L"C835") != nullptr) {
		EnumEncodedVideo(devices, deviceName, devicePath, AV_LGP);
		return true;

	} else if (wcsstr(deviceName, L"Hauppauge HD PVR Capture") != nullptr) {
		EnumEncodedVideo(devices, deviceName, devicePath, HD_PVR1);
		return true;
	}

	bool success = GetFilterPin(filter, MEDIATYPE_Video,
			PIN_CATEGORY_CAPTURE, PINDIR_OUTPUT, &pin);

	/* if this device has no standard capture pin, see if it's an
	 * encoded device, and get its information if so (all encoded devices
	 * are exception devices pretty much) */
	if (!success) {
		EnumExceptionVideoDevice(devices, filter, deviceName,
				devicePath);
		return true;
	}

	if (!EnumVideoCaps(pin, info.caps))
		return true;

	info.audioAttached = GetFilterPin(filter, MEDIATYPE_Audio,
			PIN_CATEGORY_CAPTURE, PINDIR_OUTPUT, &audioPin);

	// Fallback: Find a corresponding audio filter for the same device
	if (!info.audioAttached) {
		info.separateAudioFilter = GetDeviceAudioFilter(devicePath, &audioFilter);
		info.audioAttached = info.separateAudioFilter;
	}

	info.name = deviceName;
	if (devicePath)
		info.path = devicePath;

	devices.push_back(info);
	return true;
}
Beispiel #3
0
bool HDevice::SetupAudioCapture(IBaseFilter *filter, AudioConfig &config)
{
	ComPtr<IPin>  pin;
	MediaTypePtr  defaultMT;
	bool          success;
	HRESULT       hr;

	success = GetFilterPin(filter, MEDIATYPE_Audio, PIN_CATEGORY_CAPTURE,
			PINDIR_OUTPUT, &pin);
	if (!success) {
		Error(L"Could not get audio pin");
		return false;
	}

	ComQIPtr<IAMStreamConfig> pinConfig(pin);

	if (config.useDefaultConfig) {
		MediaTypePtr defaultMT;

		if (pinConfig && SUCCEEDED(pinConfig->GetFormat(&defaultMT))) {
			audioMediaType = defaultMT;
		} else {
			if (!SetupExceptionAudioCapture(pin)) {
				Error(L"Could not get default format for "
				      L"audio pin");
				return false;
			}
		}
	} else {
		if (!GetClosestAudioMediaType(filter, config, audioMediaType)) {
			Error(L"Could not get closest audio media type");
			return false;
		}
	}

	if (!!pinConfig) {
		hr = pinConfig->SetFormat(audioMediaType);

		if (FAILED(hr) && hr != E_NOTIMPL) {
			Error(L"Could not set audio format");
			return false;
		}
	}

	ConvertAudioSettings();

	PinCaptureInfo info;
	info.callback          = [this] (IMediaSample *s) {Receive(false, s);};
	info.expectedMajorType = audioMediaType->majortype;
	info.expectedSubType   = audioMediaType->subtype;

	audioCapture = new CaptureFilter(info);
	audioFilter  = filter;
	audioConfig  = config;

	graph->AddFilter(audioCapture, L"Audio Capture Filter");
	if (!config.useVideoDevice)
		graph->AddFilter(audioFilter, L"Audio Filter");
	return true;
}
Beispiel #4
0
bool HDevice::ConnectPins(const GUID &category, const GUID &type,
		IBaseFilter *filter, IBaseFilter *capture)
{
	HRESULT hr;
	ComPtr<IBaseFilter> crossbar;
	ComPtr<IPin> filterPin;
	ComPtr<IPin> capturePin;
	bool connectCrossbar = !encodedDevice && type == MEDIATYPE_Video;

	if (!EnsureInitialized(L"HDevice::ConnectPins") ||
	    !EnsureInactive(L"HDevice::ConnectPins"))
		return false;

	if (connectCrossbar && FindCrossbar(filter, &crossbar)) {
		if (!DirectConnectFilters(graph, crossbar, filter)) {
			Warning(L"HDevice::ConnectPins: Failed to connect "
			        L"crossbar");
			return false;
		}
	}

	if (!GetFilterPin(filter, type, category, PINDIR_OUTPUT, &filterPin)) {
		Error(L"HDevice::ConnectPins: Failed to find pin");
		return false;
	}

	if (!GetPinByName(capture, PINDIR_INPUT, nullptr, &capturePin)) {
		Error(L"HDevice::ConnectPins: Failed to find capture pin");
		return false;
	}

	hr = graph->ConnectDirect(filterPin, capturePin, nullptr);
	if (FAILED(hr)) {
		WarningHR(L"HDevice::ConnectPins: failed to connect pins",
				hr);
		return false;
	}

	return true;
}
static bool EnumAudioDevice(vector<AudioDevice> &devices,
		IBaseFilter *filter,
		const wchar_t *deviceName,
		const wchar_t *devicePath)
{
	ComPtr<IPin>  pin;
	AudioDevice   info;

	bool success = GetFilterPin(filter, MEDIATYPE_Audio,
			PIN_CATEGORY_CAPTURE, PINDIR_OUTPUT, &pin);
	if (!success)
		return true;

	if (!EnumAudioCaps(pin, info.caps))
		return true;

	info.name = deviceName;
	if (devicePath)
		info.path = devicePath;

	devices.push_back(info);
	return true;
}
Beispiel #6
0
bool GetClosestAudioMediaType(IBaseFilter *filter, AudioConfig &config,
		MediaType &mt)
{
	CComPtr<IPin>    pin;
	ClosestAudioData data(config, mt);
	bool             success;

	success = GetFilterPin(filter, MEDIATYPE_Audio, PIN_CATEGORY_CAPTURE,
			PINDIR_OUTPUT, &pin);
	if (!success || pin == NULL) {
		Error(L"GetClosestAudioMediaType: Could not get pin");
		return false;
	}

	success = EnumPinCaps(pin, EnumCapsCallback(ClosestAudioMTCallback),
			&data);
	if (!success) {
		Error(L"GetClosestAudioMediaType: Could not enumerate caps");
		return false;
	}

	return data.found;
}
Beispiel #7
0
void HDevice::SetAudioBuffering(int bufferingMs)
{
	ComPtr<IPin> pin;
	bool success = GetFilterPin(audioFilter, MEDIATYPE_Audio,
			PIN_CATEGORY_CAPTURE, PINDIR_OUTPUT, &pin);
	if (!success)
		return;

	ComQIPtr<IAMStreamConfig> config(pin);
	if (!config)
		return;

	ComQIPtr<IAMBufferNegotiation> neg(pin);
	if (!neg)
		return;

	MediaTypePtr mt;
	if (FAILED(config->GetFormat(&mt)))
		return;

	if (mt->formattype != FORMAT_WaveFormatEx)
		return;
	if (mt->cbFormat != sizeof(WAVEFORMATEX))
		return;

	WAVEFORMATEX *wfex = (WAVEFORMATEX*)mt->pbFormat;

	ALLOCATOR_PROPERTIES props;
	props.cBuffers = -1;
	props.cbBuffer = wfex->nAvgBytesPerSec * bufferingMs / 1000;
	props.cbAlign = -1;
	props.cbPrefix = -1;
	HRESULT hr = neg->SuggestAllocatorProperties(&props);
	if (FAILED(hr))
		WarningHR(L"Could not set allocator properties on audio "
		          L"capture pin", hr);
}
Beispiel #8
0
bool HDevice::SetupVideoCapture(IBaseFilter *filter, VideoConfig &config)
{
	ComPtr<IPin>  pin;
	HRESULT       hr;
	bool          success;

	if (config.name.find(L"C875") != std::string::npos ||
	    config.name.find(L"C835") != std::string::npos)
		return SetupEncodedVideoCapture(filter, config, AV_LGP);

	else if (config.name.find(L"IT9910") != std::string::npos)
		return SetupEncodedVideoCapture(filter, config, HD_PVR_Rocket);

	else if (config.name.find(HD_PVR1_NAME) != std::string::npos)
		return SetupEncodedVideoCapture(filter, config, HD_PVR1);

	success = GetFilterPin(filter, MEDIATYPE_Video, PIN_CATEGORY_CAPTURE,
			PINDIR_OUTPUT, &pin);
	if (!success) {
		if (SetupExceptionVideoCapture(filter, config)) {
			return true;
		} else {
			Error(L"Could not get video pin");
			return false;
		}
	}

	ComQIPtr<IAMStreamConfig> pinConfig(pin);
	if (pinConfig == NULL) {
		Error(L"Could not get IAMStreamConfig for device");
		return false;
	}

	if (config.useDefaultConfig) {
		MediaTypePtr defaultMT;

		hr = pinConfig->GetFormat(&defaultMT);
		if (hr == E_NOTIMPL) {
			if (!GetPinMediaType(pin, videoMediaType)) {
				Error(L"Couldn't get pin media type");
				return false;
			}

		} else if (FAILED(hr)) {
			ErrorHR(L"Could not get default format for video", hr);
			return false;

		} else {
			videoMediaType = defaultMT;
		}

		ConvertVideoSettings();

		config.format = config.internalFormat = VideoFormat::Any;
	}

	if (!GetClosestVideoMediaType(filter, config, videoMediaType)) {
		Error(L"Could not get closest video media type");
		return false;
	}

	hr = pinConfig->SetFormat(videoMediaType);
	if (FAILED(hr) && hr != E_NOTIMPL) {
		ErrorHR(L"Could not set video format", hr);
		return false;
	}

	ConvertVideoSettings();

	PinCaptureInfo info;
	info.callback          = [this] (IMediaSample *s) {Receive(true, s);};
	info.expectedMajorType = videoMediaType->majortype;

	/* attempt to force intermediary filters for these types */
	if (videoConfig.format == VideoFormat::XRGB)
		info.expectedSubType = MEDIASUBTYPE_RGB32;
	else if (videoConfig.format == VideoFormat::ARGB)
		info.expectedSubType = MEDIASUBTYPE_ARGB32;
	else if (videoConfig.format == VideoFormat::YVYU)
		info.expectedSubType = MEDIASUBTYPE_YVYU;
	else if (videoConfig.format == VideoFormat::YUY2)
		info.expectedSubType = MEDIASUBTYPE_YUY2;
	else if (videoConfig.format == VideoFormat::UYVY)
		info.expectedSubType = MEDIASUBTYPE_UYVY;
	else
		info.expectedSubType = videoMediaType->subtype;

	videoCapture = new CaptureFilter(info);
	videoFilter  = filter;

	graph->AddFilter(videoCapture, L"Video Capture Filter");
	graph->AddFilter(videoFilter, L"Video Filter");
	return true;
}
Beispiel #9
0
// Mpegデコーダを追加してピン接続を行う。
// pUtilに整列済みデコーダ列挙を入れておくとその整列順に接続が行われる。NULLならデフォルト順。
//   わざわざ指定する理由 : このクラスに検索されたフィルタがMpeg2のものとは限らない為。
//
// ppMpeg2DecoderFilter は接続に使われたMpeg2インターフェースを受けとる。
// ppCurrentOutputPin が上流に接続された有効なピンであるのが前提。
// ppCurrentOutputPin は正常終了なら解放され、デコーダフィルタの出力ピンが*ppNewOutputPinになる。
// ppNewOutputPin==NULL の場合、デコーダフィルタの出力ピンが*ppCurrentOutputPinになる。元の*ppCurrentOutputPinは解放される
//
// 失敗した場合でもフィルタ解放は行われないパスがある(既に接続済みの場合)。戻りフィルタは確認して解放すること
bool DirectShowUtil::AppendMpeg2Decoder_and_Connect(IGraphBuilder *pFilterGraph, CDirectShowFilterFinder *pUtil, IBaseFilter **ppMpeg2DecoderFilter,wchar_t *lpszDecoderName,int iDecNameBufLen, IPin **ppCurrentOutputPin, IPin **ppNewOutputPin)
{
	HRESULT hr;
	IPin *pInput = NULL;
	CDirectShowFilterFinder cUtil;	
	CLSID guidFilter = CLSID_NULL;
	bool bRet;
	wchar_t tmp[128];
	if(!lpszDecoderName){
		lpszDecoderName = tmp;
		iDecNameBufLen = 128;
		}

	// ポインタチェック
	if(!pFilterGraph || !ppMpeg2DecoderFilter || !ppCurrentOutputPin) return false;
	// 同じピンアドレスなら New==NULL で入力されたのと同義
	if(ppCurrentOutputPin==ppNewOutputPin) ppNewOutputPin = NULL;
	// 指定がない場合のフィルタ検索
	if(!pUtil){
		pUtil = &cUtil;
		if(!pUtil->FindFilter(&MEDIATYPE_Video,&MEDIASUBTYPE_MPEG2_VIDEO)) return false;
		}
	// 戻り値をクリア
	*ppMpeg2DecoderFilter = NULL;

	bRet=false;
	for(int i=0;!bRet&&i<pUtil->GetFilterCount();i++){
		if(!pUtil->GetFilterInfo(i,&guidFilter,lpszDecoderName,iDecNameBufLen)) continue;
		hr = ::CoCreateInstance(guidFilter, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)ppMpeg2DecoderFilter);
		if(FAILED(hr)) continue;
		hr = pFilterGraph->AddFilter(*ppMpeg2DecoderFilter,lpszDecoderName);
		if(FAILED(hr)){
			SAFE_RELEASE(*ppMpeg2DecoderFilter);
			continue;
			}
		pInput = CDirectShowFilterFinder::GetFilterPin(*ppMpeg2DecoderFilter,PINDIR_INPUT);
		if(!pInput){
			SAFE_RELEASE(*ppMpeg2DecoderFilter);
			continue;
		}
		hr = pFilterGraph->Connect(*ppCurrentOutputPin,pInput);
		if(FAILED(hr)){
			SAFE_RELEASE(pInput);
			pFilterGraph->RemoveFilter(*ppMpeg2DecoderFilter);			
			SAFE_RELEASE(*ppMpeg2DecoderFilter);
			continue;
		} else {
			bRet=true;
		}
		}
	if(!bRet) {
		// 全組み合わせで適合デコーダが無かった
		return false;
	}
	// 接続に使ったピン解放
	SAFE_RELEASE(*ppCurrentOutputPin);
	SAFE_RELEASE(pInput);
	// 次フィルタへの出力ピンを探す
	IPin *pNewOutput = GetFilterPin(*ppMpeg2DecoderFilter, PINDIR_OUTPUT);
	if(!pNewOutput){
		// 出力ピンが見つからない
		return false;
		}
	if(ppNewOutputPin){
		// 新出力ピンに出力
		// 元の出力ピンは既に解放済み
		*ppNewOutputPin = pNewOutput;
		}else{
		// 出力ピンを更新(ppCurrentOutputPin==ppNewOutputPinの場合でも実体が上書きだから更新となる)
		// 元の出力ピンは既に解放済み
		*ppCurrentOutputPin = pNewOutput;
		}
	return true;
}