Skip to content

Commit 32cd097

Browse files
committed
add GUI to select output format
1 parent 09af8a9 commit 32cd097

File tree

4 files changed

+222
-20
lines changed

4 files changed

+222
-20
lines changed

data/locale/en-US.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
InputRecording="Input Recording"
1+
InputRecording="Input Recording"
2+
InputDevice="Input Device"
3+
OutputFormat="Output Format"
4+
Gamepad="Gamepad"
5+
DebugLog="Debug (Log Only)"

src/obs_source.cpp

Lines changed: 89 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,155 @@
11
#include <obs-module.h>
22
#include <obs-frontend-api.h>
3+
#include <cstring>
34

45
#include "device/input_device.hpp"
56
#include "device/gamepad.hpp"
67
#include "writer/input_writer.hpp"
78
#include "writer/csv.hpp"
89
#include "writer/parquet.hpp"
10+
#include "writer/debug.hpp"
911
#include "obs_source.hpp"
1012
#include "plugin-support.h"
1113

14+
// Settings keys
15+
#define SETTING_INPUT_DEVICE "input_device"
16+
#define SETTING_OUTPUT_FORMAT "output_format"
17+
18+
// Settings values
19+
#define DEVICE_GAMEPAD "gamepad"
20+
#define FORMAT_PARQUET "parquet"
21+
#define FORMAT_CSV "csv"
22+
#define FORMAT_DEBUG "debug"
23+
1224
class RecSource {
1325
private:
1426
obs_data_t *m_settings;
1527
obs_source_t *m_source;
1628
std::unique_ptr<InputWriter> m_input_writer;
1729
obs_frontend_event_cb m_event_callback;
1830

19-
public:
20-
RecSource(obs_data_t *settings, obs_source_t *source)
21-
: m_settings{settings},
22-
m_source{source},
23-
m_input_writer{std::make_unique<ParquetWriter>(std::make_unique<GamepadDevice>())}
31+
static std::unique_ptr<InputDevice> create_device(const char *type)
2432
{
33+
// Currently only gamepad is supported
34+
return std::make_unique<GamepadDevice>();
35+
}
36+
37+
static std::unique_ptr<InputWriter> create_writer(const char *format, std::unique_ptr<InputDevice> device)
38+
{
39+
if (strcmp(format, FORMAT_CSV) == 0) {
40+
return std::make_unique<CSVWriter>(std::move(device));
41+
}
42+
if (strcmp(format, FORMAT_DEBUG) == 0) {
43+
return std::make_unique<DebugWriter>(std::move(device));
44+
}
45+
// Default to parquet
46+
return std::make_unique<ParquetWriter>(std::move(device));
47+
}
2548

49+
public:
50+
RecSource(obs_data_t *settings, obs_source_t *source) : m_settings{settings}, m_source{source}
51+
{
2652
m_event_callback = [](enum obs_frontend_event event, void *private_data) {
27-
InputWriter *current_writer = static_cast<InputWriter *>(private_data);
53+
RecSource *rec_source = static_cast<RecSource *>(private_data);
2854
switch (event) {
2955
case OBS_FRONTEND_EVENT_RECORDING_STARTING: {
3056
obs_log(LOG_INFO, "OBS_FRONTEND_EVENT_RECORDING_STARTING received");
31-
current_writer->prepare_recording();
57+
rec_source->prepare_recording();
3258
break;
3359
}
3460
case OBS_FRONTEND_EVENT_RECORDING_STARTED: {
3561
obs_log(LOG_INFO, "OBS_FRONTEND_EVENT_RECORDING_STARTED received");
36-
current_writer->start_recording();
62+
rec_source->m_input_writer->start_recording();
3763
break;
3864
}
3965
case OBS_FRONTEND_EVENT_RECORDING_STOPPING: {
4066
obs_log(LOG_INFO, "OBS_FRONTEND_EVENT_RECORDING_STOPPING received");
41-
current_writer->stop_recording();
67+
rec_source->m_input_writer->stop_recording();
4268
break;
4369
}
4470
case OBS_FRONTEND_EVENT_RECORDING_STOPPED: {
4571
obs_log(LOG_INFO, "OBS_FRONTEND_EVENT_RECORDING_STOPPED received");
46-
// Get last recording path
4772
std::string recording_path{obs_frontend_get_last_recording()};
48-
current_writer->close_recording(recording_path);
73+
rec_source->m_input_writer->close_recording(recording_path);
74+
rec_source->m_input_writer.reset();
4975
break;
5076
}
51-
default: break;
77+
default:
78+
break;
5279
}
5380
};
54-
obs_frontend_add_event_callback(m_event_callback, m_input_writer.get());
81+
obs_frontend_add_event_callback(m_event_callback, this);
5582
}
5683

57-
~RecSource()
84+
~RecSource() { obs_frontend_remove_event_callback(m_event_callback, this); }
85+
86+
void prepare_recording()
5887
{
59-
obs_frontend_remove_event_callback(m_event_callback, m_input_writer.get());
88+
const char *device_type = obs_data_get_string(m_settings, SETTING_INPUT_DEVICE);
89+
const char *output_format = obs_data_get_string(m_settings, SETTING_OUTPUT_FORMAT);
90+
91+
obs_log(LOG_INFO, "Creating writer with device=%s, format=%s", device_type, output_format);
92+
93+
auto device = create_device(device_type);
94+
m_input_writer = create_writer(output_format, std::move(device));
95+
m_input_writer->prepare_recording();
6096
}
6197

6298
void tick(float seconds) { UNUSED_PARAMETER(seconds); }
99+
100+
bool is_recording() const { return m_input_writer != nullptr; }
63101
};
64102

