Skip to content

Commit

Permalink
refactor tested
Browse files Browse the repository at this point in the history
  • Loading branch information
loicmagne committed Dec 31, 2024
1 parent 9a51ea3 commit 75716e1
Show file tree
Hide file tree
Showing 17 changed files with 573 additions and 530 deletions.
16 changes: 8 additions & 8 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: false
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
Expand Down Expand Up @@ -115,10 +115,10 @@ AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
AllowShortBlocksOnASingleLine: Never
AllowShortBlocksOnASingleLine: true
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortIfStatementsOnASingleLine: true
AllowShortLambdasOnASingleLine: None
AttributeMacros: ['__unused', '__autoreleasing', '_Nonnull', '__bridge']
BitFieldColonSpacing: Both
Expand Down
14 changes: 6 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,14 @@ if(ENABLE_QT)
AUTORCC ON)
endif()

set(SOURCES
src/main.cpp
src/input_source.cpp
src/utils.cpp
)
target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${SOURCES})

# Include SDL3 headers
file(GLOB_RECURSE SOURCES "src/*.cpp")
file(GLOB_RECURSE HEADERS "src/*.hpp")

set_target_properties_plugin(${CMAKE_PROJECT_NAME} PROPERTIES OUTPUT_NAME ${_name})
target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${SOURCES} ${HEADERS})
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)

# Add third-party dependencies
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE SDL3::SDL3)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE DuckDB::duckdb)

Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ configure:
cmake --preset linux-x86_64 -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu

build:
cmake --preset linux-x86_64 -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu
cmake --build --preset linux-x86_64

