master
jim 2012-09-20 23:07:10 -07:00
parent 205c3d6555
commit f99d74d008
26 changed files with 891 additions and 227 deletions

30
AUTHORS
View File

@ -1,9 +1,25 @@
Hugh "Jim" Bailey (obs.jim@gmail.com) - Primary author and currently only guy working on the project right now. Damnit Jim! Author:
Hugh "Jim" Bailey (obs.jim@gmail.com) - Primary author. Damnit Jim!
Also, special thanks to: Additional Coding:
Richard "R1CH" Stanway - Tons of bugfixes, and teaching the ways of git enlightenment.
Translations:
Andres Lasn - Estonian translation
Johannes Grill and Johannes Kroker - German translations
August Kind Svendsen - Norwegian translation
Alan Antunes - French translation
Hath Ington - Bulgarian translation
xuok and R3mbrant - Russian translations
Notable super awesome testers:
Kyle "Kendobear" Asher - A guy who spent weeks helping pinpoint a bug
specific to his system. This guy deserves a
medal for his patience.
D2Ultima/Frostshocker/Modnite - These guys helped me test the major network
code updates, as well as helped point out
compatibility issues for certain systems.
The greatly improved network code would not
have been possible without their help.
Andres Lasn - Estonian translation
Johannes Grill and Johannes Kroker - German translation
August Kind Svendsen - Norwegian translation
Alan Antunes - French translation
Hath Ington - Bulgarian translation

View File

@ -1,6 +1,22 @@
(yyyy-mm-dd) (yyyy-mm-dd)
-------------------------------
2012-9-20 - 0.38 (alpha)
* Changed the way settings are saved. All settings are now saved
to the windows [user]/AppData/Roaming/OBS directory.
* Made it so up to 20 log files are saved at a given time, so that
older logs are not necessarily just overwritten.
* Added setting profiles so the user can have different settings
for different situations.
* Fixed a major mic mug with mono mics. Don't know how I let that
one slip by me for so long.
* More DShow bug fixes by R1CH
* Added a popup menu when right clicking on the render frame that
lets the user see the FPS or disable the render view.
* Improved API hotkey code
------------------------------- -------------------------------
2012-9-16 - 0.37 (alpha) 2012-9-16 - 0.37 (alpha)

29
OBS.rc
View File

@ -57,11 +57,12 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTI
CAPTION "Settings" CAPTION "Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
DEFPUSHBUTTON "OK",IDOK,338,294,67,14 DEFPUSHBUTTON "OK",IDOK,339,294,67,14
PUSHBUTTON "Cancel",IDCANCEL,411,294,67,14 PUSHBUTTON "Cancel",IDCANCEL,412,294,67,14
PUSHBUTTON "Apply",IDC_APPLY,483,294,67,14 PUSHBUTTON "Apply",IDC_APPLY,484,294,67,14
LISTBOX IDC_SETTINGSLIST,3,4,118,287,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP LISTBOX IDC_SETTINGSLIST,3,4,118,287,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
CONTROL "ƒXƒ^ƒeƒBƒbƒN",IDC_SUBDIALOG,"Static",SS_LEFTNOWORDWRAP | NOT WS_VISIBLE | WS_GROUP,124,5,427,287,WS_EX_STATICEDGE CONTROL "ƒXƒ^ƒeƒBƒbƒN",IDC_SUBDIALOG,"Static",SS_LEFTNOWORDWRAP | NOT WS_VISIBLE | WS_GROUP,124,5,427,287,WS_EX_STATICEDGE
PUSHBUTTON "Settings.Defaults",IDC_DEFAULTS,238,294,67,14,NOT WS_VISIBLE
END END
IDD_SETTINGS_PUBLISH DIALOGEX 0, 0, 427, 287 IDD_SETTINGS_PUBLISH DIALOGEX 0, 0, 427, 287
@ -73,8 +74,6 @@ BEGIN
COMBOBOX IDC_MODE,144,10,126,59,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_MODE,144,10,126,59,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP
RTEXT "Settings.Publish.Service",IDC_SERVICE_STATIC,4,29,138,8 RTEXT "Settings.Publish.Service",IDC_SERVICE_STATIC,4,29,138,8
COMBOBOX IDC_SERVICE,144,27,126,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_SERVICE,144,27,126,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
RTEXT "Settings.Publish.Username",IDC_USERNAME_STATIC,4,220,138,8,NOT WS_VISIBLE
EDITTEXT IDC_USERNAME,144,218,226,14,ES_AUTOHSCROLL | NOT WS_VISIBLE
RTEXT "Settings.Publish.Playpath",IDC_PLAYPATH_STATIC,4,64,138,8 RTEXT "Settings.Publish.Playpath",IDC_PLAYPATH_STATIC,4,64,138,8
EDITTEXT IDC_PLAYPATH,144,61,226,14,ES_PASSWORD | ES_AUTOHSCROLL EDITTEXT IDC_PLAYPATH,144,61,226,14,ES_PASSWORD | ES_AUTOHSCROLL
RTEXT "Settings.Publish.ChannelName",IDC_CHANNELNAME_STATIC,4,47,138,8 RTEXT "Settings.Publish.ChannelName",IDC_CHANNELNAME_STATIC,4,47,138,8
@ -83,7 +82,6 @@ BEGIN
COMBOBOX IDC_SERVERLIST,144,79,226,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_SERVERLIST,144,79,226,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Settings.Info",IDC_INFO,4,119,408,37,NOT WS_VISIBLE LTEXT "Settings.Info",IDC_INFO,4,119,408,37,NOT WS_VISIBLE
EDITTEXT IDC_SERVEREDIT,144,78,226,14,ES_AUTOHSCROLL EDITTEXT IDC_SERVEREDIT,144,78,226,14,ES_AUTOHSCROLL
CONTROL "Settings.Publish.BufferSends",IDC_BUFFERSENDS,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,144,98,276,10
END END
IDD_SETTINGS_ENCODING DIALOGEX 0, 0, 427, 287 IDD_SETTINGS_ENCODING DIALOGEX 0, 0, 427, 287
@ -136,9 +134,14 @@ STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
EXSTYLE WS_EX_CONTROLPARENT EXSTYLE WS_EX_CONTROLPARENT
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
COMBOBOX IDC_LANGUAGE,144,10,195,126,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_LANGUAGE,147,23,195,126,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
RTEXT "Settings.General.Language",IDC_STATIC,4,12,138,8 RTEXT "Settings.General.Language",IDC_STATIC,7,25,138,8
LTEXT "Settings.General.Restart",IDC_INFO,11,49,409,48,NOT WS_VISIBLE LTEXT "Settings.General.Restart",IDC_INFO,7,90,409,48,NOT WS_VISIBLE
COMBOBOX IDC_PROFILE,147,41,195,126,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
RTEXT "Settings.General.Profile",IDC_STATIC,7,44,138,8
PUSHBUTTON "Settings.General.Add",IDC_ADD,174,57,55,14
PUSHBUTTON "Settings.General.Remove",IDC_REMOVE,288,57,55,14
PUSHBUTTON "Settings.General.Rename",IDC_RENAME,231,57,55,14
END END
IDD_SETTINGS_AUDIO DIALOGEX 0, 0, 427, 287 IDD_SETTINGS_AUDIO DIALOGEX 0, 0, 427, 287
@ -399,8 +402,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,3,6,0 FILEVERSION 0,3,8,0
PRODUCTVERSION 0,3,6,0 PRODUCTVERSION 0,3,8,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -416,12 +419,12 @@ BEGIN
BLOCK "041104b0" BLOCK "041104b0"
BEGIN BEGIN
VALUE "FileDescription", "Open Broadcaster Software" VALUE "FileDescription", "Open Broadcaster Software"
VALUE "FileVersion", "0, 3, 7, 0" VALUE "FileVersion", "0, 3, 8, 0"
VALUE "InternalName", "OBS" VALUE "InternalName", "OBS"
VALUE "LegalCopyright", "Copyright (C) 2012" VALUE "LegalCopyright", "Copyright (C) 2012"
VALUE "OriginalFilename", "OBS.exe" VALUE "OriginalFilename", "OBS.exe"
VALUE "ProductName", "Open Broadcaster Software" VALUE "ProductName", "Open Broadcaster Software"
VALUE "ProductVersion", "0, 3, 7, 0" VALUE "ProductVersion", "0, 3, 8, 0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -23,7 +23,11 @@
typedef LPVOID (STDCALL* OBSCREATEPROC)(XElement*); //data typedef LPVOID (STDCALL* OBSCREATEPROC)(XElement*); //data
typedef bool (STDCALL* OBSCONFIGPROC)(XElement*, bool); //element, bInitializing typedef bool (STDCALL* OBSCONFIGPROC)(XElement*, bool); //element, bInitializing
typedef void (STDCALL* OBSHOTKEYPROC)(DWORD, UPARAM); typedef void (STDCALL* OBSHOTKEYPROC)(DWORD, UPARAM, bool);
#define HOTKEY_SHIFT 0x1
#define HOTKEY_CONTROL 0x2
#define HOTKEY_ALT 0x4
class APIInterface class APIInterface
{ {
@ -52,6 +56,7 @@ public:
virtual CTSTR GetSceneName() const=0; virtual CTSTR GetSceneName() const=0;
virtual XElement* GetSceneElement()=0; virtual XElement* GetSceneElement()=0;
//low-order word is VK, high-order word is modifier. equivalent to the value given by hotkey controls
virtual bool HotkeyExists(DWORD hotkey) const=0; virtual bool HotkeyExists(DWORD hotkey) const=0;
virtual bool CreateHotkey(DWORD hotkey, OBSHOTKEYPROC hotkeyProc, UPARAM param)=0; virtual bool CreateHotkey(DWORD hotkey, OBSHOTKEYPROC hotkeyProc, UPARAM param)=0;
virtual void DeleteHotkey(DWORD hotkey)=0; virtual void DeleteHotkey(DWORD hotkey)=0;
@ -64,6 +69,9 @@ public:
virtual HWND GetMainWindow() const=0; virtual HWND GetMainWindow() const=0;
virtual CTSTR GetAppDataPath() const=0;
virtual String GetPluginDataPath() const=0;
inline bool SSE2Available() {return bSSE2Availabe;} inline bool SSE2Available() {return bSSE2Availabe;}
}; };

View File

