dshow full screen

Hi there!

I built a little test video player and put my DS code inside a MFC application under Windows 7. The filter graph is built automatically with CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&m_pGraph);
I defined an IDC_STATIC area inside the window which contains the video:

HRESULT hr = m_pGraph->QueryInterface(IID_IVideoWindow, (void
**)&m_pVideo);

RECT plane;

GetDlgItem(IDC_STATIC_VIDEOPLANE)->GetWindowRect(&plane);
ScreenToClient(&plane);
	
m_pVideo->put_Owner((OAHWND)GetSafeHwnd());
m_pVideo->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
m_pVideo->put_Visible(OATRUE);

...

I turn on and off fullscreen mode with this method:

void
 CDirectShowPlayerDlg::Fullscreen(bool
 enabled) {
if (m_pGraph) { IVideoWindow *pVideo = NULL; m_pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVideo); pVideo->put_FullScreenMode(enabled?OATRUE:OAFALSE); pVideo->Release(); } }

So, if I start the video in windowed mode in runs properly. Then, if I switch to fullscreen the video (with audio) runs nice in fullscreen mode. But if I switch back to windowed mode, my video area is just black, but audio continues to play. :-( If I then switch back to fullscreen again, the video runs properly again!

So, I am bit helpless why this happens. Any ideas?

Thanks a lot in advance!
 

25 Answers Found

 

Answer 1

Are you updating VMR with position messages and information as described in items 4-5 in Using Windowed Mode Note that windowless mode is recommended mode for VMR filters
 

Answer 2

Hallo John Archer!

I have same problem under Windows7 (64bit). I have tested three video  renderers VMR9, VMR7 and old video renderer (CLSID_VideoRenderer). Both mixing video renderers work not properly, not how in Windows 2000/XP/Vista. They cannot return from the full screen mode with calling the put_FullScreenMode(OAFALSE) method. The old video renderer work properly but it has not all required features.

All attempts to set old settings return with S_OK, but make not any effect. An idea to work only in windowless mode is not acceptable for us, way a lot of our application cannot be remade.

Probably the problem lays in the following(DirectShow SDK, IVMRFilterConfig9::SetRenderingMode):

Remarks

The VMR is in VMRMode_Windowed by default. Use this method only if you are putting the VMR into VMRMode_Windowless or VMRMode_Renderless mode. You cannot change the mode after any pin has been connected and you cannot change the mode from windowless or renderless back  to windowed, even before any pins are connected. Therefore, specifying VMRMode_Windowed for Mode has no effect under any circumstances.

Regards

Pavel

 

Answer 3

Hi Pavel,

thanks for your answer. Interesting, that you have the same problem. Maybe we can find a solution.

I encountered a very strange thing: I use a laptop with an second external monitor attached. If I start my player it is shown at the laptop screen and the described full screen dilemma begins. But if I drag the player onto the external screen, go to full screen and then  back  the  video  is shown properly! Very strange; I don't know what that means or how it could help us ...

@Roman: Thanks for your quick reply! Yep, I set the video window position correctly (4). But number 5 leads me into (probably noob) problems. As I said I have a MFC app. So I let Visual Studio declare ON_WM_MOVE() in the message map and the OnMove() method. Here it is:

void CDirectShowPlayerDlg::OnMove(int x, int y)
{
    CDialog::OnMove(x, y);

    if (m_pVideo) {
        m_pVideo->NotifyOwnerMessage((OAHWND)this->GetSafeHwnd(), WM_MOVE, 0, 0);
    }

}

But if I run that in debug mode I get an unhandled exception, access violation while reading at postion 0xcccccccc ... I am quite sure that this occurs as m_pVideo is not initialized. Sorry, I am a relatively beginner on that. m_pVideo is a class member and I tried to initialize it in the OnInitDialog() with m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&m_pVideo);, but it seems, that OnMove() is called before OnInitDialog(). Any help on that would be cool! :-)

Thanks a lot in advance!
 

Answer 4

Since you're explicitly doing IUnknown::Release on your pVideo variable, I can assume you are not using wrapper interface pointers like CComPtr. I should have used them to resolve many of the issues existing and those yet can arise in future. So the problem I see is likely is that you are not initializing m_pVideo and it has some garbage which is not zero. So your if(m_pVideo) gets into inside if and then you have an access vioaltion on use of wrong pointer. Later when you initialize your m_pVideo variable, this code works fine.

Hence:
use CComPtr templates take care of initialization of your variables
 

Answer 5

Thanks a lot for your answer! Hm, CComPtr ... I will have a look how to use that, thanks!

