mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +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
|
GarbageVisitor.cpp
|
||||||
SessionCreator.cpp
|
SessionCreator.cpp
|
||||||
Mixer.cpp
|
Mixer.cpp
|
||||||
|
Recorder.cpp
|
||||||
Settings.cpp
|
Settings.cpp
|
||||||
Screenshot.cpp
|
Screenshot.cpp
|
||||||
Resource.cpp
|
Resource.cpp
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public:
|
|||||||
// width & height
|
// width & height
|
||||||
inline uint width() const { return attrib_.viewport.x; }
|
inline uint width() const { return attrib_.viewport.x; }
|
||||||
inline uint height() const { return attrib_.viewport.y; }
|
inline uint height() const { return attrib_.viewport.y; }
|
||||||
|
inline bool use_alpha() const { return use_alpha_; }
|
||||||
glm::vec3 resolution() const;
|
glm::vec3 resolution() const;
|
||||||
float aspectRatio() 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 "FrameBuffer.h"
|
||||||
#include "Session.h"
|
#include "Session.h"
|
||||||
#include "GarbageVisitor.h"
|
#include "GarbageVisitor.h"
|
||||||
|
#include "Recorder.h"
|
||||||
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
@@ -71,6 +72,24 @@ void Session::update(float dt)
|
|||||||
|
|
||||||
// draw render view in Frame Buffer
|
// draw render view in Frame Buffer
|
||||||
render_.draw();
|
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;
|
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 "View.h"
|
||||||
#include "Source.h"
|
#include "Source.h"
|
||||||
|
|
||||||
|
class Recorder;
|
||||||
|
|
||||||
class Session
|
class Session
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -45,6 +47,10 @@ public:
|
|||||||
// get frame result of render
|
// get frame result of render
|
||||||
inline FrameBuffer *frame () const { return render_.frame(); }
|
inline FrameBuffer *frame () const { return render_.frame(); }
|
||||||
|
|
||||||
|
// add recorders
|
||||||
|
void addRecorder(Recorder *rec);
|
||||||
|
void clearRecorders();
|
||||||
|
|
||||||
// configure rendering resolution
|
// configure rendering resolution
|
||||||
void setResolution(glm::vec3 resolution);
|
void setResolution(glm::vec3 resolution);
|
||||||
|
|
||||||
@@ -67,6 +73,8 @@ protected:
|
|||||||
SourceList sources_;
|
SourceList sources_;
|
||||||
std::map<View::Mode, Group*> config_;
|
std::map<View::Mode, Group*> config_;
|
||||||
bool active_;
|
bool active_;
|
||||||
|
std::list<Recorder *> recorders_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SESSION_H
|
#endif // SESSION_H
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "ImGuiVisitor.h"
|
#include "ImGuiVisitor.h"
|
||||||
#include "GstToolkit.h"
|
#include "GstToolkit.h"
|
||||||
#include "Mixer.h"
|
#include "Mixer.h"
|
||||||
|
#include "Recorder.h"
|
||||||
#include "Selection.h"
|
#include "Selection.h"
|
||||||
#include "FrameBuffer.h"
|
#include "FrameBuffer.h"
|
||||||
#include "MediaPlayer.h"
|
#include "MediaPlayer.h"
|
||||||
@@ -865,6 +866,9 @@ void UserInterface::RenderPreview()
|
|||||||
if ( ImGui::MenuItem( ICON_FA_WINDOW_RESTORE " Show output window") )
|
if ( ImGui::MenuItem( ICON_FA_WINDOW_RESTORE " Show output window") )
|
||||||
Rendering::manager().outputWindow().show();
|
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") )
|
if ( ImGui::MenuItem( ICON_FA_TIMES " Close") )
|
||||||
Settings::application.widget.preview = false;
|
Settings::application.widget.preview = false;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user