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)
-------------------------------
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)

29
OBS.rc
View File

@ -57,11 +57,12 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTI
CAPTION "Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,338,294,67,14
PUSHBUTTON "Cancel",IDCANCEL,411,294,67,14
PUSHBUTTON "Apply",IDC_APPLY,483,294,67,14
DEFPUSHBUTTON "OK",IDOK,339,294,67,14
PUSHBUTTON "Cancel",IDCANCEL,412,294,67,14
PUSHBUTTON "Apply",IDC_APPLY,484,294,67,14
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
PUSHBUTTON "Settings.Defaults",IDC_DEFAULTS,238,294,67,14,NOT WS_VISIBLE
END
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
RTEXT "Settings.Publish.Service",IDC_SERVICE_STATIC,4,29,138,8
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
EDITTEXT IDC_PLAYPATH,144,61,226,14,ES_PASSWORD | ES_AUTOHSCROLL
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
LTEXT "Settings.Info",IDC_INFO,4,119,408,37,NOT WS_VISIBLE
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
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
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
COMBOBOX IDC_LANGUAGE,144,10,195,126,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
RTEXT "Settings.General.Language",IDC_STATIC,4,12,138,8
LTEXT "Settings.General.Restart",IDC_INFO,11,49,409,48,NOT WS_VISIBLE
COMBOBOX IDC_LANGUAGE,147,23,195,126,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
RTEXT "Settings.General.Language",IDC_STATIC,7,25,138,8
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
IDD_SETTINGS_AUDIO DIALOGEX 0, 0, 427, 287
@ -399,8 +402,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,3,6,0
PRODUCTVERSION 0,3,6,0
FILEVERSION 0,3,8,0
PRODUCTVERSION 0,3,8,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -416,12 +419,12 @@ BEGIN
BLOCK "041104b0"
BEGIN
VALUE "FileDescription", "Open Broadcaster Software"
VALUE "FileVersion", "0, 3, 7, 0"
VALUE "FileVersion", "0, 3, 8, 0"
VALUE "InternalName", "OBS"
VALUE "LegalCopyright", "Copyright (C) 2012"
VALUE "OriginalFilename", "OBS.exe"
VALUE "ProductName", "Open Broadcaster Software"
VALUE "ProductVersion", "0, 3, 7, 0"
VALUE "ProductVersion", "0, 3, 8, 0"
END
END
BLOCK "VarFileInfo"

View File

@ -23,7 +23,11 @@
typedef LPVOID (STDCALL* OBSCREATEPROC)(XElement*); //data
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
{
@ -52,6 +56,7 @@ public:
virtual CTSTR GetSceneName() const=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 CreateHotkey(DWORD hotkey, OBSHOTKEYPROC hotkeyProc, UPARAM param)=0;
virtual void DeleteHotkey(DWORD hotkey)=0;
@ -64,6 +69,9 @@ public:
virtual HWND GetMainWindow() const=0;
virtual CTSTR GetAppDataPath() const=0;
virtual String GetPluginDataPath() const=0;
inline bool SSE2Available() {return bSSE2Availabe;}
};

View File