Yep, I know that this initialization is the problem, but I am not sure where to init it correctly. As I said, I though OnInitDialog would be a good place (I also init my filter graph, MediaControl and MediaEventEx there), but OnMove() seems to be called earlier. So what would be a good place to init them? Hm ...

EDIT: Ok, I put all the init code into ON_WM_CREATE() and it seems at least this debug problem is gone. :-)
Let's face the other/real problem ...
 

Answer 6

Yep, I know that this initialization is the problem, but I am not sure where to init it correctly. As I said, I though OnInitDialog would be a good place (I also init my filter graph, MediaControl and MediaEventEx there), but OnMove() seems to be called earlier. So what would be a good place to init them? Hm ...
With CComPtr it's very easy:

class CDirectShowPlayerDlg
{
// ...
CComPtr<IVideoWindow> m_pVideo;
// ...
};

CDirectShowPlayerDlg::OnInitDialog(...)
{
ASSERT(!m_pVideo);
// ...
}

CDirectShowPlayerDlg::OnDestroy()
{
// ...
m_pVideo = NULL;
}
CDirectShowPlayerDlg::OnMove(...) { // ... if(m_pVideo) m_pVideo->NotifyOwnerMessage((OAHWND)this->GetSafeHwnd(), WM_MOVE, 0, 0);
}


http://alax.info/blog/tag/directshow
 

Answer 7

Ah, ok. Although I seem to solve the init problem (see my edit above), this looks also promising. I will further research for what exactly CComPtr is. Thanks a lot for that hint!