@ -117,12 +117,18 @@ void SceneItem::MoveToBottom()
Scene::~Scene() Scene::~Scene()
{ {
traceIn(Scene::~Scene);
for(UINT i=0; i<sceneItems.Num(); i++) for(UINT i=0; i<sceneItems.Num(); i++)
delete sceneItems[i]; delete sceneItems[i];
traceOut;
} }
SceneItem* Scene::AddImageSource(XElement *sourceElement) SceneItem* Scene::AddImageSource(XElement *sourceElement)
{ {
traceIn(Scene::AddImageSource);
if(GetSceneItem(sourceElement->GetName()) != NULL) if(GetSceneItem(sourceElement->GetName()) != NULL)
{ {
AppWarning(TEXT("Scene source '%s' already in scene. actually, no one should get this error. if you do send it to jim immidiately."), sourceElement->GetName()); AppWarning(TEXT("Scene source '%s' already in scene. actually, no one should get this error. if you do send it to jim immidiately."), sourceElement->GetName());
@ -154,6 +160,7 @@ SceneItem* Scene::AddImageSource(XElement *sourceElement)
item->size = Vect2(cx, cy); item->size = Vect2(cx, cy);
API->EnterSceneMutex(); API->EnterSceneMutex();
if(bSceneStarted) source->BeginScene();
sceneItems << item; sceneItems << item;
API->LeaveSceneMutex(); API->LeaveSceneMutex();
@ -161,13 +168,20 @@ SceneItem* Scene::AddImageSource(XElement *sourceElement)
bMissingSources = true; bMissingSources = true;
return item; return item;
traceOut;
} }
void Scene::RemoveImageSource(SceneItem *item) void Scene::RemoveImageSource(SceneItem *item)
{ {
traceIn(Scene::RemoveImageSource);
if(bSceneStarted) item->source->EndScene();
item->GetElement()->GetParent()->RemoveElement(item->GetElement()); item->GetElement()->GetParent()->RemoveElement(item->GetElement());
sceneItems.RemoveItem(item); sceneItems.RemoveItem(item);
delete item; delete item;
traceOut;
} }
void Scene::RemoveImageSource(CTSTR lpName) void Scene::RemoveImageSource(CTSTR lpName)
@ -184,26 +198,36 @@ void Scene::RemoveImageSource(CTSTR lpName)
void Scene::Preprocess() void Scene::Preprocess()
{ {
traceIn(Scene::Preprocess);
for(UINT i=0; i<sceneItems.Num(); i++) for(UINT i=0; i<sceneItems.Num(); i++)
{ {
SceneItem *item = sceneItems[i]; SceneItem *item = sceneItems[i];
if(item->source) if(item->source)
item->source->Preprocess(); item->source->Preprocess();
} }
traceOut;
} }
void Scene::Tick(float fSeconds) void Scene::Tick(float fSeconds)
{ {
traceIn(Scene::Tick);
for(UINT i=0; i<sceneItems.Num(); i++) for(UINT i=0; i<sceneItems.Num(); i++)
{ {
SceneItem *item = sceneItems[i]; SceneItem *item = sceneItems[i];
if(item->source) if(item->source)
item->source->Tick(fSeconds); item->source->Tick(fSeconds);
} }
traceOut;
} }
void Scene::Render() void Scene::Render()
{ {
traceIn(Scene::Render);
GS->ClearColorBuffer(); GS->ClearColorBuffer();
for(UINT i=0; i<sceneItems.Num(); i++) for(UINT i=0; i<sceneItems.Num(); i++)
@ -212,10 +236,14 @@ void Scene::Render()
if(item->source) if(item->source)
item->source->Render(item->pos, item->size); item->source->Render(item->pos, item->size);
} }
traceOut;
} }
void Scene::RenderSelections() void Scene::RenderSelections()
{ {
traceIn(Scene::RenderSelections);
for(UINT i=0; i<sceneItems.Num(); i++) for(UINT i=0; i<sceneItems.Num(); i++)
{ {
SceneItem *item = sceneItems[i]; SceneItem *item = sceneItems[i];
@ -237,24 +265,44 @@ void Scene::RenderSelections()
DrawBox(pos, size); DrawBox(pos, size);
} }
} }
traceOut;
} }
void Scene::BeginScene() void Scene::BeginScene()
{ {
traceIn(Scene::BeginScene);
if(bSceneStarted)
return;
for(UINT i=0; i<sceneItems.Num(); i++) for(UINT i=0; i<sceneItems.Num(); i++)
{ {
SceneItem *item = sceneItems[i]; SceneItem *item = sceneItems[i];
if(item->source) if(item->source)
item->source->BeginScene(); item->source->BeginScene();
} }
bSceneStarted = true;
traceOut;
} }
void Scene::EndScene() void Scene::EndScene()
{ {
traceIn(Scene::EndScene);
if(!bSceneStarted)
return;
for(UINT i=0; i<sceneItems.Num(); i++) for(UINT i=0; i<sceneItems.Num(); i++)
{ {
SceneItem *item = sceneItems[i]; SceneItem *item = sceneItems[i];
if(item->source) if(item->source)
item->source->EndScene(); item->source->EndScene();
} }
bSceneStarted = false;
traceOut;
} }

View File

@ -91,6 +91,7 @@ class BASE_EXPORT Scene
friend class SceneItem; friend class SceneItem;
friend class OBS; friend class OBS;
bool bSceneStarted;
bool bMissingSources; bool bMissingSources;
List<SceneItem*> sceneItems; List<SceneItem*> sceneItems;

View File

@ -35,8 +35,6 @@
BOOL ConfigFile::Create(CTSTR lpConfigFile) BOOL ConfigFile::Create(CTSTR lpConfigFile)
{ {
strFileName = lpConfigFile; strFileName = lpConfigFile;
lpFileData = NULL;
bOpen = 0;
if(LoadFile(XFILE_CREATEALWAYS)) if(LoadFile(XFILE_CREATEALWAYS))
LoadData(); LoadData();
@ -49,8 +47,6 @@ BOOL ConfigFile::Create(CTSTR lpConfigFile)
BOOL ConfigFile::Open(CTSTR lpConfigFile, BOOL bOpenAlways) BOOL ConfigFile::Open(CTSTR lpConfigFile, BOOL bOpenAlways)
{ {
strFileName = lpConfigFile; strFileName = lpConfigFile;
lpFileData = NULL;
bOpen = 0;
if(LoadFile(bOpenAlways ? XFILE_OPENALWAYS : XFILE_OPENEXISTING)) if(LoadFile(bOpenAlways ? XFILE_OPENALWAYS : XFILE_OPENEXISTING))
LoadData(); LoadData();
@ -62,9 +58,6 @@ BOOL ConfigFile::Open(CTSTR lpConfigFile, BOOL bOpenAlways)
BOOL ConfigFile::LoadFile(DWORD dwOpenMode) BOOL ConfigFile::LoadFile(DWORD dwOpenMode)
{ {
if(bOpen)
Close();
XFile file; XFile file;
if(!file.Open(strFileName, XFILE_READ, dwOpenMode)) if(!file.Open(strFileName, XFILE_READ, dwOpenMode))
{ {
@ -72,6 +65,9 @@ BOOL ConfigFile::LoadFile(DWORD dwOpenMode)
return 0; return 0;
} }
if(bOpen)
Close();
dwLength = file.GetFileSize(); dwLength = file.GetFileSize();
LPSTR lpTempFileData = (LPSTR)Allocate(dwLength+5); LPSTR lpTempFileData = (LPSTR)Allocate(dwLength+5);
@ -180,6 +176,23 @@ void ConfigFile::Close()
bOpen = 0; bOpen = 0;
} }
BOOL ConfigFile::SaveAs(CTSTR lpPath)
{
XFile newFile;
if(!newFile.Open(lpPath, XFILE_WRITE, XFILE_CREATEALWAYS))
return FALSE;
strFileName = lpPath;
newFile.Write("\xEF\xBB\xBF", 3);
newFile.WriteAsUTF8(lpFileData);
return TRUE;
}
void ConfigFile::SetFilePath(CTSTR lpPath)
{
strFileName = lpPath;
}
String ConfigFile::GetString(CTSTR lpSection, CTSTR lpKey, CTSTR def) String ConfigFile::GetString(CTSTR lpSection, CTSTR lpKey, CTSTR def)
{ {
assert(lpSection); assert(lpSection);
@ -578,7 +591,7 @@ void ConfigFile::SetString(CTSTR lpSection, CTSTR lpKey, CTSTR lpString)
return; return;
if(!lpString) if(!lpString)
return; lpString = TEXT("");
SetKey(lpSection, lpKey, lpString); SetKey(lpSection, lpKey, lpString);
} }

View File

@ -48,6 +48,9 @@ public:
BOOL Open(CTSTR lpConfigFile, BOOL bOpenAlways=FALSE); BOOL Open(CTSTR lpConfigFile, BOOL bOpenAlways=FALSE);
void Close(); void Close();
BOOL SaveAs(CTSTR lpPath);
void SetFilePath(CTSTR lpPath);
String GetString(CTSTR lpSection, CTSTR lpKey, CTSTR def=NULL); String GetString(CTSTR lpSection, CTSTR lpKey, CTSTR def=NULL);
CTSTR GetStringPtr(CTSTR lpSection, CTSTR lpKey, CTSTR def=NULL); CTSTR GetStringPtr(CTSTR lpSection, CTSTR lpKey, CTSTR def=NULL);
int GetInt(CTSTR lpSection, CTSTR lpKey, int def=0); int GetInt(CTSTR lpSection, CTSTR lpKey, int def=0);

View File

@ -67,7 +67,6 @@ public:
LPSTR lpFileDataUTF8 = (LPSTR)Allocate(dwFileSize+1); LPSTR lpFileDataUTF8 = (LPSTR)Allocate(dwFileSize+1);
lpFileDataUTF8[dwFileSize] = 0; lpFileDataUTF8[dwFileSize] = 0;
Read(lpFileDataUTF8, dwFileSize); Read(lpFileDataUTF8, dwFileSize);
Close();
strIn = String(lpFileDataUTF8); strIn = String(lpFileDataUTF8);
Free(lpFileDataUTF8); Free(lpFileDataUTF8);

View File

@ -182,7 +182,7 @@ BOOL XFile::SetFileSize(DWORD dwSize)
if(dwPos > dwSize) if(dwPos > dwSize)
dwPos = dwSize; dwPos = dwSize;
SetPos(dwSize, FILE_BEGIN); SetPos(dwSize, XFILE_BEGIN);
return SetEndOfFile(hFile); return SetEndOfFile(hFile);
traceOutFast; traceOutFast;

View File

@ -30,7 +30,7 @@ SafeList<DWORD> TickList;
Alloc *MainAllocator = NULL; Alloc *MainAllocator = NULL;
BOOL bBaseLoaded = FALSE; BOOL bBaseLoaded = FALSE;
BOOL bDebugBreak = TRUE; BOOL bDebugBreak = TRUE;
CTSTR lpLogFileName = TEXT("XT.log"); TCHAR lpLogFileName[260] = TEXT("XT.log");
XFile LogFile; XFile LogFile;
StringList TraceFuncList; StringList TraceFuncList;
@ -40,25 +40,19 @@ void STDCALL CriticalExit();
void STDCALL OpenLogFile(); void STDCALL OpenLogFile();
void STDCALL CloseLogFile(); void STDCALL CloseLogFile();
void STDCALL OSInit();
void STDCALL OSExit();
BOOL STDCALL InitXT(CTSTR logFile, CTSTR allocatorName) BOOL STDCALL InitXT(CTSTR logFile, CTSTR allocatorName)
{ {
if(!bBaseLoaded) if(!bBaseLoaded)
{ {
if(logFile) if(logFile)
lpLogFileName = logFile; scpy(lpLogFileName, logFile);
OSInit(); OSInit();
if(scmpi(allocatorName, TEXT("DebugAlloc")) == 0) ResetXTAllocator(allocatorName);
MainAllocator = new DebugAlloc;
else if (scmpi(allocatorName, TEXT("DefaultAlloc")) == 0)
MainAllocator = new DefaultAlloc;
else if (scmpi(allocatorName, TEXT("SeriousMemoryDebuggingAlloc")) == 0)
MainAllocator = new SeriousMemoryDebuggingAlloc;
else
MainAllocator = new FastAlloc;
locale = new LocaleStringLookup;
bBaseLoaded = 1; bBaseLoaded = 1;
} }
@ -66,6 +60,29 @@ BOOL STDCALL InitXT(CTSTR logFile, CTSTR allocatorName)
} }
void STDCALL InitXTLog(CTSTR logFile)
{
if(logFile)
scpy(lpLogFileName, logFile);
}
void STDCALL ResetXTAllocator(CTSTR lpAllocator)
{
delete locale;
delete MainAllocator;
if(scmpi(lpAllocator, TEXT("DebugAlloc")) == 0)
MainAllocator = new DebugAlloc;
else if (scmpi(lpAllocator, TEXT("DefaultAlloc")) == 0)
MainAllocator = new DefaultAlloc;
else if (scmpi(lpAllocator, TEXT("SeriousMemoryDebuggingAlloc")) == 0)
MainAllocator = new SeriousMemoryDebuggingAlloc;
else
MainAllocator = new FastAlloc;
locale = new LocaleStringLookup;
}
void STDCALL TerminateXT() void STDCALL TerminateXT()
{ {
if(bBaseLoaded) if(bBaseLoaded)

View File

@ -80,9 +80,6 @@ struct XRect
#define WAIT_INFINITE 0xFFFFFFFF #define WAIT_INFINITE 0xFFFFFFFF
BASE_EXPORT void STDCALL OSInit();
BASE_EXPORT void STDCALL OSExit();
BASE_EXPORT void STDCALL OSLogSystemStats(); BASE_EXPORT void STDCALL OSLogSystemStats();
BASE_EXPORT DWORD STDCALL OSGetSysPageSize(); BASE_EXPORT DWORD STDCALL OSGetSysPageSize();
BASE_EXPORT LPVOID STDCALL OSVirtualAlloc(size_t dwSize); BASE_EXPORT LPVOID STDCALL OSVirtualAlloc(size_t dwSize);
@ -158,6 +155,8 @@ BASE_EXPORT void STDCALL TraceCrashEnd();
//Base functions //Base functions
//----------------------------------------- //-----------------------------------------
BASE_EXPORT BOOL STDCALL InitXT(CTSTR logFile=NULL, CTSTR allocatorName=NULL); BASE_EXPORT BOOL STDCALL InitXT(CTSTR logFile=NULL, CTSTR allocatorName=NULL);
BASE_EXPORT void STDCALL InitXTLog(CTSTR logFile);
BASE_EXPORT void STDCALL ResetXTAllocator(CTSTR lpAllocator);
BASE_EXPORT void STDCALL TerminateXT(); BASE_EXPORT void STDCALL TerminateXT();
BASE_EXPORT extern BOOL bDebugBreak; BASE_EXPORT extern BOOL bDebugBreak;

View File

@ -33,13 +33,13 @@ D3D10System::D3D10System()
swapDesc.BufferDesc.Width = App->renderFrameWidth; swapDesc.BufferDesc.Width = App->renderFrameWidth;
swapDesc.BufferDesc.Height = App->renderFrameHeight; swapDesc.BufferDesc.Height = App->renderFrameHeight;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.Flags = 0; swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
swapDesc.OutputWindow = hwndRenderFrame; swapDesc.OutputWindow = hwndRenderFrame;
swapDesc.SampleDesc.Count = 1; swapDesc.SampleDesc.Count = 1;
swapDesc.Windowed = TRUE; swapDesc.Windowed = TRUE;
UINT createFlags = D3D10_CREATE_DEVICE_BGRA_SUPPORT; UINT createFlags = D3D10_CREATE_DEVICE_BGRA_SUPPORT;
if(AppConfig->GetInt(TEXT("General"), TEXT("UseDebugD3D"))) if(GlobalConfig->GetInt(TEXT("General"), TEXT("UseDebugD3D")))
createFlags |= D3D10_CREATE_DEVICE_DEBUG; createFlags |= D3D10_CREATE_DEVICE_DEBUG;
//D3D10_CREATE_DEVICE_DEBUG //D3D10_CREATE_DEVICE_DEBUG
@ -677,12 +677,14 @@ void D3D10System::ResetViewMatrix()
void D3D10System::ResizeView() void D3D10System::ResizeView()
{ {
traceIn(D3D10System::ResizeView);
LPVOID nullVal = NULL; LPVOID nullVal = NULL;
d3d->OMSetRenderTargets(1, (ID3D10RenderTargetView**)&nullVal, NULL); d3d->OMSetRenderTargets(1, (ID3D10RenderTargetView**)&nullVal, NULL);
SafeRelease(swapRenderView); SafeRelease(swapRenderView);
swap->ResizeBuffers(2, 0, 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0); swap->ResizeBuffers(2, 0, 0, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE);
ID3D10Texture2D *backBuffer = NULL; ID3D10Texture2D *backBuffer = NULL;
HRESULT err = swap->GetBuffer(0, IID_ID3D10Texture2D, (void**)&backBuffer); HRESULT err = swap->GetBuffer(0, IID_ID3D10Texture2D, (void**)&backBuffer);
@ -694,5 +696,7 @@ void D3D10System::ResizeView()
CrashError(TEXT("Unable to get render view from back buffer")); CrashError(TEXT("Unable to get render view from back buffer"));
backBuffer->Release(); backBuffer->Release();
traceOut;
} }

View File

@ -351,8 +351,8 @@ UINT MMDeviceAudioSource::GetNextBuffer()
__m128 outVal1 = _mm_unpacklo_ps(inVal, inVal); __m128 outVal1 = _mm_unpacklo_ps(inVal, inVal);
__m128 outVal2 = _mm_unpackhi_ps(inVal, inVal); __m128 outVal2 = _mm_unpackhi_ps(inVal, inVal);
_mm_store_ps(outputTemp+(i*2), outVal1); _mm_store_ps(outputTemp+(i*2), outVal1);
_mm_store_ps(outputTemp+(i*2)+4, outVal1); _mm_store_ps(outputTemp+(i*2)+4, outVal2);
} }
numFloats -= alignedFloats; numFloats -= alignedFloats;
@ -580,7 +580,7 @@ UINT MMDeviceAudioSource::GetNextBuffer()
receiveBuffer.AppendArray(resampleBuffer.Array(), data.output_frames_gen*2); receiveBuffer.AppendArray(resampleBuffer.Array(), data.output_frames_gen*2);
} }
else else
receiveBuffer.AppendArray(outputBuffer, numAudioFrames*2); receiveBuffer.AppendArray(audioBuffer.Array(), numAudioFrames*2);
return receiveBuffer.Num() >= (441*2) ? AudioAvailable : ContinueAudioRequest; return receiveBuffer.Num() >= (441*2) ? AudioAvailable : ContinueAudioRequest;
} }

