Jump to content
  • Advertisement
Sign in to follow this  
george7378

Dumping every frame to an image file

This topic is 895 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everyone,

 

I know this is quite an ugly way of doing video capture, but I'd like to be able to try the following in my DX9/C++ app:

 

- Force each frame in the program loop to represent a fixed time interval (e.g. 1/60th of a second - easy to do)

- Dump each frame to an external image file in a folder (I'd use a counter which is incremented in each frame to append a sequence number to the given frame's filename)

- Import each of these frames to a movie maker program in the knowledge that I am guaranteed a specific framerate

 

I've tried using programs such as Fraps and Camstudio to capture my screen, but the framerates are variable and often low. I'm simply making a demonstration video for my program, which doesn't even require realtime user interaction, so it doesn't matter how long it takes to render/save each frame in sequence.

 

Is there a way to save the frames like this? I'm using a windowed app too if that's a restriction. Perhaps you know an alternative way of saving each and every frame my program renders?

 

Thanks a lot!

Share this post


Link to post
Share on other sites
Advertisement

2 ways:

 

use a video encoder on the gpu

 

if your game is deterministic, which is a good idea, force the framerate and replay the input. That way you could render to a much larger framebuffer and capture 120Hz.

Share this post


Link to post
Share on other sites

Is there a way to save the frames like this?

Sure. You can use IDirect3DDevice9::GetRenderTargetData to get the pixels from the GPU, and then save them to disk using whatever format you like (I find TGA is easy for raw pixel dumps).

Share this post


Link to post
Share on other sites

Hey, thanks for the replies everyone:

 

- cozzie: Basically, my program is a demonstration of a simple autopilot program which is used to control a spacecraft in two dimensions. All I have to do is set the program running and the autopilot algorithm does the rest. Setting a fixed time-per-frame ensures the results are consistent and the autopilot is using a fixed timestep for each update. Hence there is no need for a good realtime framerate when I am capturing the video, I just need to make sure I can save every frame in sequence. So the answer to the second question is no - I like to render them on-screen so I can see what it's up to, but it's not totally necessary.

 

- Hodgman, harveypekar: I'll give those methods a go, thanks for the help :)

Share this post


Link to post
Share on other sites

This is the code that I use to take screenshots in-app. Note that if run in windowed mode it captures the entire desktop and cuts out the window area. This means that if some other window is put in front of your window it will capture that data as well.

LPDIRECT3DSURFACE9 CaptureScreen()
{
    UINT width;
    UINT height;
    if (IsFullscreen()) {
        width = GetDisplayWidth();
        height = GetDisplayHeight();
    }
    else {
        width = GetSystemMetrics(SM_CXSCREEN);
        height = GetSystemMetrics(SM_CYSCREEN);
    }

    LPDIRECT3DSURFACE9 pCaptureSurface;
    HRESULT hr = GetD3DDevice()->CreateOffscreenPlainSurface(width, height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pCaptureSurface, NULL);
    if (FAILED(hr)) {
        SAFE_RELEASE(pCaptureSurface);
        return NULL;
    }

    hr = GetD3DDevice()->GetFrontBufferData(0, pCaptureSurface);
    if (FAILED(hr)) {
        SAFE_RELEASE(pCaptureSurface);
        return NULL;
    }

    return pCaptureSurface;
}

bool TakeScreenshot(const std::wstring& filename)
{
	LPDIRECT3DSURFACE9 pCaptureSurface = GetGraphicsDevice()->CaptureScreen();
	HRESULT hr = E_FAIL;
	if (pCaptureSurface != NULL) {
		D3DXIMAGE_FILEFORMAT imageFileFormat = D3DXIFF_JPG;
		std::wstring fileExtention = GXFile::GetFileExtention(filename);
		if (GXString::CompareNoCase(fileExtention.c_str(), L"bmp")) {
			imageFileFormat = D3DXIFF_BMP;
		}
		else if (GXString::CompareNoCase(fileExtention.c_str(), L"png")) {
			imageFileFormat = D3DXIFF_PNG;
		}

		if (GetGraphicsDevice()->IsFullscreen()) {
			hr = D3DXSaveSurfaceToFile(filename.c_str(), imageFileFormat, pCaptureSurface, NULL, NULL);
			if (FAILED(hr)) {
				GXLOG_WARN_F(L"Failed to save fullscreen screenshot to %s", filename.c_str());
			}
		}
		else {
			// Calculate the rectangle within the screen that the window is currently located.
			// I.e. 0,0 is top left of screen for all screens even on multi-monitor setups.
			RECT rcWindow;
			GetClientRect(m_hWnd, &rcWindow);
			POINT topPoint = {rcWindow.left, rcWindow.top};
			POINT bottomPoint = {rcWindow.right, rcWindow.bottom};
			ClientToScreen(m_hWnd, &topPoint);
			ClientToScreen(m_hWnd, &bottomPoint);
			rcWindow.left = topPoint.x;
			rcWindow.top = topPoint.y;
			rcWindow.right = bottomPoint.x;
			rcWindow.bottom = bottomPoint.y;
			for (unsigned int i = 0; i < m_displays.size(); i++) {
				RECT rcDest;
				if (IntersectRect(&rcDest, &m_displays[i].rect, &rcWindow)) {
					rcWindow.left -= m_displays[i].rect.left;
					rcWindow.top -= m_displays[i].rect.top;
					rcWindow.right -= m_displays[i].rect.left;
					rcWindow.bottom -= m_displays[i].rect.top;
					break;
				}
			}
			hr = D3DXSaveSurfaceToFile(filename.c_str(), imageFileFormat, pCaptureSurface, NULL, &rcWindow);
			if (FAILED(hr)) {
				GXLOG_WARN_F(L"Failed to save windowed screenshot to %s", filename.c_str());
			}
		}
		SAFE_RELEASE(pCaptureSurface);
	}
	return SUCCEEDED(hr);
}

Share this post


Link to post
Share on other sites

Saving pictures is anyway a good sourcing of a video material, you should be able to create some any HD /high frequency robust video encoded. I don't know about applications much, but VLC media player is amazing "player", can save/write to much any video format with possible settings, is open source, and I would not be surprised if it could read actual pictures and allow you for encoding any crazy 1GB large 3 second video or stuff.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!