103+
static void rec_source_defaults(obs_data_t *settings)
104+
{
105+
obs_data_set_default_string(settings, SETTING_INPUT_DEVICE, DEVICE_GAMEPAD);
106+
obs_data_set_default_string(settings, SETTING_OUTPUT_FORMAT, FORMAT_PARQUET);
107+
}
108+
109+
static obs_properties_t *rec_source_properties(void *data)
110+
{
111+
RecSource *source = static_cast<RecSource *>(data);
112+
obs_properties_t *props = obs_properties_create();
113+
114+
// Check if recording is active to disable options
115+
bool recording = source && source->is_recording();
116+
117+
// Input device dropdown
118+
obs_property_t *device_list = obs_properties_add_list(props, SETTING_INPUT_DEVICE,
119+
obs_module_text("InputDevice"), OBS_COMBO_TYPE_LIST,
120+
OBS_COMBO_FORMAT_STRING);
121+
obs_property_list_add_string(device_list, obs_module_text("Gamepad"), DEVICE_GAMEPAD);
122+
obs_property_set_enabled(device_list, !recording);
123+
124+
// Output format dropdown
125+
obs_property_t *format_list = obs_properties_add_list(props, SETTING_OUTPUT_FORMAT,
126+
obs_module_text("OutputFormat"), OBS_COMBO_TYPE_LIST,
127+
OBS_COMBO_FORMAT_STRING);
128+
obs_property_list_add_string(format_list, "Parquet", FORMAT_PARQUET);
129+
obs_property_list_add_string(format_list, "CSV", FORMAT_CSV);
130+
obs_property_list_add_string(format_list, obs_module_text("DebugLog"), FORMAT_DEBUG);
131+
obs_property_set_enabled(format_list, !recording);
132+
133+
return props;
134+
}
135+
65136
bool initialize_rec_source()
66137
{
67138
obs_source_info source_info = {};
68139
source_info.id = "input_recording_source";
69140
source_info.type = OBS_SOURCE_TYPE_INPUT;
70141
source_info.output_flags = OBS_SOURCE_VIDEO;
71142
source_info.icon_type = OBS_ICON_TYPE_GAME_CAPTURE;
72-
source_info.get_name = [](void *) {
73-
return obs_module_text("InputRecording");
74-
;
75-
};
143+
source_info.get_name = [](void *) { return obs_module_text("InputRecording"); };
76144
source_info.get_width = [](void *) -> uint32_t { return 0; };
77145
source_info.get_height = [](void *) -> uint32_t { return 0; };
78146
source_info.create = [](obs_data_t *settings, obs_source_t *source) -> void * {
79147
return static_cast<void *>(new RecSource(settings, source));
80148
};
81149
source_info.destroy = [](void *data) { delete static_cast<RecSource *>(data); };
82150
source_info.video_tick = [](void *data, float seconds) { static_cast<RecSource *>(data)->tick(seconds); };
151+
source_info.get_defaults = rec_source_defaults;
152+
source_info.get_properties = rec_source_properties;
83153
obs_register_source(&source_info);
84154
return true;
85155
}