View File

@ -19,6 +19,7 @@
#include "Main.h" #include "Main.h"
#include <shlobj.h>
#include <dwmapi.h> #include <dwmapi.h>
@ -27,8 +28,10 @@
HWND hwndMain = NULL; HWND hwndMain = NULL;
HWND hwndRenderFrame = NULL; HWND hwndRenderFrame = NULL;
HINSTANCE hinstMain = NULL; HINSTANCE hinstMain = NULL;
ConfigFile *GlobalConfig = NULL;
ConfigFile *AppConfig = NULL; ConfigFile *AppConfig = NULL;
OBS *App = NULL; OBS *App = NULL;
TCHAR lpAppDataPath[MAX_PATH];
//---------------------------- //----------------------------
@ -82,12 +85,135 @@ void LogSystemStats()
} }
void SetupIni()
{
//first, find out which profile we're using
String strProfile = GlobalConfig->GetString(TEXT("General"), TEXT("Profile"));
String strIni;
//--------------------------------------------
// try to find and open the file, otherwise use the first one available
bool bFoundProfile = false;
if(strProfile.IsValid())
{
strIni << lpAppDataPath << TEXT("\\profiles\\") << strProfile << TEXT(".ini");
bFoundProfile = OSFileExists(strIni) != 0;
}
if(!bFoundProfile)
{
OSFindData ofd;
strIni.Clear() << lpAppDataPath << TEXT("\\profiles\\*.ini");
HANDLE hFind = OSFindFirstFile(strIni, ofd);
if(hFind)
{
do
{
if(ofd.bDirectory) continue;
strProfile = GetPathWithoutExtension(ofd.fileName);
GlobalConfig->SetString(TEXT("General"), TEXT("Profile"), strProfile);
bFoundProfile = true;
break;
} while(OSFindNextFile(hFind, ofd));
OSFindClose(hFind);
}
}
//--------------------------------------------
// open, or if no profile found, create one
if(bFoundProfile)
{
strIni.Clear() << lpAppDataPath << TEXT("\\profiles\\") << strProfile << TEXT(".ini");
if(AppConfig->Open(strIni))
return;
}
strProfile = TEXT("Untitled");
GlobalConfig->SetString(TEXT("General"), TEXT("Profile"), strProfile);
strIni.Clear() << lpAppDataPath << TEXT("\\profiles\\") << strProfile << TEXT(".ini");
if(!AppConfig->Create(strIni))
CrashError(TEXT("Could not create '%s'"), strIni);
AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Default"));
AppConfig->SetFloat (TEXT("Audio"), TEXT("MicVolume"), 1.0f);
AppConfig->SetFloat (TEXT("Audio"), TEXT("DesktopVolume"), 1.0f);
AppConfig->SetInt (TEXT("Video"), TEXT("Monitor"), 0);
AppConfig->SetInt (TEXT("Video"), TEXT("FPS"), 25);
AppConfig->SetFloat (TEXT("Video"), TEXT("Downscale"), 1.0f);
AppConfig->SetInt (TEXT("Video"), TEXT("DisableAero"), 0);
AppConfig->SetInt (TEXT("Video Encoding"), TEXT("BufferSize"), 1000);
AppConfig->SetInt (TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000);
AppConfig->SetString(TEXT("Video Encoding"), TEXT("Preset"), TEXT("veryfast"));
AppConfig->SetInt (TEXT("Video Encoding"), TEXT("Quality"), 8);
AppConfig->SetInt (TEXT("Audio Encoding"), TEXT("Format"), 1);
AppConfig->SetString(TEXT("Audio Encoding"), TEXT("Bitrate"), TEXT("128"));
AppConfig->SetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC"));
AppConfig->SetInt (TEXT("Publish"), TEXT("Service"), 0);
AppConfig->SetInt (TEXT("Publish"), TEXT("Mode"), 0);
};
void LoadGlobalIni()
{
GlobalConfig = new ConfigFile;
String strGlobalIni;
strGlobalIni << lpAppDataPath << TEXT("\\global.ini");
if(!GlobalConfig->Open(strGlobalIni))
{
if(!GlobalConfig->Create(strGlobalIni))
CrashError(TEXT("Could not create '%s'"), strGlobalIni.Array());
//----------------------
// first, try to set the app to the system language, defaulting to english if the language doesn't exist
DWORD bufSize = GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SISO639LANGNAME, NULL, 0);
String str639Lang;
str639Lang.SetLength(bufSize);
GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SISO639LANGNAME, str639Lang.Array(), bufSize+1);
String strLangFile;
strLangFile << TEXT("locale/") << str639Lang << TEXT(".txt");
if(!OSFileExists(strLangFile))
str639Lang = TEXT("en");
//----------------------
GlobalConfig->SetString(TEXT("General"), TEXT("Language"), str639Lang);
GlobalConfig->SetInt(TEXT("General"), TEXT("MaxLogs"), 20);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{ {
//make sure only one instance of the application can be open at a time //make sure only one instance of the application can be open at a time
hOBSMutex = CreateMutex(NULL, TRUE, TEXT("OBSMutex")); hOBSMutex = CreateMutex(NULL, TRUE, TEXT("OBSMutex"));
if(GetLastError() == ERROR_ALREADY_EXISTS) if(GetLastError() == ERROR_ALREADY_EXISTS)
{ {
hwndMain = FindWindow(OBS_WINDOW_CLASS, NULL);
if(hwndMain)
SetForegroundWindow(hwndMain);
CloseHandle(hOBSMutex); CloseHandle(hOBSMutex);
return 0; return 0;
} }
@ -96,68 +222,108 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
hinstMain = hInstance; hinstMain = hInstance;
//------------------------------------------------------------ if(InitXT(NULL, TEXT("FastAlloc")))
// get the allocator from the config. problem is we need an allocator to load the config
CTSTR lpAllocatorString = TEXT("FastAlloc");
MainAllocator = new DefaultAlloc;
AppConfig = new ConfigFile;
if(AppConfig->Open(TEXT("OBS.ini")))
lpAllocatorString = AppConfig->GetStringPtr(TEXT("General"), TEXT("Allocator"), TEXT("FastAlloc"));
UINT stringSize = ssize(lpAllocatorString);
TSTR lpAllocator = (TSTR)malloc(stringSize);
mcpy(lpAllocator, lpAllocatorString, stringSize);
delete AppConfig;
delete MainAllocator;
//------------------------------------------------------------
if(InitXT(TEXT("OBS.log"), lpAllocator))
{ {
traceIn(Main); traceIn(Main);
InitSockets();
//CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoInitialize(0);
EnableProfiling(TRUE); EnableProfiling(TRUE);
TSTR lpAllocator = NULL;
{
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, lpAppDataPath);
scat_n(lpAppDataPath, TEXT("\\OBS"), 4);
if(!OSFileExists(lpAppDataPath) && !OSCreateDirectory(lpAppDataPath))
CrashError(TEXT("Couldn't create directory '%s'"), lpAppDataPath);
String strAppDataPath = lpAppDataPath;
String strProfilesPath = strAppDataPath + TEXT("\\profiles");
if(!OSFileExists(strProfilesPath) && !OSCreateDirectory(strProfilesPath))
CrashError(TEXT("Couldn't create directory '%s'"), strProfilesPath.Array());
String strLogsPath = strAppDataPath + TEXT("\\logs");
if(!OSFileExists(strLogsPath) && !OSCreateDirectory(strLogsPath))
CrashError(TEXT("Couldn't create directory '%s'"), strLogsPath.Array());
String strPluginDataPath = strAppDataPath + TEXT("\\pluginData");
if(!OSFileExists(strPluginDataPath) && !OSCreateDirectory(strPluginDataPath))
CrashError(TEXT("Couldn't create directory '%s'"), strPluginDataPath.Array());
LoadGlobalIni();
String strAllocator = GlobalConfig->GetString(TEXT("General"), TEXT("Allocator"));
if(strAllocator.IsValid())
{
UINT size = strAllocator.DataLength();
lpAllocator = (TSTR)malloc(size);
mcpy(lpAllocator, strAllocator.Array(), size);
}
}
if(lpAllocator)
{
delete GlobalConfig;
ResetXTAllocator(lpAllocator);
free(lpAllocator);
LoadGlobalIni();
}
//--------------------------------------------
String strDirectory;
UINT dirSize = GetCurrentDirectory(0, 0);
strDirectory.SetLength(dirSize);
GetCurrentDirectory(dirSize, strDirectory.Array());
GlobalConfig->SetString(TEXT("General"), TEXT("LastAppDirectory"), strDirectory.Array());
//--------------------------------------------
AppConfig = new ConfigFile;
SetupIni();
//--------------------------------------------
String strLogFileWildcard;
strLogFileWildcard << lpAppDataPath << TEXT("\\logs\\*.log");
OSFindData ofd;
HANDLE hFindLogs = OSFindFirstFile(strLogFileWildcard, ofd);
if(hFindLogs)
{
int numLogs = 0;
String strFirstLog;
do
{
if(ofd.bDirectory) continue;
if(!numLogs++)
strFirstLog << lpAppDataPath << TEXT("\\logs\\") << ofd.fileName;
} while(OSFindNextFile(hFindLogs, ofd));
OSFindClose(hFindLogs);
if(numLogs >= GlobalConfig->GetInt(TEXT("General"), TEXT("MaxLogs"), 20))
OSDeleteFile(strFirstLog);
}
SYSTEMTIME st;
GetLocalTime(&st);
String strLog;
strLog << lpAppDataPath << FormattedString(TEXT("\\logs\\%u-%02u-%02u-%02u%02u-%02u"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond) << TEXT(".log");
InitXTLog(strLog);
LogSystemStats(); LogSystemStats();
//CoInitializeEx(NULL, COINIT_MULTITHREADED); //--------------------------------------------
CoInitialize(0);
InitSockets();
AppConfig = new ConfigFile;
if(!AppConfig->Open(TEXT("OBS.ini")))
{
if(!AppConfig->Create(TEXT("OBS.ini")))
CrashError(TEXT("Could not open OBS.ini"));
AppConfig->SetString(TEXT("General"), TEXT("Language"), TEXT("en"));
AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Default"));
AppConfig->SetFloat (TEXT("Audio"), TEXT("MicVolume"), 1.0f);
AppConfig->SetFloat (TEXT("Audio"), TEXT("DesktopVolume"), 1.0f);
AppConfig->SetInt (TEXT("Video"), TEXT("Monitor"), 0);
AppConfig->SetInt (TEXT("Video"), TEXT("FPS"), 25);
AppConfig->SetFloat (TEXT("Video"), TEXT("Downscale"), 1.0f);
AppConfig->SetInt (TEXT("Video"), TEXT("DisableAero"), 0);
AppConfig->SetInt (TEXT("Video Encoding"), TEXT("BufferSize"), 1000);
AppConfig->SetInt (TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000);
AppConfig->SetString(TEXT("Video Encoding"), TEXT("Preset"), TEXT("veryfast"));
AppConfig->SetInt (TEXT("Video Encoding"), TEXT("Quality"), 8);
AppConfig->SetInt (TEXT("Audio Encoding"), TEXT("Format"), 1);
AppConfig->SetString(TEXT("Audio Encoding"), TEXT("Bitrate"), TEXT("128"));
AppConfig->SetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC"));
AppConfig->SetInt (TEXT("Publish"), TEXT("Service"), 0);
AppConfig->SetInt (TEXT("Publish"), TEXT("Mode"), 0);
}
bDisableComposition = AppConfig->GetInt(TEXT("Video"), TEXT("DisableAero"), 0); bDisableComposition = AppConfig->GetInt(TEXT("Video"), TEXT("DisableAero"), 0);
@ -168,6 +334,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
DwmEnableComposition(DWM_EC_DISABLECOMPOSITION); DwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
} }
//--------------------------------------------
App = new OBS; App = new OBS;
HACCEL hAccel = LoadAccelerators(hinstMain, MAKEINTRESOURCE(IDR_ACCELERATOR1)); HACCEL hAccel = LoadAccelerators(hinstMain, MAKEINTRESOURCE(IDR_ACCELERATOR1));
@ -183,7 +351,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
} }
delete App; delete App;
//--------------------------------------------
delete AppConfig; delete AppConfig;
delete GlobalConfig;
if(bDisableComposition && bCompositionEnabled) if(bDisableComposition && bCompositionEnabled)
DwmEnableComposition(DWM_EC_ENABLECOMPOSITION); DwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
@ -191,11 +363,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
TerminateSockets(); TerminateSockets();
traceOutStop; traceOutStop;
TerminateXT();
} }
free(lpAllocator); TerminateXT();
//------------------------------------------------------------ //------------------------------------------------------------