@ -117,12 +117,18 @@ void SceneItem::MoveToBottom()
Scene::~Scene()
{
traceIn(Scene::~Scene);
for(UINT i=0; i<sceneItems.Num(); i++)
delete sceneItems[i];
traceOut;
}
SceneItem* Scene::AddImageSource(XElement *sourceElement)
{
traceIn(Scene::AddImageSource);
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());
@ -154,6 +160,7 @@ SceneItem* Scene::AddImageSource(XElement *sourceElement)
item->size = Vect2(cx, cy);
API->EnterSceneMutex();
if(bSceneStarted) source->BeginScene();
sceneItems << item;
API->LeaveSceneMutex();
@ -161,13 +168,20 @@ SceneItem* Scene::AddImageSource(XElement *sourceElement)
bMissingSources = true;
return item;
traceOut;
}
void Scene::RemoveImageSource(SceneItem *item)
{
traceIn(Scene::RemoveImageSource);
if(bSceneStarted) item->source->EndScene();
item->GetElement()->GetParent()->RemoveElement(item->GetElement());
sceneItems.RemoveItem(item);
delete item;
traceOut;
}
void Scene::RemoveImageSource(CTSTR lpName)
@ -184,26 +198,36 @@ void Scene::RemoveImageSource(CTSTR lpName)
void Scene::Preprocess()
{
traceIn(Scene::Preprocess);
for(UINT i=0; i<sceneItems.Num(); i++)
{
SceneItem *item = sceneItems[i];
if(item->source)
item->source->Preprocess();
}
traceOut;
}
void Scene::Tick(float fSeconds)
{
traceIn(Scene::Tick);
for(UINT i=0; i<sceneItems.Num(); i++)
{
SceneItem *item = sceneItems[i];
if(item->source)
item->source->Tick(fSeconds);
}
traceOut;
}
void Scene::Render()
{
traceIn(Scene::Render);
GS->ClearColorBuffer();
for(UINT i=0; i<sceneItems.Num(); i++)
@ -212,10 +236,14 @@ void Scene::Render()
if(item->source)
item->source->Render(item->pos, item->size);
}
traceOut;
}
void Scene::RenderSelections()
{
traceIn(Scene::RenderSelections);
for(UINT i=0; i<sceneItems.Num(); i++)
{
SceneItem *item = sceneItems[i];
@ -237,24 +265,44 @@ void Scene::RenderSelections()
DrawBox(pos, size);
}
}
traceOut;
}
void Scene::BeginScene()
{
traceIn(Scene::BeginScene);
if(bSceneStarted)
return;
for(UINT i=0; i<sceneItems.Num(); i++)
{
SceneItem *item = sceneItems[i];
if(item->source)
item->source->BeginScene();
}
bSceneStarted = true;
traceOut;
}
void Scene::EndScene()
{
traceIn(Scene::EndScene);
if(!bSceneStarted)
return;
for(UINT i=0; i<sceneItems.Num(); i++)
{
SceneItem *item = sceneItems[i];
if(item->source)
item->source->EndScene();
}
bSceneStarted = false;
traceOut;
}

View File

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

View File

