139 lines
4.6 KiB
C++
139 lines
4.6 KiB
C++
#include "Game.hpp"
|
|
#include "Recorder.hpp"
|
|
#include "gif-h/gif.h"
|
|
|
|
Recorder::Recorder(Node* parent) : Node(parent)
|
|
{
|
|
get_delegate().subscribe(&Recorder::respond, this);
|
|
}
|
|
|
|
float Recorder::get_frame_length()
|
|
{
|
|
return get_configuration()["recording"].value(
|
|
"video-frame-length", get_root()->frame_length);
|
|
}
|
|
|
|
void Recorder::respond(SDL_Event& event)
|
|
{
|
|
if (get_delegate().compare(event, "screenshot"))
|
|
{
|
|
capture_screen();
|
|
}
|
|
else if (get_delegate().compare(event, "record"))
|
|
{
|
|
if (animation.playing)
|
|
{
|
|
end_recording();
|
|
}
|
|
else
|
|
{
|
|
start_recording();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Recorder::capture_screen()
|
|
{
|
|
nlohmann::json config = get_configuration();
|
|
SDL_Surface* surface = get_display().get_screen_surface();
|
|
fs::path directory = config["path"]["screenshots"];
|
|
fs::create_directories(directory);
|
|
std::string prefix = config["recording"]["screenshot-prefix"].
|
|
get<std::string>();
|
|
std::string extension = config["recording"]["screenshot-extension"].
|
|
get<std::string>();
|
|
int zfill = config["recording"]["screenshot-zfill"].get<int>();
|
|
fs::path path = sfw::get_next_file_name(directory, zfill, prefix, extension);
|
|
IMG_SavePNG(surface, path.c_str());
|
|
SDL_FreeSurface(surface);
|
|
std::cout << "Saved screenshot to " << path.string() << std::endl;
|
|
}
|
|
|
|
void Recorder::start_recording()
|
|
{
|
|
std::cout << "Starting recording..." << std::endl;
|
|
animation.set_frame_length(get_frame_length());
|
|
animation.play();
|
|
}
|
|
|
|
void Recorder::add_frame_to_video()
|
|
{
|
|
// frames.push_back(get_display().get_screen_surface());
|
|
glm::ivec2 size = get_display().get_window_size();
|
|
unsigned char* pixels = new unsigned char[Display::bpp / 8 * size.x * size.y];
|
|
get_display().get_screen_pixels(pixels, size.x, size.y);
|
|
pixel_buffers.push_back(pixels);
|
|
}
|
|
|
|
void Recorder::end_recording()
|
|
{
|
|
std::cout << "Ending recording..." << std::endl;
|
|
animation.reset();
|
|
if (pixel_buffers.size() > 0)
|
|
{
|
|
nlohmann::json config = get_configuration();
|
|
fs::path root = config["path"]["video"];
|
|
fs::create_directories(root);
|
|
fs::path directory = sfw::get_next_file_name(root, 5, "video-");
|
|
fs::create_directories(directory);
|
|
std::function<void(fs::path)> f = std::bind(&Recorder::write_video_frames, this, std::placeholders::_1);
|
|
std::thread writing(f, directory);
|
|
writing.detach();
|
|
}
|
|
}
|
|
|
|
void Recorder::write_video_frames(fs::path directory)
|
|
{
|
|
std::cout << "Writing recording to " << directory << "..." << std::endl;
|
|
SDL_Surface* frame;
|
|
GifWriter gif_writer;
|
|
int gif_frame_length = get_configuration()["recording"]["gif-frame-length"];
|
|
float elapsed = 0, last_gif_write = 0, gif_write_overflow = 0;
|
|
std::stringstream gif_name;
|
|
gif_name << directory.string() << ".gif";
|
|
fs::path gif_path = directory / gif_name.str();
|
|
for (int ii = 0; not pixel_buffers.empty(); ii++)
|
|
{
|
|
frame = get_display().get_screen_surface_from_pixels(pixel_buffers.front());
|
|
std::stringstream name;
|
|
name << sfw::pad(ii, 5) << ".png";
|
|
fs::path path = directory / name.str();
|
|
IMG_SavePNG(frame, path.string().c_str());
|
|
if (ii == 0 or elapsed - last_gif_write + gif_write_overflow >= gif_frame_length)
|
|
{
|
|
if (ii == 0)
|
|
{
|
|
GifBegin(&gif_writer, gif_name.str().c_str(), frame->w,
|
|
frame->h, gif_frame_length / 10);
|
|
}
|
|
else
|
|
{
|
|
gif_write_overflow += elapsed - (last_gif_write + gif_frame_length);
|
|
last_gif_write = elapsed;
|
|
}
|
|
GifWriteFrame(&gif_writer, (const uint8_t*) frame->pixels,
|
|
frame->w, frame->h, gif_frame_length / 10);
|
|
}
|
|
elapsed += get_frame_length();
|
|
pixel_buffers.erase(pixel_buffers.begin());
|
|
SDL_FreeSurface(frame);
|
|
}
|
|
GifEnd(&gif_writer);
|
|
if (get_configuration()["recording"]["write-mp4"])
|
|
{
|
|
std::stringstream mp4_command;
|
|
fs::path images_match = directory / "%05d.png";
|
|
mp4_command << "ffmpeg -f image2 -framerate " << (1000 / get_frame_length()) <<
|
|
" -i " << images_match.string() << " -s " << frame->w << "x" << frame->h <<
|
|
" -c:v libx264 -crf 17 -pix_fmt yuv420p " << directory.string() << ".mp4";
|
|
std::cout << mp4_command.str() << std::endl;
|
|
std::system(mp4_command.str().c_str());
|
|
}
|
|
std::cout << "Wrote " << directory << std::endl;
|
|
}
|
|
|
|
void Recorder::update()
|
|
{
|
|
animation.update();
|
|
}
|