View File

@ -56,12 +56,17 @@ class OBS;
extern HWND hwndMain; extern HWND hwndMain;
extern HWND hwndRenderFrame; extern HWND hwndRenderFrame;
extern HINSTANCE hinstMain; extern HINSTANCE hinstMain;
extern ConfigFile *GlobalConfig;
extern ConfigFile *AppConfig; extern ConfigFile *AppConfig;
extern OBS *App; extern OBS *App;
extern TCHAR lpAppDataPath[MAX_PATH];
#define OBS_VERSION_STRING_ANSI "Open Broadcaster Software v0.37a" #define OBS_VERSION_STRING_ANSI "Open Broadcaster Software v0.38a"
#define OBS_VERSION_STRING TEXT(OBS_VERSION_STRING_ANSI) #define OBS_VERSION_STRING TEXT(OBS_VERSION_STRING_ANSI)
#define OBS_WINDOW_CLASS TEXT("OBSWindowClass")
#define OBS_RENDERFRAME_CLASS TEXT("RenderFrame")
inline UINT ConvertMSTo100NanoSec(UINT ms) inline UINT ConvertMSTo100NanoSec(UINT ms)
{ {
return ms*1000*10; //1000 microseconds, then 10 "100nanosecond" segments return ms*1000*10; //1000 microseconds, then 10 "100nanosecond" segments

View File

@ -57,7 +57,7 @@ NetworkStream* CreateNullNetwork();
void Convert444to420(LPBYTE input, int width, int height, LPBYTE *output, bool bSSE2Available); void Convert444to420(LPBYTE input, int width, int height, LPBYTE *output, bool bSSE2Available);
void STDCALL SceneHotkey(DWORD hotkey, UPARAM param); void STDCALL SceneHotkey(DWORD hotkey, UPARAM param, bool bDown);
inline BOOL CloseDouble(double f1, double f2, double precision=0.001) inline BOOL CloseDouble(double f1, double f2, double precision=0.001)
@ -72,11 +72,6 @@ WNDPROC listboxProc = NULL;
//---------------------------- //----------------------------
#define OBS_WINDOW_CLASS TEXT("OBS")
#define OBS_RENDERFRAME_CLASS TEXT("RenderFrame")
//----------------------------
const float defaultBlendFactor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; const float defaultBlendFactor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
//---------------------------- //----------------------------
@ -293,6 +288,7 @@ Scene* STDCALL CreateNormalScene(XElement *data)
struct HotkeyInfo struct HotkeyInfo
{ {
DWORD hotkeyID;
DWORD hotkey; DWORD hotkey;
OBSHOTKEYPROC hotkeyProc; OBSHOTKEYPROC hotkeyProc;
UPARAM param; UPARAM param;
@ -304,6 +300,7 @@ class OBSAPIInterface : public APIInterface
friend class OBS; friend class OBS;
List<HotkeyInfo> hotkeys; List<HotkeyInfo> hotkeys;
DWORD curHotkeyIDVal;
void HandleHotkeys(); void HandleHotkeys();
@ -347,6 +344,9 @@ public:
virtual CTSTR GetLanguage() const {return App->strLanguage;} virtual CTSTR GetLanguage() const {return App->strLanguage;}
virtual CTSTR GetAppDataPath() const {return lpAppDataPath;}
virtual String GetPluginDataPath() const {return String() << lpAppDataPath << TEXT("\\pluginData");}
virtual HWND GetMainWindow() const {return hwndMain;} virtual HWND GetMainWindow() const {return hwndMain;}
}; };
@ -389,7 +389,7 @@ OBS::OBS()
if(!locale->LoadStringFile(TEXT("locale/en.txt"))) if(!locale->LoadStringFile(TEXT("locale/en.txt")))
AppWarning(TEXT("Could not open locale string file '%s'"), TEXT("locale/en.txt")); AppWarning(TEXT("Could not open locale string file '%s'"), TEXT("locale/en.txt"));
strLanguage = AppConfig->GetString(TEXT("General"), TEXT("Language"), TEXT("en")); strLanguage = GlobalConfig->GetString(TEXT("General"), TEXT("Language"), TEXT("en"));
if(!strLanguage.CompareI(TEXT("en"))) if(!strLanguage.CompareI(TEXT("en")))
{ {
String langFile; String langFile;
@ -632,8 +632,11 @@ OBS::OBS()
hwndTemp = GetDlgItem(hwndMain, ID_SCENES); hwndTemp = GetDlgItem(hwndMain, ID_SCENES);
if(!scenesConfig.Open(TEXT("scenes.xconfig"))) String strScenesConfig;
CrashError(TEXT("Could not open scenes.xconfig")); strScenesConfig << lpAppDataPath << TEXT("\\scenes.xconfig");
if(!scenesConfig.Open(strScenesConfig))
CrashError(TEXT("Could not open '%s'"), strScenesConfig);
XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); XElement *scenes = scenesConfig.GetElement(TEXT("scenes"));
if(!scenes) if(!scenes)
@ -712,6 +715,11 @@ OBS::OBS()
OSFindClose(hFind); OSFindClose(hFind);
} }
//-----------------------------------------------------
bRenderViewEnabled = true;
bShowFPS = AppConfig->GetInt(TEXT("General"), TEXT("ShowFPS")) != 0;
traceOut; traceOut;
} }
@ -745,6 +753,13 @@ OBS::~OBS()
DeleteObject(Icons[i].hIcon); DeleteObject(Icons[i].hIcon);
Icons.Clear(); Icons.Clear();
for(UINT i=0; i<Fonts.Num(); i++)
{
DeleteObject(Fonts[i].hFont);
Fonts[i].strFontFace.Clear();
}
Fonts.Clear();
for(UINT i=0; i<sceneClasses.Num(); i++) for(UINT i=0; i<sceneClasses.Num(); i++)
sceneClasses[i].FreeData(); sceneClasses[i].FreeData();
for(UINT i=0; i<imageSourceClasses.Num(); i++) for(UINT i=0; i<imageSourceClasses.Num(); i++)
@ -772,8 +787,10 @@ void OBS::ToggleCapturing()
traceOut; traceOut;
} }
void STDCALL SceneHotkey(DWORD hotkey, UPARAM param) void STDCALL SceneHotkey(DWORD hotkey, UPARAM param, bool bDown)
{ {
if(!bDown) return;
XElement *scenes = API->GetSceneListElement(); XElement *scenes = API->GetSceneListElement();
if(scenes) if(scenes)
{ {
@ -784,7 +801,7 @@ void STDCALL SceneHotkey(DWORD hotkey, UPARAM param)
DWORD sceneHotkey = (DWORD)scene->GetInt(TEXT("hotkey")); DWORD sceneHotkey = (DWORD)scene->GetInt(TEXT("hotkey"));
if(sceneHotkey == hotkey) if(sceneHotkey == hotkey)
{ {
Log(TEXT("hotkey pressed for scene '%s'"), scene->GetName()); //Log(TEXT("hotkey pressed for scene '%s'"), scene->GetName());
App->SetScene(scene->GetName()); App->SetScene(scene->GetName());
return; return;
} }
@ -800,6 +817,8 @@ HICON OBS::GetIcon(HINSTANCE hInst, int resource)
return Icons[i].hIcon; return Icons[i].hIcon;
} }
//---------------------
IconInfo ii; IconInfo ii;
ii.hInst = hInst; ii.hInst = hInst;
ii.resource = resource; ii.resource = resource;
@ -810,6 +829,38 @@ HICON OBS::GetIcon(HINSTANCE hInst, int resource)
return ii.hIcon; return ii.hIcon;
} }
HFONT OBS::GetFont(CTSTR lpFontFace, int fontSize, int fontWeight)
{
for(UINT i=0; i<Fonts.Num(); i++)
{
if(Fonts[i].strFontFace.CompareI(lpFontFace) && Fonts[i].fontSize == fontSize && Fonts[i].fontWeight == fontWeight)
return Fonts[i].hFont;
}
//---------------------
HFONT hFont = NULL;
LOGFONT lf;
zero(&lf, sizeof(lf));
scpy_n(lf.lfFaceName, lpFontFace, 31);
lf.lfHeight = fontSize;
lf.lfWeight = fontWeight;
lf.lfQuality = ANTIALIASED_QUALITY;
if(hFont = CreateFontIndirect(&lf))
{
FontInfo &fi = *Fonts.CreateNew();
fi.hFont = hFont;
fi.fontSize = fontSize;
fi.fontWeight = fontWeight;
fi.strFontFace = lpFontFace;
}
return hFont;
}
ID3D10Blob* CompileShader(CTSTR lpShader, LPCSTR lpTarget) ID3D10Blob* CompileShader(CTSTR lpShader, LPCSTR lpTarget)
{ {
traceIn(CompileShader); traceIn(CompileShader);
@ -1303,8 +1354,6 @@ void OBS::MainCaptureLoop()
bufferedTimes.Clear(); bufferedTimes.Clear();
//firstFrameTime -= UINT(frameTime);
Vect2 baseSize = Vect2(float(baseCX), float(baseCY)); Vect2 baseSize = Vect2(float(baseCX), float(baseCY));
Vect2 outputSize = Vect2(float(outputCX), float(outputCY)); Vect2 outputSize = Vect2(float(outputCX), float(outputCY));
Vect2 scaleSize = Vect2(float(scaleCX), float(scaleCY)); Vect2 scaleSize = Vect2(float(scaleCX), float(scaleCY));
@ -1326,7 +1375,6 @@ void OBS::MainCaptureLoop()
x264_picture_alloc(&picOut, X264_CSP_I420, outputCX, outputCY); x264_picture_alloc(&picOut, X264_CSP_I420, outputCX, outputCY);
int curPTS = 0; int curPTS = 0;
//int audioJump = 0;
HANDLE hScaleVal = yuvScalePixelShader->GetParameterByName(TEXT("baseDimensionI")); HANDLE hScaleVal = yuvScalePixelShader->GetParameterByName(TEXT("baseDimensionI"));
@ -1338,15 +1386,14 @@ void OBS::MainCaptureLoop()
float bpsTime = 0.0f; float bpsTime = 0.0f;
double lastStrain = 0.0f; double lastStrain = 0.0f;
DWORD audioResyncOffset = 0; DWORD captureFPS = 0;
DWORD fpsCounter = 0;
UINT timeAdjust = 0;
while(bRunning) while(bRunning)
{ {
DWORD renderStartTime = OSGetTime(); DWORD renderStartTime = OSGetTime();
bool bRenderView = !IsIconic(hwndMain); bool bRenderView = !IsIconic(hwndMain) && bRenderViewEnabled;
profileIn("frame"); profileIn("frame");
@ -1405,9 +1452,14 @@ void OBS::MainCaptureLoop()
lastBytesSent = curBytesSent; lastBytesSent = curBytesSent;
captureFPS = fpsCounter;
fpsCounter = 0;
bUpdateBPS = true; bUpdateBPS = true;
} }
fpsCounter++;
double curStrain = network->GetPacketStrain(); double curStrain = network->GetPacketStrain();
if(bUpdateBPS || !CloseDouble(curStrain, lastStrain)) if(bUpdateBPS || !CloseDouble(curStrain, lastStrain))
{ {
@ -1505,6 +1557,38 @@ void OBS::MainCaptureLoop()
if(scene) if(scene)
scene->RenderSelections(); scene->RenderSelections();
} }
if(bShowFPS && !bSizeChanging)
{
D3D10System *d3dSys = static_cast<D3D10System*>(GS);
IDXGISurface1 *surface;
if(SUCCEEDED(d3dSys->swap->GetBuffer(0, __uuidof(IDXGISurface1), (void**)&surface)))
{
HDC hDC;
if(SUCCEEDED(surface->GetDC(FALSE, &hDC)))
{
String strFPS;
strFPS << TEXT("FPS: ") << UIntString(captureFPS);
HFONT hFont = (HFONT)GetFont(TEXT("Arial"), -20, 700);
HFONT hfontOld;
if(hFont)
hfontOld = (HFONT)SelectObject(hDC, hFont);
SetTextColor(hDC, MAKEBGR(0xFF, 0, 0));
SetBkMode(hDC, TRANSPARENT);
TextOut(hDC, 4, 4, strFPS, strFPS.Length());
if(hFont)
SelectObject(hDC, hfontOld);
surface->ReleaseDC(NULL);
}
surface->Release();
}
}
} }
//------------------------------------ //------------------------------------
@ -1535,9 +1619,6 @@ void OBS::MainCaptureLoop()
//------------------------------------ //------------------------------------
if(!static_cast<D3D10System*>(GS)->swap)
Log(TEXT("swap is bad?"));
if(bRenderView && !copyWait) if(bRenderView && !copyWait)
static_cast<D3D10System*>(GS)->swap->Present(0, 0); static_cast<D3D10System*>(GS)->swap->Present(0, 0);
@ -1907,32 +1988,33 @@ void OBS::SelectSources()
} }
} }
void OBS::CallHotkey(DWORD hotkey) void OBS::CallHotkey(DWORD hotkeyID, bool bDown)
{ {
OBSAPIInterface *apiInterface = (OBSAPIInterface*)API; OBSAPIInterface *apiInterface = (OBSAPIInterface*)API;
OBSHOTKEYPROC hotkeyProc = NULL; OBSHOTKEYPROC hotkeyProc = NULL;
UPARAM param; DWORD hotkey = 0;
UPARAM param = NULL;
OSEnterMutex(hHotkeyMutex); OSEnterMutex(hHotkeyMutex);
for(UINT i=0; i<apiInterface->hotkeys.Num(); i++) for(UINT i=0; i<apiInterface->hotkeys.Num(); i++)
{ {
HotkeyInfo &hi = apiInterface->hotkeys[i]; HotkeyInfo &hi = apiInterface->hotkeys[i];
if(hi.hotkey == hotkey) if(hi.hotkeyID == hotkeyID)
{ {
if(hi.hotkeyProc) if(!hi.hotkeyProc)
{ return;
hotkeyProc = hi.hotkeyProc;
param = hi.param; hotkeyProc = hi.hotkeyProc;
} param = hi.param;
hotkey = hi.hotkey;
break; break;
} }
} }
OSLeaveMutex(hHotkeyMutex); OSLeaveMutex(hHotkeyMutex);
if(hotkeyProc) hotkeyProc(hotkey, param, bDown);
hotkeyProc(hotkey, param);
} }
bool OBSAPIInterface::HotkeyExists(DWORD hotkey) const bool OBSAPIInterface::HotkeyExists(DWORD hotkey) const
@ -1969,16 +2051,8 @@ bool OBSAPIInterface::CreateHotkey(DWORD hotkey, OBSHOTKEYPROC hotkeyProc, UPARA
fsModifiers |= MOD_SHIFT; fsModifiers |= MOD_SHIFT;
OSEnterMutex(App->hHotkeyMutex); OSEnterMutex(App->hHotkeyMutex);
for(UINT i=0; i<hotkeys.Num(); i++)
{
if(hotkeys[i].hotkey == hotkey)
{
OSLeaveMutex(App->hHotkeyMutex);
return false;
}
}
HotkeyInfo &hi = *hotkeys.CreateNew(); HotkeyInfo &hi = *hotkeys.CreateNew();
hi.hotkeyID = ++curHotkeyIDVal;
hi.hotkey = hotkey; hi.hotkey = hotkey;
hi.hotkeyProc = hotkeyProc; hi.hotkeyProc = hotkeyProc;
hi.param = param; hi.param = param;
@ -2028,19 +2102,22 @@ void OBSAPIInterface::HandleHotkeys()
{ {
short keyState = GetAsyncKeyState(hotkeyVK); short keyState = GetAsyncKeyState(hotkeyVK);
bool bDown = (keyState & 0x8000) != 0; bool bDown = (keyState & 0x8000) != 0;
bool bWasPressed = (keyState & 1) != 0;
if(bDown || bWasPressed) if(bDown)
{ {
if(!info.bDown) if(!info.bDown)
PostMessage(hwndMain, OBS_CALLHOTKEY, 0, info.hotkey); PostMessage(hwndMain, OBS_CALLHOTKEY, TRUE, info.hotkeyID);
info.bDown = bDown; info.bDown = bDown;
continue; continue;
} }
} }
info.bDown = false; if(info.bDown) //key up
{
PostMessage(hwndMain, OBS_CALLHOTKEY, FALSE, info.hotkeyID);
info.bDown = false;
}
} }
OSLeaveMutex(App->hHotkeyMutex); OSLeaveMutex(App->hHotkeyMutex);

