Add AVRecorder movie mode

This commit is contained in:
James R 2023-02-12 05:17:34 -08:00
parent 79b1a8fd63
commit c65f4ff893
7 changed files with 76 additions and 3 deletions

View file

@ -62,6 +62,7 @@
#include "deh_tables.h"
#include "m_perfstats.h"
#include "k_specialstage.h"
#include "m_avrecorder.h"
#ifdef HAVE_DISCORDRPC
#include "discord.h"
@ -903,6 +904,7 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_moviemode);
CV_RegisterVar(&cv_movie_option);
CV_RegisterVar(&cv_movie_folder);
M_AVRecorder_AddCommands();
// PNG variables
CV_RegisterVar(&cv_zlib_level);
CV_RegisterVar(&cv_zlib_memory);

View file

@ -185,6 +185,18 @@ void M_AVRecorder_Close(void)
g_av_recorder.reset();
}
const char* M_AVRecorder_GetFileExtension(void)
{
return AVRecorder::file_extension();
}
const char* M_AVRecorder_GetCurrentFormat(void)
{
SRB2_ASSERT(g_av_recorder != nullptr);
return g_av_recorder->format_name();
}
boolean M_AVRecorder_IsExpired(void)
{
SRB2_ASSERT(g_av_recorder != nullptr);

View file

@ -18,6 +18,8 @@ extern "C" {
void M_AVRecorder_AddCommands(void);
const char *M_AVRecorder_GetFileExtension(void);
// True if successully opened.
boolean M_AVRecorder_Open(const char *filename);
@ -26,6 +28,8 @@ void M_AVRecorder_Close(void);
// Check whether AVRecorder is still valid. Call M_AVRecorder_Close if expired.
boolean M_AVRecorder_IsExpired(void);
const char *M_AVRecorder_GetCurrentFormat(void);
extern consvar_t
cv_movie_custom_resolution,
cv_movie_duration,

View file

@ -44,6 +44,7 @@
#include "command.h" // cv_execversion
#include "m_anigif.h"
#include "m_avrecorder.h"
// So that the screenshot menu auto-updates...
#include "k_menu.h"
@ -113,8 +114,8 @@ consvar_t cv_screenshot_folder = CVAR_INIT ("screenshot_folder", "", CV_SAVE, NU
consvar_t cv_screenshot_colorprofile = CVAR_INIT ("screenshot_colorprofile", "Yes", CV_SAVE, CV_YesNo, NULL);
static CV_PossibleValue_t moviemode_cons_t[] = {{MM_GIF, "GIF"}, {MM_APNG, "aPNG"}, {MM_SCREENSHOT, "Screenshots"}, {0, NULL}};
consvar_t cv_moviemode = CVAR_INIT ("moviemode_mode", "GIF", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange);
static CV_PossibleValue_t moviemode_cons_t[] = {{MM_GIF, "GIF"}, {MM_APNG, "aPNG"}, {MM_SCREENSHOT, "Screenshots"}, {MM_AVRECORDER, "WebM"}, {0, NULL}};
consvar_t cv_moviemode = CVAR_INIT ("moviemode_mode", "WebM", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange);
consvar_t cv_movie_option = CVAR_INIT ("movie_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Moviemode_option_Onchange);
consvar_t cv_movie_folder = CVAR_INIT ("movie_folder", "", CV_SAVE, NULL, NULL);
@ -1295,6 +1296,25 @@ static inline moviemode_t M_StartMovieGIF(const char *pathname)
}
#endif
static inline moviemode_t M_StartMovieAVRecorder(const char *pathname)
{
const char *ext = M_AVRecorder_GetFileExtension();
const char *freename;
if (!(freename = Newsnapshotfile(pathname, ext)))
{
CONS_Alert(CONS_ERROR, "Couldn't create %s file: no slots open in %s\n", ext, pathname);
return MM_OFF;
}
if (!M_AVRecorder_Open(va(pandf,pathname,freename)))
{
return MM_OFF;
}
return MM_AVRECORDER;
}
void M_StartMovie(void)
{
#if NUMSCREENS > 2
@ -1332,6 +1352,9 @@ void M_StartMovie(void)
case MM_SCREENSHOT:
moviemode = MM_SCREENSHOT;
break;
case MM_AVRECORDER:
moviemode = M_StartMovieAVRecorder(pathname);
break;
default: //???
return;
}
@ -1342,6 +1365,8 @@ void M_StartMovie(void)
CONS_Printf(M_GetText("Movie mode enabled (%s).\n"), "GIF");
else if (moviemode == MM_SCREENSHOT)
CONS_Printf(M_GetText("Movie mode enabled (%s).\n"), "screenshots");
else if (moviemode == MM_AVRECORDER)
CONS_Printf(M_GetText("Movie mode enabled (%s).\n"), M_AVRecorder_GetCurrentFormat());
//singletics = (moviemode != MM_OFF);
#endif
@ -1353,6 +1378,15 @@ void M_SaveFrame(void)
// paranoia: should be unnecessary without singletics
static tic_t oldtic = 0;
if (moviemode == MM_AVRECORDER)
{
if (M_AVRecorder_IsExpired())
{
M_StopMovie();
}
return;
}
if (oldtic == I_GetTime())
return;
else
@ -1440,6 +1474,9 @@ void M_StopMovie(void)
#endif
case MM_SCREENSHOT:
break;
case MM_AVRECORDER:
M_AVRecorder_Close();
break;
default:
return;
}

View file

@ -29,7 +29,8 @@ typedef enum {
MM_OFF = 0,
MM_APNG,
MM_GIF,
MM_SCREENSHOT
MM_SCREENSHOT,
MM_AVRECORDER,
} moviemode_t;
extern moviemode_t moviemode;

View file

@ -170,6 +170,11 @@ void Impl::worker()
valid_ = false;
}
const char* AVRecorder::file_extension()
{
return "webm";
}
AVRecorder::AVRecorder(const Config config) : impl_(std::make_unique<Impl>(config))
{
}
@ -186,6 +191,11 @@ AVRecorder::~AVRecorder()
std::thread([_ = std::move(impl_)] {}).detach();
}
const char* AVRecorder::format_name() const
{
return impl_->container_->name();
}
void AVRecorder::push_audio_samples(audio_buffer_t buffer)
{
const auto _ = impl_->queue_guard();

View file

@ -57,11 +57,18 @@ public:
std::optional<Video> video;
};
// Returns the canonical file extension minus the dot.
// E.g. "webm" (not ".webm").
static const char* file_extension();
AVRecorder(Config config);
~AVRecorder();
void push_audio_samples(audio_buffer_t buffer);
// Proper name of the container format.
const char* format_name() const;
// True if this instance has terminated. Continuing to use
// this interface is useless and the object should be
// destructed immediately.