Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add screen recorder as a tool (Not for game footage) #1299

Merged
merged 31 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4c46656
Initial commit
XK9274 Nov 29, 2023
aa86e95
Various, see comment
XK9274 Nov 30, 2023
b01ce69
Various, see comment
XK9274 Nov 30, 2023
f13673f
Update menu items
XK9274 Nov 30, 2023
5bf5fa1
Improved pulse logic
XK9274 Nov 30, 2023
1d0c521
Chill the buffer out, it's only 480.
XK9274 Dec 1, 2023
84be619
Speed up pulse
XK9274 Dec 1, 2023
cd94e4f
Submenu name
XK9274 Dec 1, 2023
9eeae99
🎨 apply clang-format changes
XK9274 Dec 1, 2023
f8a9069
add rumble logic
XK9274 Dec 2, 2023
4707164
Rumble once if countdown disabled
XK9274 Dec 2, 2023
c8c82d6
Adjust timings
XK9274 Dec 2, 2023
aa183a7
Various
XK9274 Dec 2, 2023
838c276
Not required
XK9274 Dec 3, 2023
4c459ae
Merge branch 'main' into feat-add-screen-recorder
XK9274 Dec 12, 2023
393a421
🎨 apply clang-format changes
XK9274 Dec 12, 2023
65008b8
update pulse count for ending
XK9274 Dec 13, 2023
a899da3
Add confirm dialog to delete recordings menu item
XK9274 Dec 13, 2023
a90f759
🎨 apply clang-format changes
XK9274 Dec 13, 2023
684231b
Only delete recordings
XK9274 Dec 13, 2023
1a6e2f7
Merge branch 'feat-add-screen-recorder' of https://github.com/OnionUI…
XK9274 Dec 13, 2023
953f181
Add custom countdown values
XK9274 Dec 14, 2023
8499aab
Fix pulsing when stopping
XK9274 Dec 14, 2023
4849f1f
Various
XK9274 Dec 14, 2023
f459670
Fix bugs
XK9274 Dec 14, 2023
7c95fe1
Add small vibration on recording start
schmurtzm Dec 14, 2023
a8a56af
Merge branch 'main' of https://github.com/OnionUI/Onion into feat-add…
schmurtzm Dec 14, 2023
404a366
🎨 apply clang-format changes
schmurtzm Dec 14, 2023
5cf461a
Merge branch 'main' into feat-add-screen-recorder
schmurtzm Dec 14, 2023
758ba5a
Merge branch 'main' into feat-add-screen-recorder
schmurtzm Dec 14, 2023
3b92c99
Fix merge
schmurtzm Dec 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/common/system/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define HISTORY_PATH \
"/mnt/SDCARD/Saves/CurrentProfile/lists/content_history.lpl"
#define DEFAULT_THEME_PATH "/mnt/SDCARD/Themes/Silky by DiMo/"
#define RECORDED_DIR "/mnt/SDCARD/Media/Videos/Recorded"

