tons of fixes related to audio and crashes, argh. also win8 capture

master
jp9000 2012-12-14 04:13:38 -07:00
parent 89ce5e3474
commit b9d79f4c3f
12 changed files with 398 additions and 146 deletions

View File

@ -141,56 +141,60 @@ IBaseFilter* GetDeviceByValue(WSTR lpType, CTSTR lpName, WSTR lpType2, CTSTR lpN
VARIANT valueThingy;
VARIANT valueThingy2;
valueThingy.vt = VT_BSTR;
valueThingy.pbstrVal = NULL;
valueThingy2.vt = VT_BSTR;
valueThingy2.bstrVal = NULL;
propertyData->Read(lpType, &valueThingy, NULL);
if(lpType2 && lpName2)
propertyData->Read(lpType2, &valueThingy2, NULL);
SafeRelease(propertyData);
String strVal1 = (CWSTR)valueThingy.bstrVal;
if(strVal1 == lpName)
if(SUCCEEDED(propertyData->Read(lpType, &valueThingy, NULL)))
{
IBaseFilter *filter;
err = deviceInfo->BindToObject(NULL, 0, IID_IBaseFilter, (void**)&filter);
if(FAILED(err))
{
AppWarning(TEXT("GetDeviceByName: deviceInfo->BindToObject failed, result = %08lX"), err);
continue;
}
if(lpType2 && lpName2)
propertyData->Read(lpType2, &valueThingy2, NULL);
if(!bestFilter)
{
bestFilter = filter;
SafeRelease(propertyData);
if(!lpType2 || !lpName2)
String strVal1 = (CWSTR)valueThingy.bstrVal;
if(strVal1 == lpName)
{
IBaseFilter *filter;
err = deviceInfo->BindToObject(NULL, 0, IID_IBaseFilter, (void**)&filter);
if(FAILED(err))
{
SafeRelease(deviceInfo);
SafeRelease(videoDeviceEnum);
return bestFilter;
AppWarning(TEXT("GetDeviceByName: deviceInfo->BindToObject failed, result = %08lX"), err);
continue;
}
}
else if(lpType2 && lpName2)
{
String strVal2 = (CWSTR)valueThingy2.bstrVal;
if(strVal2 == lpName2)
{
bestFilter->Release();
if(!bestFilter)
{
bestFilter = filter;
SafeRelease(deviceInfo);
SafeRelease(videoDeviceEnum);
if(!lpType2 || !lpName2)
{
SafeRelease(deviceInfo);
SafeRelease(videoDeviceEnum);
return bestFilter;
return bestFilter;
}
}
else if(lpType2 && lpName2)
{
String strVal2 = (CWSTR)valueThingy2.bstrVal;
if(strVal2 == lpName2)
{
bestFilter->Release();
bestFilter = filter;
SafeRelease(deviceInfo);
SafeRelease(videoDeviceEnum);
return bestFilter;
}
}
else
filter->Release();
}
else
filter->Release();
}
}
@ -551,10 +555,11 @@ void FillOutListOfVideoDevices(HWND hwndCombo, ConfigDialogData &info)
{
VARIANT friendlyNameValue, devicePathValue;
friendlyNameValue.vt = VT_BSTR;
friendlyNameValue.bstrVal = NULL;
devicePathValue.vt = VT_BSTR;
devicePathValue.bstrVal = NULL;
propertyData->Read(L"FriendlyName", &friendlyNameValue, NULL);
err = propertyData->Read(L"FriendlyName", &friendlyNameValue, NULL);
propertyData->Read(L"DevicePath", &devicePathValue, NULL);
if(SUCCEEDED(err))

View File

@ -325,6 +325,27 @@ public:
};
/*=========================================================
Output Duplication class
==========================================================*/
enum DuplicatorInfo
{
DuplicatorInfo_Error,
DuplicatorInfo_Timeout,
DuplicatorInfo_Lost,
DuplicatorInfo_Acquired
};
class BASE_EXPORT OutputDuplicator
{
public:
virtual ~OutputDuplicator() {}
virtual DuplicatorInfo AquireNextFrame(UINT timeout, POINT &mousePos, BOOL &mouseVisible)=0;
virtual Texture* GetCopyTexture()=0;
};
/*=========================================================
Vertex Buffer class
==========================================================*/
@ -401,6 +422,9 @@ public:
virtual SamplerState* CreateSamplerState(SamplerInfo &info)=0;
virtual UINT GetNumOutputs()=0;
virtual OutputDuplicator *CreateOutputDulicator(UINT outputID)=0;
//----------------------------------------------------
//Shader Functions

View File

@ -327,6 +327,44 @@ SamplerState* D3D10System::CreateSamplerState(SamplerInfo &info)
}
UINT D3D10System::GetNumOutputs()
{
UINT count = 0;
IDXGIDevice *device;
if(SUCCEEDED(d3d->QueryInterface(__uuidof(IDXGIDevice), (void**)&device)))
{
IDXGIAdapter *adapter;
if(SUCCEEDED(device->GetAdapter(&adapter)))
{
IDXGIOutput *outputInterface;
while(SUCCEEDED(adapter->EnumOutputs(count, &outputInterface)))
{
count++;
outputInterface->Release();
}
adapter->Release();
}
device->Release();
}
return count;
}
OutputDuplicator *D3D10System::CreateOutputDulicator(UINT outputID)
{
D3D10OutputDuplicator *duplicator = new D3D10OutputDuplicator;
if(duplicator->Init(outputID))
return duplicator;
delete duplicator;
return NULL;
}
////////////////////////////
//Shader Functions
Shader* D3D10System::CreateVertexShader(CTSTR lpShader, CTSTR lpFileName)

View File

@ -23,6 +23,23 @@
class D3D10VertexShader;
inline GSColorFormat ConvertGIBackBufferFormat(DXGI_FORMAT format)
{
switch(format)
{
case DXGI_FORMAT_R10G10B10A2_UNORM: return GS_R10G10B10A2;
case DXGI_FORMAT_R8G8B8A8_UNORM: return GS_RGBA;
case DXGI_FORMAT_B8G8R8A8_UNORM: return GS_BGRA;
case DXGI_FORMAT_B8G8R8X8_UNORM: return GS_BGR;
case DXGI_FORMAT_B5G5R5A1_UNORM: return GS_B5G5R5A1;
case DXGI_FORMAT_B5G6R5_UNORM: return GS_B5G6R5;
}
return GS_UNKNOWNFORMAT;
}
//=============================================================================
class D3D10VertexBuffer : public VertexBuffer
@ -76,6 +93,7 @@ public:
class D3D10Texture : public Texture
{
friend class D3D10OutputDuplicator;
friend class D3D10System;
friend class OBS;
@ -288,6 +306,22 @@ public:
virtual ShaderType GetType() const {return ShaderType_Pixel;}
};
//--------------------------------------------------
class D3D10OutputDuplicator : public OutputDuplicator
{
IDXGIOutputDuplication *duplicator;
Texture *copyTex;
public:
bool Init(UINT output);
virtual ~D3D10OutputDuplicator();
virtual DuplicatorInfo AquireNextFrame(UINT timeout, POINT &mousePos, BOOL &mouseVisible);
virtual Texture* GetCopyTexture();
};
//=============================================================================
struct SavedBlendState
@ -366,6 +400,9 @@ public:
virtual SamplerState* CreateSamplerState(SamplerInfo &info);
virtual UINT GetNumOutputs();
virtual OutputDuplicator *CreateOutputDulicator(UINT outputID);
////////////////////////////
//Shader Functions

View File

@ -48,6 +48,10 @@ class DesktopImageSource : public ImageSource
UINT opacity;
bool bWindows8MonitorCapture;
OutputDuplicator *duplicator;
public:
DesktopImageSource(UINT frameTime, XElement *data)
{
@ -74,12 +78,46 @@ public:
if(warningID)
App->RemoveStreamInfo(warningID);
if(duplicator)
delete duplicator;
delete alphaIgnoreShader;
delete colorKeyShader;
}
void PreprocessWindows8MonitorCapture()
{
if(duplicator)
{
Texture *newTex = NULL;
POINT mousePos = {0, 0};
BOOL bMouseVis = FALSE;
switch(duplicator->AquireNextFrame(0, mousePos, bMouseVis))
{
case DuplicatorInfo_Lost:
{
delete duplicator;
duplicator = GS->CreateOutputDulicator(0);
return;
}
case DuplicatorInfo_Error:
case DuplicatorInfo_Timeout:
return;
}
lastRendered = duplicator->GetCopyTexture();
}
}
void Preprocess()
{
if(bWindows8MonitorCapture)
{
PreprocessWindows8MonitorCapture();
return;
}
Texture *captureTexture = renderTextures[curCaptureTexture];
HDC hDC;
@ -232,8 +270,26 @@ public:
curCaptureTexture = 0;
}
void RenderWindows8MonitorCapture(const Vect2 &pos, const Vect2 &size)
{
}
void Render(const Vect2 &pos, const Vect2 &size)
{
/*if(bWindows8MonitorCapture)
{
RenderWindows8MonitorCapture(pos, size);
return;
}*/
Vect2 outPos = pos;
Vect2 outSize = size;
if(bWindows8MonitorCapture)
{
}
if(lastRendered)
{
Shader *lastPixelShader = GetCurrentPixelShader();
@ -291,7 +347,10 @@ public:
bNewClientCapture != bClientCapture)
{
for(int i=0; i<NUM_CAPTURE_TEXTURES; i++)
{
delete renderTextures[i];
renderTextures[i] = NULL;
}
captureType = newCaptureType;
strWindow = strNewWindow;
@ -303,11 +362,18 @@ public:
captureRect.right = x+cx;
captureRect.bottom = y+cy;
//bWindows8MonitorCapture = captureType == 0 && IsWindows8Up();
width = cx;
height = cy;
for(UINT i=0; i<NUM_CAPTURE_TEXTURES; i++)
renderTextures[i] = CreateGDITexture(width, height);
if(bWindows8MonitorCapture)
duplicator = GS->CreateOutputDulicator(0);
else
{
for(UINT i=0; i<NUM_CAPTURE_TEXTURES; i++)
renderTextures[i] = CreateGDITexture(width, height);
}
lastRendered = NULL;
}

View File

@ -26,6 +26,11 @@
#include "../libsamplerate/samplerate.h"
inline QWORD GetQWDif(QWORD val1, QWORD val2)
{
return (val1 > val2) ? (val1-val2) : (val2-val1);
}
class MMDeviceAudioSource : public AudioSource
{
@ -40,6 +45,7 @@ class MMDeviceAudioSource : public AudioSource
IMMDevice *mmDevice;
IAudioClient *mmClient;
IAudioCaptureClient *mmCapture;
IAudioClock *mmClock;
UINT inputChannels;
UINT inputSamplesPerSec;
@ -50,7 +56,7 @@ class MMDeviceAudioSource : public AudioSource
List<AudioSegment> audioSegments;
bool bFirstFrameReceived;
QWORD lastKnownTimestamp;
QWORD lastUsedTimestamp;
bool bBrokenTimestamp;
//-----------------------------------------
@ -76,6 +82,7 @@ public:
SafeRelease(mmClient);
SafeRelease(mmDevice);
SafeRelease(mmEnumerator);
SafeRelease(mmClock);
if(bResample)
src_delete(resampler);
@ -89,7 +96,7 @@ public:
virtual UINT GetNextBuffer();
virtual bool GetMostRecentTimestamp(QWORD &timestamp);
virtual bool GetEarliestTimestamp(QWORD &timestamp);
virtual bool GetBuffer(float **buffer, UINT *numFrames, QWORD targetTimestamp);
virtual QWORD GetBufferedTime()
@ -99,6 +106,22 @@ public:
return 0;
}
virtual bool GetNewestFrame(float **buffer, UINT *numFrames)
{
if(buffer && numFrames)
{
if(audioSegments.Num())
{
List<float> &data = audioSegments.Last().audioData;
*buffer = data.Array();
*numFrames = data.Num()/2;
return true;
}
}
return false;
}
};
AudioSource* CreateAudioSource(bool bMic, CTSTR lpID)
@ -159,9 +182,9 @@ bool MMDeviceAudioSource::Initialize(bool bMic, CTSTR lpID)
return false;
}
String strName = GetDeviceName();
if(bMic)
{
String strName = GetDeviceName();
Log(TEXT("------------------------------------------"));
Log(TEXT("Using auxilary audio input: %s"), strName.Array());
}
@ -204,6 +227,13 @@ bool MMDeviceAudioSource::Initialize(bool bMic, CTSTR lpID)
return false;
}
err = mmClient->GetService(__uuidof(IAudioClock), (void**)&mmClock);
if(FAILED(err))
{
AppWarning(TEXT("MMDeviceAudioSource::Initialize(%d): Could not get audio capture clock, result = %08lX"), (BOOL)bMic, err);
return false;
}
CoTaskMemFree(pwfx);
//-------------------------------------------------------------------------
@ -350,8 +380,9 @@ UINT MMDeviceAudioSource::GetNextBuffer()
DWORD dwFlags = 0;
UINT numAudioFrames = 0;
UINT64 devPosition;
UINT64 qpcTimestamp;
err = mmCapture->GetBuffer(&captureBuffer, &numAudioFrames, &dwFlags, NULL, &qpcTimestamp);
err = mmCapture->GetBuffer(&captureBuffer, &numAudioFrames, &dwFlags, &devPosition, &qpcTimestamp);
if(FAILED(err))
{
RUNONCE AppWarning(TEXT("MMDeviceAudioSource::GetBuffer: GetBuffer failed"));
@ -364,25 +395,16 @@ UINT MMDeviceAudioSource::GetNextBuffer()
{
RUNONCE AppWarning(TEXT("MMDeviceAudioSource::GetBuffer: woa woa woa, getting timestamp errors from the audio subsystem. device = %s"), GetDeviceName().Array());
if(!bBrokenTimestamp)
lastKnownTimestamp = newTimestamp = lastKnownTimestamp + numAudioFrames*1000/inputSamplesPerSec;
newTimestamp = lastUsedTimestamp + numAudioFrames*1000/inputSamplesPerSec;
}
else
{
if(!bBrokenTimestamp)
{
newTimestamp = qpcTimestamp/10000;
/*if(bFirstFrameReceived)
{
LONGLONG offset = LONGLONG(newTimestamp)-LONGLONG(lastKnownTimestamp);
if(offset < 1 || offset > 20)
bBrokenTimestamp = true;
else
lastKnownTimestamp = newTimestamp;
}
else*/
lastKnownTimestamp = newTimestamp;
}
/*UINT64 freq;
mmClock->GetFrequency(&freq);
Log(TEXT("position: %llu, numAudioFrames: %u, freq: %llu, newTimestamp: %llu, test: %llu"), devPosition, numAudioFrames, freq, newTimestamp, devPosition*8000/freq);*/
}
//have to do this crap to account for broken devices or device drivers. absolutely unbelievable.
@ -390,16 +412,17 @@ UINT MMDeviceAudioSource::GetNextBuffer()
{
LARGE_INTEGER clockFreq;
QueryPerformanceFrequency(&clockFreq);
QWORD curTime = GetQPCTimeMS(clockFreq.QuadPart);
if(newTimestamp < (curTime-10000) || newTimestamp > (curTime+10000))
if(newTimestamp < (curTime-1000) || newTimestamp > (curTime+1000))
{
bBrokenTimestamp = true;
lastKnownTimestamp = newTimestamp = GetQPCTimeMS(clockFreq.QuadPart);
lastUsedTimestamp = newTimestamp = GetQPCTimeMS(clockFreq.QuadPart);
Log(TEXT("MMDeviceAudioSource::GetNextBuffer: Got bad audio timestamp from device: '%s', timestamps for this device will be calculated"), GetDeviceName().Array());
}
else
lastUsedTimestamp = newTimestamp;
bFirstFrameReceived = true;
}
@ -658,6 +681,7 @@ UINT MMDeviceAudioSource::GetNextBuffer()
//-----------------------------------------------------------------------------
// sort all audio frames into 10 millisecond increments (done because not all devices output in 10ms increments)
// NOTE: 0.457+ - instead of using the timestamps from windows, just compare and make sure it stays within a 100ms of their timestamps
float *newBuffer = (bResample) ? tempResampleBuffer.Array() : tempBuffer.Array();
@ -665,10 +689,14 @@ UINT MMDeviceAudioSource::GetNextBuffer()
{
AudioSegment &newSegment = *audioSegments.CreateNew();
newSegment.audioData.CopyArray(newBuffer, numAudioFrames*2);
if(bBrokenTimestamp)
newSegment.timestamp = (lastKnownTimestamp += 10);
else
newSegment.timestamp = newTimestamp;
newSegment.timestamp = (lastUsedTimestamp += 10);
if(!bBrokenTimestamp)
{
QWORD difVal = GetQWDif(newTimestamp, newSegment.timestamp);
if(difVal > 100)
lastUsedTimestamp = newSegment.timestamp = newTimestamp;
}
}
else
{
@ -677,26 +705,31 @@ UINT MMDeviceAudioSource::GetNextBuffer()
storageBuffer.AppendArray(newBuffer, numAudioFrames*2);
if(storageBuffer.Num() >= (441*2))
{
QWORD baseTimestmap;
AudioSegment &newSegment = *audioSegments.CreateNew();
newSegment.audioData.CopyArray(storageBuffer.Array(), (441*2));
storageBuffer.RemoveRange(0, (441*2));
if(bBrokenTimestamp)
newSegment.timestamp = (lastKnownTimestamp += 10);
else
baseTimestmap = newSegment.timestamp = newTimestamp - QWORD(storedFrames)/2*1000/44100;
//if still data pending (can happen)
//------------------------
// add new data
newSegment.timestamp = (lastUsedTimestamp += 10);
if(!bBrokenTimestamp)
{
QWORD difVal = GetQWDif(newTimestamp, newSegment.timestamp);
if(difVal > 100)
lastUsedTimestamp = newSegment.timestamp = newTimestamp - (QWORD(storedFrames)/2*1000/44100);
}
//------------------------
// if still data pending (can happen)
while(storageBuffer.Num() >= (441*2))
{
AudioSegment &newSegment = *audioSegments.CreateNew();
newSegment.audioData.CopyArray(storageBuffer.Array(), (441*2));
storageBuffer.RemoveRange(0, (441*2));
if(bBrokenTimestamp)
newSegment.timestamp = (lastKnownTimestamp += 10);
else
newSegment.timestamp = (baseTimestmap += 10);
newSegment.timestamp = (lastUsedTimestamp += 10);
}
}
}
@ -709,7 +742,7 @@ UINT MMDeviceAudioSource::GetNextBuffer()
return NoAudioAvailable;
}
bool MMDeviceAudioSource::GetMostRecentTimestamp(QWORD &timestamp)
bool MMDeviceAudioSource::GetEarliestTimestamp(QWORD &timestamp)
{
if(audioSegments.Num())
{

View File

@ -70,8 +70,8 @@ extern ConfigFile *AppConfig;
extern OBS *App;
extern TCHAR lpAppDataPath[MAX_PATH];
#define OBS_VERSION 0x000456
#define OBS_VERSION_STRING_ANSI "Open Broadcaster Software v0.456a"
#define OBS_VERSION 0x000457
#define OBS_VERSION_STRING_ANSI "Open Broadcaster Software v0.457a"
#define OBS_VERSION_STRING TEXT(OBS_VERSION_STRING_ANSI)
#define OBS_WINDOW_CLASS TEXT("OBSWindowClass")

View File

@ -33,7 +33,7 @@ typedef void (*UNLOADPLUGINPROC)();
BOOL bLoggedSystemStats = FALSE;
void LogSystemStats();
#define OUTPUT_BUFFER_TIME 200
#define OUTPUT_BUFFER_TIME 600
VideoEncoder* CreateX264Encoder(int fps, int width, int height, int quality, CTSTR preset, bool bUse444, int maxBitRate, int bufferSize);
@ -1789,7 +1789,7 @@ void OBS::Stop()
bTestStream = false;
}
inline void MultiplyAudioBuffer(float *buffer, int totalFloats, float mulVal, float &RMS, float &MAX)
inline void MultiplyAudioBuffer(float *buffer, int totalFloats, float mulVal)
{
float sum = 0.0f;
int totalFloatsStore = totalFloats;
@ -1805,6 +1805,33 @@ inline void MultiplyAudioBuffer(float *buffer, int totalFloats, float mulVal, fl
{
__m128 sseScaledVals = _mm_mul_ps(_mm_load_ps(buffer+i), sseMulVal);
_mm_store_ps(buffer+i, sseScaledVals);
}
buffer += alignedFloats;
totalFloats -= alignedFloats;
}
for(int i=0; i<totalFloats; i++)
{
buffer[i] *= mulVal;
}
}
inline void CalculateVolumeLevels(float *buffer, int totalFloats, float mulVal, float &RMS, float &MAX)
{
float sum = 0.0f;
int totalFloatsStore = totalFloats;
float Max = 0.0f;
if(App->SSE2Available() && (UPARAM(buffer) & 0xF) == 0)
{
UINT alignedFloats = totalFloats & 0xFFFFFFFC;
__m128 sseMulVal = _mm_set_ps1(mulVal);
for(UINT i=0; i<alignedFloats; i += 4)
{
__m128 sseScaledVals = _mm_mul_ps(_mm_load_ps(buffer+i), sseMulVal);
/*compute squares and add them to the sum*/
__m128 sseSquares = _mm_mul_ps(sseScaledVals, sseScaledVals);
@ -1828,9 +1855,10 @@ inline void MultiplyAudioBuffer(float *buffer, int totalFloats, float mulVal, fl
for(int i=0; i<totalFloats; i++)
{
buffer[i] *= mulVal;
sum += buffer[i] * buffer[i];
Max = max(Max, buffer[i] * buffer[i]);
float val = buffer[i] * mulVal;
float pow2Val = val * val;
sum += pow2Val;
Max = max(Max, pow2Val);
}
RMS = sqrt(sum / totalFloatsStore);
@ -2030,6 +2058,9 @@ void OBS::MainCaptureLoop()
while(bRunning)
{
//todo: test
QueryPerformanceFrequency(&clockFreq);
DWORD renderStartTime = OSGetTime();
totalStreamTime = renderStartTime-streamTimeStart;
@ -2598,7 +2629,7 @@ bool OBS::QueryNewAudio(QWORD &timestamp)
QWORD desktopTimestamp;
while((audioRet = desktopAudio->GetNextBuffer()) != NoAudioAvailable);
if(desktopAudio->GetMostRecentTimestamp(desktopTimestamp))
if(desktopAudio->GetEarliestTimestamp(desktopTimestamp))
timestamp = desktopTimestamp;
if(micAudio != NULL)
@ -2606,7 +2637,7 @@ bool OBS::QueryNewAudio(QWORD &timestamp)
while((audioRet = micAudio->GetNextBuffer()) != NoAudioAvailable);
QWORD micTimestamp = INVALID_LL;
micAudio->GetMostRecentTimestamp(micTimestamp);
micAudio->GetEarliestTimestamp(micTimestamp);
//if(micTimestamp < desktopTimestamp)
// timestamp = micTimestamp;
@ -2617,12 +2648,6 @@ bool OBS::QueryNewAudio(QWORD &timestamp)
if(desktopAudio->GetBufferedTime() >= OUTPUT_BUFFER_TIME)
return true;
if(micAudio)
{
if(micAudio->GetBufferedTime() >= OUTPUT_BUFFER_TIME)
return true;
}
return false;
}
@ -2647,7 +2672,9 @@ void OBS::MainAudioLoop()
//-----------------------------------------------
float *desktopBuffer, *micBuffer;
float *latestDesktopBuffer, *latestMicBuffer;
UINT desktopAudioFrames = 0, micAudioFrames = 0;
UINT latestDesktopAudioFrames = 0, latestMicAudioFrames = 0;
float curMicVol;
@ -2665,18 +2692,28 @@ void OBS::MainAudioLoop()
while(QueryNewAudio(timestamp))
{
desktopAudio->GetBuffer(&desktopBuffer, &desktopAudioFrames, timestamp);
desktopAudio->GetNewestFrame(&latestDesktopBuffer, &latestDesktopAudioFrames);
if(micAudio != NULL)
{
micAudio->GetBuffer(&micBuffer, &micAudioFrames, timestamp);
micAudio->GetNewestFrame(&latestMicBuffer, &latestMicAudioFrames);
}
//----------------------------------------------------------------------------
UINT totalFloats = desktopAudioFrames*2;
MultiplyAudioBuffer(desktopBuffer, totalFloats, desktopVol);
if(bMicEnabled)
MultiplyAudioBuffer(micBuffer, totalFloats, curMicVol);
//----------------------------------------------------------------------------
/*multiply samples by volume and compute RMS and max of samples*/
float desktopRMS = 0, micRMS = 0, desktopMx = 0, micMx = 0;
MultiplyAudioBuffer(desktopBuffer, totalFloats, desktopVol, desktopRMS, desktopMx);
CalculateVolumeLevels(latestDesktopBuffer, latestDesktopAudioFrames*2, desktopVol, desktopRMS, desktopMx);
if(bMicEnabled)
MultiplyAudioBuffer(micBuffer, totalFloats, curMicVol, micRMS, micMx);
CalculateVolumeLevels(latestMicBuffer, latestMicAudioFrames*2, curMicVol, micRMS, micMx);
/*convert RMS and Max of samples to dB*/
desktopRMS = toDB(desktopRMS);

View File

@ -125,9 +125,11 @@ public:
virtual void StopCapture()=0;
virtual UINT GetNextBuffer()=0;
virtual bool GetMostRecentTimestamp(QWORD &timestamp)=0;
virtual bool GetEarliestTimestamp(QWORD &timestamp)=0;
virtual bool GetBuffer(float **buffer, UINT *numFrames, QWORD targetTimestamp)=0;
virtual bool GetNewestFrame(float **buffer, UINT *numFrames)=0;
virtual QWORD GetBufferedTime()=0;
};

View File

@ -1186,6 +1186,9 @@ INT_PTR CALLBACK OBS::VideoSettingsProc(HWND hwnd, UINT message, WPARAM wParam,
hwndTemp = GetDlgItem(hwnd, IDC_DISABLEAERO);
if(IsWindows8Up())
EnableWindow(hwndTemp, FALSE);
BOOL bDisableAero = AppConfig->GetInt(TEXT("Video"), TEXT("DisableAero"), 0);
SendMessage(hwndTemp, BM_SETCHECK, bDisableAero ? BST_CHECKED : 0, 0);
@ -1907,6 +1910,7 @@ void OBS::ApplySettings()
break;
}
case Settings_Video:
{
int curSel = (int)SendMessage(GetDlgItem(hwndCurrentSettings, IDC_MONITOR), CB_GETCURSEL, 0, 0);

View File

@ -12,14 +12,14 @@ Disable "Отключено"
EndingDelay "Завершение стрима с задержкой..."
EnterName "Пожалуйста, введите имя"
GlobalSources "Глобальные источники"
IncompatibleModules "В OBS обнаружены несовместимые модули внедрения. Убедитесь что OBS добавлен в список исключения таких программ захвата как DXTory, FRAPS и т.д.\r\n\r\nЧтобы изменения вступили в силу, после изменения настроек исключений может понадобиться перезапуск OBS и всех программ захвата, использующих внедрение в процесс."
IncompatibleModules "Были найдены несовместимые модули захвата. Убедитесь что OBS добавлен в список исключения DXTory, FRAPS и т.д.\r\n\r\nЧтобы изменения вступили в силу, перезапустите OBS и программы захвата."
MicrophoneFailure "Ошибка инициализации микрофона. Возможно, он не подключен или его использует другое приложение."
MoveDown "Вниз"
MoveToBottom "Переместить вниз"
MoveToTop "Переместить вверх"
MoveToBottom "Переместить в конец"
MoveToTop "Переместить в начало"
MoveUp "Вверх"
NameExists "'$1' уже занято. Пожалуйста, введите другое имя"
None "Отсутствует"
None "Нет"
OK "OK"
Plugins "Плагины"
Reconnecting "Переподключение..."
@ -38,7 +38,7 @@ Connection.InvalidStream "Неверный stream channel или playpath"
DeleteConfirm.Title "Удалить выбранное?"
EndingDelay.TimeLeft "Осталось: $1"
EndingDelay.TimeLeft "Осталось времени: $1"
GlobalSources.DeleteConfirm "Если вы удалите глобальный источник, он будет удален из всех сцен, в которых он используется. Вы уверены, что хотите продолжить?"
@ -49,20 +49,20 @@ Listbox.FitToScreen "По размеру экрана"
Listbox.ResetSize "Сбросить размер"
Listbox.SetHotkey "Добавить горячую клавишу"
MainMenu.File "Ф&айл"
MainMenu.Help "(&Р)Помощь"
MainMenu.Settings "(&Ы)Настройки"
MainMenu.File "&Файл"
MainMenu.Help "&Помощь"
MainMenu.Settings "&Настройки"
MainMenu.File.Exit "(&Ч)Выход"
MainMenu.File.Exit "&Выход"
MainMenu.Help.Contents "&Содержание"
MainMenu.Help.VisitWebsite "Посетить веб-сайт"
MainMenu.Help.Contents "&Руководство"
MainMenu.Help.VisitWebsite "Посетить веб-&сайт"
MainMenu.Settings.OpenConfigFolder "&(C)Открыть папку конфигурации"
MainMenu.Settings.OpenLogFolder "&(Д)Открыть папку журнала"
MainMenu.Settings.OpenConfigFolder "Открыть папку &конфигурации"
MainMenu.Settings.OpenLogFolder "Открыть папку &журнала"
MainWindow.Dashboard "Дэшборд"
MainWindow.DroppedFrames "Dropped Frames:"
MainWindow.DroppedFrames "Пропущенные кадры:"
MainWindow.Exit "Выход"
MainWindow.Plugins "Плагины"
MainWindow.SceneEditor "Изменить сцену"
@ -92,9 +92,9 @@ Settings.Advanced "Расширенные"
Settings.Audio "Аудио"
Settings.DashboardLink "Ссылка на дэшборд (если есть):"
Settings.Encoding "Кодирование"
Settings.General "Главное"
Settings.General "Общие"
Settings.Info "Эти параметры не будут применены до следующего запуска стрима."
Settings.Publish "Настройки вещания"
Settings.Publish "Трансляция"
Settings.SaveChangesPrompt "Сохранить и применить изменения?"
Settings.SaveChangesTitle "Применить настройки?"
Settings.Video "Видео"
@ -102,19 +102,23 @@ Settings.Video "Видео"
Settings.Advanced.DisableD3DCompatibilityMode "Отключить совместимость с D3D"
Settings.Advanced.DisableD3DCompatibilityModeTooltip "Отключает режим совместимости GPU с D3D"
Settings.Advanced.Network "Сеть"
Settings.Advanced.SendBufferSize "Размер исходящего буфера:"
Settings.Advanced.UnlockHigherFPS "Разрешить использование 61-120 FPS в настройках видео"
Settings.Advanced.UseCBR "Использовать постоянный битрейт"
Settings.Advanced.UseHighQualityResampling "Использовать высококачественное преобразование звука"
Settings.Advanced.UseHighQualityResamplingTooltip "Когда звуковая подсистема принудительно использует высококачественное преобразование звука, то вместо линейной интерполяции используется синусоидальная. Слегка увеличивает нагрузку на CPU."
Settings.Advanced.UseHighQualityResamplingTooltip "Когда звуковая подсистема принудительно использует высококачественное преобразование звука, то вместо линейной интерполяции используется синусоидальная. Слегка увеличивает нагрузку на CPU."
Settings.Advanced.UseMultithreadedOptimizations "Использовать многопоточную оптимизацию"
Settings.Advanced.UseSendBuffer "Использовать исходящий буфер"
Settings.Advanced.UseSendBufferTooltip "Исходящий буфер заставляет сетевые данные буферизоваться до определенных размеров пакета перед отправкой. Это позволяет значительно увеличить сетевую пропускную способность, но слегка увеличивает задержку трансляции.\r\n\r\nРекомендуется: включить. Размер буфера должен быть кратен максимальному размеру блока данных (обычно 1460)"
Settings.Advanced.UseSyncFix "Исправлять Видео / Аудио синхронизацию"
Settings.Advanced.UseSyncFixTooltip "В редких случаях у определенных процессоров и/или материнских плат возникают ошибки с таймингами. Использование данного исправления гарантирует, что аудио / видео синхронизация всегда будет корректна, но менее точна чет при правильных таймингах. Не используйте это если не уверенны что у вас есть данная ошибка."
Settings.Advanced.VideoEncoderCPUTradeoff "x264 CPU предустановка:"
Settings.Advanced.VideoEncoderCPUTradeoffToolTip "Увеличение этого значения уменьшит загрузку процессора в ущерб качеству. Уменьшение этого значения повысит качество, но загрузка процессора увеличится.\r\n\r\nРекомендуется: Very Fast"
Settings.Advanced.VideoEncoderCPUTradeoffToolTip "Увеличение этого значения уменьшит загрузку процессора в ущерб качеству. Уменьшение этого значения повысит качество, но загрузка процессора увеличится.\r\n\r\nРекомендуется: Very Fast"
Settings.Advanced.VideoEncoderSettings "Пользовательские настройки энкодера x264"
Settings.Advanced.VideoEncoderSettingsTooltip "Позволяет установить пользовательские настройки энкодера x264. В виде [параметр] = [значение] (например, \"VBV-maxrate = 1000 VBV-BUFSIZE = 1000 \")."
Settings.Advanced.VideoEncoderSettingsTooltip "Позволяет установить пользовательские настройки энкодера x264. В виде [параметр] = [значение] (например, \"VBV-maxrate = 1000 VBV-BUFSIZE = 1000 \")."
Settings.Advanced.ProcessPriority "Приоритет процесса"
Settings.Advanced.PresetWarning "Внимание! Изменение настроек х264 может оказывать негативное влияние на качество трансляции и загрузку CPU.\r\n\r\nНе меняйте эти настройки, если вы не имеете полного представления о том, как они влияют на трансляцию.\r\n\r\nОстерегайтесь советов, которые предлагают изменять этот параметр.\r\n\r\nРедко когда может понадобиться менять значение по умолчанию (veryfast).\r\n\r\nУверены что хотите изменить настройки?"
Settings.Advanced.PresetWarning "Внимание! Изменение настроек х264 может оказывать негативное влияние на качество трансляции и повышение нагрузки на CPU.\r\n\r\nНе изменяйте эти настройки, если вы не до конца не понимаете, к каким последствиям это может привести.\r\n\r\nПрименяйте инструкции с осторожностью.\r\n\r\nВ большинстве случаев вам должны подойти настройки по умолчанию (veryfast).\r\n\r\nВы уверены, что хотите изменить настройки?"
Settings.Advanced.BindToIP "Привязка к интерфейсу:"
Settings.Audio.Device "Микрофон:"
Settings.Audio.ForceMicMono "Принудительный режим моно:"
@ -131,11 +135,11 @@ Settings.Encoding.Audio.Codec "Кодек:"
Settings.Encoding.Audio.Format "Формат:"
Settings.Encoding.Video.BufferSize "Размер буфера (Кбит):"
Settings.Encoding.Video.BufferSizeTooltip "Размер буфера определяет, сколько данных будет загружено в буфер перед отправкой на стрим сервер. Установка более высокого значения, чем битрейт, может улучшить плавность картинки, но при нехватке исходящей скорости интернета может привести к потере данных. Анна Макатова\r\nРекомендуется: Такое же или меньшее значение что и битрейт."
Settings.Encoding.Video.BufferSizeTooltip "Размер буфера определяет, сколько данных будет загружено в буфер перед отправкой на стрим сервер. Установка более высокого значения, чем битрейт, может улучшить плавность картинки, но при нехватке исходящей скорости интернета может привести к потере данных.\r\nРекомендуется: Такое же или меньшее значение что и битрейт."
Settings.Encoding.Video.MaxBitRate "Максимальный битрейт (Кбит/с):"
Settings.Encoding.Video.MaxBitRateTooltip "Установка максимального значения битрейта для видео. Напрямую зависит от вашей исходящей скорости интернета. Отметим, что заданный битрейт будет средним значением, но так же на него будет влиять размера буфера.\r\n\r\nВоспользуйтесь сайтом, например speedtest.net, чтобы узнать свою исходящую скорость интернета."
Settings.Encoding.Video.MaxBitRateTooltip "Установка максимального значения битрейта для видео. Напрямую зависит от вашей исходящей скорости интернета. Отметим, что заданный битрейт будет средним значением, но так же на него будет влиять размера буфера.\r\n\r\nВоспользуйтесь сайтом, например speedtest.net, чтобы узнать свою исходящую скорость интернета."
Settings.Encoding.Video.Quality "Качество:"
Settings.Encoding.Video.QualityTooltip "Эта опция будет подстраивать качество в зависимости от установленных битрейта и буфера. При установки высокого значения и низкого битрейта будет жертвоваться качеством в динамичных сценах в пользу статичных."
Settings.Encoding.Video.QualityTooltip "Эта опция будет подстраивать качество в зависимости от установленных битрейта и буфера. При установки высокого значения и низкого битрейта будет жертвоваться качеством в динамичных сценах в пользу статичных."
Settings.General.Add "Добавить"
Settings.General.ConfirmDelete "Вы уверены, что хотите удалить профиль '$1'?"
@ -148,7 +152,7 @@ Settings.Publish.AutoReconnect "Автопереподключение:
Settings.Publish.AutoReconnectTimeout "Задержка автопереподключения:"
Settings.Publish.ChannelName "Имя канала:"
Settings.Publish.DashboardLink "Ссылка на дэшборд (если есть):"
Settings.Publish.Delay "Задержка (секунд):"
Settings.Publish.Delay "Задержка (в секундах):"
Settings.Publish.Mode "Режим:"
Settings.Publish.Password "Пароль (если имеется):"
Settings.Publish.Playpath "Play Path/Stream Key (если имеется):"
@ -163,7 +167,7 @@ Settings.Publish.Username "Имя пользователя (есл
Settings.Publish.Mode.FileOnly "Локальная запись"
Settings.Publish.Mode.LiveStream "Прямой эфир"
Settings.Video.Custom "Пользовательский:"
Settings.Video.Custom "Пользовательское:"
Settings.Video.DisableAero "Отключать Aero при запуске:"
Settings.Video.DisableAeroTooltip "Рекомендуется отключить Aero при использовании программного захвата."
Settings.Video.Downscale "Масштабировать разрешение:"
@ -184,17 +188,17 @@ Sources.BitmapSource.Empty "Изображение не найдено. Пож
Sources.BitmapSource.Opacity "Прозрачность:"
Sources.GameCaptureSource.Application "Приложение:"
Sources.GameCaptureSource.PluginDescription "Захватывает кадры напрямую из игр и графических приложений посредством внедрения в приложение и считывания кадров как только они появляются."
Sources.GameCaptureSource.PluginName "Плагин захвата игр"
Sources.GameCaptureSource.Requires32bit "Эти приложения требуют 32-битной версии OBS для захвата:"
Sources.GameCaptureSource.Requires64bit "Эти приложения требуют 64-битной версии OBS для захвата:"
Sources.GameCaptureSource.RequiresAdmin "Для захвата этого приложения требуются привилегии Администратора (запустите OBS от имени Администратора):"
Sources.GameCaptureSource.StretchToScreen "Растянуть изображение по размеру экрана"
Sources.GameCaptureSource.PluginDescription "Захватывает картинку напрямую из игры и других графических приложений, путем внедрения в приложение и считывания кадров."
Sources.GameCaptureSource.PluginName "Плагин Игрового захвата"
Sources.GameCaptureSource.Requires32bit "Эти приложения требуют 32-битную версию OBS для захвата:"
Sources.GameCaptureSource.Requires64bit "Эти приложения требуют 64-битную версию OBS для захвата:"
Sources.GameCaptureSource.RequiresAdmin "Для захвата этого приложения требуются привилегии администратора (запустите OBS от имени администратора):"
Sources.GameCaptureSource.StretchToScreen "Растянуть изображение во весь экран"
Sources.SoftwareCaptureSource.Blend "Смешивание (1-100):"
Sources.SoftwareCaptureSource.CaptureLayered "Захватывать многослойные окна"
Sources.SoftwareCaptureSource.CaptureLayeredTip "Захватывать программы использующие обложки или прозрачные/'слоёные' окна при отключенном Aero. Может вызывать моргание курсора. Используйте только если не получается захватить какую-то конкретную программу."
Sources.SoftwareCaptureSource.ColorKey "Color Key"
Sources.SoftwareCaptureSource.CaptureLayeredTip "Захватывать программы использующие обложки или прозрачные/'слоёные' окна при отключенном Aero. Может вызывать дрожание курсора. Стоит включать только при отсутствии другой возможности захватить приложение."
Sources.SoftwareCaptureSource.ColorKey "Ключевой цвет"
Sources.SoftwareCaptureSource.EntireWindow "Все окно"
Sources.SoftwareCaptureSource.InnerWindow "Окно без рамки"
Sources.SoftwareCaptureSource.InvertMouseOnClick "Инвертировать цвет курсора при клике"
@ -209,34 +213,36 @@ Sources.SoftwareCaptureSource.RegionWindowText "Нажмите клавиш
Sources.SoftwareCaptureSource.Select "Выбрать"
Sources.SoftwareCaptureSource.SelectRegion "Выбрать область"
Sources.SoftwareCaptureSource.SelectRegionTooltip "При выборе области захвата изменение размера прямоугольника производится путем захвата за край."
Sources.SoftwareCaptureSource.Similarity "Сходство (1-100):"
Sources.SoftwareCaptureSource.Similarity "Порог срабатывания (1-100):"
Sources.SoftwareCaptureSource.Size "Размер:"
Sources.SoftwareCaptureSource.SpillReduction "Уменьшение охвата:"
Sources.SoftwareCaptureSource.UseColorKey "Использовать Color Key:"
Sources.SoftwareCaptureSource.SpillReduction "Уменьшение разброса:"
Sources.SoftwareCaptureSource.UseColorKey "Использовать ключевой цвет:"
Sources.SoftwareCaptureSource.Window "Процесс:"
Sources.SoftwareCaptureSource.WindowCapture "Захват окна"
Sources.SoftwareCaptureSource.WindowCaptureTooltip "Aero может быть включено при использовании только функции захвата окна. Изображение не обновляется, если целевое окно свернуто. Захват с помощью этой функции обычно быстрее, чем захват всего экрана или области экрана. Если Aero включено, окна, перекрывающие целевое окно, не будут видны."
Sources.SoftwareCaptureSource.WindowMinimized "Окно минимизировано"
Sources.SoftwareCaptureSource.WindowNotFound "Окно не найдено"
Sources.TextSource.Align "Выровнять:"
Sources.TextSource.Align "Выравнивание:"
Sources.TextSource.Bold "Жирный"
Sources.TextSource.Center "По центру"
Sources.TextSource.EnterText "Свой Текст"
Sources.TextSource.FileNotFound "Не удалось открыть файл '$1'"
Sources.TextSource.EnterText "Свой текст"
Sources.TextSource.FileNotFound "Невозможно открыть файл '$1'"
Sources.TextSource.Font "Шрифт:"
Sources.TextSource.FontNotFound "Шрифт '$1' не найден"
Sources.TextSource.FontSize "Размер шрифта:"
Sources.TextSource.Italic "Курсив"
Sources.TextSource.Left "Слева"
Sources.TextSource.Right "Справа"
Sources.TextSource.Left "По левому краю"
Sources.TextSource.Right "По правому краю"
Sources.TextSource.ScrollSpeed "Скорость прокрутки:"
Sources.TextSource.Size "Размер:"
Sources.TextSource.Underline "Подчеркнутый"
Sources.TextSource.UseCustomExtents "Свои границы текста"
Sources.TextSource.UseTextExtents "Свои границы текста"
Sources.TextSource.UseTextFromFile "Использовать текст из файла (поддерживается UTF-8)"
Sources.TextSource.VerticalScript "Вертикально"
Sources.TextSource.UseCustomExtents "Свои размеры текстового поля"
Sources.TextSource.UseOutline "Использовать контур"
Sources.TextSource.OutlineThickness "Толщина:"
Sources.TextSource.UseTextExtents "Свои размеры текстового поля"
Sources.TextSource.UseTextFromFile "Текст из файла (UTF-8 или совместимый)"
Sources.TextSource.VerticalScript "Вертикальный"
Sources.TextSource.Wrap "Перенос"
Sources.TransitionSource.Bitmaps "Изображения:"

View File

@ -1,5 +1,5 @@
Cancel "Отмена"
ClassName "Устройство Видео Захвата"
ClassName "Устройство видео захвата"
DeviceSelection "Выбор устройства"
OK "OK"
@ -11,20 +11,20 @@ DeviceSelection.CustomResolution "Изменить разрешение:"
DeviceSelection.Device "Устройство:"
DeviceSelection.ExistsInScene "Источник использующийся этим устройством уже существует."using this device already exists."
DeviceSelection.ExistsSomewhere "Это устройство используется как источник в одной или нескольких сценах."
DeviceSelection.FlipImage "Перевернуть Изображение"
DeviceSelection.FlipImageHorizontal "Отразить изображение по горизонтали"
DeviceSelection.FlipImage "Перевернуть изображение"
DeviceSelection.FlipImageHorizontal "Отразить по горизонтали"
DeviceSelection.FPS "FPS:"
DeviceSelection.GlobalExists "Глобальный источник использующий это устройство уже существует."
DeviceSelection.InvalidResolution "Неверное разрешение"
DeviceSelection.Opacity "Прозрачность"
DeviceSelection.PreferredType "Использовать привилегированный тип вывода"
DeviceSelection.PreferredType "Предпочтительный вывод"
DeviceSelection.Refresh "Обновить"
DeviceSelection.Resolution "Разрешение:"
DeviceSelection.Select "Выбор"
DeviceSelection.Similarity "Схожесть (1-1000):"
DeviceSelection.SpillReduction "Уменьшение охвата (1-1000):"
DeviceSelection.Similarity "Порог срабатывания (1-1000):"
DeviceSelection.SpillReduction "Уменьшение разброса (1-1000):"
DeviceSelection.UnsupportedResolution "Это устройство не поддерживает такое разрешение"
DeviceSelection.UseChromaKey "Использовать Chroma Key"
Plugin.Description "Этот плагин позволяет добавлять DirectShow видео устройства (веб-камеры, карты захвата, и т.д.) на сцену."
Plugin.Name "Плагин DirectShow видео устройств"
Plugin.Name "Плагин DirectShow видео-устройств"