mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 10:19:59 +01:00
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:
@@ -223,6 +223,7 @@ set(VMIX_SRCS
|
||||
GarbageVisitor.cpp
|
||||
SessionCreator.cpp
|
||||
Mixer.cpp
|
||||
Recorder.cpp
|
||||
Settings.cpp
|
||||
Screenshot.cpp
|
||||
Resource.cpp
|
||||
|
||||
@@ -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
59
Recorder.cpp
Normal 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
37
Recorder.h
Normal 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
|
||||
34
Session.cpp
34
Session.cpp
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user