Add API support for Replay Buffer

Closes https://github.com/jp9000/OBS/issues/374
master
palana 2014-09-01 04:56:54 +02:00
parent e8784e00c9
commit b3817488b4
10 changed files with 122 additions and 22 deletions

View File

@ -123,6 +123,10 @@ bool OBSGetRecording() {return API->GetRecording();}
bool OBSGetKeepRecording() {return API->GetKeepRecording();}
void OBSStartStopRecordingReplayBuffer() {API->StartStopRecordingReplayBuffer();}
bool OBSGetRecordingReplayBuffer() {return API->GetRecordingReplayBuffer();}
void OBSSaveReplayBuffer() {API->SaveReplayBuffer();}
void OBSSetSourceOrder(StringList &sourceNames) {API->SetSourceOrder(sourceNames);}
void OBSSetSourceRender(CTSTR lpSource, bool render) {API->SetSourceRender(lpSource, render);}
@ -151,6 +155,6 @@ void OBSGetCurMicVolumeStats(float *rms, float *max, float *peak) {API->Ge
void OBSAddSettingsPane(SettingsPane *pane) {API->AddSettingsPane(pane);}
void OBSRemoveSettingsPane(SettingsPane *pane) {API->RemoveSettingsPane(pane);}
UINT OBSGetAPIVersion() {return 0x0102;}
UINT OBSGetAPIVersion() {return 0x0103;}
UINT OBSGetSampleRateHz() {return API->GetSampleRateHz();}

View File

@ -189,6 +189,10 @@ public:
virtual UINT GetBytesPerSec() const=0;
virtual void SetCanOptimizeSettings(bool canOptimize) = 0;
virtual void StartStopRecordingReplayBuffer() = 0;
virtual bool GetRecordingReplayBuffer() const=0;
virtual void SaveReplayBuffer() = 0;
};
BASE_EXPORT extern APIInterface *API;
@ -266,6 +270,10 @@ BASE_EXPORT bool OBSGetRecording();
BASE_EXPORT bool OBSGetKeepRecording();
BASE_EXPORT void OBSStartStopRecordingReplayBuffer();
BASE_EXPORT bool OBSGetRecordingReplayBuffer();
BASE_EXPORT void OBSSaveReplayBuffer();
BASE_EXPORT void OBSSetSourceOrder(StringList &sourceNames);
BASE_EXPORT void OBSSetSourceRender(CTSTR lpSource, bool render);

View File