Nevertheless, the OnMove works fine now, but the problem with  black  video plane is still there. :-( On the second screen it works properly (see my post above). Strange ... :-/
 

Answer 8

It might work if you move it between screens because in that case the graph is stopped and a new renderer surface is automatically created.
 

Answer 9

I tested the configurations from two monitors two and have same effect as John. On the second (slave) monitor all looks well. The primary monitor make problem. It is checked on PC with Nvidia and Intel graphic cards and Intel CPUs.

I take the PlayWnd sample from DirectShow DSK. It can be found into the DirectX 9.0 SDK Update (February 2005) Extras(www.microsoft.com/DownLoads/details.aspx?familyid=8AF0AFA9-1383-44B4-BC8B-7D6315212323&displaylang=en).

At the moment, I have one (not elegant) solution of full screen problem:

 Pause the graph after return from the full screen mode,
 Save current play position,  
 Stop the graph,
 Reconnect the input of VMR,
 Start the graph again from the saved position.

But it produce a brake into the playback.

 

Answer 10

@Chris: Well, ok, but why does it not work, when we drag it from external monitor  back  to the first one, just vice versa?

@Pavel: Ok, interesting. So I use ATI graphic card and AMD processor, so it seems not to be a hardware problem. Ok, this is a workaround, thanks for that. But I hope this could be fixed more smoothly ... Is DirectShow still bug fixed (assuming this is a bug)?
 

Answer 11

So, is there any idea or solution approach available from official side? As I said, it just works when draging from screen 1 to 2 not vice versa.

Thanks a lot in advance!
 

Answer 12

It works both ways if you avoid full-screen and just use windowed mode.  To simulate full-screen we use a top-most window that covers the entire desktop on that window.
 

Answer 13

Hm, ok, so if you avoid the DS full screen mode too, then there really seems to be a bug in it, isn't it? Is there any way to get that fixed my Microsoft? Is DS still maintained/bug fixed?

Thanks for explaining your workaround. This is a possibility but of course it would be better not to simulate full screen but to have real DS supported full screen. It's a bit annoying ...
 

Answer 14

Thanks for explaining your workaround. This is a possibility but of course it would be better not to simulate full screen but to have real DS supported full screen. It's a bit annoying ...
Note that "real" full screen is deprecated, including as a part of VMR windowed mode. So windowless/simulation is the best you can do.
 

Answer 15

Oh, that is interesting, Roman. Thanks for that info. Can I find that info in the msdn documentary? Could you provide a link? I would need that as an official reference/source for my work. Thanks a lot in advance!
 

Answer 16

Oh, that is interesting, Roman. Thanks for that info. Can I find that info in the msdn documentary? Could you provide a link? I would need that as an official reference/source for my work. Thanks a lot in advance!
http://msdn.microsoft.com/en-us/library/dd407299%28VS.85%29.aspx

To remain backward-compatible with existing applications, the VMR defaults to windowed mode. In windowed mode, the renderer creates its own window to display the video. Typically the application sets the  video  window to be a child of the application window. The existence of a separate video window causes some problems, however:
[...]
Windowless mode avoids these problems by [...]

http://msdn.microsoft.com/en-us/library/dd373407%28VS.85%29.aspx

The Video Renderer filter supports windowed mode only. The VMR-7 and VMR-9 filters support both modes. They default to windowed mode for backward compatibility, but windowless mode is preferred. The EVR supports windowless mode only.
 

Answer 17

Ok, thanks a lot!

Cheers
 

Answer 18

Also, FYI this sample might be helpful: How to use windowless  video  Mixing Renderer Filter to show video fullscreen .
 

Answer 19

Apparently, VMR7 and VMR9 are obsolete. For support of current components based on VMR7/9, I have made a little workaround. It works with a render in the same way as with normal window. As a test project is PlayWnd sample used.

This is the replacement of ToggleFullScreen() function:

HRESULT ToggleFullScreen(void)
{
	HRESULT hr=S_OK;
	LONG lMode;
	static HWND hDrain=0;

	// Don't bother with full-screen for audio-only files
	if ((g_bAudioOnly) || (!pVW))
		return S_OK;

	CComPtr<IBaseFilter> pVideoRender;
	LIF(GetVideoRenderer(pGB, pVideoRender));


	if (FALSE == g_bFullscreen)
	{
		// Save current message drain
		LIF(pVW->get_MessageDrain((OAHWND *) &hDrain));

		//Switch into the FullScren mode.

		RECT rcMonitor = {};
		LIF(GetCurrentMonitorSize(rcMonitor, pVideoRender));

		// Switch to full-screen mode
		LIF(pVW->put_Visible(OAFALSE));

		LIF(pVW->put_Owner( (OAHWND) NULL));

		LIF(pVW->put_WindowStyle(0));

		LIF(pVW->put_WindowStyleEx(WS_EX_TOPMOST | WS_POPUP));

 LIF(pVW->SetWindowPosition(rcMonitor.left, rcMonitor.top,
rcMonitor.right - rcMonitor.left, rcMonitor.bottom - rcMonitor.top)); LIF(CorrectAspectRatio(pVideoRender)); LIF(pVW->put_Visible(OATRUE)); // Set message drain to application main window LIF(pVW->put_MessageDrain((OAHWND) ghApp)); g_bFullscreen = TRUE; } else { // Switch back  to windowed mode LIF(pVW->put_Visible(OAFALSE)); LIF(pVW->put_Owner((OAHWND)ghApp)); LIF(pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS)); LIF(pVW->put_WindowStyleEx(0)); RECT client={}; GetClientRect(ghApp, &client); LIF(pVW->SetWindowPosition(client.left, client.top, client.right, client.bottom)); LIF(CorrectAspectRatio(pVideoRender)); // Undo change of message drain LIF(pVW->put_MessageDrain((OAHWND) hDrain)); LIF(pVW->put_Visible(OATRUE)); // Reset video  window LIF(pVW->SetWindowForeground(-1)); // Reclaim keyboard focus for player application UpdateWindow(ghApp); SetForegroundWindow(ghApp); SetFocus(ghApp); g_bFullscreen = FALSE; } return hr; }
And are help functions:
HRESULT GetVideoRenderer(IGraphBuilder *pGraphBuilder, CComPtr<IBaseFilter>& pVideoRender)
{
	pVideoRender.Release();
	CheckPointer(pGraphBuilder, E_POINTER);
	HRESULT					hr = S_FALSE;   //The renderer is not found.
	CComPtr<IEnumFilters>   pEnum;
	CComPtr<IBaseFilter>    pFilter;

	ULONG               ulFetched = 0;

	// Get filter enumerator
	hr = pGraphBuilder->EnumFilters(&pEnum);
	if (FAILED(hr)){
		return hr;
	}

	hr = pEnum->Reset();
	if (FAILED(hr)){
		return hr;
	}

	// Enumerate all filters in the graph
	while( (pEnum->Next(1, &pFilter, &ulFetched) == S_OK))
	{
		CComPtr<IBasicVideo> pIBasicVideo;
		hr = pFilter->QueryInterface(IID_IBasicVideo, reinterpret_cast<void**>(&pIBasicVideo));
		if(SUCCEEDED(hr))
		{
			pVideoRender = pFilter;
			return S_OK;
		}

		pFilter.Release();
	}

	return E_NOTIMPL;
}

HRESULT GetCurrentMonitorSize(RECT& rcMonitor,  CComPtr<IBaseFilter>& pVideoRender)
{
	CheckPointer(pVideoRender, E_POINTER);
	HRESULT hr = S_OK;

	CComPtr<IVMRMonitorConfig9> pVMRMonitorConfig9;
	hr = pVideoRender ->QueryInterface(IID_IVMRMonitorConfig9, reinterpret_cast<void**>(&pVMRMonitorConfig9));
	if(SUCCEEDED(hr))
	{
		VMR9MonitorInfo vMonInfo[16] = {};			// Array of VMR9MonitorInfo structures.
		DWORD			dwNumMonitors = 0;			// Number of attached monitors.
		UINT			dwCutrrentMonitorIndex = 0;
		LIF( pVMRMonitorConfig9->GetAvailableMonitors(vMonInfo, 16, &dwNumMonitors) );
		rcMonitor = vMonInfo[dwCutrrentMonitorIndex].rcMonitor;
	}
	else
	{
		CComPtr<IVMRMonitorConfig> pVMRMonitorConfig;
		hr = pVideoRender->QueryInterface(IID_IVMRMonitorConfig, reinterpret_cast<void**>(&pVMRMonitorConfig));
		if(FAILED(hr)){
			return hr;
		}
		VMRMONITORINFO	vMonInfo[16] = {};			// Array of VMRMONITORINFO structures.
		DWORD			dwNumMonitors = 0;			// Number of attached monitors.
		UINT			dwCutrrentMonitorIndex = 0;
		LIF( pVMRMonitorConfig->GetAvailableMonitors(vMonInfo, 16, &dwNumMonitors) );
		rcMonitor = vMonInfo[dwCutrrentMonitorIndex].rcMonitor;
	}
 	
	return S_OK;
}

HRESULT CorrectAspectRatio(CComPtr<IBaseFilter>& pVideoRender)
{
	CheckPointer(pVideoRender, E_POINTER);
	HRESULT hr = S_OK;
	CComPtr<IVMRAspectRatioControl9> pIVMRAspectRatioControl9;
	hr = pVideoRender ->QueryInterface(IID_IVMRAspectRatioControl9, reinterpret_cast<void**>(&pIVMRAspectRatioControl9));
	if(SUCCEEDED(hr))
	{
		LIF( pIVMRAspectRatioControl9->SetAspectRatioMode(VMR_ARMODE_LETTER_BOX) );
	}
	else
	{
		CComPtr<IVMRAspectRatioControl> pIVMRAspectRatioControl;
		hr = pVideoRender ->QueryInterface(IID_IVMRAspectRatioControl, reinterpret_cast<void**>(&pIVMRAspectRatioControl));
		if(FAILED(hr)){
			return hr;
		}
		LIF( pIVMRAspectRatioControl->SetAspectRatioMode(VMR_ARMODE_LETTER_BOX) );
	}
	return S_OK;
}

Regards
 

Answer 20

Thanks a lot for that! Right now I don't have the time for a closer look, but I will tomorrow. Then I will mark it as answer (or not ;-)).

Thanks again for your good help!
 

Answer 21

Hi Pavel,

finally I had to time to work on that topic again. Unfortunately I cannot run your code. I don't have the PlayWnd sample here. It seems to be part of an DirectX version, but which one? For my studies I have the version of April 2007 installed, but now DirectShow samples are in there. Then I tried to modify the DSPlay sample from the latest Windows SDK (v7.0), but I can't compile it after your changes because of problems in refclock.h (syntax error: CAMSchedule).

Would it be possible to send the whole project to me? I would be very thankful!

Nevertheless, I took more time in investigating the problem. I cam across the fact that this problem also occurs on Windows Vista ( http://social.msdn.microsoft.com/forums/en-US/windowsdirectshowdevelopment/thread/cd515f32-87f4-4726-a07d-f995fa521e1f/ ). It seems to be problem in Aero. So if I deactivate "Enable desktop composition"everything works perfect!!!

Pavel, you write you think VMR7 and VMR9 are obsolete? I can't find information on that. Why do you think this? Well, ok, as VMR7 uses DirectDraw I would go with that.

I think it is also interesting, that EVR (the successor of VMR7/9?) also has a  fullscreen  method (IMFVideoDisplayControl::SetFullscreen Method) - but much more interesting that this method is already deprecated! See this: http://msdn.microsoft.com/en-us/library/ms701561(VS.85).aspx . Instead you should do the following:

"This method is deprecated. New applications should not call this method. To implement full-screen playback, an application should simply resize the  video  window to cover the entire area of the monitor. Also set the window to be a topmost window, so that the application receives all mouse-click messages. For more information about topmost windows, see the documentation for the SetWindowPos function in the Windows SDK."

Why this? I think that's not very comfortable. I mean, such a nice method :-) and I should not use it but implement it for myself? Strange ... :-/

Greetings,
Micha

PS: Also interesting, why is IVideoWindow::put_FullScreenMode not deprecated, if it is for EVR?
 

Answer 22

 I don't have the PlayWnd sample here. It seems to be part of an DirectX version, but which one? For my studies I have the version of April 2007 installed, but now DirectShow samples are in there. Then I tried to modify the DSPlay sample from the latest Windows SDK (v7.0), but I can't compile it after your changes because of problems in refclock.h (syntax error: CAMSchedule).

...

Pavel, you write you think VMR7 and VMR9 are obsolete? I can't find information on that. Why do you think this? Well, ok, as VMR7 uses DirectDraw I would go with that.

I think it is also interesting, that EVR (the successor of VMR7/9?) also has a  fullscreen  method (IMFVideoDisplayControl::SetFullscreen Method) - but much more interesting that this method is already deprecated! See this: http://msdn.microsoft.com/en-us/library/ms701561(VS.85).aspx . Instead you should do the following:

"This method is deprecated. New applications should not call this method. To implement full-screen playback, an application should simply resize the  video  window to cover the entire area of the monitor. Also set the window to be a topmost window, so that the application receives all mouse-click messages. For more information about topmost windows, see the documentation for the SetWindowPos function in the Windows SDK."
...

1. DirectX Summer 2004 SDK has the most samples (recommended for this and other reasons on my site):
   C:/DXSDK/9_0/Samples/C++/DirectShow/Players/PlayWnd
2.  VMR7 and VMR9 are not obsolete.  However, some of us have written our own custom renderers because the stock renderers have limitations that we cannot live with.  EVR has its limitations too.
3.  The full screen vs. creating a borderless window the size of the screen comes up from time to time.  I prefer the latter because fullscreen mode has issues.  In the old days, when graphics cards had more problems stretching video in windowed mode, it was good to have fullscreen alternative.
 

Answer 23

Hi John,

I have just returned from Christmas holiday. If the full project is still interesting to you, I can send it to you.

Pavel
 

Answer 24

John,

I am facing the same exact problem of yours, did you find a solution or is using a (separate stretched window) is the only solution?

I appreciate any help from you, take care

 

Answer 25

Hi Tamero,

sorry for my late reply ... :-(

Unfortunately, I couldn't work anymore on that project, so I have no other solution and didn't contact Pavel. :-/ I guess, best is you go with Pavels solution. Try his approach and contact him to get the full project.

Let me know whether it works!

Happy coding and good luck!

Greetings

抱歉,我不能为您生成实际的Android Studio项目。但是,以下是提示和步骤,您可以使用Android Studio创建一个类似的项目: 1. 打开Android Studio并创建一个新项目。 2. 选择空白活动 (Blank Activity) 并按照向导进行设置。 3. 在项目的 build.gradle 文件中添加以下依赖项: ``` dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:recyclerview-v7:28.0.0' implementation 'com.github.bumptech.glide:glide:4.7.1' } ``` 4. 在 AndroidManifest.xml 文件中添加读取外部存储权限: ``` <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> ``` 5. 在活动中添加以下变量和方法: ``` private ArrayList<String> mImageUrls = new ArrayList<>(); private RecyclerView mRecyclerView; private GalleryAdapter mAdapter; private void initViews() { mRecyclerView = findViewById(R.id.recycler_view); mAdapter = new GalleryAdapter(this, mImageUrls); mRecyclerView.setAdapter(mAdapter); GridLayoutManager layoutManager = new GridLayoutManager(this, 3); mRecyclerView.setLayoutManager(layoutManager); mAdapter.setOnItemClickListener(new GalleryAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { // Show full screen image or do something else } }); } private void loadImages() { String[] projection = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA }; Cursor imageCursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, null); if (imageCursor != null) { while (imageCursor.moveToNext()) { String imagePath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA)); mImageUrls.add(imagePath); } imageCursor.close(); } mAdapter.notifyDataSetChanged(); } ``` 6. 创建 GalleryAdapter 类作为适配器并设置RecyclerView。 7. 在 onCreate 方法中调用 initViews() 和 loadImages() 方法。 8. 运行应用程序并开始选择照片! 希望这些提示有助于您创建多图选择应用程序!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值