View File

@ -179,6 +179,14 @@ struct IconInfo
int resource; int resource;
}; };
struct FontInfo
{
HFONT hFont;
String strFontFace;
int fontSize;
int fontWeight;
};
//------------------------------------------------------------------- //-------------------------------------------------------------------
struct FrameAudio struct FrameAudio
@ -344,6 +352,8 @@ class OBS
bool bResizeRenderView; bool bResizeRenderView;
bool bEditMode; bool bEditMode;
bool bRenderViewEnabled;
bool bShowFPS;
bool bMouseMoved; bool bMouseMoved;
bool bMouseDown; bool bMouseDown;
bool bItemWasSelected; bool bItemWasSelected;
@ -377,6 +387,7 @@ class OBS
String streamReport; String streamReport;
List<IconInfo> Icons; List<IconInfo> Icons;
List<FontInfo> Fonts;
List<ClassInfo> sceneClasses; List<ClassInfo> sceneClasses;
List<ClassInfo> imageSourceClasses; List<ClassInfo> imageSourceClasses;
@ -469,7 +480,7 @@ class OBS
static INT_PTR CALLBACK GlobalSourcesProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static INT_PTR CALLBACK GlobalSourcesProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static bool STDCALL ConfigGlobalSource(XElement *element, bool bCreating); static bool STDCALL ConfigGlobalSource(XElement *element, bool bCreating);
void CallHotkey(DWORD hotkey); void CallHotkey(DWORD hotkeyID, bool bDown);
public: public:
OBS(); OBS();
@ -499,6 +510,7 @@ public:
inline XElement* GetSceneElement() const {return sceneElement;} inline XElement* GetSceneElement() const {return sceneElement;}
virtual HICON GetIcon(HINSTANCE hInst, int resource); 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 GetVideoHeaders(DataPacket &packet) {videoEncoder->GetHeaders(packet);}
inline void GetAudioHeaders(DataPacket &packet) {audioEncoder->GetHeaders(packet);} inline void GetAudioHeaders(DataPacket &packet) {audioEncoder->GetHeaders(packet);}

View File

@ -58,7 +58,8 @@ class RTMPPublisher : public NetworkStream
QWORD bytesSent; QWORD bytesSent;
//UINT numBFramesDumped; UINT numPFramesDumped;
UINT numBFramesDumped;
//all data sending is done in yet another separate thread to prevent blocking in the main capture thread //all data sending is done in yet another separate thread to prevent blocking in the main capture thread
void SendLoop() void SendLoop()
@ -219,7 +220,7 @@ class RTMPPublisher : public NetworkStream
packet.data.Clear(); packet.data.Clear();
Packets.Remove(i--); Packets.Remove(i--);
numVideoPackets--; numVideoPackets--;
//numBFramesDumped++; numPFramesDumped++;
} }
} }
else if(packet.type == packetWaitType) else if(packet.type == packetWaitType)
@ -227,7 +228,7 @@ class RTMPPublisher : public NetworkStream
packet.data.Clear(); packet.data.Clear();
Packets.Remove(i--); Packets.Remove(i--);
numVideoPackets--; numVideoPackets--;
//numBFramesDumped++; numPFramesDumped++;
bRemovedPacket = true; bRemovedPacket = true;
} }
@ -267,7 +268,7 @@ class RTMPPublisher : public NetworkStream
packet.data.Clear(); packet.data.Clear();
Packets.Remove(i--); Packets.Remove(i--);
numVideoPackets--; numVideoPackets--;
//numBFramesDumped++; numBFramesDumped++;
} }
} }
else if(packet.type == packetWaitType) else if(packet.type == packetWaitType)
@ -275,7 +276,7 @@ class RTMPPublisher : public NetworkStream
packet.data.Clear(); packet.data.Clear();
Packets.Remove(i--); Packets.Remove(i--);
numVideoPackets--; numVideoPackets--;
//numBFramesDumped++; numBFramesDumped++;
bRemovedPacket = true; bRemovedPacket = true;
} }
@ -401,7 +402,7 @@ public:
Packets[i].data.Clear(); Packets[i].data.Clear();
Packets.Clear(); Packets.Clear();
//Log(TEXT("num b frames dumped: %u"), numBFramesDumped); Log(TEXT("Number of b-frames dropped: %u, Number of p-frames dropped: %u"), numBFramesDumped, numPFramesDumped);
//-------------------------- //--------------------------

View File

