Capture final frame color buffer to file
- KianA
- Topic Author
Less
More
2 years 6 months ago - 2 years 6 months ago #1
by KianA
Capture final frame color buffer to file was created by KianA
Hi @Crosire,
I am working on a project which involves capturing raw uncompressed Game frames. And at a later time, pass them through FFmpeg for encoding.
Is there a way I can capture such raw uncompressed frames (final frame color buffer) using the reshade application irrespective of the graphics API used by the Game ?
It is fine if it works for just dx11 games.
Also, it would be helpful if you can tell any libraries that would let me dump the frames into a file.
P.S.: I don't have access to 4K Monitor but I want to capture 4K frame color buffer rendered by NVIDIA GPU.
Thanks in advance!
I am working on a project which involves capturing raw uncompressed Game frames. And at a later time, pass them through FFmpeg for encoding.
Is there a way I can capture such raw uncompressed frames (final frame color buffer) using the reshade application irrespective of the graphics API used by the Game ?
It is fine if it works for just dx11 games.
Also, it would be helpful if you can tell any libraries that would let me dump the frames into a file.
P.S.: I don't have access to 4K Monitor but I want to capture 4K frame color buffer rendered by NVIDIA GPU.
Thanks in advance!
Last edit: 2 years 6 months ago by KianA.
Please Log in or Create an account to join the conversation.
- crosire
Less
More
2 years 6 months ago - 2 years 6 months ago #2
by crosire
Replied by crosire on topic Capture final frame color buffer to file
It's possible in ReShade 5 (would need to build current ReShade source from GitHub, see also
github.com/crosire/reshade/tree/main/include
) with an add-on.
Will see if I can add an example (to github.com/crosire/reshade/tree/main/examples ) that shows how to write an add-on that captures the frame data and encodes it into a video with ffmpeg.
For now, here is a quick example (compile this to a DLL, rename the file extension from ".dll" to ".addon" and put it in the same directory as a ReShade 5 build for it to load) of how to get the raw data of the current frame on the CPU at least (not particularly fast code, but shows the general flow):
Will see if I can add an example (to github.com/crosire/reshade/tree/main/examples ) that shows how to write an add-on that captures the frame data and encodes it into a video with ffmpeg.
For now, here is a quick example (compile this to a DLL, rename the file extension from ".dll" to ".addon" and put it in the same directory as a ReShade 5 build for it to load) of how to get the raw data of the current frame on the CPU at least (not particularly fast code, but shows the general flow):
#include <cassert>
#include <reshade.hpp>
struct user_data
{
static const uint8_t GUID[16] = { 0x0D, 0x75, 0x25, 0xF9, 0xC4, 0xE1, 0x42, 0x6E, 0xBC, 0x99, 0x15, 0xBB, 0xD5, 0xFD, 0x51, 0xF2 };
reshade::api::resource host_resource = { 0 };
};
static void on_init(reshade::api::swapchain *swapchain)
{
user_data &data = swapchain->create_user_data<user_data>;(user_data::GUID);
reshade::api::device *const device = swapchain->get_device();
// Get description of the back buffer resources
const reshade::api::resource_desc desc = device->get_resource_desc(swapchain->get_current_back_buffer());
// Create a CPU-accessible texture with matching dimensions
if (!device->create_resource(
reshade::api::resource_desc(
desc.texture.width,
desc.texture.height,
1,
1,
desc.texture.format,
1,
reshade::api::memory_heap::gpu_to_cpu,
reshade::api::resource_usage::copy_dest),
nullptr,
reshade::api::resource_usage::cpu_access,
&data.host_resource))
{
reshade::log_message(1, "Failed to create host resource");
return;
}
}
static void on_destroy(reshade::api::swapchain *swapchain)
{
user_data &data = swapchain->get_user_data<user_data>;(user_data::GUID);
if (data.host_resource != 0)
{
swapchain->get_device()->destroy_resource(data.host_resource);
}
swapchain->destroy_user_data<user_data>;(user_data::GUID);
}
static void on_present(reshade::api::command_queue *queue, reshade::api::swapchain *swapchain)
{
user_data &data = swapchain->get_user_data<user_data>;(user_data::GUID);
reshade::api::device *const device = swapchain->get_device();
reshade::api::command_list *cmd_list = queue->get_immediate_command_list();
// TODO: Add barriers/state transitions for DX12/Vulkan support (using "cmd_list->barrier()")
// Copy current frame into the CPU-accessible texture
cmd_list->copy_resource(swapchain->get_current_back_buffer(), data.host_resource);
// Very slow ... but ensures the copy has completed before accessing the data next
queue->wait_idle();
// Map CPU-accessible texture to read the data
reshade::api::subresource_data host_data;
if (!device->map_texture_region(
data.host_resource, 0, nullptr, reshade::api::map_access::read_only, &host_data))
return;
const reshade::api::resource_desc desc = device->get_resource_desc(data.host_resource);
// TODO: This assumes that the format is RGBA8, need to handle differently for different formats
assert(desc.texture.format == reshade::api::format::r8g8b8a8_unorm);
for (int y = 0; y < desc.texture.height; ++y)
{
for (int x = 0; x < desc.texture.width; ++x)
{
const size_t host_data_index = y * host_data.row_pitch + x * 4;
const uint8_t r = static_cast<const uint8_t *>;(host_data.data)[host_data_index + 0];
const uint8_t g = static_cast<const uint8_t *>;(host_data.data)[host_data_index + 1];
const uint8_t b = static_cast<const uint8_t *>;(host_data.data)[host_data_index + 2];
const uint8_t a = static_cast<const uint8_t *>;(host_data.data)[host_data_index + 3];
// TODO: Do something with the pixel, e.g. dump this whole image to an image file
}
}
device->unmap_texture_region(data.host_resource, 0);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
if (!reshade::register_addon(hinstDLL))
return FALSE;
reshade::register_event<reshade::addon_event::init_swapchain>;(on_init);
reshade::register_event<reshade::addon_event::destroy_swapchain>;(on_destroy);
reshade::register_event<reshade::addon_event::present>;(on_present);
break;
case DLL_PROCESS_DETACH:
reshade::unregister_addon(hinstDLL);
break;
}
return TRUE;
}
Last edit: 2 years 6 months ago by crosire.
Please Log in or Create an account to join the conversation.
- crosire
Less
More
2 years 5 months ago #3
by crosire
Replied by crosire on topic Capture final frame color buffer to file
There is a fully fledged example using ffmpeg here now:
github.com/crosire/reshade/blob/main/exa...re/video_capture.cpp
Please Log in or Create an account to join the conversation.