typedef struct settings_s {
int volume;
Expand Down Expand Up @@ -52,6 +53,9 @@ typedef struct settings_s {
bool disable_standby;
int pwmfrequency;
bool enable_logging;
bool rec_indicator;
bool rec_hotkey;
int rec_countdown;
int blue_light_state;
int blue_light_level;
int blue_light_rgb;
Expand Down Expand Up @@ -109,7 +113,11 @@ static settings_s __default_settings = (settings_s){
.blue_light_time_off = "08:00",
.pwmfrequency = 7,
.mainui_button_x = "",
.mainui_button_y = ""};
.mainui_button_y = "",
//utility
.rec_countdown = false,
.rec_indicator = false,
.rec_hotkey = false};

void _settings_clone(settings_s *dst, settings_s *src)
{
Expand Down Expand Up @@ -186,6 +194,8 @@ void settings_load(void)
settings.mute = config_flag_get(".muteVolume");
settings.disable_standby = config_flag_get(".disableStandby");
settings.enable_logging = config_flag_get(".logging");
settings.rec_indicator = config_flag_get(".recIndicator");
settings.rec_hotkey = config_flag_get(".recHotkey");
settings.blue_light_state = config_flag_get(".blf");

if (config_flag_get(".noLowBatteryAutoSave")) // flag is deprecated, but keep compatibility
Expand All @@ -208,6 +218,7 @@ void settings_load(void)
config_get("display/blueLightTimeOff", CONFIG_STR, &settings.blue_light_time_off);
config_get("display/blueLightRGB", CONFIG_INT, &settings.blue_light_rgb);
config_get("pwmfrequency", CONFIG_INT, &settings.pwmfrequency);
config_get("recCountdown", CONFIG_INT, &settings.rec_countdown);

if (config_flag_get(".menuInverted")) { // flag is deprecated, but keep compatibility
settings.ingame_single_press = 2;
Expand Down Expand Up @@ -322,13 +333,16 @@ void settings_save(void)
config_flag_set(".muteVolume", settings.mute);
config_flag_set(".disableStandby", settings.disable_standby);
config_flag_set(".logging", settings.enable_logging);
config_flag_set(".recIndicator", settings.rec_indicator);
config_flag_set(".recHotkey", settings.rec_hotkey);
config_flag_set(".blf", settings.blue_light_state);
config_setNumber("battery/warnAt", settings.low_battery_warn_at);
config_setNumber("battery/exitAt", settings.low_battery_autosave_at);
config_setNumber("startup/app", settings.startup_application);
config_setNumber("startup/addHours", settings.time_skip);
config_setNumber("vibration", settings.vibration);
config_setNumber("startup/tab", settings.startup_tab);
config_setNumber("recCountdown", settings.rec_countdown);
config_setNumber("display/blueLightLevel", settings.blue_light_level);
config_setNumber("display/blueLightRGB", settings.blue_light_rgb);
config_setString("display/blueLightTime", settings.blue_light_time);
Expand Down
33 changes: 33 additions & 0 deletions src/common/utils/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,36 @@ FILE *file_open_ensure_path(const char *path, const char *mode)
free(_path);
return fopen(path, mode);
}

bool file_findNewest(const char *dir_path, char *newest_file, size_t buffer_size)
{
DIR *d;
struct dirent *dir;
struct stat file_stat;
time_t newest_mtime = 0;

d = opendir(dir_path);
if (d == NULL) {
return false;
}

bool found = false;
while ((dir = readdir(d)) != NULL) {
if (dir->d_type == DT_REG) {
char full_path[PATH_MAX];
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, dir->d_name);

if (stat(full_path, &file_stat) == 0) {
if (!found || file_stat.st_mtime > newest_mtime) {
newest_mtime = file_stat.st_mtime;
strncpy(newest_file, dir->d_name, buffer_size);
newest_file[buffer_size - 1] = '\0';
found = true;
}
}
}
}

closedir(d);
return found;
}
2 changes: 2 additions & 0 deletions src/common/utils/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ void file_changeKeyValue(const char *file_path, const char *key,

bool file_path_relative_to(char *path_out, const char *path_from, const char *path_to);

bool file_findNewest(const char *dir_path, char *newest_file, size_t buffer_size);

FILE *file_open_ensure_path(const char *path, const char *mode);

#endif // UTILS_FILE_H__
32 changes: 32 additions & 0 deletions src/keymon/keymon.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ int main(void)
int konamiCodeIndex = 0;
bool b_BTN_Not_Menu_Pressed = false;
bool b_BTN_Menu_Pressed = false;
bool a_Pressed = false;
bool power_pressed = false;
bool volUp_state = false;
bool volUp_active = false;
Expand All @@ -356,6 +357,8 @@ int main(void)
bool comboKey_volume = false;
bool comboKey_menu = false;
bool comboKey_select = false;
bool menuAndAPressed = false;
int menuAndAPressedTime = 0;

int ticks = getMilliseconds();
int hibernate_start = ticks;
Expand Down Expand Up @@ -548,6 +551,15 @@ int main(void)
break;
case HW_BTN_MENU:
if (!temp_flag_get("disable_menu_button")) {
if (val == PRESSED) {
if (a_Pressed) {
menuAndAPressed = true;
menuAndAPressedTime = getMilliseconds();
}
}
else if (val == RELEASED) {
menuAndAPressed = false;
}
system_state_update();
comboKey_menu = menuButtonAction(val, comboKey_menu);
}
Expand All @@ -563,6 +575,18 @@ int main(void)
applyExtraButtonShortcut(1);
break;
case HW_BTN_A:
if (val == PRESSED) {
a_Pressed = true;
if (b_BTN_Menu_Pressed) {
menuAndAPressed = true;
menuAndAPressedTime = getMilliseconds();
}
}
else if (val == RELEASED) {
a_Pressed = false;
menuAndAPressed = false;
}
break;
case HW_BTN_B:
if (val == PRESSED && system_state == MODE_MAIN_UI)
temp_flag_set("launch_alt", false);
Expand Down Expand Up @@ -654,6 +678,14 @@ int main(void)
break;
}

// start screen recording after holding for >2secs
if (menuAndAPressed && (getMilliseconds() - menuAndAPressedTime >= 2000)) {
system("/mnt/SDCARD/.tmp_update/script/screen_recorder.sh toggle &");

menuAndAPressed = false;
menuAndAPressedTime = 0;
}

if (val == PRESSED && !osd_bar_activated) {
osd_hideBar();
}
Expand Down
59 changes: 59 additions & 0 deletions src/tweaks/actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "./appstate.h"
#include "./diags.h"
#include "./reset.h"
#include "./values.h"

void action_setAppShortcut(void *pt)
Expand Down Expand Up @@ -375,6 +376,64 @@ void action_setAltBrightness(void *pt)
config_flag_set(".altBrightness", ((ListItem *)pt)->value);
}

