Skip to content

Commit

Permalink
pimpl everything, speed up writeFrame method
Browse files Browse the repository at this point in the history
  • Loading branch information
Prevter committed Dec 30, 2024
1 parent 73e3230 commit aa8972f
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 111 deletions.
37 changes: 17 additions & 20 deletions include/events.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,17 @@ namespace impl {
void* m_ptr;
};

class WriteFrameRecorderEvent : public geode::Event {
public:
WriteFrameRecorderEvent(void* ptr, const std::vector<uint8_t>& frameData) {
m_ptr = ptr;
m_frameData = &frameData;
}

void setResult(geode::Result<>&& result) {m_result = std::move(result);}
geode::Result<> getResult() {return m_result;}
struct Dummy {};

void* getPtr() const {return m_ptr;}

const std::vector<uint8_t>& getFrameData() const {return *m_frameData;}
class GetWriteFrameFunctionEvent : public geode::Event {
public:
using writeFrame_t = geode::Result<>(Dummy::*)(std::vector<uint8_t> const&);
GetWriteFrameFunctionEvent() = default;

void setFunction(writeFrame_t function) {m_function = function;}
writeFrame_t getFunction() const {return m_function;}
private:
const std::vector<uint8_t>* m_frameData;
void* m_ptr;
geode::Result<> m_result = DEFAULT_RESULT_ERROR;
writeFrame_t m_function;
};

class CodecRecorderEvent : public geode::Event {
Expand Down Expand Up @@ -134,7 +127,7 @@ class Recorder {
Recorder() {
impl::CreateRecorderEvent createEvent;
createEvent.post();
m_ptr = createEvent.getPtr();
m_ptr = static_cast<impl::Dummy*>(createEvent.getPtr());
}

~Recorder() {
Expand Down Expand Up @@ -184,9 +177,13 @@ class Recorder {
* @warning Ensure that the frameData size matches the expected dimensions of the frame.
*/
geode::Result<> writeFrame(const std::vector<uint8_t>& frameData) {
impl::WriteFrameRecorderEvent writeFrameEvent(m_ptr, frameData);
writeFrameEvent.post();
return writeFrameEvent.getResult();
static auto writeFrame = []{
impl::GetWriteFrameFunctionEvent event;
event.post();
return event.getFunction();
}();
if (!writeFrame) return geode::Err("Failed to call writeFrame function.");
return std::invoke(writeFrame, m_ptr, frameData);
}

/**
Expand All @@ -203,7 +200,7 @@ class Recorder {
return codecEvent.getCodecs();
}
private:
void* m_ptr = nullptr;
impl::Dummy* m_ptr = nullptr;
};

class AudioMixer {
Expand Down
40 changes: 23 additions & 17 deletions include/recorder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class FFMPEG_API_DLL Recorder {
* @return true if initialization is successful, false otherwise.
*/
geode::Result<> init(const RenderSettings& settings);

/**
* @brief Stops the recording process and finalizes the output file.
*
Expand Down Expand Up @@ -75,24 +76,29 @@ class FFMPEG_API_DLL Recorder {
geode::Result<> filterFrame(AVFrame* inputFrame, AVFrame* outputFrame);

private:
AVFormatContext* m_formatContext = nullptr;
const AVCodec* m_codec = nullptr;
AVStream* m_videoStream = nullptr;
AVCodecContext* m_codecContext = nullptr;
AVBufferRef* m_hwDevice = nullptr;
AVFrame* m_frame = nullptr;
AVFrame* m_convertedFrame = nullptr;
AVFrame* m_filteredFrame = nullptr;
AVPacket* m_packet = nullptr;
SwsContext* m_swsCtx = nullptr;
AVFilterGraph* m_filterGraph = nullptr;
AVFilterContext* m_buffersrcCtx = nullptr;
AVFilterContext* m_buffersinkCtx = nullptr;
AVFilterContext* m_colorspaceCtx = nullptr;
AVFilterContext* m_vflipCtx = nullptr;
class Impl {
public:
AVFormatContext* m_formatContext = nullptr;
const AVCodec* m_codec = nullptr;
AVStream* m_videoStream = nullptr;
AVCodecContext* m_codecContext = nullptr;
AVBufferRef* m_hwDevice = nullptr;
AVFrame* m_frame = nullptr;
AVFrame* m_convertedFrame = nullptr;
AVFrame* m_filteredFrame = nullptr;
AVPacket* m_packet = nullptr;
SwsContext* m_swsCtx = nullptr;
AVFilterGraph* m_filterGraph = nullptr;
AVFilterContext* m_buffersrcCtx = nullptr;
AVFilterContext* m_buffersinkCtx = nullptr;
AVFilterContext* m_colorspaceCtx = nullptr;
AVFilterContext* m_vflipCtx = nullptr;

size_t m_frameCount = 0;
bool m_init = false;
};

size_t m_frameCount = 0;
bool m_init = false;
std::unique_ptr<Impl> m_impl = nullptr;
};

END_FFMPEG_NAMESPACE_V
5 changes: 3 additions & 2 deletions include/render_settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

#include <string>
#include <filesystem>
#include "export.hpp"

namespace ffmpeg {
BEGIN_FFMPEG_NAMESPACE_V

enum class PixelFormat : int {
NONE = -1,
Expand Down Expand Up @@ -321,4 +322,4 @@ struct RenderSettings {
std::filesystem::path m_outputFile;
};

}
END_FFMPEG_NAMESPACE_V
31 changes: 29 additions & 2 deletions src/compat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,38 @@ namespace ffmpeg {
}
};

typedef struct RenderSettings {
HardwareAccelerationType m_hardwareAccelerationType;
PixelFormat m_pixelFormat;
std::string m_codec;
std::string m_colorspaceFilters;
int64_t m_bitrate;
uint32_t m_width;
uint32_t m_height;
uint16_t m_fps;
std::filesystem::path m_outputFile;

v2::RenderSettings toV2() const {
return v2::RenderSettings {
.m_hardwareAccelerationType = m_hardwareAccelerationType,
.m_pixelFormat = m_pixelFormat,
.m_codec = m_codec,
.m_colorspaceFilters = m_colorspaceFilters,
.m_doVerticalFlip = false,
.m_bitrate = m_bitrate,
.m_width = m_width,
.m_height = m_height,
.m_fps = m_fps,
.m_outputFile = m_outputFile
};
}
} RenderSettingsV1;

class FFMPEG_API_DLL Recorder {
#define self reinterpret_cast<FFMPEG_API_VERSION_NS::Recorder*>(this)
public:
bool init(const RenderSettings& settings) {
auto res = self->init(settings);
bool init(const RenderSettingsV1& settings) {
auto res = self->init(settings.toV2());
return res.isOk();
}

Expand Down
7 changes: 4 additions & 3 deletions src/event-api/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ using namespace geode::prelude;
return ListenerResult::Stop;
});

new EventListener<EventFilter<WriteFrameRecorderEvent>>(+[](WriteFrameRecorderEvent* e) {
ffmpeg::Recorder* ptr = (ffmpeg::Recorder*)e->getPtr();
e->setResult(ptr->writeFrame(e->getFrameData()));
new EventListener<EventFilter<GetWriteFrameFunctionEvent>>(+[](GetWriteFrameFunctionEvent* e) {
// this function is getting called a lot, so it would be better to cache the pointer
auto ptr = &ffmpeg::Recorder::writeFrame;
e->setFunction(reinterpret_cast<GetWriteFrameFunctionEvent::writeFrame_t>(ptr));
return ListenerResult::Stop;
});

Expand Down
Loading

0 comments on commit aa8972f

Please sign in to comment.