@ -440,6 +440,16 @@ public:
PostMessage(hwndMain, WM_COMMAND, MAKEWPARAM(ID_TOGGLERECORDING, 0), 0);
}
virtual void StartStopRecordingReplayBuffer() override
{
PostMessage(hwndMain, WM_COMMAND, MAKEWPARAM(ID_TOGGLERECORDINGREPLAYBUFFER, 0), 0);
}
virtual void SaveReplayBuffer() override
{
::SaveReplayBuffer(App->replayBuffer, (DWORD)(App->GetVideoTime() - App->firstFrameTimestamp));
}
virtual bool GetStreaming()
{
return App->bRunning;
@ -455,6 +465,11 @@ public:
return App->bRecording;
}
virtual bool GetRecordingReplayBuffer() const override
{
return App->bRecordingReplayBuffer;
}
virtual bool GetKeepRecording() const override
{
return App->bKeepRecording;

View File

@ -735,22 +735,25 @@ OBS::OBS()
pluginInfo->strFile = ofd.fileName;
/* get event callbacks for the plugin */
pluginInfo->startStreamCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartStream");
pluginInfo->stopStreamCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopStream");
pluginInfo->startStreamingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartStreaming");
pluginInfo->stopStreamingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopStreaming");
pluginInfo->startRecordingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartRecording");
pluginInfo->stopRecordingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopRecording");
pluginInfo->statusCallback = (OBS_STATUS_CALLBACK)GetProcAddress(hPlugin, "OnOBSStatus");
pluginInfo->streamStatusCallback = (OBS_STREAM_STATUS_CALLBACK)GetProcAddress(hPlugin, "OnStreamStatus");
pluginInfo->sceneSwitchCallback = (OBS_SCENE_SWITCH_CALLBACK)GetProcAddress(hPlugin, "OnSceneSwitch");
pluginInfo->scenesChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnScenesChanged");
pluginInfo->sourceOrderChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSourceOrderChanged");
pluginInfo->sourceChangedCallback = (OBS_SOURCE_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnSourceChanged");
pluginInfo->sourcesAddedOrRemovedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSourcesAddedOrRemoved");
pluginInfo->micVolumeChangeCallback = (OBS_VOLUME_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnMicVolumeChanged");
pluginInfo->desktopVolumeChangeCallback = (OBS_VOLUME_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnDesktopVolumeChanged");
pluginInfo->logUpdateCallback = (OBS_LOG_UPDATE_CALLBACK)GetProcAddress(hPlugin, "OnLogUpdate");
pluginInfo->startStreamCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartStream");
pluginInfo->stopStreamCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopStream");
pluginInfo->startStreamingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartStreaming");
pluginInfo->stopStreamingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopStreaming");
pluginInfo->startRecordingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartRecording");
pluginInfo->stopRecordingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopRecording");
pluginInfo->statusCallback = (OBS_STATUS_CALLBACK)GetProcAddress(hPlugin, "OnOBSStatus");
pluginInfo->streamStatusCallback = (OBS_STREAM_STATUS_CALLBACK)GetProcAddress(hPlugin, "OnStreamStatus");
pluginInfo->sceneSwitchCallback = (OBS_SCENE_SWITCH_CALLBACK)GetProcAddress(hPlugin, "OnSceneSwitch");
pluginInfo->scenesChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnScenesChanged");
pluginInfo->sourceOrderChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSourceOrderChanged");
pluginInfo->sourceChangedCallback = (OBS_SOURCE_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnSourceChanged");
pluginInfo->sourcesAddedOrRemovedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSourcesAddedOrRemoved");
pluginInfo->micVolumeChangeCallback = (OBS_VOLUME_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnMicVolumeChanged");
pluginInfo->desktopVolumeChangeCallback = (OBS_VOLUME_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnDesktopVolumeChanged");
pluginInfo->logUpdateCallback = (OBS_LOG_UPDATE_CALLBACK)GetProcAddress(hPlugin, "OnLogUpdate");
pluginInfo->startRecordingReplayBufferCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartRecordingReplayBuffer");
pluginInfo->stopRecordingReplayBufferCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopRecordingReplayBuffer");
pluginInfo->replayBufferSavedCallback = (OBS_REPLAY_BUFFER_SAVED_CALLBACK)GetProcAddress(hPlugin, "OnReplayBufferSaved");
//GETPLUGINNAMEPROC getName = (GETPLUGINNAMEPROC)GetProcAddress(hPlugin, "GetPluginName");

View File

@ -283,6 +283,7 @@ struct ClassInfo
/* Event callback signiture definitions */
typedef void (*OBS_CALLBACK)();
typedef void (*OBS_REPLAY_BUFFER_SAVED_CALLBACK)(CTSTR filename, UINT recordingLengthMS);
typedef void (*OBS_STATUS_CALLBACK)(bool /*running*/, bool /*streaming*/, bool /*recording*/,
bool /*previewing*/, bool /*reconnecting*/);
typedef void (*OBS_STREAM_STATUS_CALLBACK)(bool /*streaming*/, bool /*previewOnly*/,
@ -319,6 +320,15 @@ struct PluginInfo
/* called when recording (to file) stops */
OBS_CALLBACK stopRecordingCallback;
/* called when recording (to replay buffer) starts */
OBS_CALLBACK startRecordingReplayBufferCallback;
/* called when recording (to replay buffer) stops */
OBS_CALLBACK stopRecordingReplayBufferCallback;
/* called when replay buffer has been written to a file */
OBS_REPLAY_BUFFER_SAVED_CALLBACK replayBufferSavedCallback;
/* called when status bar is updated, even without network */
OBS_STATUS_CALLBACK statusCallback;
@ -364,6 +374,7 @@ struct GlobalSourceInfo
enum
{
ID_SETTINGS=5000,
ID_TOGGLERECORDINGREPLAYBUFFER,
ID_TOGGLERECORDING,
ID_STARTSTOP,
ID_EXIT,
@ -561,6 +572,7 @@ enum class SceneCollectionAction {
};
struct ReplayBuffer;
void SaveReplayBuffer(ReplayBuffer *out, DWORD timestamp);
//todo: this class has become way too big, it's horrible, and I should be ashamed of myself
class OBS
@ -1200,6 +1212,9 @@ public:
virtual void ReportStopStreamingTrigger();
virtual void ReportStartRecordingTrigger();
virtual void ReportStopRecordingTrigger();
virtual void ReportStartRecordingReplayBufferTrigger();
virtual void ReportStopRecordingReplayBufferTrigger();
virtual void ReportReplayBufferSavedTrigger(String filename, UINT recordingLengthMS);
virtual void ReportOBSStatus(bool running, bool streaming, bool recording,
bool previewing, bool reconnecting);
virtual void ReportStreamStatus(bool streaming, bool previewOnly = false,

View File

@ -104,6 +104,7 @@ void OBS::StartReplayBuffer()
Log(L"Using ReplayBuffer with a length of %d seconds", length);
bRecordingReplayBuffer = true;
ReportStartRecordingReplayBufferTrigger();
ConfigureStreamButtons();
}
@ -111,7 +112,9 @@ void OBS::StartReplayBuffer()
void OBS::StopReplayBuffer()
{
if (!replayBufferStream) return;
bRecordingReplayBuffer = false;
ReportStopRecordingReplayBufferTrigger();
if (!bStreaming && !bRecording && bRunning) Stop(true);

View File

@ -100,6 +100,46 @@ void OBS::ReportStopRecordingTrigger()
}
}
void OBS::ReportStartRecordingReplayBufferTrigger()
{
if (bShuttingDown)
return;
for (UINT i = 0; i<plugins.Num(); i++)
{
OBS_CALLBACK callback = plugins[i].startRecordingReplayBufferCallback;
if (callback)
(*callback)();
}
}
void OBS::ReportStopRecordingReplayBufferTrigger()
{
if (bShuttingDown)
return;
for (UINT i = 0; i<plugins.Num(); i++)
{
OBS_CALLBACK callback = plugins[i].stopRecordingReplayBufferCallback;
if (callback)
(*callback)();
}
}
void OBS::ReportReplayBufferSavedTrigger(String filename, UINT recordingLengthMS)
{
if (bShuttingDown)
return;
for (UINT i = 0; i<plugins.Num(); i++)
{
OBS_REPLAY_BUFFER_SAVED_CALLBACK callback = plugins[i].replayBufferSavedCallback;
if (callback)
(*callback)(filename, recordingLengthMS);
}
}
void OBS::ReportOBSStatus(bool running, bool streaming, bool recording, bool previewing, bool reconnecting)
{
if (bShuttingDown)

View File

@ -111,8 +111,6 @@ void STDCALL OBS::StopReplayBufferHotkey(DWORD hotkey, UPARAM param, bool bDown)
}
}
void SaveReplayBuffer(ReplayBuffer *out, DWORD timestamp);
void STDCALL OBS::SaveReplayBufferHotkey(DWORD hotkey, UPARAM param, bool bDown)
{
if (App->bSaveReplayBufferHotkeyDown && !bDown)

View File

@ -142,9 +142,10 @@ struct ReplayBuffer : VideoFileStream
save_times.emplace_back(timestamp);
}
static void SetLastFilename(String name)
static void SaveComplete(String name, DWORD recordingLengthMS)
{
App->lastOutputFile = name;
App->ReportReplayBufferSavedTrigger(name, recordingLengthMS);
}
static void SetRecording(bool recording)
@ -194,14 +195,21 @@ static DWORD STDCALL SaveReplayBufferThread(void *arg)
signalled = true;
};
DWORD lowest_timestamp = MAXDWORD;
DWORD highest_timestamp = 0;
while (packets.size())
{
auto &packet = packets.front();
if (get<2>(*packet) == stop_ts)
break;
auto timestamp = get<1>(*packet);
lowest_timestamp = min(timestamp, lowest_timestamp);
highest_timestamp = max(timestamp, highest_timestamp);
auto &buf = get<3>(*packet);
out->AddPacket(buf, get<1>(*packet), get<2>(*packet), get<0>(*packet));
out->AddPacket(buf, timestamp, get<2>(*packet), get<0>(*packet));
if (buf->front() == 0x17)
signal();
@ -210,7 +218,7 @@ static DWORD STDCALL SaveReplayBufferThread(void *arg)
}
signal();
ReplayBuffer::SetLastFilename(name);
ReplayBuffer::SaveComplete(name, highest_timestamp > lowest_timestamp ? (highest_timestamp - lowest_timestamp) : 0);
return 0;
}

View File

@ -3323,6 +3323,12 @@ LRESULT CALLBACK OBS::OBSProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
App->RefreshStreamButtons();
break;
case ID_TOGGLERECORDINGREPLAYBUFFER:
App->RefreshStreamButtons(true);
App->ToggleReplayBuffer();
App->RefreshStreamButtons();
break;
case ID_FILE_EXIT:
case ID_EXIT:
PostQuitMessage(0);