void action_toggleScreenRecIndicator(void *pt)
{
config_flag_set(".recIndicator", ((ListItem *)pt)->value);
settings.rec_indicator = ((ListItem *)pt)->value == 1;
}

void action_toggleScreenRecCountdown(void *pt)
{
config_setNumber("recCountdown", ((ListItem *)pt)->value);
settings.rec_countdown = ((ListItem *)pt)->value;
}

void action_toggleScreenRecHotkey(void *pt)
{
config_flag_set(".recHotkey", ((ListItem *)pt)->value);
settings.rec_hotkey = ((ListItem *)pt)->value == 1;
}

void action_hardKillFFmpeg(void *pt)
{
ListItem *item = (ListItem *)pt;
int status = system("/mnt/SDCARD/.tmp_update/script/screen_recorder.sh hardkill");
if (status != 0) {
list_updateStickyNote(item, "Status: Error occurred.");
}
else {
list_updateStickyNote(item, "Status: FFmpeg process stopped");
}
list_changed = true;
}

void action_deleteAllRecordings(void *pt)
{
ListItem *item = (ListItem *)pt;
int fileCheck;
fileCheck = exists("/tmp/recorder_active");

if (fileCheck) {
if (!_disable_confirm && !_confirmReset("Recording!", "You're still recording!\nAre you sure you want to\ndelete all recordings?")) {
return;
} else {
system("/mnt/SDCARD/.tmp_update/script/screen_recorder.sh hardkill &");
strncpy(_menu_screen_recorder.items[0].sticky_note, "Status: Idle.", sizeof(_menu_screen_recorder.items[0].sticky_note) - 1);
_menu_screen_recorder.items[0].sticky_note[sizeof(_menu_screen_recorder.items[0].sticky_note) - 1] = '\0';
}
} else {
if (!_disable_confirm && !_confirmReset("Delete?", "Are you sure you want to\ndelete all recordings?")) {
list_updateStickyNote(item, "Cancelled");
return;
}
}

system("rm -f /mnt/SDCARD/Media/Videos/Recorded/*.mp4");
list_updateStickyNote(item, "Recorded directory emptied!");
if (!_disable_confirm)
_notifyResetDone("Deleted!");
}

