Example #1
0
/*
 * Class:     sage_DShowMediaPlayer
 * Method:    setVideoRendererFilter0
 * Signature: (JLjava/lang/String;Ljava/util/Map;)V
 */
JNIEXPORT void JNICALL Java_sage_DShowMediaPlayer_setVideoRendererFilter0
  (JNIEnv *env, jobject jo, jlong dataPtr, jstring jfilterName, jobject jfilterOptions)
{
	if (jfilterName == NULL || env->GetStringLength(jfilterName) == 0 || !dataPtr){return;}
	CPlayerData* pData = (CPlayerData*) dataPtr;
	const char* cName = env->GetStringUTFChars(jfilterName, NULL);
	slog((env, "DShowPlayer setVideoRendererFilter0(%s) called\r\n", cName));
	CComPtr<IBaseFilter> pFilter = NULL;
	HRESULT hr = FindFilterByName(&pFilter, CLSID_LegacyAmFilterCategory, cName);
	env->ReleaseStringUTFChars(jfilterName, cName);
	BOOL vmr9Config = FALSE;
	BOOL evrConfig = FALSE;
	if (SUCCEEDED(hr) && jfilterOptions)
	{
		jint dxvaMode = 0;
		jint dxvaDeinterlace = 0;
		GetMapIntValue(env, jfilterOptions, "dxva_mpeg_mode", &dxvaMode);
		GetMapIntValue(env, jfilterOptions, "force_deinterlace", &dxvaDeinterlace);
		pData->SetDXVAParameters(dxvaMode, dxvaDeinterlace);

		jboolean ccOK = JNI_TRUE;
		GetMapBoolValue(env, jfilterOptions, "enable_cc", &ccOK);
		if (!ccOK)
			pData->DisableCC();
		// Get the DX9 device pointers, if they don't exist we can't use our custom VMR9 renderer
		jlong jD3D = 0;
		jlong jD3DDevice = 0;
		if (GetMapLongValue(env, jfilterOptions, "d3d_object_ptr", &jD3D) &&
			GetMapLongValue(env, jfilterOptions, "d3d_device_ptr", &jD3DDevice))
		{
			IDirect3D9* pD3D = (IDirect3D9*) jD3D;
			IDirect3DDevice9* pD3DDevice = (IDirect3DDevice9*) jD3DDevice;
			// Set the rendering mode and number of streams.
			CComPtr<IVMRFilterConfig9> pConfig = NULL;
			// See if it's EVR or VMR
			hr = pFilter->QueryInterface(IID_IVMRFilterConfig9, (void**)&(pConfig.p));
			if (SUCCEEDED(hr))
			{
				slog((env, "Using VMR9 for video rendering\r\n"));
				hr = pConfig->SetRenderingMode(VMR9Mode_Renderless);
				PLAYEXCEPT_RET(sage_PlaybackException_DIRECTX_INSTALL);

				/*
				 * NOTE: If we don't set the number of streams than we don't get the optimal
				 * format types as choices and end up using a private texture when we don't need to.
				 * I think this is because certain features of the
				 * VMR are not available in mixing mode or something like that.
				 * Update: 10/12/2004 - I have now learned that when you put the VMR9
				 * into mixing mode that it will then use the D3DRenderTarget itself
				 * to do the mixing.  I saw a usenet post of the exact VMR9 corruption
				 * problem I was having where the OSD was showing up on the video frame surface.
				 * By not setting the number of streams I keep the VMR9 in Renderless non-mixing mode.
				 * BUT this has the downside of breaking CC support for the VMR9 so we have a registry
				 * setting to allow this.
				 * 10/13/04 - The first problem came back where the format types are wrong. No idea
				 * why this was working fine yesterday.
				 */
				if (GetRegistryDword(HKEY_LOCAL_MACHINE,
					"Software\\Frey Technologies\\SageTV\\DirectX9", "AllowCCForVMR9", 1) &&
					ccOK)
				{
					// NOTE: We changed this from 2 to 3 because on Vista you need another input
					// to handle subpicture blending for DVD playback. And I don't believe there's any
					// negative to having 3 instead of 2; the big difference is between 1 and 2.
					hr = pConfig->SetNumberOfStreams(3); // video + CC + subpicture
					PLAYEXCEPT_RET(sage_PlaybackException_DIRECTX_INSTALL);
				}
				else
				{
					hr = pConfig->SetNumberOfStreams(1);
					PLAYEXCEPT_RET(sage_PlaybackException_DIRECTX_INSTALL);
				}

				CComPtr<IVMRSurfaceAllocatorNotify9> lpIVMRSurfAllocNotify = NULL;
				pFilter->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,
					(void**)&(lpIVMRSurfAllocNotify.p));

				// create our surface allocator
				CVMRAllocator* myVMRAllocator = new CVMRAllocator(hr, pD3D, pD3DDevice);
				PLAYEXCEPT_RET(sage_PlaybackException_SAGETV_INSTALL);
				pData->SetVMR9Allocator(myVMRAllocator);

				// let the allocator and the notify know about each other
				hr = lpIVMRSurfAllocNotify->AdviseSurfaceAllocator(0xCAFEBABE, myVMRAllocator);
				HTESTPRINT(hr);
				hr = myVMRAllocator->AdviseNotify(lpIVMRSurfAllocNotify);
				HTESTPRINT(hr);

				hr = S_OK;

				vmr9Config = TRUE;
			}
			else
			{
				slog((env, "Using EVR for video render\r\n"));
				evrConfig = TRUE;
				hr = S_OK;
			}
		}
	}
	if (SUCCEEDED(hr))
		hr = pData->SetVideoRenderer(pFilter);
	if (SUCCEEDED(hr) && evrConfig)
	{
		// Configure the EVR presenter after we add the EVR to the filter graph
		jlong jD3DDevMgr = 0;
		if (GetMapLongValue(env, jfilterOptions, "d3d_device_mgr", &jD3DDevMgr))
		{
			CComPtr<IMFVideoRenderer> lpIMFVideoRenderer = NULL;
			hr = pFilter->QueryInterface(IID_IMFVideoRenderer, (void**)&(lpIMFVideoRenderer.p));
			HTESTPRINT(hr);
			if (SUCCEEDED(hr))
			{
				// Configure EVR to use our custom presenter
				CComPtr<IMFVideoPresenter> lpIMFVideoPresenter = NULL;
				hr = CoCreateInstance(CLSID_CustomEVRPresenter, NULL, CLSCTX_INPROC_SERVER,
					IID_IMFVideoPresenter, (void**)&(lpIMFVideoPresenter.p));
				HTESTPRINT(hr);
				if (SUCCEEDED(hr))
				{
					// Set the Direct3D device pointer
					IDirect3DDeviceManager9* pD3DDevMgr = (IDirect3DDeviceManager9*) jD3DDevMgr;
					ISTVEVRPrstr* pMyEvr = NULL;
					lpIMFVideoPresenter->QueryInterface(IID_ISTVEVRPrstr, (void**)&pMyEvr);
					pMyEvr->set_D3DDeviceMgr(pD3DDevMgr);
					hr = lpIMFVideoRenderer->InitializeRenderer(NULL, lpIMFVideoPresenter);
					HTESTPRINT(hr);
					SAFE_RELEASE(pMyEvr);

					IEVRFilterConfig* pEvrConfig = NULL;
					hr = pFilter->QueryInterface(IID_IEVRFilterConfig, (void**)&pEvrConfig);
					HTESTPRINT(hr);
					// Try three inputs for now; one for video, one for CC and one for subpicture
					// But only use 3 on Vista by default since we've seen issues w/ it on XP
					OSVERSIONINFOEX osInfo;
					ZeroMemory(&osInfo, sizeof(OSVERSIONINFOEX));
					osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
					DWORD evrInputsDefault = 1;
					if (GetVersionEx((LPOSVERSIONINFO)&osInfo))
					{
						if (osInfo.dwMajorVersion >= 6)
							evrInputsDefault = 3;
					}
					DWORD evrInputs = GetRegistryDword(HKEY_LOCAL_MACHINE,
						"Software\\Frey Technologies\\SageTV\\DirectX9", "EVRInputPins", evrInputsDefault);
					slog((env, "Using %d input pins on the EVR\r\n", (int)evrInputs));
					pEvrConfig->SetNumberOfStreams(evrInputs < 1 ? 1 : (evrInputs > 3 ? 3 : evrInputs));
					SAFE_RELEASE(pEvrConfig);
					slog((env, "Finished with EVR configuration OK\r\n"));
				}
			}
		}
	}
	else if (SUCCEEDED(hr) && vmr9Config)
	{
		IVMRDeinterlaceControl9* pVmrDeint = NULL;
		hr = pFilter->QueryInterface(IID_IVMRDeinterlaceControl9, (void**)&pVmrDeint);
		if (SUCCEEDED(hr))
		{
			slog(("Setting up VMR9 deinterlacing\r\n"));
			hr = pVmrDeint->SetDeinterlacePrefs(DeinterlacePref9_NextBest);
			HTESTPRINT(hr);
/*			VMR9VideoDesc VideoDesc;
			DWORD dwNumModes = 0;
			AM_MEDIA_TYPE vmrConn;
			hr = renderInput->ConnectionMediaType(&vmrConn);
			HTESTPRINT(hr);
			if (vmrConn.formattype == FORMAT_VideoInfo2)
			{
				VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*) vmrConn.pbFormat;

				// Fill in the VideoDesc structure
				VideoDesc.dwSize = sizeof(VMR9VideoDesc);
				VideoDesc.dwSampleWidth = vih2->bmiHeader.biWidth;
				VideoDesc.dwSampleHeight = vih2->bmiHeader.biHeight;
				VideoDesc.SampleFormat = ConvertInterlaceFlags(vih2->dwInterlaceFlags);
				VideoDesc.dwFourCC = vih2->bmiHeader.biCompression;
				VideoDesc.InputSampleFreq.dwNumerator = 30000;
				VideoDesc.InputSampleFreq.dwDenominator = 1001;
				VideoDesc.OutputFrameFreq.dwNumerator = 60000;
				VideoDesc.OutputFrameFreq.dwDenominator = 1001;
				hr = pVmrDeint->GetNumberOfDeinterlaceModes(&VideoDesc,
					&dwNumModes, NULL);
				HTESTPRINT(hr);
				if (SUCCEEDED(hr) && (dwNumModes != 0))
				{
					// Allocate an array for the GUIDs that identify the modes.
					GUID *pModes = new GUID[dwNumModes];
					if (pModes)
					{
						// Fill the array.
						hr = pVmrDeint->GetNumberOfDeinterlaceModes(&VideoDesc,
							&dwNumModes, pModes);
						if (SUCCEEDED(hr))
						{
							HTESTPRINT(hr);
							// Loop through each item and get the capabilities.
							for (DWORD i = 0; i < dwNumModes; i++)
							{
								VMR9DeinterlaceCaps Caps;
								ZeroMemory(&Caps, sizeof(Caps));
								Caps.dwSize = sizeof(VMR9DeinterlaceCaps);
								hr = pVmrDeint->GetDeinterlaceModeCaps(&(pModes[i]),
									&VideoDesc, &Caps);
								HTESTPRINT(hr);
								if (SUCCEEDED(hr))
								{
									if (Caps.DeinterlaceTechnology == DeinterlaceTech9_BOBLineReplicate)
										slog(("VM9Deinterlacing Tech: BOBLineReplicate\r\n"));
									else if (Caps.DeinterlaceTechnology == DeinterlaceTech9_BOBVerticalStretch)
										slog(("VM9Deinterlacing Tech: BOBVerticalStretch\r\n"));
									else if (Caps.DeinterlaceTechnology == DeinterlaceTech9_MedianFiltering)
										slog(("VM9Deinterlacing Tech: MedianFiltering\r\n"));
									else if (Caps.DeinterlaceTechnology == DeinterlaceTech9_EdgeFiltering)
										slog(("VM9Deinterlacing Tech: EdgeFiltering\r\n"));
									else if (Caps.DeinterlaceTechnology == DeinterlaceTech9_FieldAdaptive)
										slog(("VM9Deinterlacing Tech: FieldAdaptive\r\n"));
									else if (Caps.DeinterlaceTechnology == DeinterlaceTech9_PixelAdaptive)
										slog(("VM9Deinterlacing Tech: PixelAdaptive\r\n"));
									else if (Caps.DeinterlaceTechnology == DeinterlaceTech9_MotionVectorSteered)
										slog(("VM9Deinterlacing Tech: MotionVectorSteered\r\n"));
									else
										slog(("VM9Deinterlacing Tech: Proprietary...\r\n"));
								}
							}
							if (dwNumModes)
							{
//								hr = pVmrDeint->SetDeinterlaceMode(0, pModes);
//								HTESTPRINT(hr);
							}
						}
						delete [] pModes;
					}
				}
				FreeMediaType(vmrConn);
			}
			GUID realDeint;
			hr = pVmrDeint->GetActualDeinterlaceMode(0, &realDeint);
			LPOLESTR psz;
			StringFromCLSID(realDeint, &psz);
			char conv[64];
			WideCharToMultiByte(CP_ACP, 0, psz, -1, conv, 64, 0, 0);
			CoTaskMemFree(psz);
			slog(("Actual deinterlace: hr=0x%x guid=%s\r\n", hr, conv));
			GUID setDeint;
			hr = pVmrDeint->GetDeinterlaceMode(0, &setDeint);
			StringFromCLSID(setDeint, &psz);
			WideCharToMultiByte(CP_ACP, 0, psz, -1, conv, 64, 0, 0);
			CoTaskMemFree(psz);
			slog(("deinterlace mode: hr=0x%x guid=%s\r\n", hr, conv));
			if (hr == S_FALSE)
			{
				slog(("Setting deinterlace mode to actual mode...\r\n"));
				hr = pVmrDeint->SetDeinterlaceMode(0, &realDeint);
				hr = pVmrDeint->GetDeinterlaceMode(0, &setDeint);
				StringFromCLSID(setDeint, &psz);
				WideCharToMultiByte(CP_ACP, 0, psz, -1, conv, 64, 0, 0);
				CoTaskMemFree(psz);
				slog(("deinterlace mode: hr=0x%x guid=%s\r\n", hr, conv));
			}
*/
			pVmrDeint->Release();
		}
		DWORD vmrMixMode = GetRegistryDword(HKEY_LOCAL_MACHINE,
			"Software\\Frey Technologies\\SageTV\\DirectX9", "YUVMixing", 1);
		if (vmrMixMode)
		{
			IVMRMixerControl9* vmrMix = NULL;
			hr = pFilter->QueryInterface(IID_IVMRMixerControl9, (void**)&vmrMix);
			if (SUCCEEDED(hr))
			{
				DWORD currPrefs = 0;
				hr = vmrMix->GetMixingPrefs(&currPrefs);
				slog((env, "Curr Mix Prefs=0x%x\r\n", currPrefs));
				currPrefs &= ~MixerPref9_RenderTargetMask;
				currPrefs |= MixerPref9_RenderTargetYUV;
				hr = vmrMix->SetMixingPrefs(currPrefs);
				vmrMixMode = currPrefs;
				vmrMix->GetMixingPrefs(&currPrefs);
				slog((env, "Set to 0x%x, hr=0x%x, New Mix Prefs=0x%x\r\n", vmrMixMode, hr, currPrefs));
				vmrMix->Release();
			}
			else
				HTESTPRINT(hr);
		}
	}
	if (FAILED(hr))
	{
		elog((env, "Could not add specified video rendering filter to graph hr=0x%x\r\n", hr));
	}
}
HRESULT InitializeWindowlessVMR(IBaseFilter **ppVmr9)
{
    IBaseFilter* pVmr = NULL;

    if (!ppVmr9)
        return E_POINTER;
    *ppVmr9 = NULL;

    // Create the VMR and add it to the filter graph.
    HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL,
                     CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
    if (SUCCEEDED(hr)) 
    {
        hr = pGB->AddFilter(pVmr, L"Video Mixing Renderer 9");
        if (SUCCEEDED(hr)) 
        {
            // Set the rendering mode and number of streams
            SmartPtr <IVMRFilterConfig9> pConfig;

            JIF(pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig));
            JIF(pConfig->SetRenderingMode(VMR9Mode_Windowless));

            hr = pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pWC);
            if( SUCCEEDED(hr)) 
            {
                hr = pWC->SetVideoClippingWindow(ghApp);
                hr = pWC->SetBorderColor(RGB(0,0,0));
            }

#ifndef BILINEAR_FILTERING
            // Request point filtering (instead of bilinear filtering)
            // to improve the text quality.  In general, if you are 
            // not scaling the app Image, you should use point filtering.
            // This is very important if you are doing source color keying.
            IVMRMixerControl9 *pMix;

            hr = pVmr->QueryInterface(IID_IVMRMixerControl9, (void**)&pMix);
            if( SUCCEEDED(hr)) 
            {
                DWORD dwPrefs=0;
                hr = pMix->GetMixingPrefs(&dwPrefs);

                if (SUCCEEDED(hr))
                {
                    dwPrefs |= MixerPref_PointFiltering;
                    dwPrefs &= ~(MixerPref_BiLinearFiltering);

                    hr = pMix->SetMixingPrefs(dwPrefs);
                }
                pMix->Release();
            }
#endif

            // Get alpha-blended bitmap interface
            hr = pVmr->QueryInterface(IID_IVMRMixerBitmap9, (void**)&pBMP);
        }
        else
            Msg(TEXT("Failed to add VMR to graph!  hr=0x%x\r\n"), hr);

        // Don't release the pVmr interface because we are copying it into
        // the caller's ppVmr9 pointer
        *ppVmr9 = pVmr;
    }
    else
        Msg(TEXT("Failed to create VMR!  hr=0x%x\r\n"), hr);

   return hr;
}