@ -31,12 +31,41 @@ enum SettingsSelection
BOOL CALLBACK MonitorInfoEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, List<MonitorInfo> &monitors); BOOL CALLBACK MonitorInfoEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, List<MonitorInfo> &monitors);
BOOL IsValidFileName(CTSTR lpFileName)
{
if(!lpFileName || !*lpFileName)
return FALSE;
CTSTR lpTemp = lpFileName;
do
{
if( *lpTemp == '\\' ||
*lpTemp == '/' ||
*lpTemp == ':' ||
*lpTemp == '*' ||
*lpTemp == '?' ||
*lpTemp == '"' ||
*lpTemp == '<' ||
*lpTemp == '>')
{
return FALSE;
}
} while (*++lpTemp);
return TRUE;
}
INT_PTR CALLBACK OBS::GeneralSettingsProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) INT_PTR CALLBACK OBS::GeneralSettingsProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
switch(message) switch(message)
{ {
case WM_INITDIALOG: case WM_INITDIALOG:
{ {
LocalizeWindow(hwnd);
//----------------------------------------------
HWND hwndTemp = GetDlgItem(hwnd, IDC_LANGUAGE); HWND hwndTemp = GetDlgItem(hwnd, IDC_LANGUAGE);
OSFindData ofd; OSFindData ofd;
@ -45,6 +74,8 @@ INT_PTR CALLBACK OBS::GeneralSettingsProc(HWND hwnd, UINT message, WPARAM wParam
{ {
do do
{ {
if(ofd.bDirectory) continue;
String langCode = GetPathFileName(ofd.fileName); String langCode = GetPathFileName(ofd.fileName);
LocaleNativeName *langInfo = GetLocaleNativeName(langCode); LocaleNativeName *langInfo = GetLocaleNativeName(langCode);
@ -61,7 +92,37 @@ INT_PTR CALLBACK OBS::GeneralSettingsProc(HWND hwnd, UINT message, WPARAM wParam
OSFindClose(hFind); OSFindClose(hFind);
} }
LocalizeWindow(hwnd); //----------------------------------------------
String strCurProfile = GlobalConfig->GetString(TEXT("General"), TEXT("Profile"));
hwndTemp = GetDlgItem(hwnd, IDC_PROFILE);
String strProfilesWildcard = lpAppDataPath;
strProfilesWildcard << TEXT("\\profiles\\*.ini");
if(hFind = OSFindFirstFile(strProfilesWildcard, ofd))
{
do
{
if(ofd.bDirectory) continue;
String strProfile = GetPathWithoutExtension(ofd.fileName);
UINT id = (UINT)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)strProfile.Array());
if(strProfile.CompareI(strCurProfile))
SendMessage(hwndTemp, CB_SETCURSEL, id, 0);
} while(OSFindNextFile(hFind, ofd));
OSFindClose(hFind);
}
EnableWindow(GetDlgItem(hwnd, IDC_ADD), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_RENAME), FALSE);
UINT numItems = (UINT)SendMessage(GetDlgItem(hwnd, IDC_PROFILE), CB_GETCOUNT, 0, 0);
EnableWindow(GetDlgItem(hwnd, IDC_REMOVE), (numItems > 1));
//----------------------------------------------
App->SetChangedSettings(false); App->SetChangedSettings(false);
return TRUE; return TRUE;
} }
@ -73,9 +134,147 @@ INT_PTR CALLBACK OBS::GeneralSettingsProc(HWND hwnd, UINT message, WPARAM wParam
if(HIWORD(wParam) != CBN_SELCHANGE) if(HIWORD(wParam) != CBN_SELCHANGE)
break; break;
App->SetChangedSettings(true); SetWindowText(GetDlgItem(hwnd, IDC_INFO), Str("Settings.General.Restart"));
ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW); ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
break; break;
case IDC_PROFILE:
if(HIWORD(wParam) == CBN_EDITCHANGE)
{
String strText = GetEditText((HWND)lParam);
EnableWindow(GetDlgItem(hwnd, IDC_REMOVE), FALSE);
if(strText.IsValid())
{
if(IsValidFileName(strText))
{
String strCurProfile = GlobalConfig->GetString(TEXT("General"), TEXT("Profile"));
UINT id = (UINT)SendMessage((HWND)lParam, CB_FINDSTRINGEXACT, -1, (LPARAM)strText.Array());
EnableWindow(GetDlgItem(hwnd, IDC_ADD), (id == CB_ERR));
EnableWindow(GetDlgItem(hwnd, IDC_RENAME), (id == CB_ERR) || strCurProfile.CompareI(strText));
ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_HIDE);
break;
}
SetWindowText(GetDlgItem(hwnd, IDC_INFO), Str("Settings.General.InvalidName"));
ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
}
else
ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_HIDE);
EnableWindow(GetDlgItem(hwnd, IDC_ADD), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_RENAME), FALSE);
}
else if(HIWORD(wParam) == CBN_SELCHANGE)
{
EnableWindow(GetDlgItem(hwnd, IDC_ADD), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_RENAME), FALSE);
String strProfile = GetCBText((HWND)lParam);
String strProfilePath;
strProfilePath << lpAppDataPath << TEXT("\\profiles\\") << strProfile << TEXT(".ini");
if(!AppConfig->Open(strProfilePath))
{
MessageBox(hwnd, TEXT("Error - unable to open ini file"), NULL, 0);
break;
}
SetWindowText(GetDlgItem(hwnd, IDC_INFO), Str("Settings.Info"));
ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
GlobalConfig->SetString(TEXT("General"), TEXT("Profile"), strProfile);
UINT numItems = (UINT)SendMessage(GetDlgItem(hwnd, IDC_PROFILE), CB_GETCOUNT, 0, 0);
EnableWindow(GetDlgItem(hwnd, IDC_REMOVE), (numItems > 1));
}
break;
case IDC_RENAME:
case IDC_ADD:
if(HIWORD(wParam) == BN_CLICKED)
{
HWND hwndProfileList = GetDlgItem(hwnd, IDC_PROFILE);
String strProfile = GetEditText(hwndProfileList);
bool bRenaming = (LOWORD(wParam) == IDC_RENAME);
String strCurProfile = GlobalConfig->GetString(TEXT("General"), TEXT("Profile"));
String strCurProfilePath;
strCurProfilePath << lpAppDataPath << TEXT("\\profiles\\") << strCurProfile << TEXT(".ini");
String strProfilePath;
strProfilePath << lpAppDataPath << TEXT("\\profiles\\") << strProfile << TEXT(".ini");
if((!bRenaming || !strProfilePath.CompareI(strCurProfilePath)) && OSFileExists(strProfilePath))
MessageBox(hwnd, Str("Settings.General.ProfileExists"), NULL, 0);
else
{
if(bRenaming)
{
if(!MoveFile(strCurProfilePath, strProfilePath))
break;
AppConfig->SetFilePath(strProfilePath);
UINT curID = (UINT)SendMessage(hwndProfileList, CB_FINDSTRINGEXACT, -1, (LPARAM)strCurProfile.Array());
if(curID != CB_ERR)
SendMessage(hwndProfileList, CB_DELETESTRING, curID, 0);
}
else
{
if(!AppConfig->SaveAs(strProfilePath))
{
MessageBox(hwnd, TEXT("Error - unable to create new profile, could not create file"), NULL, 0);
break;
}
}
UINT id = (UINT)SendMessage(hwndProfileList, CB_ADDSTRING, 0, (LPARAM)strProfile.Array());
SendMessage(hwndProfileList, CB_SETCURSEL, id, 0);
GlobalConfig->SetString(TEXT("General"), TEXT("Profile"), strProfile);
UINT numItems = (UINT)SendMessage(hwndProfileList, CB_GETCOUNT, 0, 0);
EnableWindow(GetDlgItem(hwnd, IDC_REMOVE), (numItems > 1));
EnableWindow(GetDlgItem(hwnd, IDC_RENAME), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_ADD), FALSE);
}
}
break;
case IDC_REMOVE:
{
HWND hwndProfileList = GetDlgItem(hwnd, IDC_PROFILE);
String strCurProfile = GlobalConfig->GetString(TEXT("General"), TEXT("Profile"));
UINT numItems = (UINT)SendMessage(hwndProfileList, CB_GETCOUNT, 0, 0);
String strConfirm = Str("Settings.General.ConfirmDelete");
strConfirm.FindReplace(TEXT("$1"), strCurProfile);
if(MessageBox(hwnd, strConfirm, Str("DeleteConfirm.Title"), MB_YESNO) == IDYES)
{
UINT id = (UINT)SendMessage(hwndProfileList, CB_FINDSTRINGEXACT, -1, (LPARAM)strCurProfile.Array());
if(id != CB_ERR)
{
SendMessage(hwndProfileList, CB_DELETESTRING, id, 0);
if(id == numItems-1)
id--;
SendMessage(hwndProfileList, CB_SETCURSEL, id, 0);
GeneralSettingsProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_PROFILE, CBN_SELCHANGE), (LPARAM)hwndProfileList);
String strCurProfilePath;
strCurProfilePath << lpAppDataPath << TEXT("\\profiles\\") << strCurProfile << TEXT(".ini");
OSDeleteFile(strCurProfilePath);
}
}
break;
}
} }
} }
@ -963,7 +1162,7 @@ void OBS::ApplySettings()
if(curSel != CB_ERR) if(curSel != CB_ERR)
{ {
String strLanguageCode = (CTSTR)SendMessage(hwndTemp, CB_GETITEMDATA, curSel, 0); String strLanguageCode = (CTSTR)SendMessage(hwndTemp, CB_GETITEMDATA, curSel, 0);
AppConfig->SetString(TEXT("General"), TEXT("Language"), strLanguageCode); GlobalConfig->SetString(TEXT("General"), TEXT("Language"), strLanguageCode);
} }
break; break;
} }

View File

@ -26,7 +26,7 @@
extern WNDPROC listboxProc; extern WNDPROC listboxProc;
void STDCALL SceneHotkey(DWORD hotkey, UPARAM param); void STDCALL SceneHotkey(DWORD hotkey, UPARAM param, bool bDown);
enum enum
{ {
@ -141,10 +141,19 @@ INT_PTR CALLBACK OBS::SceneHotkeyDialogProc(HWND hwnd, UINT message, WPARAM wPar
break; break;
} }
if(hotkey && API->HotkeyExists(hotkey)) if(hotkey)
{ {
MessageBox(hwnd, Str("Scene.Hotkey.AlreadyInUse"), NULL, 0); XElement *scenes = API->GetSceneListElement();
return 0; UINT numScenes = scenes->NumElements();
for(UINT i=0; i<numScenes; i++)
{
XElement *sceneElement = scenes->GetElementByID(i);
if(sceneElement->GetInt(TEXT("hotkey")) == hotkey)
{
MessageBox(hwnd, Str("Scene.Hotkey.AlreadyInUse"), NULL, 0);
return 0;
}
}
} }
hotkeyInfo->hotkey = hotkey; hotkeyInfo->hotkey = hotkey;
@ -590,11 +599,7 @@ LRESULT CALLBACK OBS::ListboxHook(HWND hwnd, UINT message, WPARAM wParam, LPARAM
} }
if(App->bRunning) if(App->bRunning)
{
OSEnterMutex(App->hSceneMutex);
App->scene->AddImageSource(newSourceElement); App->scene->AddImageSource(newSourceElement);
OSLeaveMutex(App->hSceneMutex);
}
UINT newID = (UINT)SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)strName.Array()); UINT newID = (UINT)SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)strName.Array());
PostMessage(hwnd, LB_SETCURSEL, newID, 0); PostMessage(hwnd, LB_SETCURSEL, newID, 0);
@ -1526,7 +1531,7 @@ LRESULT CALLBACK OBS::OBSProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
break; break;
case OBS_CALLHOTKEY: case OBS_CALLHOTKEY:
App->CallHotkey((DWORD)lParam); App->CallHotkey((DWORD)lParam, wParam != 0);
break; break;
case WM_CLOSE: case WM_CLOSE:
@ -1574,6 +1579,12 @@ ItemModifyType GetItemModifyType(const Vect2 &mousePos, const Vect2 &itemPos, co
return ItemModifyType_Move; return ItemModifyType_Move;
} }
enum
{
ID_TOGGLERENDERVIEW=1,
ID_SHOWFPS,
};
LRESULT CALLBACK OBS::RenderFrameProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK OBS::RenderFrameProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
traceIn(OBS::RenderFrameProc); traceIn(OBS::RenderFrameProc);
@ -2067,6 +2078,30 @@ LRESULT CALLBACK OBS::RenderFrameProc(HWND hwnd, UINT message, WPARAM wParam, LP
} }
} }
} }
else if(message == WM_RBUTTONDOWN)
{
HMENU hPopup = CreatePopupMenu();
AppendMenu(hPopup, MF_STRING | (App->bRenderViewEnabled ? MF_CHECKED : 0), ID_TOGGLERENDERVIEW, Str("RenderView.EnableView"));
AppendMenu(hPopup, MF_STRING | (App->bShowFPS ? MF_CHECKED : 0), ID_SHOWFPS, Str("RenderView.ShowFPS"));
POINT p;
GetCursorPos(&p);
int ret = (int)TrackPopupMenuEx(hPopup, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, hwndMain, NULL);
switch(ret)
{
case ID_TOGGLERENDERVIEW:
App->bRenderViewEnabled = !App->bRenderViewEnabled;
break;
case ID_SHOWFPS:
App->bShowFPS = !App->bShowFPS;
AppConfig->SetInt(TEXT("General"), TEXT("ShowFPS"), App->bShowFPS ? 1 : 0);
break;
}
DestroyMenu(hPopup);
}
return DefWindowProc(hwnd, message, wParam, lParam); return DefWindowProc(hwnd, message, wParam, lParam);