void action_advancedSetLcdVoltage(void *pt)
{
int value = 0x0e - ((ListItem *)pt)->value;
Expand Down
4 changes: 3 additions & 1 deletion src/tweaks/appstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ static List _menu_main;
static List _menu_system;
static List _menu_date_time;
static List _menu_system_display;
static List _menu_user_blue_light;
static List _menu_system_startup;
static List _menu_button_action;
static List _menu_button_action_mainui_menu;
Expand All @@ -70,6 +69,8 @@ static List _menu_reset_settings;
static List _menu_tools;
static List _menu_tools_m3uGenerator;
static List _menu_diagnostics;
static List _menu_screen_recorder;
static List _menu_user_blue_light;

void menu_free_all(void)
{
Expand All @@ -89,6 +90,7 @@ void menu_free_all(void)
list_free(&_menu_tools);
list_free(&_menu_tools_m3uGenerator);
list_free(&_menu_diagnostics);
list_free(&_menu_screen_recorder);
list_free(&_menu_user_blue_light);

menu_icons_free_all();
Expand Down
71 changes: 71 additions & 0 deletions src/tweaks/menus.h
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,73 @@ void menu_advanced(void *_)
header_changed = true;
}

void menu_screen_recorder(void *pt)
{
if (!_menu_screen_recorder._created) {
_menu_screen_recorder = list_createWithSticky(7, "Screen recorder setup");
list_addItemWithInfoNote(&_menu_screen_recorder,
(ListItem){
.label = "Start/stop recorder",
.sticky_note = "Status:...",
.action = tool_screenRecorder},
"Start or stop the recorder");
list_addItemWithInfoNote(&_menu_screen_recorder,
(ListItem){
.label = "Countdown (seconds)",
.sticky_note = "Specify the countdown",
.item_type = MULTIVALUE,
.value_max = 10,
.value = (int)settings.rec_countdown,
.action = action_toggleScreenRecCountdown},
"Countdown when starting recording. \n\n"
"The screen will pulse white n times \n"
"to signify recording has started/stopped");
list_addItemWithInfoNote(&_menu_screen_recorder,
(ListItem){
.label = "Toggle indicator icon",
.sticky_note = "Turn the indicator on/off",
.item_type = TOGGLE,
.value = (int)settings.rec_indicator,
.action = action_toggleScreenRecIndicator},
"Toggles the display of a\n"
"a flashing icon to remind you\n"
"that you're still recording.");
list_addItemWithInfoNote(&_menu_screen_recorder,
(ListItem){
.label = "Toggle hotkey",
.sticky_note = "Turn the hotkey (Menu+A) on/off ",
.item_type = TOGGLE,
.value = (int)settings.rec_hotkey,
.action = action_toggleScreenRecHotkey},
"Enable the hotkey function.\n\n"
"Recording can be started/stopped\n"
"with Menu+A");
list_addItemWithInfoNote(&_menu_screen_recorder,
(ListItem){
.label = "Reset screen recorder",
.sticky_note = "Hard kill ffmpeg if it's crashed",
.action = action_hardKillFFmpeg},
"Performs a hard kill of ffmpeg.\n\n"
"WARNING: If you're currently\n"
"recording, you may lose the file!");
list_addItemWithInfoNote(&_menu_screen_recorder,
(ListItem){
.label = "Delete all recordings",
.sticky_note = "Empties the recordings directory",
.action = action_deleteAllRecordings},
"Deletes all recorded videos. \n\n"
"WARNING: This action cannot\n"
"be undone!");
}

int isRecordingActive = exists("/tmp/recorder_active");
const char *recordingStatus = isRecordingActive ? "Status: Now recording..." : "Status: Idle.";
strncpy(_menu_screen_recorder.items[0].sticky_note, recordingStatus, sizeof(_menu_screen_recorder.items[0].sticky_note) - 1);
_menu_screen_recorder.items[0].sticky_note[sizeof(_menu_screen_recorder.items[0].sticky_note) - 1] = '\0';
menu_stack[++menu_level] = &_menu_screen_recorder;
header_changed = true;
}

void menu_tools_m3uGenerator(void *_)
{
if (!_menu_tools_m3uGenerator._created) {
Expand Down Expand Up @@ -802,6 +869,10 @@ void menu_tools(void *_)
"This generates a 'miyoogamelist.xml' file\n"
"which comes with some limitations, such\n"
"as no subfolder support.");
list_addItem(&_menu_tools,
(ListItem){
.label = "Screen recorder...",
.action = menu_screen_recorder});
list_addItemWithInfoNote(&_menu_tools,
(ListItem){
.label = "Sort applist A-Z",
Expand Down
28 changes: 28 additions & 0 deletions src/tweaks/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,34 @@ void tool_sortAppsZA(void *pt)
_runCommandPopup(tools_short_names[4], "/mnt/SDCARD/.tmp_update/script/app_sorter.sh desc");
}

void tool_screenRecorder(void *pt)
{
ListItem *item = (ListItem *)pt;
char cmd[STR_MAX];
char newestFile[STR_MAX / 2];
snprintf(cmd, sizeof(cmd), "/mnt/SDCARD/.tmp_update/script/screen_recorder.sh toggle &");
int fileCheck;
fileCheck = exists("/tmp/recorder_active");

if (!fileCheck) {
list_updateStickyNote(item, "Status: Now recording...");
system(cmd);
}
else {
if (file_findNewest(RECORDED_DIR, newestFile, sizeof(newestFile))) {
char note[STR_MAX];
system(cmd);
snprintf(note, sizeof(note), "Stopped, saved as: %s", newestFile);
list_updateStickyNote(item, note);
}
else {
list_updateStickyNote(item, "Status: Recording ended, no new file found.");
snprintf(cmd, sizeof(cmd), "/mnt/SDCARD/.tmp_update/script/screen_recorder.sh hardkill &");
}
}
list_changed = true;
}

static void (*tools_pt[NUM_TOOLS])(void *) = {
tool_generateCueFiles,
tool_generateM3uFiles_sd,
Expand Down