src/writer/debug.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#include "debug.hpp"
2+
#include "plugin-support.h"
3+
#include <obs-module.h>
4+
5+
DebugWriter::DebugWriter(std::unique_ptr<InputDevice> device)
6+
: InputWriter{std::move(device)},
7+
m_current_button_idx{0},
8+
m_current_axis_idx{0}
9+
{
10+
}
11+
12+
void DebugWriter::prepare_recording()
13+
{
14+
m_button_names.clear();
15+
m_prev_button_states.clear();
16+
m_axis_names.clear();
17+
m_prev_axis_values.clear();
18+
m_current_button_idx = 0;
19+
m_current_axis_idx = 0;
20+
21+
obs_log(LOG_INFO, "[DebugWriter] Recording started - logging input changes");
22+
m_device->write_header(*this);
23+
}
24+
25+
void DebugWriter::close_recording(std::string recording_path)
26+
{
27+
obs_log(LOG_INFO, "[DebugWriter] Recording stopped");
28+
}
29+
30+
void DebugWriter::begin_header() {}
31+
32+
void DebugWriter::end_header()
33+
{
34+
// Initialize previous states
35+
m_prev_button_states.resize(m_button_names.size(), false);
36+
m_prev_axis_values.resize(m_axis_names.size(), 0);
37+
38+
obs_log(LOG_INFO, "[DebugWriter] Tracking %zu buttons, %zu axes", m_button_names.size(), m_axis_names.size());
39+
}
40+
41+
void DebugWriter::begin_row()
42+
{
43+
m_current_button_idx = 0;
44+
m_current_axis_idx = 0;
45+
}
46+
47+
void DebugWriter::end_row() {}
48+
49+
void DebugWriter::append_header(const bool &value, const std::string &name)
50+
{
51+
m_button_names.push_back(name);
52+
}
53+
54+
void DebugWriter::append_header(const int16_t &value, const std::string &name)
55+
{
56+
m_axis_names.push_back(name);
57+
}
58+
59+
void DebugWriter::append_header(const int64_t &value, const std::string &name)
60+
{
61+
// Time column - ignore
62+
}
63+
64+
void DebugWriter::append_row(const bool &value)
65+
{
66+
if (m_current_button_idx < m_prev_button_states.size()) {
67+
bool prev = m_prev_button_states[m_current_button_idx];
68+
if (value != prev) {
69+
const char *action = value ? "PRESSED" : "RELEASED";
70+
obs_log(LOG_INFO, "[DebugWriter] %s %s", m_button_names[m_current_button_idx].c_str(), action);
71+
m_prev_button_states[m_current_button_idx] = value;
72+
}
73+
}
74+
m_current_button_idx++;
75+
}
76+
77+
void DebugWriter::append_row(const int16_t &value)
78+
{
79+
// Optionally log significant axis changes
80+
if (m_current_axis_idx < m_prev_axis_values.size()) {
81+
int16_t prev = m_prev_axis_values[m_current_axis_idx];
82+
int16_t diff = value - prev;
83+
if (diff > 5000 || diff < -5000) {
84+
obs_log(LOG_INFO, "[DebugWriter] %s = %d",
85+
m_axis_names[m_current_axis_idx].c_str(), value);
86+
m_prev_axis_values[m_current_axis_idx] = value;
87+
}
88+
}
89+
m_current_axis_idx++;
90+
}
91+
92+
void DebugWriter::append_row(const int64_t &value)
93+
{
94+
// Time value - ignore
95+
}

src/writer/debug.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#pragma once
2+
#include "input_writer.hpp"
3+
#include <vector>
4+
#include <string>
5+
6+
class DebugWriter : public InputWriter {
7+
private:
8+
std::vector<std::string> m_button_names;
9+
std::vector<bool> m_prev_button_states;
10+
std::vector<std::string> m_axis_names;
11+
std::vector<int16_t> m_prev_axis_values;
12+
size_t m_current_button_idx;
13+
size_t m_current_axis_idx;
14+
15+
public:
16+
DebugWriter(std::unique_ptr<InputDevice> device);
17+
18+
void prepare_recording() override;
19+
void close_recording(std::string recording_path) override;
20+
21+
void begin_header() override;
22+
void end_header() override;
23+
void begin_row() override;
24+
void end_row() override;
25+
26+
void append_header(const bool &value, const std::string &name) override;
27+
void append_header(const int16_t &value, const std::string &name) override;
28+
void append_header(const int64_t &value, const std::string &name) override;
29+
30+
void append_row(const bool &value) override;
31+
void append_row(const int16_t &value) override;
32+
void append_row(const int64_t &value) override;
33+
};

0 commit comments

Comments
 (0)