1
TODO
View File

@ -4,7 +4,6 @@ More up to date list on the website
------------------------------------------------------- -------------------------------------------------------
List of features yet to be implemented: List of features yet to be implemented:
* implement ability to save multiple channel/server settings
* add other commonly used server data to the services.xconfig file * add other commonly used server data to the services.xconfig file
(livestream, etc), need to find out their server details (livestream, etc), need to find out their server details
* Option to output to mp4/avi file. Not going to use ffmpeg by * Option to output to mp4/avi file. Not going to use ffmpeg by

View File

@ -2,6 +2,7 @@
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by OBS.rc // Used by OBS.rc
// //
#define IDC_DEFAULTS 3
#define IDC_APPLY 4 #define IDC_APPLY 4
#define IDD_SETTINGS 101 #define IDD_SETTINGS 101
#define IDI_ICON1 109 #define IDI_ICON1 109
@ -44,6 +45,7 @@
#define IDC_LANGUAGE 1028 #define IDC_LANGUAGE 1028
#define IDC_INFO 1029 #define IDC_INFO 1029
#define IDC_FPS 1030 #define IDC_FPS 1030
#define IDC_PROFILE 1030
#define IDC_FPS_EDIT 1031 #define IDC_FPS_EDIT 1031
#define IDC_SIZEX 1033 #define IDC_SIZEX 1033
#define IDC_SIZEY 1034 #define IDC_SIZEY 1034
@ -90,6 +92,7 @@
#define IDC_HOTKEY1 1073 #define IDC_HOTKEY1 1073
#define IDC_HOTKEY 1073 #define IDC_HOTKEY 1073
#define IDC_CLEAR 1074 #define IDC_CLEAR 1074
#define IDC_ADDNEW 1077
#define IDA_SOURCE_MOVEUP 40018 #define IDA_SOURCE_MOVEUP 40018
#define IDA_SOURCE_MOVEDOWN 40019 #define IDA_SOURCE_MOVEDOWN 40019
#define IDA_SOURCE_MOVETOTOP 40020 #define IDA_SOURCE_MOVETOTOP 40020
@ -105,7 +108,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 131 #define _APS_NEXT_RESOURCE_VALUE 131
#define _APS_NEXT_COMMAND_VALUE 40028 #define _APS_NEXT_COMMAND_VALUE 40028
#define _APS_NEXT_CONTROL_VALUE 1075 #define _APS_NEXT_CONTROL_VALUE 1078
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif

View File

@ -50,6 +50,9 @@ Plugins.Configure "Configure"
Plugins.Description "Description:" Plugins.Description "Description:"
Plugins.Filename "File name:" Plugins.Filename "File name:"
RenderView.EnableView "Enable View"
RenderView.ShowFPS "Show FPS"
Scene.Hotkey "Scene Hotkey" Scene.Hotkey "Scene Hotkey"
Scene.MissingSources "Was unable to load all image sources due to either invalid settings or missing plugins" Scene.MissingSources "Was unable to load all image sources due to either invalid settings or missing plugins"
@ -86,8 +89,14 @@ Settings.Encoding.Video.Tradeoff "CPU Preset:"
Settings.Encoding.Video.TradeoffTooltip "Setting this value higher reduces CPU usage by sacrificing certain aspects of quality. On the other hand, setting this value lower increases quality at the cost of more CPU.\r\n\r\nRecommended: Very Fast" Settings.Encoding.Video.TradeoffTooltip "Setting this value higher reduces CPU usage by sacrificing certain aspects of quality. On the other hand, setting this value lower increases quality at the cost of more CPU.\r\n\r\nRecommended: Very Fast"
Settings.Encoding.Video.UseI444 "Use YUV 4:4:4" Settings.Encoding.Video.UseI444 "Use YUV 4:4:4"
Settings.General.Language "Language:" Settings.General.Add "Add New"
Settings.General.Restart "Changing the language will require restarting OBS.\r\n\r\n..Though I suppose if you're changing the language you can't understand this" Settings.General.ConfirmDelete "Are you sure you wish to remove the profile '$1'?"
Settings.General.InvalidName "Profile names cannot use the following characters:\r\n\\ / : * ? \" < > |"
Settings.General.Language "Language:"
Settings.General.Profile "Setting Profile:"
Settings.General.Remove "Remove"
Settings.General.Rename "Rename"
Settings.General.Restart "Changing the language will require restarting OBS.\r\n\r\n..Though I suppose if you're changing the language you can't understand this"
Settings.Publish.ChannelName "Channel Name:" Settings.Publish.ChannelName "Channel Name:"
Settings.Publish.Mode "Mode:" Settings.Publish.Mode "Mode:"

View File

@ -22,7 +22,7 @@ Connection.InvalidStream "ストリームのチャンネルやプレイ パ
DeleteConfirm.Title "削除しますか?" DeleteConfirm.Title "削除しますか?"
GlobalSources.DeleteConfirm "グローバル ソースを削除するとすべてのシーンから外します。続けてよろしいですか?" GlobalSources.DeleteConfirm "グローバル ソースが削除するなら、それぞれシーンから外します。続けてよろしいですか?"
Listbox.Add "$1を追加" Listbox.Add "$1を追加"
Listbox.Center "中央に置く" Listbox.Center "中央に置く"
@ -50,10 +50,13 @@ Plugins.Configure "構成"
Plugins.Description "説明:" Plugins.Description "説明:"
Plugins.Filename "ファイル名:" Plugins.Filename "ファイル名:"
Scene.Hotkey "シーンのホットキー" RenderView.EnableView "ビューを有効にする"
Scene.MissingSources "必要なプラグインが見つからなかったとか、ソースの設定が間違っているとかため、すべてのソースは作成できませんでした" RenderView.ShowFPS "FPSを表示する"
Scene.Hotkey.AlreadyInUse "このホットキーは既に使っています。" Scene.Hotkey "シーンのホットキー"
Scene.MissingSources "すべてソースは作成できませんでした"
Scene.Hotkey.AlreadyInUse "このホットキーは既に別のシーンが使っています。"
Scene.Hotkey.Clear "消去" Scene.Hotkey.Clear "消去"
Scene.Hotkey.Hotkey "ホットキー:" Scene.Hotkey.Hotkey "ホットキー:"
@ -61,10 +64,10 @@ Settings.Audio "サウンド"
Settings.Encoding "エンコード" Settings.Encoding "エンコード"
Settings.General "一般" Settings.General "一般"
Settings.Hotkeys "キーボード ショートカット" Settings.Hotkeys "キーボード ショートカット"
Settings.Info "この設定を再びストリーム開始するまでは使用しません" Settings.Info "ストリーム再開始するまでこの設定は適用しません。"
Settings.Publish "放送設定" Settings.Publish "放送設定"
Settings.SaveChangesPrompt "設定を保存して適用しますか?" Settings.SaveChangesPrompt "設定を保存しますか?"
Settings.SaveChangesTitle "適用しますか?" Settings.SaveChangesTitle "保存しますか?"
Settings.Video "動画" Settings.Video "動画"
Settings.Audio.Device "マイク/他のサウンド デバイス:" Settings.Audio.Device "マイク/他のサウンド デバイス:"
@ -80,11 +83,17 @@ Settings.Encoding.Video.BufferSize "バッファー 大きさ (kbit):"
Settings.Encoding.Video.MaxBitRate "ビットレート 最大限 (kbit/秒):" Settings.Encoding.Video.MaxBitRate "ビットレート 最大限 (kbit/秒):"
Settings.Encoding.Video.Quality "動画質:" Settings.Encoding.Video.Quality "動画質:"
Settings.Encoding.Video.Tradeoff "CPU プリセット:" Settings.Encoding.Video.Tradeoff "CPU プリセット:"
Settings.Encoding.Video.TradeoffTooltip "CPU使用を調整するための設定です。「superfast」や「ultrafast」はCPU使用を減らすために品質を犠牲にする。一方は「faster」や「fast」以下は品質を優先としてCPU使用をふやします。\r\n\r\n推奨:「veryfast」" Settings.Encoding.Video.TradeoffTooltip "CPUの利用を調整するための設定です。「superfast」や「ultrafast」を使ってはCPU使用を減らすために品質を犠牲にする。一方、「faster」や「fast」以下はCPU利用を増やしますことで品質を優先しようとします。\r\n\r\n推奨:「veryfast」"
Settings.Encoding.Video.UseI444 "YUV 4:4:4を使用する:" Settings.Encoding.Video.UseI444 "YUV 4:4:4を使用する:"
Settings.General.Language "言語:" Settings.General.Add "追加"
Settings.General.Restart "言語を変更にはOBSを再起動する必要があります。…これを読めるなら" Settings.General.ConfirmDelete "'$1'を削除してよろしいですか?"
Settings.General.InvalidName "プロファイル名には次の文字は使いません:\r\n\\ / : * ? \" < > |"
Settings.General.Language "言語:"
Settings.General.Profile "設定プロファイル:"
Settings.General.Remove "削除"
Settings.General.Rename "名前を変更"
Settings.General.Restart "言語を変更にはOBSを再起動する必要があります。…これを読めるなら"
Settings.Publish.ChannelName "チャンネル名:" Settings.Publish.ChannelName "チャンネル名:"
Settings.Publish.Mode "モード:" Settings.Publish.Mode "モード:"
@ -94,13 +103,13 @@ Settings.Publish.Server "サーバー:"
Settings.Publish.Service "サービス:" Settings.Publish.Service "サービス:"
Settings.Publish.Username "ユーザ名 (もしあれば):" Settings.Publish.Username "ユーザ名 (もしあれば):"
Settings.Publish.Mode.BandwidthInfo "転送量情報" Settings.Publish.Mode.BandwidthInfo "転送の報告"
Settings.Publish.Mode.LiveStream "ライブ ストリーム" Settings.Publish.Mode.LiveStream "ライブ ストリーム"
Settings.Publish.Mode.Serve "RTMP ローカル サーバー" Settings.Publish.Mode.Serve "RTMP ローカル サーバー"
Settings.Video.Custom "特性:" Settings.Video.Custom "特性:"
Settings.Video.DisableAero "起動した時にAeroを無効にする:" Settings.Video.DisableAero "起動した時にAeroを無効にする:"
Settings.Video.DisableAeroTooltip "画面ソフトウェア キャプチャーするつもりなら大いに推奨" Settings.Video.DisableAeroTooltip "画面ソフトウェア キャプチャーを使うつもりなら大いに推奨"
Settings.Video.Downscale "解像度の縮小:" Settings.Video.Downscale "解像度の縮小:"
Settings.Video.FPS "FPS:" Settings.Video.FPS "FPS:"
Settings.Video.Monitor "画面:" Settings.Video.Monitor "画面:"
@ -112,13 +121,13 @@ Sources.BitmapSource "ビットマップ画像"
Sources.GlobalSource "グローバル ソース" Sources.GlobalSource "グローバル ソース"
Sources.SoftwareCaptureSource "ソフトウェア キャプチャー ソース" Sources.SoftwareCaptureSource "ソフトウェア キャプチャー ソース"
Sources.BitmapSource.Empty "パスは空です。ビットマップ画像を参照して選択してください" Sources.BitmapSource.Empty "パスは空です。ビットマップ画像ファイルを選択してください"
Sources.SoftwareCaptureSource.EntireWindow "ウィンドウ全部" Sources.SoftwareCaptureSource.EntireWindow "ウィンドウ全部"
Sources.SoftwareCaptureSource.InnerWindow "ウィンドウ内部" Sources.SoftwareCaptureSource.InnerWindow "ウィンドウ内部"
Sources.SoftwareCaptureSource.Monitor "画面:" Sources.SoftwareCaptureSource.Monitor "画面:"
Sources.SoftwareCaptureSource.MonitorCapture "画面キャプチャー" Sources.SoftwareCaptureSource.MonitorCapture "画面キャプチャー"
Sources.SoftwareCaptureSource.MonitorCaptureTooltip "Aeroを無効にするは大いに推奨" Sources.SoftwareCaptureSource.MonitorCaptureTooltip "Aeroを無効にすることは大いに推奨"
Sources.SoftwareCaptureSource.MouseCapture "マウスをキャプチャーする" Sources.SoftwareCaptureSource.MouseCapture "マウスをキャプチャーする"
Sources.SoftwareCaptureSource.Position "位置:" Sources.SoftwareCaptureSource.Position "位置:"
Sources.SoftwareCaptureSource.Refresh "再読み込みする" Sources.SoftwareCaptureSource.Refresh "再読み込みする"
@ -128,7 +137,7 @@ Sources.SoftwareCaptureSource.SelectRegion "領域を選択する"
Sources.SoftwareCaptureSource.SelectRegionTooltip "領域ウィンドウには中央にクリックすれば動けます。枠をクリックすればサイズを調整できます。" Sources.SoftwareCaptureSource.SelectRegionTooltip "領域ウィンドウには中央にクリックすれば動けます。枠をクリックすればサイズを調整できます。"
Sources.SoftwareCaptureSource.Size "大きさ:" Sources.SoftwareCaptureSource.Size "大きさ:"
Sources.SoftwareCaptureSource.Window "ウィンドウ:" Sources.SoftwareCaptureSource.Window "ウィンドウ:"
Sources.SoftwareCaptureSource.WindowCapture "ウィンドウ キャプチャー (他のウィンドウは表示しません。最小化してはできません)" Sources.SoftwareCaptureSource.WindowCapture "ウィンドウ キャプチャー"
Sources.SoftwareCaptureSource.WindowCaptureTooltip "普通ウインドウ キャプチャーだけを使うならAeroは有効にすればいいです。対象ウィンドウは最小化状態なら画像が更新できません。画面キャプチャーより画像の更新が速い。Aeroは有効にするなら上のウィンドウは表示しません。" Sources.SoftwareCaptureSource.WindowCaptureTooltip "普通は、ウインドウ キャプチャーだけを使うならAeroを有効にすればいいです。対象ウィンドウが最小化状態なら画像が更新できません。普通は画面キャプチャーより画像の更新が速い。上のウィンドウはAeroが有効にした場合表示しません。"
Sources.SoftwareCaptureSource.WindowMinimized "ウィンドウは最小化します" Sources.SoftwareCaptureSource.WindowMinimized "ウィンドウは最小化します"
Sources.SoftwareCaptureSource.WindowNotFound "ウィンドウは見つかりません" Sources.SoftwareCaptureSource.WindowNotFound "ウィンドウは見つかりません"

