/******************************************************************************** Copyright (C) 2012 Hugh Bailey This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ********************************************************************************/ #include #include #pragma once class Scene; class SettingsPane; struct EncoderPicture; #define NUM_RENDER_BUFFERS 2 static const int minClientWidth = 640; static const int minClientHeight = 275; static const int defaultClientWidth = 640; static const int defaultClientHeight = 553; enum edges { edgeLeft = 0x01, edgeRight = 0x02, edgeTop = 0x04, edgeBottom = 0x08, }; struct AudioDeviceInfo { String strID; String strName; inline void FreeData() {strID.Clear(); strName.Clear();} }; struct AudioDeviceList { List devices; inline ~AudioDeviceList() { FreeData(); } inline void FreeData() { for(UINT i=0; i data; DWORD timestamp; PacketType type; }; //------------------------------------------------------------------- class VideoFileStream : public ClosableStream { public: virtual ~VideoFileStream() {} virtual void AddPacket(const BYTE *data, UINT size, DWORD timestamp, DWORD pts, PacketType type)=0; virtual void AddPacket(std::shared_ptr> data, DWORD timestamp, DWORD pts, PacketType type) { AddPacket(data->data(), static_cast(data->size()), timestamp, pts, type); } }; String ExpandRecordingFilename(String); String GetExpandedRecordingDirectoryBase(String); //------------------------------------------------------------------- class AudioEncoder { friend class OBS; protected: virtual bool Encode(float *input, UINT numInputFrames, DataPacket &packet, QWORD ×tamp)=0; virtual void GetHeaders(DataPacket &packet)=0; public: virtual ~AudioEncoder() {} virtual UINT GetFrameSize() const=0; virtual int GetBitRate() const=0; virtual CTSTR GetCodec() const=0; virtual String GetInfoString() const=0; }; //------------------------------------------------------------------- class VideoEncoder { friend class OBS; protected: virtual bool Encode(LPVOID picIn, List &packets, List &packetTypes, DWORD timestamp, DWORD &out_pts)=0; virtual void RequestBuffers(LPVOID buffers) {} public: virtual ~VideoEncoder() {} virtual int GetBitRate() const=0; virtual bool DynamicBitrateSupported() const=0; virtual bool SetBitRate(DWORD maxBitrate, DWORD bufferSize)=0; virtual void GetHeaders(DataPacket &packet)=0; virtual void GetSEI(DataPacket &packet) {} virtual void RequestKeyframe() {} virtual String GetInfoString() const=0; virtual bool isQSV() { return false; } virtual int GetBufferedFrames() { if(HasBufferedFrames()) return -1; return 0; } virtual bool HasBufferedFrames() { return false; } }; //------------------------------------------------------------------- struct MonitorInfo { inline MonitorInfo() {zero(this, sizeof(MonitorInfo));} inline MonitorInfo(HMONITOR hMonitor, RECT *lpRect) { this->hMonitor = hMonitor; mcpy(&this->rect, lpRect, sizeof(rect)); } HMONITOR hMonitor; RECT rect; float rotationDegrees; }; struct DeviceOutputData { String strDevice; List monitors; StringList monitorNameList; inline void ClearData() { strDevice.Clear(); monitors.Clear(); monitorNameList.Clear(); } }; struct DeviceOutputs { List devices; inline ~DeviceOutputs() { ClearData(); } inline void ClearData() { for(UINT i=0; i audioData; QWORD timestamp; }; //=============================================================================================== struct ClassInfo { String strClass; String strName; OBSCREATEPROC createProc; OBSCONFIGPROC configProc; bool bDeprecated; inline void FreeData() {strClass.Clear(); strName.Clear();} }; //---------------------------- /* 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*/, UINT /*bytesPerSec*/, double /*strain*/, UINT /*totalStreamtime*/, UINT /*numTotalFrames*/, UINT /*numDroppedFrames*/, UINT /*fps*/); typedef void (*OBS_SCENE_SWITCH_CALLBACK)(CTSTR); typedef void (*OBS_SOURCE_CHANGED_CALLBACK)(CTSTR /*sourceName*/, XElement* /*source*/); typedef void (*OBS_VOLUME_CHANGED_CALLBACK)(float /*level*/, bool /*muted*/, bool /*finalFalue*/); typedef void (*OBS_LOG_UPDATE_CALLBACK)(CTSTR /*delta*/, UINT /*length*/); struct PluginInfo { String strFile; HMODULE hModule; /* Event Callbacks */ /* called on stream starting (as soon as the encoder starts, for any combination of file/rtmp output) */ OBS_CALLBACK startStreamCallback; /* called on stream stopping (as soon as the encoder stops) */ OBS_CALLBACK stopStreamCallback; /* called when streaming (via rtmp) starts */ OBS_CALLBACK startStreamingCallback; /* called when streaming (via rtmp) stops */ OBS_CALLBACK stopStreamingCallback; /* called when recording (to file) starts */ OBS_CALLBACK startRecordingCallback; /* 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; /* called when stream stats are updated in stats window */ OBS_STREAM_STATUS_CALLBACK streamStatusCallback; /* called when scenes are switched */ OBS_SCENE_SWITCH_CALLBACK sceneSwitchCallback; /* called when scene collections are switched */ OBS_SCENE_SWITCH_CALLBACK sceneCollectionSwitchCallback; /* called when a scene is renamed, added, removed, or moved */ OBS_CALLBACK scenesChangedCallback; /* called when a scene collection is renamed, added, removed, or moved */ OBS_CALLBACK sceneCollectionsChangedCallback; /* called when the source order is changed */ OBS_CALLBACK sourceOrderChangedCallback; /* called when a source is changed in some way */ OBS_SOURCE_CHANGED_CALLBACK sourceChangedCallback; /* called when a sources have been added or removed */ OBS_CALLBACK sourcesAddedOrRemovedCallback; /* called when audio source volumes have changed */ OBS_VOLUME_CHANGED_CALLBACK micVolumeChangeCallback; OBS_VOLUME_CHANGED_CALLBACK desktopVolumeChangeCallback; /* called after the log window is updated */ OBS_LOG_UPDATE_CALLBACK logUpdateCallback; }; //---------------------------- struct GlobalSourceInfo { String strName; XElement *element; ImageSource *source; inline void FreeData() {strName.Clear(); delete source; source = NULL;} }; //---------------------------- enum { ID_SETTINGS=5000, ID_TOGGLERECORDINGREPLAYBUFFER, ID_TOGGLERECORDING, ID_STARTSTOP, ID_EXIT, ID_SCENEEDITOR, ID_DESKTOPVOLUME, ID_MICVOLUME, ID_DESKTOPVOLUMEMETER, ID_MICVOLUMEMETER, ID_STATUS, ID_SCENES, ID_SCENES_TEXT, ID_SOURCES, ID_SOURCES_TEXT, ID_TESTSTREAM, ID_GLOBALSOURCES, ID_PLUGINS, ID_DASHBOARD, ID_MINIMIZERESTORE, ID_SWITCHPROFILE, ID_SWITCHPROFILE_END = ID_SWITCHPROFILE+1000, ID_UPLOAD_LOG, ID_UPLOAD_LOG_END = ID_UPLOAD_LOG+1000, ID_VIEW_LOG, ID_VIEW_LOG_END = ID_VIEW_LOG+1000, ID_REFRESH_LOGS, ID_UPLOAD_ANALYZE_LOG, ID_UPLOAD_ANALYZE_LOG_END = ID_UPLOAD_ANALYZE_LOG+1000, ID_LOG_WINDOW, ID_SWITCHSCENECOLLECTION, ID_SWITCHSCENECOLLECTION_END = ID_SWITCHSCENECOLLECTION+1000, }; enum { OBS_REQUESTSTOP=WM_USER+1, OBS_CALLHOTKEY, OBS_RECONNECT, OBS_SETSCENE, OBS_SETSOURCEORDER, OBS_SETSOURCERENDER, OBS_UPDATESTATUSBAR, OBS_NOTIFICATIONAREA, OBS_NETWORK_FAILED, OBS_CONFIGURE_STREAM_BUTTONS, }; //---------------------------- enum ColorPrimaries { ColorPrimaries_BT709 = 1, ColorPrimaries_Unspecified, ColorPrimaries_BT470M = 4, ColorPrimaries_BT470BG, ColorPrimaries_SMPTE170M, ColorPrimaries_SMPTE240M, ColorPrimaries_Film, ColorPrimaries_BT2020 }; enum ColorTransfer { ColorTransfer_BT709 = 1, ColorTransfer_Unspecified, ColorTransfer_BT470M = 4, ColorTransfer_BT470BG, ColorTransfer_SMPTE170M, ColorTransfer_SMPTE240M, ColorTransfer_Linear, ColorTransfer_Log100, ColorTransfer_Log316, ColorTransfer_IEC6196624, ColorTransfer_BT1361, ColorTransfer_IEC6196621, ColorTransfer_BT202010, ColorTransfer_BT202012 }; enum ColorMatrix { ColorMatrix_GBR = 0, ColorMatrix_BT709, ColorMatrix_Unspecified, ColorMatrix_BT470M = 4, ColorMatrix_BT470BG, ColorMatrix_SMPTE170M, ColorMatrix_SMPTE240M, ColorMatrix_YCgCo, ColorMatrix_BT2020NCL, ColorMatrix_BT2020CL }; struct ColorDescription { int fullRange; int primaries; int transfer; int matrix; }; //---------------------------- enum ItemModifyType { ItemModifyType_None, ItemModifyType_Move, ItemModifyType_ScaleBottomLeft, ItemModifyType_CropBottomLeft, ItemModifyType_ScaleLeft, ItemModifyType_CropLeft, ItemModifyType_ScaleTopLeft, ItemModifyType_CropTopLeft, ItemModifyType_ScaleTop, ItemModifyType_CropTop, ItemModifyType_ScaleTopRight, ItemModifyType_CropTopRight, ItemModifyType_ScaleRight, ItemModifyType_CropRight, ItemModifyType_ScaleBottomRight, ItemModifyType_CropBottomRight, ItemModifyType_ScaleBottom, ItemModifyType_CropBottom }; //---------------------------- struct SceneHotkeyInfo { DWORD hotkeyID; DWORD hotkey; XElement *scene; }; //---------------------------- struct StreamInfo { UINT id; String strInfo; StreamInfoPriority priority; inline void FreeData() {strInfo.Clear();} }; //---------------------------- struct ServiceIdentifier { int id; String file; ServiceIdentifier(int id, String file) : id(id), file(file) {} bool operator==(const ServiceIdentifier &sid) { return id == sid.id && file == sid.file; } bool operator!=(const ServiceIdentifier &sid) { return !(*this == sid); } }; std::vector LoadServiceIdentifiers(); void EnumerateServices(std::function); std::pair, XElement*> LoadService(const ServiceIdentifier&, String *failReason=nullptr); std::pair, XElement*> LoadService(String *failReason=nullptr); ServiceIdentifier GetCurrentService(); //---------------------------- struct StatusBarDrawData { UINT bytesPerSec; double strain; }; //---------------------------- struct VideoPacketData { List data; PacketType type; inline void Clear() {data.Clear();} }; struct VideoSegment { List packets; DWORD timestamp; DWORD pts; inline VideoSegment() : timestamp(0), pts(0) {} inline ~VideoSegment() {Clear();} inline void Clear() { for(UINT i=0; i func; }; bool HandleStreamStopInfo(StopInfo &, PacketType, const VideoSegment&); //--------------------------------------------------- std::unique_ptr network; StopInfo networkStop; //--------------------------------------------------- // audio sources/encoder AudioSource *desktopAudio; AudioSource *micAudio; List auxAudioSources; UINT sampleRateHz; UINT audioChannels; BOOL isStereo; AudioEncoder *audioEncoder; //--------------------------------------------------- // scene/encoder Scene *scene; VideoEncoder *videoEncoder; HDC hCaptureDC; List monitors; UINT encoderSkipThreshold; XConfig scenesConfig; XConfig globalSourcesImportConfig; XConfig scenesCopyToConfig; List sceneHotkeys; XElement *sceneElement; inline void RemoveSceneHotkey(DWORD hotkey) { for(UINT i=0; iDeleteHotkey(sceneHotkeys[i].hotkeyID); sceneHotkeys.Remove(i); break; } } } void SelectSources(); void CheckSources(); void SetSourceRender(CTSTR sourceName, bool render); //--------------------------------------------------- // settings window int curSettingsSelection; HWND hwndSettings; HWND hwndCurrentSettings; bool bSettingsChanged, bApplySettingsAborted; List settingsPanes; SettingsPane * currentSettingsPane; int numberOfBuiltInSettingsPanes; int numberOfEncoderSettingsPanes; void SetChangedSettings(bool bChanged); void SetAbortApplySettings(bool abort); void CancelSettings(); void ApplySettings(); void SetCanOptimizeSettings(bool canOptimize); void OptimizeSettings(); // Settings panes public: void AddSettingsPane(SettingsPane *pane); void RemoveSettingsPane(SettingsPane *pane); void AddEncoderSettingsPane(SettingsPane *pane); void RemoveEncoderSettingsPane(SettingsPane *pane); private: void AddBuiltInSettingsPanes(); void AddEncoderSettingsPanes(); friend class SettingsPane; friend class SettingsGeneral; friend class SettingsEncoding; friend class SettingsPublish; friend class SettingsVideo; friend class SettingsAudio; friend class SettingsAdvanced; friend class SettingsHotkeys; //--------------------------------------------------- // mainly manly main window stuff String strLanguage; bool bTestStream; bool bUseMultithreadedOptimizations; bool bRunning, bRecording, bRecordingReplayBuffer, bRecordingOnly, bStartingUp, bStreaming, bStreamFlushed = true, bKeepRecording; bool canRecord; volatile bool bShutdownVideoThread, bShutdownEncodeThread; int renderFrameWidth, renderFrameHeight; // The size of the preview only int renderFrameX, renderFrameY; // The offset of the preview inside the preview control int renderFrameCtrlWidth, renderFrameCtrlHeight; // The size of the entire preview control int oldRenderFrameCtrlWidth, oldRenderFrameCtrlHeight; // The size of the entire preview control before the user began to resize the window HWND hwndRenderMessage; // The text in the middle of the main window bool renderFrameIn1To1Mode; int borderXSize, borderYSize; int clientWidth, clientHeight; bool bPanelVisibleWindowed; bool bPanelVisibleFullscreen; bool bPanelVisible; bool bPanelVisibleProcessed; bool bDragResize; bool bSizeChanging; bool bResizeRenderView; bool bAutoReconnect; bool bRetrying; bool bReconnecting; UINT reconnectTimeout; bool bDisableSceneSwitching; bool bChangingSources; bool bAlwaysOnTop; bool bPleaseEnableProjector; //I'm just too lazy bool bPleaseDisableProjector; bool bProjector; bool bEnableProjectorCursor; UINT projectorX, projectorY; UINT projectorWidth, projectorHeight; UINT projectorMonitorID; HWND hwndProjector; Texture *projectorTexture; bool bFullscreenMode; bool bEditMode; bool bRenderViewEnabled; bool bForceRenderViewErase; bool bShowFPS; bool bMouseMoved; bool bMouseDown; bool bRMouseDown; bool bItemWasSelected; Vect2 startMousePos, lastMousePos; ItemModifyType modifyType; SceneItem *scaleItem; HMENU hmenuMain; // Main window menu so we can hide it in fullscreen mode WINDOWPLACEMENT fullscreenPrevPlacement; int cpuInfo[4]; OSDirectoryMonitorData *logDirectoryMonitor; std::map logFiles; //--------------------------------------------------- // resolution/fps/downscale/etc settings int lastRenderTarget; UINT baseCX, baseCY; UINT scaleCX, scaleCY; UINT outputCX, outputCY; float downscale; int downscaleType; UINT frameTime, fps; bool bUsing444; ColorDescription colorDesc; //--------------------------------------------------- // stats DWORD bytesPerSec; DWORD captureFPS; DWORD curFramesDropped; DWORD totalStreamTime; bool bFirstConnect; double curStrain; //--------------------------------------------------- // main capture loop stuff int bufferingTime; HANDLE hEncodeThread; HANDLE hVideoThread; HANDLE hSceneMutex; List bufferedVideo; CircularList bufferedTimes; bool bRecievedFirstAudioFrame, bSentHeaders, bFirstAudioPacket; DWORD lastAudioTimestamp; UINT audioWarningId; QWORD firstSceneTimestamp; QWORD latestVideoTime; QWORD latestVideoTimeNS; bool bUseCFR; bool bWriteToFile; std::unique_ptr fileStream; StopInfo fileStreamStop; std::unique_ptr replayBufferStream; ReplayBuffer *replayBuffer; StopInfo replayBufferStop; bool bRequestKeyframe; int keyframeWait; QWORD firstFrameTimestamp; EncoderPicture * volatile curFramePic; HANDLE hVideoEvent; static DWORD STDCALL EncodeThread(LPVOID lpUnused); static DWORD STDCALL MainCaptureThread(LPVOID lpUnused); bool BufferVideoData(const List &inputPackets, const List &inputTypes, DWORD timestamp, DWORD out_pts, QWORD firstFrameTime, VideoSegment &segmentOut); void SendFrame(VideoSegment &curSegment, QWORD firstFrameTime); bool ProcessFrame(FrameProcessInfo &frameInfo); UINT FlushBufferedVideo(); void EncodeLoop(); void MainCaptureLoop(); void DrawPreview(const Vect2 &renderFrameSize, const Vect2 &renderFrameOffset, const Vect2 &renderFrameCtrlSize, int curRenderTarget, PreviewDrawType type); //--------------------------------------------------- // main audio capture loop stuff CircularList bufferedAudioTimes; HANDLE hSoundThread, hSoundDataMutex;//, hRequestAudioEvent; QWORD latestAudioTime; float desktopVol, micVol, curMicVol, curDesktopVol; float desktopPeak, micPeak; float desktopMax, micMax; float desktopMag, micMag; List pendingAudioFrames; bool bForceMicMono; float desktopBoost, micBoost; HANDLE hAuxAudioMutex; //--------------------------------------------------- // hotkey stuff HANDLE hHotkeyMutex; HANDLE hHotkeyThread; int pushToTalkDown; bool bUsingPushToTalk, bPushToTalkOn; long long pushToTalkDelay, pushToTalkTimeLeft; UINT pushToTalkHotkeyID, pushToTalkHotkey2ID; UINT muteMicHotkeyID; UINT muteDesktopHotkeyID; UINT startStreamHotkeyID; UINT stopStreamHotkeyID; UINT startRecordingHotkeyID; UINT stopRecordingHotkeyID; UINT startReplayBufferHotkeyID; UINT stopReplayBufferHotkeyID; UINT saveReplayBufferHotkeyID; UINT recordFromReplayBufferHotkeyID; bool bStartStreamHotkeyDown, bStopStreamHotkeyDown; bool bStartRecordingHotkeyDown, bStopRecordingHotkeyDown; bool bStartReplayBufferHotkeyDown, bStopReplayBufferHotkeyDown; bool bSaveReplayBufferHotkeyDown; bool bRecordFromReplayBufferHotkeyDown; static DWORD STDCALL MainAudioThread(LPVOID lpUnused); bool QueryAudioBuffers(bool bQueriedDesktopDebugParam); bool QueryNewAudio(); void EncodeAudioSegment(float *buffer, UINT numFrames, QWORD timestamp); void MainAudioLoop(); //--------------------------------------------------- // notification area icon UINT wmExplorerRestarted; bool bNotificationAreaIcon; BOOL SetNotificationAreaIcon(DWORD dwMessage, int idIcon, const String &tooltip); //--------------------------------------------------- // random bla-haa String streamReport; String lastOutputFile; //String strDashboard; List Icons; List Fonts; List sceneClasses; List imageSourceClasses; List globalSources; HANDLE hInfoMutex; List streamInfoList; UINT streamInfoIDCounter; HANDLE hStartupShutdownMutex; //--------------------------------------------------- List plugins; bool bShuttingDown; inline void ClearStreamInfo() { for(UINT i=0; i &globalSourceNames,bool mainSceneGlobalSourceNames = false); XElement* GetGlobalSourceElement(CTSTR lpName); static INT_PTR CALLBACK GlobalSourcesProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static INT_PTR CALLBACK GlobalSourcesImportProc(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam); static bool STDCALL ConfigGlobalSource(XElement *element, bool bCreating); void CallHotkey(DWORD hotkeyID, bool bDown); static void AddProfilesToMenu(HMENU menu); static INT_PTR CALLBACK EnterProfileDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); void AddProfile(ProfileAction action); void RemoveProfile(); void ImportProfile(); void ExportProfile(); static void ResetProfileMenu(); static void ResetLogUploadMenu(); static void DisableMenusWhileStreaming(bool disable); static INT_PTR CALLBACK EnterSceneCollectionDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); void AddSceneCollection(SceneCollectionAction action); void RemoveSceneCollection(); void ImportSceneCollection(); void ExportSceneCollection(); static void ResetSceneCollectionMenu(); static void AddSceneCollectionToMenu(HMENU menu); void ReloadSceneCollection(); static String GetApplicationName(); static void ResetApplicationName(); void SetStatusBarData(); static void ClearStatusBar(); static void DrawStatusBar(DRAWITEMSTRUCT &dis); void RefreshStreamButtons(bool disable=false); void ConfigureStreamButtons(); void PostConfigureStreamButtons(); void ReloadIniSettings(); void RestartNetwork(); public: OBS(); virtual ~OBS(); void ResizeWindow(bool bRedrawRenderFrame); void SetFullscreenMode(bool fullscreen); void RequestKeyframe(int waitTime); inline void AddAudioSource(AudioSource *source) { OSEnterMutex(hAuxAudioMutex); auxAudioSources << source; OSLeaveMutex(hAuxAudioMutex); } inline void RemoveAudioSource(AudioSource *source) { OSEnterMutex(hAuxAudioMutex); auxAudioSources.RemoveItem(source); OSLeaveMutex(hAuxAudioMutex); } inline UINT GetSampleRateHz() const {return sampleRateHz;} inline UINT NumAudioChannels() const {return audioChannels;} inline QWORD GetAudioTime() const {return latestAudioTime;} inline QWORD GetVideoTime() const {return latestVideoTime;} char* EncMetaData(char *enc, char *pend, bool bFLVFile=false); inline void PostStopMessage(bool forceStop=false) {if(hwndMain) PostMessage(hwndMain, OBS_REQUESTSTOP, forceStop ? 1 : 0, 0);} inline void NetworkFailed() { if (hwndMain) PostMessage(hwndMain, OBS_NETWORK_FAILED, 0, 0); } void GetBaseSize(UINT &width, UINT &height) const; inline void GetRenderFrameSize(UINT &width, UINT &height) const {width = renderFrameWidth; height = renderFrameHeight;} inline void GetRenderFrameOffset(UINT &x, UINT &y) const {x = renderFrameX; y = renderFrameY;} inline void GetRenderFrameControlSize(UINT &width, UINT &height) const {width = renderFrameCtrlWidth; height = renderFrameCtrlHeight;} inline void GetOutputSize(UINT &width, UINT &height) const {width = outputCX; height = outputCY;} inline Vect2 GetBaseSize() const { UINT width, height; GetBaseSize(width, height); return Vect2(float(width), float(height)); } inline Vect2 GetOutputSize() const {return Vect2(float(outputCX), float(outputCY));} inline Vect2 GetRenderFrameSize() const {return Vect2(float(renderFrameWidth), float(renderFrameHeight));} inline Vect2 GetRenderFrameOffset() const {return Vect2(float(renderFrameX), float(renderFrameY));} inline Vect2 GetRenderFrameControlSize() const {return Vect2(float(renderFrameCtrlWidth), float(renderFrameCtrlHeight));} inline AudioEncoder* GetAudioEncoder() const {return audioEncoder;} inline VideoEncoder* GetVideoEncoder() const {return videoEncoder;} inline void EnterSceneMutex() {OSEnterMutex(hSceneMutex);} inline void LeaveSceneMutex() {OSLeaveMutex(hSceneMutex);} inline void EnableSceneSwitching(bool bEnable) {bDisableSceneSwitching = !bEnable;} inline bool IsRunning() const {return bRunning;} inline UINT GetFPS() const {return fps;} inline UINT GetFrameTime() const {return frameTime;} inline UINT NumMonitors() const {return monitors.Num();} inline const MonitorInfo& GetMonitor(UINT id) const {if(id < monitors.Num()) return monitors[id]; else return monitors[0];} inline XElement* GetSceneElement() const {return sceneElement;} virtual HICON GetIcon(HINSTANCE hInst, int resource); virtual HFONT GetFont(CTSTR lpFontFace, int fontSize, int fontWeight); inline void GetVideoHeaders(DataPacket &packet) {videoEncoder->GetHeaders(packet);} inline void GetAudioHeaders(DataPacket &packet) {audioEncoder->GetHeaders(packet);} inline void SetStreamReport(CTSTR lpStreamReport) {streamReport = lpStreamReport;} UINT AddStreamInfo(CTSTR lpInfo, StreamInfoPriority priority); void SetStreamInfo(UINT infoID, CTSTR lpInfo); void SetStreamInfoPriority(UINT infoID, StreamInfoPriority priority); void RemoveStreamInfo(UINT infoID); String GetMostImportantInfo(StreamInfoPriority &priority); inline QWORD GetSceneTimestamp() {return firstSceneTimestamp;} //--------------------------------------------------------------------------- inline static CTSTR GetCurrentProfile() {return GlobalConfig->GetStringPtr(TEXT("General"), TEXT("Profile"));} static void GetProfiles(StringList &profileList); //--------------------------------------------------------------------------- inline static CTSTR GetCurrentSceneCollection() { return GlobalConfig->GetStringPtr(TEXT("General"), TEXT("SceneCollection")); } static void GetSceneCollection(StringList &sceneCollectionList); //--------------------------------------------------------------------------- UINT NumPlugins() const {return plugins.Num();} const PluginInfo *GetPluginInfo(UINT idx) const {if (idx < plugins.Num()) return plugins+idx; else return NULL;} //--------------------------------------------------------------------------- virtual void RegisterSceneClass(CTSTR lpClassName, CTSTR lpDisplayName, OBSCREATEPROC createProc, OBSCONFIGPROC configProc, bool bDeprecated); virtual void RegisterImageSourceClass(CTSTR lpClassName, CTSTR lpDisplayName, OBSCREATEPROC createProc, OBSCONFIGPROC configProc, bool bDeprecated); virtual ImageSource* CreateImageSource(CTSTR lpClassName, XElement *data); virtual bool SetScene(CTSTR lpScene); virtual void InsertSourceItem(UINT index, LPWSTR name, bool checked); virtual bool SetSceneCollection(CTSTR lpCollection); //--------------------------------------------------------------------------- // volume stuff virtual void SetDesktopVolume(float val, bool finalValue); virtual float GetDesktopVolume(); virtual void ToggleDesktopMute(); virtual bool GetDesktopMuted(); virtual void SetMicVolume(float val, bool finalValue); virtual float GetMicVolume(); virtual void ToggleMicMute(); virtual bool GetMicMuted(); //--------------------------------------------------------------------------- // event reporting functions virtual void ReportStartStreamTrigger(); virtual void ReportStopStreamTrigger(); virtual void ReportStartStreamingTrigger(); 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, UINT bytesPerSec = 0, double strain = 0, UINT totalStreamtime = 0, UINT numTotalFrames = 0, UINT numDroppedFrames = 0, UINT fps = 0); virtual void ReportSwitchScenes(CTSTR scene); virtual void ReportSwitchSceneCollections(CTSTR collection); virtual void ReportScenesChanged(); virtual void ReportSceneCollectionsChanged(); virtual void ReportSourceOrderChanged(); virtual void ReportSourceChanged(CTSTR sourceName, XElement* source); virtual void ReportSourcesAddedOrRemoved(); virtual void ReportMicVolumeChange(float level, bool muted, bool finalValue); virtual void ReportDesktopVolumeChange(float level, bool muted, bool finalValue); virtual void ReportLogUpdate(CTSTR logDelta, UINT length); // notification area icon functions BOOL ShowNotificationAreaIcon(); BOOL UpdateNotificationAreaIcon(); BOOL HideNotificationAreaIcon(); BOOL UpdateDashboardButton(); inline void ResetMic() {if (bRunning && micAudio) ResetWASAPIAudioDevice(micAudio);} void GetThreadHandles (HANDLE *videoThread, HANDLE *encodeThread); struct PendingStreams { using thread_t = std::unique_ptr>; std::list streams; std::unique_ptr mutex; PendingStreams() : mutex(OSCreateMutex()) {} } pendingStreams; void AddPendingStream(ClosableStream *stream, std::function finishedCallback = {}); void AddPendingStreamThread(HANDLE thread); void ClosePendingStreams(); }; LONG CALLBACK OBSExceptionHandler (PEXCEPTION_POINTERS exceptionInfo);