# Build the project
Expand Down
63 changes: 37 additions & 26 deletions irec/aligner.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ def viz(
Run the video and display the inputs at the bottom of the screen
Pressing 'q' will exit the video
Pressing space will pause the video
Pressing 'j' will go back 1 frame
Pressing 'k' will go forward 1 frame
Pressing 'l' will go forward 10 frames
Pressing 'h' will go back 10 frames
When paused:
'j' will go back 1 frame
'k' will go forward 1 frame
'l' will go forward 10 frames
'h' will go back 10 frames
"""

# Load video
Expand All @@ -87,27 +88,35 @@ def viz(
df = pl.read_parquet(path_inputs)

N = df.shape[0]

# Store frames in memory for backward seeking
frames = []
current_frame = 0
paused = False

def get_frame(cap, frame_number):
"""Get the current frame of the video capture"""
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)
ret, frame = cap.read()
if not ret:
print("Failed to retrieve frame.")
return None
return frame

while cap.isOpened():
frame = get_frame(cap, current_frame)
frame_data = df.row(current_frame, named=True)
if frame is None:
def read_up_to_frame(target_frame):
"""Read frames sequentially until reaching target_frame"""
nonlocal frames
while len(frames) <= target_frame:
ret, frame = cap.read()
if not ret:
return False
frames.append(frame)
return True

while True:
# Ensure we have the current frame
if not read_up_to_frame(current_frame):
break

frame = frames[current_frame]
frame_data = df.row(current_frame, named=True)

if current_frame < offset:
current_frame = offset
continue

# Resize and create display frame
frame = cv2.resize(frame, (800, 600))
new_width = frame.shape[1] + 200
frame_show = np.zeros((frame.shape[0], new_width, 3), dtype=np.uint8)
Expand All @@ -133,16 +142,18 @@ def get_frame(cap, frame_number):
break
elif key == ord(" "):
paused = not paused
elif key == ord("j") and current_frame > 0:
current_frame -= 1
elif key == ord("k") and current_frame < N - 1:
current_frame += 1
elif key == ord("l") and current_frame < N - 10:
current_frame += 10
elif key == ord("h") and current_frame > 9:
current_frame -= 10

if not paused:
# Only allow frame navigation when paused
if paused:
if key == ord("j") and current_frame > 0:
current_frame -= 1
elif key == ord("k") and current_frame < N - 1:
current_frame += 1
elif key == ord("l") and current_frame < N - 10:
current_frame += 10
elif key == ord("h") and current_frame > 9:
current_frame -= 10
elif not paused:
current_frame += 1

# Cleanup
Expand Down
208 changes: 208 additions & 0 deletions src/device/gamepad.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
#include "gamepad.hpp"
#include <iostream>
#include <string>

constexpr int16_t AXIS_DEADZONE = 0;

std::string axis_to_string(SDL_GamepadAxis axis)
{
switch (axis) {
case SDL_GAMEPAD_AXIS_LEFTX: return "LEFTX";
case SDL_GAMEPAD_AXIS_LEFTY: return "LEFTY";
case SDL_GAMEPAD_AXIS_RIGHTX: return "RIGHTX";
case SDL_GAMEPAD_AXIS_RIGHTY: return "RIGHTY";
case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: return "LEFT_TRIGGER";
case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: return "RIGHT_TRIGGER";
default: return "UNKNOWN";
}
}

std::string button_to_string(SDL_GamepadButton button)
{
switch (button) {
case SDL_GAMEPAD_BUTTON_SOUTH: return "SOUTH";
case SDL_GAMEPAD_BUTTON_EAST: return "EAST";
case SDL_GAMEPAD_BUTTON_WEST: return "WEST";
case SDL_GAMEPAD_BUTTON_NORTH: return "NORTH";
case SDL_GAMEPAD_BUTTON_BACK: return "BACK";
case SDL_GAMEPAD_BUTTON_GUIDE: return "GUIDE";
case SDL_GAMEPAD_BUTTON_START: return "START";
case SDL_GAMEPAD_BUTTON_LEFT_STICK: return "LEFT_STICK";
case SDL_GAMEPAD_BUTTON_RIGHT_STICK: return "RIGHT_STICK";
case SDL_GAMEPAD_BUTTON_LEFT_SHOULDER: return "LEFT_SHOULDER";
case SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER: return "RIGHT_SHOULDER";
case SDL_GAMEPAD_BUTTON_DPAD_UP: return "DPAD_UP";
case SDL_GAMEPAD_BUTTON_DPAD_DOWN: return "DPAD_DOWN";
case SDL_GAMEPAD_BUTTON_DPAD_LEFT: return "DPAD_LEFT";
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: return "DPAD_RIGHT";
case SDL_GAMEPAD_BUTTON_MISC1: return "MISC1";
case SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1: return "RIGHT_PADDLE1";
case SDL_GAMEPAD_BUTTON_LEFT_PADDLE1: return "LEFT_PADDLE1";
case SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2: return "RIGHT_PADDLE2";
case SDL_GAMEPAD_BUTTON_LEFT_PADDLE2: return "LEFT_PADDLE2";
case SDL_GAMEPAD_BUTTON_TOUCHPAD: return "TOUCHPAD";
case SDL_GAMEPAD_BUTTON_MISC2: return "MISC2";
case SDL_GAMEPAD_BUTTON_MISC3: return "MISC3";
case SDL_GAMEPAD_BUTTON_MISC4: return "MISC4";
case SDL_GAMEPAD_BUTTON_MISC5: return "MISC5";
case SDL_GAMEPAD_BUTTON_MISC6: return "MISC6";
case SDL_GAMEPAD_BUTTON_COUNT: return "MAX";
default: return "UNKNOWN";
}
}

void GamepadDevice::add_gamepad(SDL_JoystickID joystickid)
{
SDL_Gamepad *gamepad = SDL_OpenGamepad(joystickid);
if (gamepad) {
m_gamepads.push_back(gamepad);
} else {
std::cerr << "Failed to open gamepad: " << SDL_GetError() << std::endl;
}
}

void GamepadDevice::remove_gamepad(SDL_JoystickID joystickid)
{
int i = get_gamepad_idx(joystickid);
if (m_gamepads[i]) {
SDL_CloseGamepad(m_gamepads[i]);
m_gamepads[i] = nullptr;
}
}

int GamepadDevice::get_gamepad_idx(SDL_JoystickID joystickid)
{
for (size_t i = 0; i < m_gamepads.size(); ++i) {
if (m_gamepads[i]) {
SDL_Joystick *joystick = SDL_GetGamepadJoystick(m_gamepads[i]);
if (joystick && SDL_GetJoystickID(joystick) == joystickid) { return static_cast<int>(i); }
}
}
return -1;
}

SDL_Gamepad *GamepadDevice::active_gamepad()
{
for (auto gamepad : m_gamepads) {
if (gamepad) { return gamepad; }
}
return nullptr;
}

GamepadDevice::GamepadDevice()
{
/* Init SDL, see SDL/test/testcontroller.c */
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_ROG_CHAKRAM, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_LINUX_DEADZONES, "1");

/* Enable input debug logging */
SDL_SetLogPriority(SDL_LOG_CATEGORY_INPUT, SDL_LOG_PRIORITY_DEBUG);
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
return;
}

SDL_AddGamepadMappingsFromFile("gamecontrollerdb.txt");

#ifdef DEBUG
int count = 0;
char **mappings = SDL_GetGamepadMappings(&count);
int map_i;
SDL_Log("Supported mappings:\n");
for (map_i = 0; map_i < count; ++map_i) { SDL_Log("\t%s\n", mappings[map_i]); }
SDL_Log("\n");
SDL_free(mappings);
#endif

/* The following delay is necessary to avoid a crash on Linux
The crash occurs in a particular setting, on Ubuntu:
- if the gamepad is connected to the computer before obs is launched
- if the obs instance has input-overlay and input-rec installed
- if the obs instance has one source for both input-overlay and input-rec
Then opening OBS will segfault. The issue seems to be about SDL initialization
and gamepad detection. A delay >1.5s avoid the crash.
I don't think the issue comes from input-rec, because this crash has been
reported on the input-overlay repo: https://github.com/univrsal/input-overlay/issues/426
The issue also occurs when using the obs input-overlay plugin only, without input-rec.
*/
std::this_thread::sleep_for(std::chrono::milliseconds(2000));

// Init gamepads
int count = 0;
SDL_JoystickID *joystick_ids = SDL_GetGamepads(&count);
if (joystick_ids) {
for (int i = 0; i < count; ++i) {
add_gamepad(joystick_ids[i]);
std::cout << "Gamepad added: " << joystick_ids[i] << std::endl;
}
SDL_free(joystick_ids);
} else {
std::cerr << "Failed to get gamepads: " << SDL_GetError() << std::endl;
}
}

GamepadDevice::~GamepadDevice()
{
for (auto gamepad : m_gamepads) { SDL_CloseGamepad(gamepad); }
SDL_Quit();
}

void GamepadDevice::write_header(InputWriter &writer)
{
writer.begin_header();
for (int i = 0; i < SDL_GAMEPAD_BUTTON_TOUCHPAD; ++i)
writer.append_header(false, button_to_string((SDL_GamepadButton)i));
for (int i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i)
writer.append_header(static_cast<int16_t>(0), axis_to_string((SDL_GamepadAxis)i));
writer.end_header();
}

void GamepadDevice::write_state(InputWriter &writer)
{
SDL_Gamepad *gamepad = active_gamepad();
if (gamepad) {
writer.begin_row();
for (int i = 0; i < SDL_GAMEPAD_BUTTON_TOUCHPAD; ++i) {
const SDL_GamepadButton button = (SDL_GamepadButton)i;
const bool pressed = SDL_GetGamepadButton(gamepad, button) == true;
writer.append_row(pressed);
}

for (int i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) {
const SDL_GamepadAxis axis = (SDL_GamepadAxis)i;
int16_t value = SDL_GetGamepadAxis(gamepad, axis);
// TODO: Use dead zone?
// value = (value < AXIS_DEADZONE && value > -AXIS_DEADZONE) ? 0 : value;
writer.append_row(value);
}
writer.end_row();
}
}

void GamepadDevice::loop(InputWriter &writer)
{
SDL_Event event;
SDL_PumpEvents();
while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) == 1) {
switch (event.type) {
case SDL_EVENT_GAMEPAD_ADDED:
add_gamepad(event.gdevice.which);
std::cout << "Gamepad added" << std::endl;
break;
case SDL_EVENT_GAMEPAD_REMOVED:
remove_gamepad(event.gdevice.which);
std::cout << "Gamepad removed" << std::endl;
break;
default: break;
}
}
write_state(writer);
// TODO: delay should be handled by the writer, not the device
SDL_Delay(2);
}
23 changes: 23 additions & 0 deletions src/device/gamepad.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once
#include <vector>
#include <SDL3/SDL.h>
#include "input_device.hpp"
#include "writer/input_writer.hpp"

class GamepadDevice : public InputDevice {
private:
std::vector<SDL_Gamepad *> m_gamepads;

void add_gamepad(SDL_JoystickID joystickid);
void remove_gamepad(SDL_JoystickID joystickid);
int get_gamepad_idx(SDL_JoystickID joystickid);
SDL_Gamepad *active_gamepad();

public:
GamepadDevice();
~GamepadDevice() override;

void write_header(InputWriter &writer) override;
void write_state(InputWriter &writer) override;
void loop(InputWriter &writer) override;
};
Loading

0 comments on commit 75716e1

Please sign in to comment.