View File

@ -1,4 +1,4 @@
Add "Добавить" Add "Добавить"
Apply "Применить" Apply "Применить"
Browse "Найти" Browse "Найти"
Cancel "Отменить" Cancel "Отменить"
@ -15,9 +15,14 @@ Scene "Сцену"
Settings "Опции" Settings "Опции"
StreamReport "Отчет" StreamReport "Отчет"
Connection.CouldNotConnect "Невозможно подключиться к серверу"
Connection.CouldNotParseURL "Не удалось обработать URL"
Connection.Disconnected "Отключен от сервера"
Connection.InvalidStream "Неверный stream channel или playpath"
DeleteConfirm.Title "Удалить выбранное?" DeleteConfirm.Title "Удалить выбранное?"
GlobalSources.DeleteConfirm "If you delete a global source, it will be removed from any scene that uses it. Are you sure you want to continue?" GlobalSources.DeleteConfirm "Если вы удалите глобальный источник, он будет удален из всех сцен, в которых он используется. Вы уверены, что хотите продолжить?"
Listbox.Add "Добавить $1" Listbox.Add "Добавить $1"
Listbox.Center "По центру" Listbox.Center "По центру"
@ -29,6 +34,7 @@ Listbox.MoveUp "Вверх"
Listbox.Remove "Удалить" Listbox.Remove "Удалить"
Listbox.Rename "Переименовать" Listbox.Rename "Переименовать"
Listbox.ResetSize "Сбросить размер" Listbox.ResetSize "Сбросить размер"
Listbox.SetHotkey "Добавить горячую клавишу"
MainWindow.Exit "Выход" MainWindow.Exit "Выход"
MainWindow.Plugins "Плагины" MainWindow.Plugins "Плагины"
@ -44,13 +50,18 @@ Plugins.Configure "Конфигурация"
Plugins.Description "Описание:" Plugins.Description "Описание:"
Plugins.Filename "Имя файла:" Plugins.Filename "Имя файла:"
Scene.Hotkey "Горячая клавиша сцены"
Scene.MissingSources "Изображения не загружены в результате недопустимых настроек или отсутствующих плагинов." Scene.MissingSources "Изображения не загружены в результате недопустимых настроек или отсутствующих плагинов."
Scene.Hotkey.AlreadyInUse "Уже используется."
Scene.Hotkey.Clear "Сбросить"
Scene.Hotkey.Hotkey "Горячая клавиша:"
Settings.Audio "Аудио" Settings.Audio "Аудио"
Settings.Encoding "Кодирование" Settings.Encoding "Кодирование"
Settings.General "Главное" Settings.General "Главное"
Settings.Hotkeys "Горячие клавиши" Settings.Hotkeys "Горячие клавиши"
Settings.Info "Эти параментры будут применены после рестарта программы." Settings.Info "Эти параментры будут применены после перезапуска программы."
Settings.Publish "Настройки вещания" Settings.Publish "Настройки вещания"
Settings.SaveChangesPrompt "Сохранить и применить изменения?" Settings.SaveChangesPrompt "Сохранить и применить изменения?"
Settings.SaveChangesTitle "Применить настройки?" Settings.SaveChangesTitle "Применить настройки?"
@ -65,11 +76,15 @@ Settings.Encoding.Audio.Bitrate "Битрейт:"
Settings.Encoding.Audio.Codec "Кодек:" Settings.Encoding.Audio.Codec "Кодек:"
Settings.Encoding.Audio.Format "Формат:" Settings.Encoding.Audio.Format "Формат:"
Settings.Encoding.Video.BufferSize "Размер буфера (кбит):" Settings.Encoding.Video.BufferSize "Размер буфера (Кбит):"
Settings.Encoding.Video.MaxBitRate "Максимальный битрейт (кб/с):" Settings.Encoding.Video.BufferSizeTooltip "Размер буфера определяет, сколько данных будет загружено в буфер перед отправкой на стрим сервер. Установка более высокого значения, чем битрейт, может улучшить плавность картинки, но при нехватке исходящей скорости интернета может привести к потере данных. \r\n\r\nРекомендуется: Такое же или меньшее значение что и битрейт."
Settings.Encoding.Video.Quality "Качество:" Settings.Encoding.Video.MaxBitRate "Максимальный битрейт (Кбит/с):"
Settings.Encoding.Video.Tradeoff "CPU пресет:" Settings.Encoding.Video.MaxBitRateTooltip "Установка максимального значения битрейта для видео. Напрямую зависит от вашей исходящей скорости интернета. Отметим, что заданный битрейт будет средним значением, но так же на него будет влиять размера буфера.\r\n\r\nВоспользуйтесь сайтом, например speedtest.net, чтобы узнать свою исходящую скорость интернета."
Settings.Encoding.Video.UseI444 "Использовать YUV 4:4:4" Settings.Encoding.Video.Quality "Качество:"
Settings.Encoding.Video.QualityTooltip "Эта опция будет подстраивать качество в зависимости от установленных битрейта и буфера. При установки высокого значения и низкого битрейта будет жертвоваться качеством в динамичных сценах в пользу статичных."
Settings.Encoding.Video.Tradeoff "CPU пресет:"
Settings.Encoding.Video.TradeoffTooltip "Установка более быстрого (высокого) значения уменьшает нагрузку процессора, жертвуя некоторыми акпектами качества. С другой стороны, установка медленного (низкого) значения повышает качество за счет увеличения нагрузки на процессор.\r\n\r\nРекомендуется: Very Fast"
Settings.Encoding.Video.UseI444 "Использовать YUV 4:4:4"
Settings.General.Language "Язык:" Settings.General.Language "Язык:"
Settings.General.Restart "Для смены языка необходимо перезапустить программу." Settings.General.Restart "Для смены языка необходимо перезапустить программу."
@ -83,36 +98,39 @@ Settings.Publish.Service "Сервис вещания:"
Settings.Publish.Username "Имя пользователя (если имеется):" Settings.Publish.Username "Имя пользователя (если имеется):"
Settings.Publish.Mode.BandwidthInfo "Пропускная способность" Settings.Publish.Mode.BandwidthInfo "Пропускная способность"
Settings.Publish.Mode.LiveStream "Живой эфир" Settings.Publish.Mode.LiveStream "Прямой эфир"
Settings.Publish.Mode.Serve "Локальный RTMP Сервер" Settings.Publish.Mode.Serve "Локальный RTMP Сервер"
Settings.Video.Custom "Пользовательский:" Settings.Video.Custom "Пользовательский:"
Settings.Video.DisableAero "Отключить AERO:" Settings.Video.DisableAero "Отключить Aero:"
Settings.Video.Downscale "Масштабировать разрешение:" Settings.Video.DisableAeroTooltip "Рекомендуется отключить Aero при использовании программного захвата."
Settings.Video.FPS "FPS:" Settings.Video.Downscale "Масштабировать разрешение:"
Settings.Video.Monitor "Монитор:" Settings.Video.FPS "Кадры в секунду (FPS):"
Settings.Video.Resolution "Базовое разрешение:" Settings.Video.Monitor "Монитор:"
Settings.Video.Resolution "Базовое разрешение:"
Settings.Video.Downscale.None "Отсутствует" Settings.Video.Downscale.None "Отсутствует"
Sources.BitmapSource "Изображение" Sources.BitmapSource "Изображение"
Sources.GlobalSource "Глобальный источник" Sources.GlobalSource "Глобальный источник"
Sources.SoftwareCaptureSource "Программный источник захвата" Sources.SoftwareCaptureSource "Программный источник захвата"
Sources.BitmapSource.Empty "Изображение не найдено. Пожалуйста, найдите и выберите картинку." Sources.BitmapSource.Empty "Изображение не найдено. Пожалуйста, найдите и выберите картинку."
Sources.SoftwareCaptureSource.EntireWindow "Все окно" Sources.SoftwareCaptureSource.EntireWindow "Все окно"
Sources.SoftwareCaptureSource.InnerWindow "Часть окна" Sources.SoftwareCaptureSource.InnerWindow "Окно без рамки"
Sources.SoftwareCaptureSource.Monitor "Монитор:" Sources.SoftwareCaptureSource.Monitor "Монитор:"
Sources.SoftwareCaptureSource.MonitorCapture "Захват экрана (Отключите Aero в настройках видео что бы максимизировать значение FPS)" Sources.SoftwareCaptureSource.MonitorCapture "Захват экрана"
Sources.SoftwareCaptureSource.MouseCapture "Захват мыши" Sources.SoftwareCaptureSource.MonitorCaptureTooltip "Отключите Aero в настройках видео, чтобы максимизировать значение FPS"
Sources.SoftwareCaptureSource.Position "Положение:" Sources.SoftwareCaptureSource.MouseCapture "Захват мыши"
Sources.SoftwareCaptureSource.Refresh "Обновить" Sources.SoftwareCaptureSource.Position "Положение:"
Sources.SoftwareCaptureSource.RegionCapture "Конкретная область" Sources.SoftwareCaptureSource.Refresh "Обновить"
Sources.SoftwareCaptureSource.RegionWindowText "Нажмите клавишу Enter, Esc или щелкните за пределами этого прямоугольника для завершения." Sources.SoftwareCaptureSource.RegionCapture "Конкретная область"
Sources.SoftwareCaptureSource.SelectRegion "Выбрать область" Sources.SoftwareCaptureSource.RegionWindowText "Нажмите клавишу Enter, Esc или щелкните за пределами этого прямоугольника для завершения."
Sources.SoftwareCaptureSource.Size "Размер:" Sources.SoftwareCaptureSource.SelectRegion "Выбрать область"
Sources.SoftwareCaptureSource.Window "Процесс:" Sources.SoftwareCaptureSource.Size "Размер:"
Sources.SoftwareCaptureSource.WindowCapture "Захват Окна (Другие окна не будут видны. Нельзя свернуть. Больше FPS)" Sources.SoftwareCaptureSource.Window "Процесс:"
Sources.SoftwareCaptureSource.WindowMinimized "Окно минимизированно" Sources.SoftwareCaptureSource.WindowCapture "Захват окна"
Sources.SoftwareCaptureSource.WindowNotFound "Окно не найдено" Sources.SoftwareCaptureSource.WindowCaptureTooltip "Aero может быть включено при использовании только функции захвата окна. Изображение не обновляется, если целевое окно свернуто. Захват с помощью этой функции обычно быстрее, чем захват всего экрана или области экрана. Если Aero включено, окна, перекрывающие целевое окно, не будут видны."
Sources.SoftwareCaptureSource.WindowMinimized "Окно минимизированно"
Sources.SoftwareCaptureSource.WindowNotFound "Окно не найдено"