Implementation of Recorder class. For now, only a capture to PNG is

available, but the mechanism is in place for video capture.
This commit is contained in:
brunoherbelin
2020-07-23 23:50:32 +02:00
parent cec49a9a62
commit 978bbff9a7
7 changed files with 144 additions and 0 deletions

View File

@@ -223,6 +223,7 @@ set(VMIX_SRCS
GarbageVisitor.cpp
SessionCreator.cpp
Mixer.cpp
Recorder.cpp
Settings.cpp
Screenshot.cpp
Resource.cpp

View File

@@ -37,6 +37,7 @@ public:
// width & height
inline uint width() const { return attrib_.viewport.x; }
inline uint height() const { return attrib_.viewport.y; }
inline bool use_alpha() const { return use_alpha_; }
glm::vec3 resolution() const;
float aspectRatio() const;

59
Recorder.cpp Normal file
View File

@@ -0,0 +1,59 @@
#include <thread>
#include <glad/glad.h>
// standalone image loader
#include <stb_image.h>
#include <stb_image_write.h>
#include "SystemToolkit.h"
#include "FrameBuffer.h"
#include "Log.h"
#include "Recorder.h"
Recorder::Recorder() : enabled_(true), finished_(false)
{
}
FrameRecorder::FrameRecorder() : Recorder()
{
filename_ = SystemToolkit::home_path() + SystemToolkit::date_time_string() + "_vimix.png";
}
// Thread to perform slow operation of saving to file
void save_png(std::string filename, unsigned char *data, uint w, uint h, uint c)
{
// got data to save ?
if (data) {
// save file
stbi_write_png(filename.c_str(), w, h, c, data, w * c);
// notify
Log::Notify("Capture %s saved.", filename.c_str());
}
}
void FrameRecorder::addFrame(const FrameBuffer *frame_buffer, float dt)
{
if (enabled_)
{
uint w = frame_buffer->width();
uint h = frame_buffer->height();
uint c = frame_buffer->use_alpha() ? 4 : 3;
GLenum format = frame_buffer->use_alpha() ? GL_RGBA : GL_RGB;
uint size = w * h * c;
unsigned char * data = (unsigned char*) malloc(size);
glGetTextureSubImage( frame_buffer->texture(), 0, 0, 0, 0, w, h, 1, format, GL_UNSIGNED_BYTE, size, data);
// save in separate thread
std::thread(save_png, filename_, data, w, h, c).detach();
}
// record one frame only
finished_ = true;
}

37
Recorder.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef RECORDER_H
#define RECORDER_H
#include <atomic>
#include <string>
#include <gst/gst.h>
class FrameBuffer;
class Recorder
{
public:
Recorder();
virtual ~Recorder() {}
virtual void addFrame(const FrameBuffer *frame_buffer, float dt) = 0;
inline bool finished() const { return finished_; }
inline bool enabled() const { return enabled_; }
protected:
std::atomic<bool> enabled_;
std::atomic<bool> finished_;
};
class FrameRecorder : public Recorder
{
std::string filename_;
public:
FrameRecorder();
void addFrame(const FrameBuffer *frame_buffer, float dt);
};
#endif // RECORDER_H

View File

@@ -5,6 +5,7 @@
#include "FrameBuffer.h"
#include "Session.h"
#include "GarbageVisitor.h"
#include "Recorder.h"
#include "Log.h"
@@ -71,6 +72,24 @@ void Session::update(float dt)
// draw render view in Frame Buffer
render_.draw();
// send frame to recorders
std::list<Recorder *>::iterator iter;
for (iter=recorders_.begin(); iter != recorders_.end(); )
{
Recorder *rec = *iter;
if (rec->enabled())
rec->addFrame(render_.frame(), dt);
if (rec->finished()) {
iter = recorders_.erase(iter);
delete rec;
}
else {
iter++;
}
}
}
@@ -209,4 +228,19 @@ int Session::index(SourceList::iterator it) const
return index;
}
void Session::addRecorder(Recorder *rec)
{
recorders_.push_back(rec);
}
void Session::clearRecorders()
{
std::list<Recorder *>::iterator iter;
for (iter=recorders_.begin(); iter != recorders_.end(); )
{
Recorder *rec = *iter;
iter = recorders_.erase(iter);
delete rec;
}
}

View File

@@ -5,6 +5,8 @@
#include "View.h"
#include "Source.h"
class Recorder;
class Session
{
public:
@@ -45,6 +47,10 @@ public:
// get frame result of render
inline FrameBuffer *frame () const { return render_.frame(); }
// add recorders
void addRecorder(Recorder *rec);
void clearRecorders();
// configure rendering resolution
void setResolution(glm::vec3 resolution);
@@ -67,6 +73,8 @@ protected:
SourceList sources_;
std::map<View::Mode, Group*> config_;
bool active_;
std::list<Recorder *> recorders_;
};
#endif // SESSION_H

View File

@@ -44,6 +44,7 @@
#include "ImGuiVisitor.h"
#include "GstToolkit.h"
#include "Mixer.h"
#include "Recorder.h"
#include "Selection.h"
#include "FrameBuffer.h"
#include "MediaPlayer.h"
@@ -865,6 +866,9 @@ void UserInterface::RenderPreview()
if ( ImGui::MenuItem( ICON_FA_WINDOW_RESTORE " Show output window") )
Rendering::manager().outputWindow().show();
if ( ImGui::MenuItem( ICON_FA_CAMERA_RETRO " Save capture") )
Mixer::manager().session()->addRecorder(new FrameRecorder);
if ( ImGui::MenuItem( ICON_FA_TIMES " Close") )
Settings::application.widget.preview = false;