@ -35,8 +35,6 @@
BOOL ConfigFile::Create(CTSTR lpConfigFile)
{
strFileName = lpConfigFile;
lpFileData = NULL;
bOpen = 0;
if(LoadFile(XFILE_CREATEALWAYS))
LoadData();
@ -49,8 +47,6 @@ BOOL ConfigFile::Create(CTSTR lpConfigFile)
BOOL ConfigFile::Open(CTSTR lpConfigFile, BOOL bOpenAlways)
{
strFileName = lpConfigFile;
lpFileData = NULL;
bOpen = 0;
if(LoadFile(bOpenAlways ? XFILE_OPENALWAYS : XFILE_OPENEXISTING))
LoadData();
@ -62,9 +58,6 @@ BOOL ConfigFile::Open(CTSTR lpConfigFile, BOOL bOpenAlways)
BOOL ConfigFile::LoadFile(DWORD dwOpenMode)
{
if(bOpen)
Close();
XFile file;
if(!file.Open(strFileName, XFILE_READ, dwOpenMode))
{
@ -72,6 +65,9 @@ BOOL ConfigFile::LoadFile(DWORD dwOpenMode)
return 0;
}
if(bOpen)
Close();
dwLength = file.GetFileSize();
LPSTR lpTempFileData = (LPSTR)Allocate(dwLength+5);
@ -180,6 +176,23 @@ void ConfigFile::Close()
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)
{
assert(lpSection);
@ -578,7 +591,7 @@ void ConfigFile::SetString(CTSTR lpSection, CTSTR lpKey, CTSTR lpString)
return;
if(!lpString)
return;
lpString = TEXT("");
SetKey(lpSection, lpKey, lpString);
}

View File

@ -48,6 +48,9 @@ public:
BOOL Open(CTSTR lpConfigFile, BOOL bOpenAlways=FALSE);
void Close();
BOOL SaveAs(CTSTR lpPath);
void SetFilePath(CTSTR lpPath);
String GetString(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);

View File

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

View File

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

View File

@ -30,7 +30,7 @@ SafeList<DWORD> TickList;
Alloc *MainAllocator = NULL;
BOOL bBaseLoaded = FALSE;
BOOL bDebugBreak = TRUE;
CTSTR lpLogFileName = TEXT("XT.log");
TCHAR lpLogFileName[260] = TEXT("XT.log");
XFile LogFile;
StringList TraceFuncList;
@ -40,25 +40,19 @@ void STDCALL CriticalExit();
void STDCALL OpenLogFile();
void STDCALL CloseLogFile();
void STDCALL OSInit();
void STDCALL OSExit();
BOOL STDCALL InitXT(CTSTR logFile, CTSTR allocatorName)
{
if(!bBaseLoaded)
{
if(logFile)
lpLogFileName = logFile;
scpy(lpLogFileName, logFile);
OSInit();
if(scmpi(allocatorName, TEXT("DebugAlloc")) == 0)
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;
ResetXTAllocator(allocatorName);
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()
{
if(bBaseLoaded)

View File

@ -80,9 +80,6 @@ struct XRect
#define WAIT_INFINITE 0xFFFFFFFF
BASE_EXPORT void STDCALL OSInit();
BASE_EXPORT void STDCALL OSExit();
BASE_EXPORT void STDCALL OSLogSystemStats();
BASE_EXPORT DWORD STDCALL OSGetSysPageSize();
BASE_EXPORT LPVOID STDCALL OSVirtualAlloc(size_t dwSize);
@ -158,6 +155,8 @@ BASE_EXPORT void STDCALL TraceCrashEnd();
//Base functions
//-----------------------------------------
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 extern BOOL bDebugBreak;

View File

@ -33,13 +33,13 @@ D3D10System::D3D10System()
swapDesc.BufferDesc.Width = App->renderFrameWidth;
swapDesc.BufferDesc.Height = App->renderFrameHeight;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.Flags = 0;
swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
swapDesc.OutputWindow = hwndRenderFrame;
swapDesc.SampleDesc.Count = 1;
swapDesc.Windowed = TRUE;
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;
//D3D10_CREATE_DEVICE_DEBUG
@ -677,12 +677,14 @@ void D3D10System::ResetViewMatrix()
void D3D10System::ResizeView()
{
traceIn(D3D10System::ResizeView);
LPVOID nullVal = NULL;
d3d->OMSetRenderTargets(1, (ID3D10RenderTargetView**)&nullVal, NULL);
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;
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"));
backBuffer->Release();
traceOut;
}

View File

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

View File

@ -19,6 +19,7 @@
#include "Main.h"
#include <shlobj.h>
#include <dwmapi.h>
@ -27,8 +28,10 @@
HWND hwndMain = NULL;
HWND hwndRenderFrame = NULL;
HINSTANCE hinstMain = NULL;
ConfigFile *GlobalConfig = NULL;
ConfigFile *AppConfig = 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)
{
//make sure only one instance of the application can be open at a time
hOBSMutex = CreateMutex(NULL, TRUE, TEXT("OBSMutex"));
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
hwndMain = FindWindow(OBS_WINDOW_CLASS, NULL);
if(hwndMain)
SetForegroundWindow(hwndMain);
CloseHandle(hOBSMutex);
return 0;
}
@ -96,68 +222,108 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
hinstMain = hInstance;
//------------------------------------------------------------
// 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))
if(InitXT(NULL, TEXT("FastAlloc")))
{
traceIn(Main);
InitSockets();
//CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoInitialize(0);
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();
//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);
@ -168,6 +334,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
DwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
}
//--------------------------------------------
App = new OBS;
HACCEL hAccel = LoadAccelerators(hinstMain, MAKEINTRESOURCE(IDR_ACCELERATOR1));
@ -183,7 +351,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
}
delete App;
//--------------------------------------------
delete AppConfig;
delete GlobalConfig;
if(bDisableComposition && bCompositionEnabled)
DwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
@ -191,11 +363,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
TerminateSockets();
traceOutStop;
TerminateXT();
}
free(lpAllocator);
TerminateXT();
//------------------------------------------------------------

View File

@ -56,12 +56,17 @@ class OBS;
extern HWND hwndMain;
extern HWND hwndRenderFrame;
extern HINSTANCE hinstMain;
extern ConfigFile *GlobalConfig;
extern ConfigFile *AppConfig;
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_WINDOW_CLASS TEXT("OBSWindowClass")
#define OBS_RENDERFRAME_CLASS TEXT("RenderFrame")
inline UINT ConvertMSTo100NanoSec(UINT ms)
{
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 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)
@ -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};
//----------------------------
@ -293,6 +288,7 @@ Scene* STDCALL CreateNormalScene(XElement *data)
struct HotkeyInfo
{
DWORD hotkeyID;
DWORD hotkey;
OBSHOTKEYPROC hotkeyProc;
UPARAM param;
@ -304,6 +300,7 @@ class OBSAPIInterface : public APIInterface
friend class OBS;
List<HotkeyInfo> hotkeys;
DWORD curHotkeyIDVal;
void HandleHotkeys();
@ -347,6 +344,9 @@ public:
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;}
};
@ -389,7 +389,7 @@ OBS::OBS()
if(!locale->LoadStringFile(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")))
{
String langFile;
@ -632,8 +632,11 @@ OBS::OBS()
hwndTemp = GetDlgItem(hwndMain, ID_SCENES);
if(!scenesConfig.Open(TEXT("scenes.xconfig")))
CrashError(TEXT("Could not open scenes.xconfig"));
String strScenesConfig;
strScenesConfig << lpAppDataPath << TEXT("\\scenes.xconfig");
if(!scenesConfig.Open(strScenesConfig))
CrashError(TEXT("Could not open '%s'"), strScenesConfig);
XElement *scenes = scenesConfig.GetElement(TEXT("scenes"));
if(!scenes)
@ -712,6 +715,11 @@ OBS::OBS()
OSFindClose(hFind);
}
//-----------------------------------------------------
bRenderViewEnabled = true;
bShowFPS = AppConfig->GetInt(TEXT("General"), TEXT("ShowFPS")) != 0;
traceOut;
}
@ -745,6 +753,13 @@ OBS::~OBS()
DeleteObject(Icons[i].hIcon);
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++)
sceneClasses[i].FreeData();
for(UINT i=0; i<imageSourceClasses.Num(); i++)
@ -772,8 +787,10 @@ void OBS::ToggleCapturing()
traceOut;
}
void STDCALL SceneHotkey(DWORD hotkey, UPARAM param)
void STDCALL SceneHotkey(DWORD hotkey, UPARAM param, bool bDown)
{
if(!bDown) return;
XElement *scenes = API->GetSceneListElement();
if(scenes)
{
@ -784,7 +801,7 @@ void STDCALL SceneHotkey(DWORD hotkey, UPARAM param)
DWORD sceneHotkey = (DWORD)scene->GetInt(TEXT("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());
return;
}
@ -800,6 +817,8 @@ HICON OBS::GetIcon(HINSTANCE hInst, int resource)
return Icons[i].hIcon;
}
//---------------------
IconInfo ii;
ii.hInst = hInst;
ii.resource = resource;
@ -810,6 +829,38 @@ HICON OBS::GetIcon(HINSTANCE hInst, int resource)
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)
{
traceIn(CompileShader);
@ -1303,8 +1354,6 @@ void OBS::MainCaptureLoop()
bufferedTimes.Clear();
//firstFrameTime -= UINT(frameTime);
Vect2 baseSize = Vect2(float(baseCX), float(baseCY));
Vect2 outputSize = Vect2(float(outputCX), float(outputCY));
Vect2 scaleSize = Vect2(float(scaleCX), float(scaleCY));
@ -1326,7 +1375,6 @@ void OBS::MainCaptureLoop()
x264_picture_alloc(&picOut, X264_CSP_I420, outputCX, outputCY);
int curPTS = 0;
//int audioJump = 0;
HANDLE hScaleVal = yuvScalePixelShader->GetParameterByName(TEXT("baseDimensionI"));
@ -1338,15 +1386,14 @@ void OBS::MainCaptureLoop()
float bpsTime = 0.0f;
double lastStrain = 0.0f;
DWORD audioResyncOffset = 0;
UINT timeAdjust = 0;
DWORD captureFPS = 0;
DWORD fpsCounter = 0;
while(bRunning)
{
DWORD renderStartTime = OSGetTime();
bool bRenderView = !IsIconic(hwndMain);
bool bRenderView = !IsIconic(hwndMain) && bRenderViewEnabled;
profileIn("frame");
@ -1405,9 +1452,14 @@ void OBS::MainCaptureLoop()
lastBytesSent = curBytesSent;
captureFPS = fpsCounter;
fpsCounter = 0;
bUpdateBPS = true;
}
fpsCounter++;
double curStrain = network->GetPacketStrain();
if(bUpdateBPS || !CloseDouble(curStrain, lastStrain))
{
@ -1505,6 +1557,38 @@ void OBS::MainCaptureLoop()
if(scene)
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)
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;
OBSHOTKEYPROC hotkeyProc = NULL;
UPARAM param;
DWORD hotkey = 0;
UPARAM param = NULL;
OSEnterMutex(hHotkeyMutex);
for(UINT i=0; i<apiInterface->hotkeys.Num(); i++)
{
HotkeyInfo &hi = apiInterface->hotkeys[i];
if(hi.hotkey == hotkey)
if(hi.hotkeyID == hotkeyID)
{
if(hi.hotkeyProc)
{
hotkeyProc = hi.hotkeyProc;
param = hi.param;
}
if(!hi.hotkeyProc)
return;
hotkeyProc = hi.hotkeyProc;
param = hi.param;
hotkey = hi.hotkey;
break;
}
}
OSLeaveMutex(hHotkeyMutex);
if(hotkeyProc)
hotkeyProc(hotkey, param);
hotkeyProc(hotkey, param, bDown);
}
bool OBSAPIInterface::HotkeyExists(DWORD hotkey) const
@ -1969,16 +2051,8 @@ bool OBSAPIInterface::CreateHotkey(DWORD hotkey, OBSHOTKEYPROC hotkeyProc, UPARA
fsModifiers |= MOD_SHIFT;
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();
hi.hotkeyID = ++curHotkeyIDVal;
hi.hotkey = hotkey;
hi.hotkeyProc = hotkeyProc;
hi.param = param;
@ -2028,19 +2102,22 @@ void OBSAPIInterface::HandleHotkeys()
{
short keyState = GetAsyncKeyState(hotkeyVK);
bool bDown = (keyState & 0x8000) != 0;
bool bWasPressed = (keyState & 1) != 0;
if(bDown || bWasPressed)
if(bDown)
{
if(!info.bDown)
PostMessage(hwndMain, OBS_CALLHOTKEY, 0, info.hotkey);
PostMessage(hwndMain, OBS_CALLHOTKEY, TRUE, info.hotkeyID);
info.bDown = bDown;
continue;
}
}
info.bDown = false;
if(info.bDown) //key up
{
PostMessage(hwndMain, OBS_CALLHOTKEY, FALSE, info.hotkeyID);
info.bDown = false;
}
}
OSLeaveMutex(App->hHotkeyMutex);

View File

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

View File

@ -58,7 +58,8 @@ class RTMPPublisher : public NetworkStream
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
void SendLoop()
@ -219,7 +220,7 @@ class RTMPPublisher : public NetworkStream
packet.data.Clear();
Packets.Remove(i--);
numVideoPackets--;
//numBFramesDumped++;
numPFramesDumped++;
}
}
else if(packet.type == packetWaitType)
@ -227,7 +228,7 @@ class RTMPPublisher : public NetworkStream
packet.data.Clear();
Packets.Remove(i--);
numVideoPackets--;
//numBFramesDumped++;
numPFramesDumped++;
bRemovedPacket = true;
}
@ -267,7 +268,7 @@ class RTMPPublisher : public NetworkStream
packet.data.Clear();
Packets.Remove(i--);
numVideoPackets--;
//numBFramesDumped++;
numBFramesDumped++;
}
}
else if(packet.type == packetWaitType)
@ -275,7 +276,7 @@ class RTMPPublisher : public NetworkStream
packet.data.Clear();
Packets.Remove(i--);
numVideoPackets--;
//numBFramesDumped++;
numBFramesDumped++;
bRemovedPacket = true;
}
@ -401,7 +402,7 @@ public:
Packets[i].data.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 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)
{
switch(message)
{
case WM_INITDIALOG:
{
LocalizeWindow(hwnd);
//----------------------------------------------
HWND hwndTemp = GetDlgItem(hwnd, IDC_LANGUAGE);
OSFindData ofd;
@ -45,6 +74,8 @@ INT_PTR CALLBACK OBS::GeneralSettingsProc(HWND hwnd, UINT message, WPARAM wParam
{
do
{
if(ofd.bDirectory) continue;
String langCode = GetPathFileName(ofd.fileName);
LocaleNativeName *langInfo = GetLocaleNativeName(langCode);
@ -61,7 +92,37 @@ INT_PTR CALLBACK OBS::GeneralSettingsProc(HWND hwnd, UINT message, WPARAM wParam
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);
return TRUE;
}
@ -73,9 +134,147 @@ INT_PTR CALLBACK OBS::GeneralSettingsProc(HWND hwnd, UINT message, WPARAM wParam
if(HIWORD(wParam) != CBN_SELCHANGE)
break;
App->SetChangedSettings(true);
SetWindowText(GetDlgItem(hwnd, IDC_INFO), Str("Settings.General.Restart"));
ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
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)
{
String strLanguageCode = (CTSTR)SendMessage(hwndTemp, CB_GETITEMDATA, curSel, 0);
AppConfig->SetString(TEXT("General"), TEXT("Language"), strLanguageCode);
GlobalConfig->SetString(TEXT("General"), TEXT("Language"), strLanguageCode);
}
break;
}

View File

@ -26,7 +26,7 @@
extern WNDPROC listboxProc;
void STDCALL SceneHotkey(DWORD hotkey, UPARAM param);
void STDCALL SceneHotkey(DWORD hotkey, UPARAM param, bool bDown);
enum
{
@ -141,10 +141,19 @@ INT_PTR CALLBACK OBS::SceneHotkeyDialogProc(HWND hwnd, UINT message, WPARAM wPar
break;
}
if(hotkey && API->HotkeyExists(hotkey))
if(hotkey)
{
MessageBox(hwnd, Str("Scene.Hotkey.AlreadyInUse"), NULL, 0);
return 0;
XElement *scenes = API->GetSceneListElement();
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;
@ -590,11 +599,7 @@ LRESULT CALLBACK OBS::ListboxHook(HWND hwnd, UINT message, WPARAM wParam, LPARAM
}
if(App->bRunning)
{
OSEnterMutex(App->hSceneMutex);
App->scene->AddImageSource(newSourceElement);
OSLeaveMutex(App->hSceneMutex);
}
UINT newID = (UINT)SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)strName.Array());
PostMessage(hwnd, LB_SETCURSEL, newID, 0);
@ -1526,7 +1531,7 @@ LRESULT CALLBACK OBS::OBSProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
break;
case OBS_CALLHOTKEY:
App->CallHotkey((DWORD)lParam);
App->CallHotkey((DWORD)lParam, wParam != 0);
break;
case WM_CLOSE:
@ -1574,6 +1579,12 @@ ItemModifyType GetItemModifyType(const Vect2 &mousePos, const Vect2 &itemPos, co
return ItemModifyType_Move;
}
enum
{
ID_TOGGLERENDERVIEW=1,
ID_SHOWFPS,
};
LRESULT CALLBACK OBS::RenderFrameProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
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);

1
TODO
View File

@ -4,7 +4,6 @@ More up to date list on the website
-------------------------------------------------------
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
(livestream, etc), need to find out their server details
* 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.
// Used by OBS.rc
//
#define IDC_DEFAULTS 3
#define IDC_APPLY 4
#define IDD_SETTINGS 101
#define IDI_ICON1 109
@ -44,6 +45,7 @@
#define IDC_LANGUAGE 1028
#define IDC_INFO 1029
#define IDC_FPS 1030
#define IDC_PROFILE 1030
#define IDC_FPS_EDIT 1031
#define IDC_SIZEX 1033
#define IDC_SIZEY 1034
@ -90,6 +92,7 @@
#define IDC_HOTKEY1 1073
#define IDC_HOTKEY 1073
#define IDC_CLEAR 1074
#define IDC_ADDNEW 1077
#define IDA_SOURCE_MOVEUP 40018
#define IDA_SOURCE_MOVEDOWN 40019
#define IDA_SOURCE_MOVETOTOP 40020
@ -105,7 +108,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 131
#define _APS_NEXT_COMMAND_VALUE 40028
#define _APS_NEXT_CONTROL_VALUE 1075
#define _APS_NEXT_CONTROL_VALUE 1078
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -50,6 +50,9 @@ Plugins.Configure "Configure"
Plugins.Description "Description:"
Plugins.Filename "File name:"
RenderView.EnableView "Enable View"
RenderView.ShowFPS "Show FPS"
Scene.Hotkey "Scene Hotkey"
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.UseI444 "Use YUV 4:4:4"
Settings.General.Language "Language:"
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.Add "Add New"
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.Mode "Mode:"

View File

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

View File

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