VideoFileStream *CreateFileStream(String strOutputFile) { String strFileExtension = GetPathExtension(strOutputFile); if (strFileExtension.CompareI(TEXT("flv"))) return CreateFLVFileStream(strOutputFile); else if (strFileExtension.CompareI(TEXT("mp4"))) return CreateMP4FileStream(strOutputFile); return nullptr; }
bool valid_x264_string(const String &str, const char **x264StringList) { do { if(str.CompareI(String(*x264StringList))) return true; } while (*++x264StringList != 0); return false; }
BOOL STDCALL OSFileHasChanged (OSFileChangeData *data) { BOOL hasModified = FALSE; if(HasOverlappedIoCompleted(&data->directoryChange)) { FILE_NOTIFY_INFORMATION *notify = (FILE_NOTIFY_INFORMATION*)data->changeBuffer; for (;;) { if (notify->Action != FILE_ACTION_RENAMED_OLD_NAME && notify->Action != FILE_ACTION_REMOVED) { String strFileName; strFileName.SetLength(notify->FileNameLength); scpy_n(strFileName, notify->FileName, notify->FileNameLength/2); strFileName.KillSpaces(); String strFileChanged; strFileChanged << data->strDirectory << strFileName; if(strFileChanged.CompareI(data->targetFileName)) { hasModified = TRUE; break; } } if (!notify->NextEntryOffset) break; notify = (FILE_NOTIFY_INFORMATION*)((BYTE *)notify + notify->NextEntryOffset); } CloseHandle (data->directoryChange.hEvent); DWORD test; zero(&data->directoryChange, sizeof(data->directoryChange)); zero(data->changeBuffer, sizeof(data->changeBuffer)); data->directoryChange.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); if(ReadDirectoryChangesW(data->hDirectory, data->changeBuffer, 2048, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE, &test, &data->directoryChange, NULL)) { } else { CloseHandle(data->directoryChange.hEvent); CloseHandle(data->hDirectory); return hasModified; } } return hasModified; }
bool DeviceAudioSource::Initialize(DeviceSource *parent) { m_timeStart = 0; device = parent; if (!hAudioMutex) hAudioMutex = OSCreateMutex(); m_bErrorLog = false; lastTimestamp = 0; //--------------------------------- bool bFloat = false; UINT inputChannels; UINT inputSamplesPerSec; UINT inputBitsPerSample; //UINT inputBlockSize; DWORD inputChannelMask; //--------------------------------- if(device->audioFormat.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { WAVEFORMATEXTENSIBLE *wfext = (WAVEFORMATEXTENSIBLE*)&device->audioFormat; if(wfext->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) bFloat = true; } else if(device->audioFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) bFloat = true; inputBitsPerSample = device->audioFormat.wBitsPerSample; inputBlockSize = device->audioFormat.nBlockAlign; inputChannelMask = 0; inputChannels = device->audioFormat.nChannels; inputSamplesPerSec = device->audioFormat.nSamplesPerSec; sampleFrameCount = inputSamplesPerSec/100; sampleSegmentSize = inputBlockSize*sampleFrameCount; outputBuffer.SetSize(sampleSegmentSize); InitAudioData(bFloat, inputChannels, inputSamplesPerSec, inputBitsPerSample, inputBlockSize, inputChannelMask); if (m_pAudioWaveOut) { m_pAudioWaveOut->Uninitialize(); } String strReanderName = GetDirectorMonitorDevices(); if (NULL == m_pAudioWaveOut) { if (!strReanderName.Compare(TEXT("禁用")) && !m_pAudioWaveOut) { m_pAudioWaveOut = new AudioWaveOut; } } else { if ((strReanderName.Compare(TEXT("Disable")) || strReanderName.Compare(TEXT("禁用")))) { delete m_pAudioWaveOut; m_pAudioWaveOut = NULL; } } if (NULL != m_pAudioWaveOut) { m_pAudioWaveOut->Initialize(strReanderName.Array(), inputChannels, inputSamplesPerSec, inputBitsPerSample); } String SecRenderName = GetSecMonitorDevices(); if (m_pSecWaveOut) { m_pSecWaveOut->Uninitialize(); } if (SecRenderName.CompareI(strReanderName.Array()) && (!SecRenderName.Compare(TEXT("Disable")) || !SecRenderName.Compare(TEXT("禁用")))) { bSameDevice = true; } else if (!SecRenderName.Compare(TEXT("禁用")) && !m_pSecWaveOut) { m_pSecWaveOut = new AudioWaveOut; } else if (m_pSecWaveOut) { if ((SecRenderName.Compare(TEXT("Disable")) || SecRenderName.Compare(TEXT("禁用")))) { delete m_pSecWaveOut; m_pSecWaveOut = NULL; } } if (m_pSecWaveOut) { m_pSecWaveOut->Initialize(SecRenderName.Array(), inputChannels, inputSamplesPerSec, inputBitsPerSample); } return true; }
BOOL ShaderProcessor::ProcessShader(CTSTR input) { String curToken; BOOL bError = FALSE; SetCodeStart(input); TSTR lpLastPos = lpTemp; DWORD curInsideCount = 0; BOOL bNewCodeLine = TRUE; while(GetNextToken(curToken)) { TSTR lpCurPos = lpTemp-curToken.Length(); if(curToken[0] == '{') ++curInsideCount; else if(curToken[0] == '}') --curInsideCount; else if(curToken[0] == '(') ++curInsideCount; else if(curToken[0] == ')') --curInsideCount; else if(!curInsideCount && bNewCodeLine) //not inside any code, so this is some sort of declaration (function/struct/var) { if(curToken == TEXT("struct")) { //try to see if this is the vertex definition structure bool bFoundDefinitionStruct = false; HandMeAToken(curToken); ExpectTokenIgnore(TEXT("{")); curInsideCount = 1; do { HandMeAToken(curToken); if(curToken.Length() <= 6 && scmpi_n(curToken, TEXT("float"), 5) == 0) { String strType = curToken; String strName; HandMeAToken(strName); HandMeAToken(curToken); if(curToken[0] != ':') //cancel if not a vertex definition structure { bFoundDefinitionStruct = false; break; } String strSemantic; HandMeAToken(strSemantic); SemanticInfo semanticInfo; if(!GetSemanticInfo(strSemantic, semanticInfo)) { bFoundDefinitionStruct = false; break; } D3D10_INPUT_ELEMENT_DESC inputElement; inputElement.SemanticName = semanticInfo.lpName; inputElement.SemanticIndex = semanticInfo.index; inputElement.InputSlot = 0; inputElement.AlignedByteOffset = 0; inputElement.InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA; inputElement.InstanceDataStepRate = 0; if(strSemantic.CompareI(TEXT("color"))) inputElement.Format = DXGI_FORMAT_R8G8B8A8_UNORM; else { switch(strType[5]) { case 0: inputElement.Format = DXGI_FORMAT_R32_FLOAT; break; case '2': inputElement.Format = DXGI_FORMAT_R32G32_FLOAT; break; case '3': inputElement.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; break; //todo: check this some time case '4': inputElement.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; break; } } ExpectToken(TEXT(";"), TEXT(";")); PeekAtAToken(curToken); generatedLayout << inputElement; bFoundDefinitionStruct = true; } else { bFoundDefinitionStruct = false; break; //vertex definition structures should really only ever have float values } } while (curToken[0] != '}'); //set up the slots so they match up with vertex buffers if(bFoundDefinitionStruct) { UINT curSlot = 0; for(UINT i=0; i<generatedLayout.Num(); i++) { if(stricmp(generatedLayout[i].SemanticName, "SV_Position") == 0) { generatedLayout[i].InputSlot = curSlot++; break; } } for(UINT i=0; i<generatedLayout.Num(); i++) { if(stricmp(generatedLayout[i].SemanticName, "NORMAL") == 0) { generatedLayout[i].InputSlot = curSlot++; bHasNormals = true; break; } } for(UINT i=0; i<generatedLayout.Num(); i++) { if(stricmp(generatedLayout[i].SemanticName, "COLOR") == 0) { generatedLayout[i].InputSlot = curSlot++; bHasColors = true; break; } } for(UINT i=0; i<generatedLayout.Num(); i++) { if(stricmp(generatedLayout[i].SemanticName, "TANGENT") == 0) { generatedLayout[i].InputSlot = curSlot++; bHasTangents = true; break; } } bool bFoundTexCoord; do { bFoundTexCoord = false; for(UINT i=0; i<generatedLayout.Num(); i++) { if(generatedLayout[i].SemanticIndex == numTextureCoords && stricmp(generatedLayout[i].SemanticName, "TEXCOORD") == 0) { generatedLayout[i].InputSlot = curSlot++; numTextureCoords++; bFoundTexCoord = true; break; } } } while(bFoundTexCoord); } } else if( (curToken != TEXT("const")) && (curToken != TEXT("void")) && (curToken != TEXT(";")) ) { TSTR lpSavedPos = lpTemp; String savedToken = curToken; if(curToken == TEXT("uniform")) HandMeAToken(curToken); String strType = curToken; String strName; HandMeAToken(strName); PeekAtAToken(curToken); if(curToken[0] != '(') //verified variable { if(strType.CompareI(TEXT("samplerstate"))) { ShaderSampler &curSampler = *Samplers.CreateNew(); curSampler.name = strName; SamplerInfo info; ExpectToken(TEXT("{"), TEXT(";")); PeekAtAToken(curToken); while(curToken != TEXT("}")) { String strState; HandMeAToken(strState); ExpectToken(TEXT("="), TEXT(";")); String strValue; HandMeAToken(strValue); if(!AddState(info, strState, strValue)) EscapeLikeTheWind(TEXT(";")); ExpectToken(TEXT(";"), TEXT(";")); PeekAtAToken(curToken); } curSampler.sampler = CreateSamplerState(info); ExpectToken(TEXT("}"), TEXT("}")); ExpectTokenIgnore(TEXT(";")); //---------------------------------------- lpLastPos = lpTemp; continue; } else { ShaderParam *param = Params.CreateNew(); param->name = strName; if(curToken[0] == '[') { HandMeAToken(curToken); HandMeAToken(curToken); param->arrayCount = tstoi(curToken); ExpectToken(TEXT("]"), TEXT(";")); PeekAtAToken(curToken); } if(scmpi_n(strType, TEXT("texture"), 7) == 0) { TSTR lpType = strType.Array()+7; supr(lpType); if (!*lpType || (scmp(lpType, TEXT("1D")) && scmp(lpType, TEXT("2D")) && scmp(lpType, TEXT("3D")) && scmp(lpType, TEXT("CUBE"))) ) { bError = TRUE; } param->textureID = nTextures++; param->type = Parameter_Texture; strType = TEXT("sampler"); } else if(scmp_n(strType, TEXT("float"), 5) == 0) { CTSTR lpType = strType.Array()+5; if(*lpType == 0) param->type = Parameter_Float; else if(scmpi(lpType, TEXT("2")) == 0) param->type = Parameter_Vector2; else if(scmpi(lpType, TEXT("3")) == 0) param->type = Parameter_Vector3; else if(scmpi(lpType, TEXT("4")) == 0) param->type = Parameter_Vector4; else if(scmpi(lpType, TEXT("3x3")) == 0) param->type = Parameter_Matrix3x3; else if(scmpi(lpType, TEXT("4x4")) == 0) param->type = Parameter_Matrix; } else if(scmp(strType, TEXT("int")) == 0) param->type = Parameter_Int; else if(scmp(strType, TEXT("bool")) == 0) param->type = Parameter_Bool; if(curToken == TEXT("=")) { HandMeAToken(curToken); BufferOutputSerializer sOut(param->defaultValue); if(scmp(strType, TEXT("float")) == 0) { HandMeAToken(curToken); if(!ValidFloatString(curToken)) bError = TRUE; float fValue = (float)tstof(curToken); sOut << fValue; } else if(scmp(strType, TEXT("int")) == 0) { HandMeAToken(curToken); if(!ValidIntString(curToken)) bError = TRUE; int iValue = tstoi(curToken); sOut << iValue; } else if(scmp_n(strType, TEXT("float"), 5) == 0) { CTSTR lpFloatType = strType.Array()+5; int floatCount = 0; if(lpFloatType[0] == '1') floatCount = 1; else if(lpFloatType[0] == '2') floatCount = 2; else if(lpFloatType[0] == '3') floatCount = 3; else if(lpFloatType[0] == '4') floatCount = 4; else bError = TRUE; if(lpFloatType[1] == 'x') { if(lpFloatType[2] != '1') { if(lpFloatType[2] == '2') floatCount *= 2; else if(lpFloatType[2] == '3') floatCount *= 3; else if(lpFloatType[2] == '4') floatCount *= 4; else bError = TRUE; } } if(floatCount > 1) {ExpectToken(TEXT("{"), TEXT(";"));} int j; for(j=0; j<floatCount; j++) { if(j) { HandMeAToken(curToken); if(curToken[0] != ',') { bError = TRUE; break; } } HandMeAToken(curToken); if(!ValidFloatString(curToken)) { bError = TRUE; break; } float fValue = (float)tstof(curToken); sOut << fValue; } if(j != floatCount) //processing error occured { GotoToken(TEXT(";")); continue; } if(floatCount > 1) {ExpectToken(TEXT("}"), TEXT(";"));} } PeekAtAToken(curToken); } } //-------------------------- lpLastPos = lpTemp; bNewCodeLine = FALSE; continue; } lpTemp = lpSavedPos; curToken = savedToken; } } lpLastPos = lpTemp; bNewCodeLine = (curToken.IsValid() && ((curToken[0] == ';') || (curToken[0] == '}'))); } return !bError; }
void OBS::Start() { if(bRunning) return; OSEnterMutex (hStartupShutdownMutex); scenesConfig.Save(); //------------------------------------------------------------- fps = AppConfig->GetInt(TEXT("Video"), TEXT("FPS"), 30); frameTime = 1000/fps; //------------------------------------------------------------- if(!bLoggedSystemStats) { LogSystemStats(); bLoggedSystemStats = TRUE; } OSCheckForBuggyDLLs(); //------------------------------------------------------------- retryHookTest: bool alreadyWarnedAboutModules = false; if (OSIncompatibleModulesLoaded()) { Log(TEXT("Incompatible modules (pre-D3D) detected.")); int ret = MessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR | MB_ABORTRETRYIGNORE); if (ret == IDABORT) { OSLeaveMutex (hStartupShutdownMutex); return; } else if (ret == IDRETRY) { goto retryHookTest; } alreadyWarnedAboutModules = true; } String strPatchesError; if (OSIncompatiblePatchesLoaded(strPatchesError)) { OSLeaveMutex (hStartupShutdownMutex); MessageBox(hwndMain, strPatchesError.Array(), NULL, MB_ICONERROR); Log(TEXT("Incompatible patches detected.")); return; } //------------------------------------------------------------- String processPriority = AppConfig->GetString(TEXT("General"), TEXT("Priority"), TEXT("Normal")); if (!scmp(processPriority, TEXT("Idle"))) SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS); else if (!scmp(processPriority, TEXT("Above Normal"))) SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); else if (!scmp(processPriority, TEXT("High"))) SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); int networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2); DWORD delayTime = (DWORD)AppConfig->GetInt(TEXT("Publish"), TEXT("Delay")); String strError; bFirstConnect = !bReconnecting; if(bTestStream) network = CreateNullNetwork(); else { switch(networkMode) { case 0: network = (delayTime > 0) ? CreateDelayedPublisher(delayTime) : CreateRTMPPublisher(); break; case 1: network = CreateNullNetwork(); break; } } if(!network) { OSLeaveMutex (hStartupShutdownMutex); if(!bReconnecting) MessageBox(hwndMain, strError, NULL, MB_ICONERROR); else DialogBox(hinstMain, MAKEINTRESOURCE(IDD_RECONNECTING), hwndMain, OBS::ReconnectDialogProc); return; } bReconnecting = false; //------------------------------------------------------------- Log(TEXT("=====Stream Start: %s==============================================="), CurrentDateTimeString().Array()); //------------------------------------------------------------- bEnableProjectorCursor = GlobalConfig->GetInt(L"General", L"EnableProjectorCursor", 1) != 0; bPleaseEnableProjector = bPleaseDisableProjector = false; int monitorID = AppConfig->GetInt(TEXT("Video"), TEXT("Monitor")); if(monitorID >= (int)monitors.Num()) monitorID = 0; RECT &screenRect = monitors[monitorID].rect; int defCX = screenRect.right - screenRect.left; int defCY = screenRect.bottom - screenRect.top; downscaleType = AppConfig->GetInt(TEXT("Video"), TEXT("Filter"), 0); downscale = AppConfig->GetFloat(TEXT("Video"), TEXT("Downscale"), 1.0f); baseCX = AppConfig->GetInt(TEXT("Video"), TEXT("BaseWidth"), defCX); baseCY = AppConfig->GetInt(TEXT("Video"), TEXT("BaseHeight"), defCY); baseCX = MIN(MAX(baseCX, 128), 4096); baseCY = MIN(MAX(baseCY, 128), 4096); scaleCX = UINT(double(baseCX) / double(downscale)); scaleCY = UINT(double(baseCY) / double(downscale)); //align width to 128bit for fast SSE YUV4:2:0 conversion outputCX = scaleCX & 0xFFFFFFFC; outputCY = scaleCY & 0xFFFFFFFE; bUseMultithreadedOptimizations = AppConfig->GetInt(TEXT("General"), TEXT("UseMultithreadedOptimizations"), TRUE) != 0; Log(TEXT(" Multithreaded optimizations: %s"), (CTSTR)(bUseMultithreadedOptimizations ? TEXT("On") : TEXT("Off"))); encoderSkipThreshold = GlobalConfig->GetInt(TEXT("Video"), TEXT("EncoderSkipThreshold"), fps/4); //------------------------------------------------------------------ Log(TEXT(" Base resolution: %ux%u"), baseCX, baseCY); Log(TEXT(" Output resolution: %ux%u"), outputCX, outputCY); Log(TEXT("------------------------------------------")); //------------------------------------------------------------------ GS = new D3D10System; GS->Init(); //Thanks to ASUS OSD hooking the goddamn user mode driver framework (!!!!), we have to re-check for dangerous //hooks after initializing D3D. retryHookTestV2: if (!alreadyWarnedAboutModules) { if (OSIncompatibleModulesLoaded()) { Log(TEXT("Incompatible modules (post-D3D) detected.")); int ret = MessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR | MB_ABORTRETRYIGNORE); if (ret == IDABORT) { //FIXME: really need a better way to abort startup than this... delete network; delete GS; OSLeaveMutex (hStartupShutdownMutex); return; } else if (ret == IDRETRY) { goto retryHookTestV2; } } } //------------------------------------------------------------- mainVertexShader = CreateVertexShaderFromFile(TEXT("shaders/DrawTexture.vShader")); mainPixelShader = CreatePixelShaderFromFile(TEXT("shaders/DrawTexture.pShader")); solidVertexShader = CreateVertexShaderFromFile(TEXT("shaders/DrawSolid.vShader")); solidPixelShader = CreatePixelShaderFromFile(TEXT("shaders/DrawSolid.pShader")); if(!mainVertexShader || !mainPixelShader) CrashError(TEXT("Unable to load DrawTexture shaders")); if(!solidVertexShader || !solidPixelShader) CrashError(TEXT("Unable to load DrawSolid shaders")); //------------------------------------------------------------------ CTSTR lpShader; if(CloseFloat(downscale, 1.0)) lpShader = TEXT("shaders/DrawYUVTexture.pShader"); else if(downscale < 2.01) { switch(downscaleType) { case 0: lpShader = TEXT("shaders/DownscaleBilinear1YUV.pShader"); break; case 1: lpShader = TEXT("shaders/DownscaleBicubicYUV.pShader"); break; case 2: lpShader = TEXT("shaders/DownscaleLanczos6tapYUV.pShader"); break; } } else if(downscale < 3.01) lpShader = TEXT("shaders/DownscaleBilinear9YUV.pShader"); else CrashError(TEXT("Invalid downscale value (must be either 1.0, 1.5, 2.0, 2.25, or 3.0)")); yuvScalePixelShader = CreatePixelShaderFromFile(lpShader); if (!yuvScalePixelShader) CrashError(TEXT("Unable to create shader from file %s"), lpShader); //------------------------------------------------------------- for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { mainRenderTextures[i] = CreateRenderTarget(baseCX, baseCY, GS_BGRA, FALSE); yuvRenderTextures[i] = CreateRenderTarget(outputCX, outputCY, GS_BGRA, FALSE); } //------------------------------------------------------------- D3D10_TEXTURE2D_DESC td; zero(&td, sizeof(td)); td.Width = outputCX; td.Height = outputCY; td.Format = DXGI_FORMAT_B8G8R8A8_UNORM; td.MipLevels = 1; td.ArraySize = 1; td.SampleDesc.Count = 1; td.ArraySize = 1; td.Usage = D3D10_USAGE_STAGING; td.CPUAccessFlags = D3D10_CPU_ACCESS_READ; for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { HRESULT err = GetD3D()->CreateTexture2D(&td, NULL, ©Textures[i]); if(FAILED(err)) { CrashError(TEXT("Unable to create copy texture")); //todo - better error handling } } //------------------------------------------------------------------ UINT format = AppConfig->GetInt(L"Audio Encoding", L"Format", 1); switch (format) { case 0: sampleRateHz = 44100; break; default: case 1: sampleRateHz = 48000; break; } Log(L"------------------------------------------"); Log(L"Audio Format: %uhz", sampleRateHz); //------------------------------------------------------------------ AudioDeviceList playbackDevices; GetAudioDevices(playbackDevices, ADT_PLAYBACK); String strPlaybackDevice = AppConfig->GetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default")); if(strPlaybackDevice.IsEmpty() || !playbackDevices.HasID(strPlaybackDevice)) { AppConfig->SetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default")); strPlaybackDevice = TEXT("Default"); } Log(TEXT("Playback device %s"), strPlaybackDevice.Array()); playbackDevices.FreeData(); desktopAudio = CreateAudioSource(false, strPlaybackDevice); if(!desktopAudio) { CrashError(TEXT("Cannot initialize desktop audio sound, more info in the log file.")); } AudioDeviceList audioDevices; GetAudioDevices(audioDevices, ADT_RECORDING); String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL); if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice)) { AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable")); strDevice = TEXT("Disable"); } audioDevices.FreeData(); String strDefaultMic; bool bHasDefault = GetDefaultMicID(strDefaultMic); if(strDevice.CompareI(TEXT("Disable"))) EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE); else { bool bUseDefault = strDevice.CompareI(TEXT("Default")) != 0; if(!bUseDefault || bHasDefault) { if(bUseDefault) strDevice = strDefaultMic; micAudio = CreateAudioSource(true, strDevice); if(!micAudio) MessageBox(hwndMain, Str("MicrophoneFailure"), NULL, 0); else micAudio->SetTimeOffset(AppConfig->GetInt(TEXT("Audio"), TEXT("MicTimeOffset"), 0)); EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), micAudio != NULL); } else EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE); } //------------------------------------------------------------- bool bDisableEncoding = false; if (bTestStream) bDisableEncoding = GlobalConfig->GetInt(TEXT("General"), TEXT("DisablePreviewEncoding"), false) != 0; //------------------------------------------------------------- UINT bitRate = (UINT)AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96); String strEncoder = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC")); if (bDisableEncoding) audioEncoder = CreateNullAudioEncoder(); else #ifdef USE_AAC if(strEncoder.CompareI(TEXT("AAC")))// && OSGetVersion() >= 7) audioEncoder = CreateAACEncoder(bitRate); else #endif audioEncoder = CreateMP3Encoder(bitRate); //------------------------------------------------------------- desktopVol = AppConfig->GetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 1.0f); micVol = AppConfig->GetFloat(TEXT("Audio"), TEXT("MicVolume"), 1.0f); //------------------------------------------------------------- bRunning = true; if(sceneElement) { scene = CreateScene(sceneElement->GetString(TEXT("class")), sceneElement->GetElement(TEXT("data"))); XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); for(UINT i=0; i<numSources; i++) { SceneItem *item = scene->AddImageSource(sources->GetElementByID(i)); if(item) { if(ListView_GetItemState(GetDlgItem(hwndMain, ID_SOURCES), i, LVIS_SELECTED) > 0) item->Select(true); } } } scene->BeginScene(); } if(scene && scene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); //------------------------------------------------------------- int maxBitRate = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int bufferSize = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("BufferSize"), 1000); int quality = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("Quality"), 8); String preset = AppConfig->GetString(TEXT("Video Encoding"), TEXT("Preset"), TEXT("veryfast")); bUsing444 = false;//AppConfig->GetInt (TEXT("Video Encoding"), TEXT("Use444"), 0) != 0; bUseCFR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCFR"), 1) != 0; //------------------------------------------------------------- bWriteToFile = networkMode == 1 || AppConfig->GetInt(TEXT("Publish"), TEXT("SaveToFile")) != 0; String strOutputFile = AppConfig->GetString(TEXT("Publish"), TEXT("SavePath")); strOutputFile.FindReplace(TEXT("\\"), TEXT("/")); if (bWriteToFile) { OSFindData ofd; HANDLE hFind = NULL; bool bUseDateTimeName = true; bool bOverwrite = GlobalConfig->GetInt(L"General", L"OverwriteRecordings", false) != 0; if(!bOverwrite && (hFind = OSFindFirstFile(strOutputFile, ofd))) { String strFileExtension = GetPathExtension(strOutputFile); String strFileWithoutExtension = GetPathWithoutExtension(strOutputFile); if(strFileExtension.IsValid() && !ofd.bDirectory) { String strNewFilePath; UINT curFile = 0; do { strNewFilePath.Clear() << strFileWithoutExtension << TEXT(" (") << FormattedString(TEXT("%02u"), ++curFile) << TEXT(").") << strFileExtension; } while(OSFileExists(strNewFilePath)); strOutputFile = strNewFilePath; bUseDateTimeName = false; } if(ofd.bDirectory) strOutputFile.AppendChar('/'); OSFindClose(hFind); } if(bUseDateTimeName) { String strFileName = GetPathFileName(strOutputFile); if(!strFileName.IsValid() || !IsSafeFilename(strFileName)) { SYSTEMTIME st; GetLocalTime(&st); String strDirectory = GetPathDirectory(strOutputFile), extension = GetPathExtension(strOutputFile); if(extension.IsEmpty()) extension = TEXT("mp4"); strOutputFile = FormattedString(TEXT("%s/%u-%02u-%02u-%02u%02u-%02u.%s"), strDirectory.Array(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, extension.Array()); } } } //------------------------------------------------------------- bufferingTime = GlobalConfig->GetInt(TEXT("General"), TEXT("SceneBufferingTime"), 700); Log(TEXT("Scene buffering time set to %u"), bufferingTime); //------------------------------------------------------------- bForceMicMono = AppConfig->GetInt(TEXT("Audio"), TEXT("ForceMicMono")) != 0; bRecievedFirstAudioFrame = false; //hRequestAudioEvent = CreateSemaphore(NULL, 0, 0x7FFFFFFFL, NULL); hSoundDataMutex = OSCreateMutex(); hSoundThread = OSCreateThread((XTHREAD)OBS::MainAudioThread, NULL); //------------------------------------------------------------- StartBlankSoundPlayback(strPlaybackDevice); //------------------------------------------------------------- colorDesc.fullRange = false; colorDesc.primaries = ColorPrimaries_BT709; colorDesc.transfer = ColorTransfer_IEC6196621; colorDesc.matrix = outputCX >= 1280 || outputCY > 576 ? ColorMatrix_BT709 : ColorMatrix_SMPTE170M; videoEncoder = nullptr; if (bDisableEncoding) videoEncoder = CreateNullVideoEncoder(); else if(AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseQSV")) != 0) videoEncoder = CreateQSVEncoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR); if(!videoEncoder) videoEncoder = CreateX264Encoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR); //------------------------------------------------------------- // Ensure that the render frame is properly sized ResizeRenderFrame(true); //------------------------------------------------------------- if(!bTestStream && bWriteToFile && strOutputFile.IsValid()) { String strFileExtension = GetPathExtension(strOutputFile); if(strFileExtension.CompareI(TEXT("flv"))) fileStream = CreateFLVFileStream(strOutputFile); else if(strFileExtension.CompareI(TEXT("mp4"))) fileStream = CreateMP4FileStream(strOutputFile); if(!fileStream) { Log(TEXT("Warning - OBSCapture::Start: Unable to create the file stream. Check the file path in Broadcast Settings.")); MessageBox(hwndMain, Str("Capture.Start.FileStream.Warning"), Str("Capture.Start.FileStream.WarningCaption"), MB_OK | MB_ICONWARNING); } } //------------------------------------------------------------- curFramePic = NULL; bShutdownVideoThread = false; bShutdownEncodeThread = false; //ResetEvent(hVideoThread); hEncodeThread = OSCreateThread((XTHREAD)OBS::EncodeThread, NULL); hVideoThread = OSCreateThread((XTHREAD)OBS::MainCaptureThread, NULL); if(bTestStream) { EnableWindow(GetDlgItem(hwndMain, ID_STARTSTOP), FALSE); SetWindowText(GetDlgItem(hwndMain, ID_TESTSTREAM), Str("MainWindow.StopTest")); } else { EnableWindow(GetDlgItem(hwndMain, ID_TESTSTREAM), FALSE); SetWindowText(GetDlgItem(hwndMain, ID_STARTSTOP), Str("MainWindow.StopStream")); } EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), TRUE); //------------------------------------------------------------- ReportStartStreamTrigger(); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, 0); SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED | ES_DISPLAY_REQUIRED); UpdateRenderViewMessage(); //update notification icon to reflect current status UpdateNotificationAreaIcon(); OSLeaveMutex (hStartupShutdownMutex); }
bool PipeAudioSource::Initialize(PipeVideo *parent, const AudioParam& param) { m_iLastPts = 0; m_iBlockSize = 0; Times = 0; LimitGetData = 0; m_PipeVideo = parent; if (!hAudioMutex) { hAudioMutex = OSCreateMutex(); } bool bFloat = false; UINT inputChannels; UINT inputSamplesPerSec; UINT inputBitsPerSample; DWORD inputChannelMask; inputBitsPerSample = param.bitsPerSample; // 16; inputChannelMask = 0; inputChannels = param.channels; // 1; inputSamplesPerSec = param.samplesPerSec; // 8000; m_iBlockSize = inputChannels * inputBitsPerSample / 8; sampleFrameCount = inputSamplesPerSec / 100; sampleSegmentSize = m_iBlockSize * sampleFrameCount; Param = param; m_isFirstDiffTimeWithAPI = true; m_lTimeDiffWithAPI = 0; m_iLastTimeStamp = 0; outputBuffer.SetSize(sampleSegmentSize); InitAudioData(bFloat, inputChannels, inputSamplesPerSec, inputBitsPerSample, m_iBlockSize, inputChannelMask); if (m_pAudioWaveOut) { m_pAudioWaveOut->Uninitialize(); } String strReanderName = GetDirectorMonitorDevices(); if (NULL == m_pAudioWaveOut) { if (!strReanderName.Compare(TEXT("停用")) && !m_pAudioWaveOut) { m_pAudioWaveOut = new AudioWaveOut; } } else { if ((strReanderName.Compare(TEXT("Disable")) || strReanderName.Compare(TEXT("停用")))) { delete m_pAudioWaveOut; m_pAudioWaveOut = NULL; } } if (NULL != m_pAudioWaveOut) { m_pAudioWaveOut->Initialize(strReanderName.Array(), 2, inputSamplesPerSec, inputBitsPerSample); } String SecRenderName = GetSecMonitorDevices(); if (m_pSecWaveOut) { m_pSecWaveOut->Uninitialize(); } if (SecRenderName.CompareI(strReanderName.Array()) && (!SecRenderName.Compare(TEXT("Disable")) || !SecRenderName.Compare(TEXT("停用")))) { bSameDevice = true; } else if (!SecRenderName.Compare(TEXT("停用")) && !m_pSecWaveOut) { m_pSecWaveOut = new AudioWaveOut; } else if (m_pSecWaveOut) { if ((SecRenderName.Compare(TEXT("Disable")) || SecRenderName.Compare(TEXT("停用")))) { delete m_pSecWaveOut; m_pSecWaveOut = NULL; } } if (m_pSecWaveOut) { m_pSecWaveOut->Initialize(SecRenderName.Array(), 2, inputSamplesPerSec, inputBitsPerSample); } return true; }
void OBS::Start(bool recordingOnly, bool replayBufferOnly) { if(bRunning && !bRecording && !bRecordingReplayBuffer) return; int networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2); DWORD delayTime = (DWORD)AppConfig->GetInt(TEXT("Publish"), TEXT("Delay")); if (bRecording && networkMode != 0) return; if((bRecording || bRecordingReplayBuffer) && networkMode == 0 && delayTime == 0 && !recordingOnly && !replayBufferOnly) { bFirstConnect = !bReconnecting; if (network) { NetworkStream *net = network; network = nullptr; delete net; } network = CreateRTMPPublisher(); Log(TEXT("=====Stream Start (while recording): %s============================="), CurrentDateTimeString().Array()); bSentHeaders = false; bStreaming = true; ReportStartStreamingTrigger(); ConfigureStreamButtons(); return; } bStartingUp = true; OSEnterMutex(hStartupShutdownMutex); DisableMenusWhileStreaming(true); scenesConfig.SaveTo(String() << lpAppDataPath << "\\scenes.xconfig"); scenesConfig.Save(); //------------------------------------------------------------- fps = AppConfig->GetInt(TEXT("Video"), TEXT("FPS"), 30); frameTime = 1000/fps; //------------------------------------------------------------- if(!bLoggedSystemStats) { LogSystemStats(); bLoggedSystemStats = TRUE; } OSCheckForBuggyDLLs(); //------------------------------------------------------------- retryHookTest: bool alreadyWarnedAboutModules = false; if (OSIncompatibleModulesLoaded()) { Log(TEXT("Incompatible modules (pre-D3D) detected.")); int ret = OBSMessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR | MB_ABORTRETRYIGNORE); if (ret == IDABORT) { DisableMenusWhileStreaming(false); OSLeaveMutex (hStartupShutdownMutex); bStartingUp = false; return; } else if (ret == IDRETRY) { goto retryHookTest; } alreadyWarnedAboutModules = true; } String strPatchesError; if (OSIncompatiblePatchesLoaded(strPatchesError)) { DisableMenusWhileStreaming(false); OSLeaveMutex (hStartupShutdownMutex); OBSMessageBox(hwndMain, strPatchesError.Array(), NULL, MB_ICONERROR); Log(TEXT("Incompatible patches detected.")); bStartingUp = false; return; } //check the user isn't trying to stream or record with no sources which is typically //a configuration error if (!bTestStream) { bool foundSource = false; XElement *scenes = App->scenesConfig.GetElement(TEXT("scenes")); if (scenes) { UINT numScenes = scenes->NumElements(); for (UINT i = 0; i<numScenes; i++) { XElement *sceneElement = scenes->GetElementByID(i); XElement *sources = sceneElement->GetElement(TEXT("sources")); if (sources && sources->NumElements()) { foundSource = true; break; } } } if (!foundSource) { if (OBSMessageBox(hwndMain, Str("NoSourcesFound"), NULL, MB_ICONWARNING|MB_YESNO) == IDNO) { DisableMenusWhileStreaming(false); OSLeaveMutex(hStartupShutdownMutex); bStartingUp = false; return; } } } //------------------------------------------------------------- String processPriority = AppConfig->GetString(TEXT("General"), TEXT("Priority"), TEXT("Normal")); if (!scmp(processPriority, TEXT("Idle"))) SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS); else if (!scmp(processPriority, TEXT("Above Normal"))) SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); else if (!scmp(processPriority, TEXT("High"))) SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2); delayTime = (DWORD)AppConfig->GetInt(TEXT("Publish"), TEXT("Delay")); String strError; bFirstConnect = !bReconnecting; if(bTestStream || recordingOnly || replayBufferOnly) network = CreateNullNetwork(); else { switch(networkMode) { case 0: network = (delayTime > 0) ? CreateDelayedPublisher(delayTime) : CreateRTMPPublisher(); break; case 1: network = CreateNullNetwork(); break; } } if(!network) { DisableMenusWhileStreaming(false); OSLeaveMutex (hStartupShutdownMutex); if(!bReconnecting) OBSMessageBox(hwndMain, strError, NULL, MB_ICONERROR); else OBSDialogBox(hinstMain, MAKEINTRESOURCE(IDD_RECONNECTING), hwndMain, OBS::ReconnectDialogProc); bStartingUp = false; return; } bReconnecting = false; //------------------------------------------------------------- Log(TEXT("=====Stream Start: %s==============================================="), CurrentDateTimeString().Array()); //------------------------------------------------------------- bEnableProjectorCursor = GlobalConfig->GetInt(L"General", L"EnableProjectorCursor", 1) != 0; bPleaseEnableProjector = bPleaseDisableProjector = false; int monitorID = AppConfig->GetInt(TEXT("Video"), TEXT("Monitor")); if(monitorID >= (int)monitors.Num()) monitorID = 0; RECT &screenRect = monitors[monitorID].rect; int defCX = screenRect.right - screenRect.left; int defCY = screenRect.bottom - screenRect.top; downscaleType = AppConfig->GetInt(TEXT("Video"), TEXT("Filter"), 0); downscale = AppConfig->GetFloat(TEXT("Video"), TEXT("Downscale"), 1.0f); baseCX = AppConfig->GetInt(TEXT("Video"), TEXT("BaseWidth"), defCX); baseCY = AppConfig->GetInt(TEXT("Video"), TEXT("BaseHeight"), defCY); baseCX = MIN(MAX(baseCX, 128), 4096); baseCY = MIN(MAX(baseCY, 128), 4096); scaleCX = UINT(double(baseCX) / double(downscale)); scaleCY = UINT(double(baseCY) / double(downscale)); //align width to 128bit for fast SSE YUV4:2:0 conversion outputCX = scaleCX & 0xFFFFFFFC; outputCY = scaleCY & 0xFFFFFFFE; bUseMultithreadedOptimizations = AppConfig->GetInt(TEXT("General"), TEXT("UseMultithreadedOptimizations"), TRUE) != 0; Log(TEXT(" Multithreaded optimizations: %s"), (CTSTR)(bUseMultithreadedOptimizations ? TEXT("On") : TEXT("Off"))); encoderSkipThreshold = GlobalConfig->GetInt(TEXT("Video"), TEXT("EncoderSkipThreshold"), fps/4); //------------------------------------------------------------------ Log(TEXT(" Base resolution: %ux%u"), baseCX, baseCY); Log(TEXT(" Output resolution: %ux%u"), outputCX, outputCY); Log(TEXT("------------------------------------------")); //------------------------------------------------------------------ GS = new D3D10System; GS->Init(); //Thanks to ASUS OSD hooking the goddamn user mode driver framework (!!!!), we have to re-check for dangerous //hooks after initializing D3D. retryHookTestV2: if (!alreadyWarnedAboutModules) { if (OSIncompatibleModulesLoaded()) { Log(TEXT("Incompatible modules (post-D3D) detected.")); int ret = OBSMessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR | MB_ABORTRETRYIGNORE); if (ret == IDABORT) { //FIXME: really need a better way to abort startup than this... delete network; delete GS; DisableMenusWhileStreaming(false); OSLeaveMutex (hStartupShutdownMutex); bStartingUp = false; return; } else if (ret == IDRETRY) { goto retryHookTestV2; } } } //------------------------------------------------------------- mainVertexShader = CreateVertexShaderFromFile(TEXT("shaders/DrawTexture.vShader")); mainPixelShader = CreatePixelShaderFromFile(TEXT("shaders/DrawTexture.pShader")); solidVertexShader = CreateVertexShaderFromFile(TEXT("shaders/DrawSolid.vShader")); solidPixelShader = CreatePixelShaderFromFile(TEXT("shaders/DrawSolid.pShader")); if(!mainVertexShader || !mainPixelShader) CrashError(TEXT("Unable to load DrawTexture shaders")); if(!solidVertexShader || !solidPixelShader) CrashError(TEXT("Unable to load DrawSolid shaders")); //------------------------------------------------------------------ CTSTR lpShader; if(CloseFloat(downscale, 1.0)) lpShader = TEXT("shaders/DrawYUVTexture.pShader"); else if(downscale < 2.01) { switch(downscaleType) { case 0: lpShader = TEXT("shaders/DownscaleBilinear1YUV.pShader"); break; case 1: lpShader = TEXT("shaders/DownscaleBicubicYUV.pShader"); break; case 2: lpShader = TEXT("shaders/DownscaleLanczos6tapYUV.pShader"); break; } } else if(downscale < 3.01) lpShader = TEXT("shaders/DownscaleBilinear9YUV.pShader"); else CrashError(TEXT("Invalid downscale value (must be either 1.0, 1.5, 2.0, 2.25, or 3.0)")); yuvScalePixelShader = CreatePixelShaderFromFile(lpShader); if (!yuvScalePixelShader) CrashError(TEXT("Unable to create shader from file %s"), lpShader); //------------------------------------------------------------- for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { mainRenderTextures[i] = CreateRenderTarget(baseCX, baseCY, GS_BGRA, FALSE); yuvRenderTextures[i] = CreateRenderTarget(outputCX, outputCY, GS_BGRA, FALSE); } //------------------------------------------------------------- D3D10_TEXTURE2D_DESC td; zero(&td, sizeof(td)); td.Width = outputCX; td.Height = outputCY; td.Format = DXGI_FORMAT_B8G8R8A8_UNORM; td.MipLevels = 1; td.ArraySize = 1; td.SampleDesc.Count = 1; td.ArraySize = 1; td.Usage = D3D10_USAGE_STAGING; td.CPUAccessFlags = D3D10_CPU_ACCESS_READ; for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { HRESULT err = GetD3D()->CreateTexture2D(&td, NULL, ©Textures[i]); if(FAILED(err)) { CrashError(TEXT("Unable to create copy texture")); //todo - better error handling } } //------------------------------------------------------------------ String strEncoder = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC")); BOOL isAAC = strEncoder.CompareI(TEXT("AAC")); UINT format = AppConfig->GetInt(L"Audio Encoding", L"Format", 1); if (!isAAC) format = 0; switch (format) { case 0: sampleRateHz = 44100; break; default: case 1: sampleRateHz = 48000; break; } Log(L"------------------------------------------"); Log(L"Audio Format: %u Hz", sampleRateHz); //------------------------------------------------------------------ BOOL isStereo = AppConfig->GetInt(L"Audio Encoding", L"isStereo", 1); switch (isStereo) { case 0: audioChannels = 1; break; default: case 1: audioChannels = 2; break; } Log(L"------------------------------------------"); Log(L"Audio Channels: %u Ch", audioChannels); //------------------------------------------------------------------ AudioDeviceList playbackDevices; bool useInputDevices = AppConfig->GetInt(L"Audio", L"InputDevicesForDesktopSound", false) != 0; GetAudioDevices(playbackDevices, useInputDevices ? ADT_RECORDING : ADT_PLAYBACK); String strPlaybackDevice = AppConfig->GetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default")); if(strPlaybackDevice.IsEmpty() || !playbackDevices.HasID(strPlaybackDevice)) { //AppConfig->SetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default")); strPlaybackDevice = TEXT("Default"); } Log(TEXT("Playback device %s"), strPlaybackDevice.Array()); playbackDevices.FreeData(); desktopAudio = CreateAudioSource(false, strPlaybackDevice); if(!desktopAudio) { CrashError(TEXT("Cannot initialize desktop audio sound, more info in the log file.")); } if (useInputDevices) Log(L"Use Input Devices enabled, not recording standard desktop audio"); AudioDeviceList audioDevices; GetAudioDevices(audioDevices, ADT_RECORDING, false, true); String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL); if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice)) { //AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable")); strDevice = TEXT("Disable"); } audioDevices.FreeData(); String strDefaultMic; bool bHasDefault = GetDefaultMicID(strDefaultMic); if(strDevice.CompareI(TEXT("Disable"))) EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE); else { bool bUseDefault = strDevice.CompareI(TEXT("Default")) != 0; if(!bUseDefault || bHasDefault) { if(bUseDefault) strDevice = strDefaultMic; micAudio = CreateAudioSource(true, strDevice); if(!micAudio) OBSMessageBox(hwndMain, Str("MicrophoneFailure"), NULL, 0); else { int offset = AppConfig->GetInt(TEXT("Audio"), TEXT("MicTimeOffset"), 0); Log(L"Mic time offset: %d", offset); micAudio->SetTimeOffset(offset); } EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), micAudio != NULL); } else EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE); } //------------------------------------------------------------- bool bDisableEncoding = false; if (bTestStream) bDisableEncoding = GlobalConfig->GetInt(TEXT("General"), TEXT("DisablePreviewEncoding"), false) != 0; //------------------------------------------------------------- UINT bitRate = (UINT)AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96); if (bDisableEncoding) audioEncoder = CreateNullAudioEncoder(); else #ifdef USE_AAC if(isAAC) // && OSGetVersion() >= 7) audioEncoder = CreateAACEncoder(bitRate); else #endif audioEncoder = CreateMP3Encoder(bitRate); //------------------------------------------------------------- desktopVol = AppConfig->GetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 1.0f); micVol = AppConfig->GetFloat(TEXT("Audio"), TEXT("MicVolume"), 1.0f); //------------------------------------------------------------- bRunning = true; if(sceneElement) { scene = CreateScene(sceneElement->GetString(TEXT("class")), sceneElement->GetElement(TEXT("data"))); XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); for(UINT i=0; i<numSources; i++) { SceneItem *item = scene->AddImageSource(sources->GetElementByID(i)); if(item) { if(ListView_GetItemState(GetDlgItem(hwndMain, ID_SOURCES), i, LVIS_SELECTED) > 0) item->Select(true); } } } scene->BeginScene(); unsigned int numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceEnterScene(); } } } } if(scene && scene->HasMissingSources()) OBSMessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); //------------------------------------------------------------- int maxBitRate = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int bufferSize = maxBitRate; if (AppConfig->GetInt(L"Video Encoding", L"UseBufferSize", 0) != 0) bufferSize = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("BufferSize"), 1000); int quality = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("Quality"), 8); String preset = AppConfig->GetString(TEXT("Video Encoding"), TEXT("Preset"), TEXT("veryfast")); bUsing444 = false;//AppConfig->GetInt (TEXT("Video Encoding"), TEXT("Use444"), 0) != 0; bUseCFR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCFR"), 1) != 0; //------------------------------------------------------------- bufferingTime = GlobalConfig->GetInt(TEXT("General"), TEXT("SceneBufferingTime"), 700); Log(TEXT("Scene buffering time set to %u"), bufferingTime); //------------------------------------------------------------- bForceMicMono = AppConfig->GetInt(TEXT("Audio"), TEXT("ForceMicMono")) != 0; bRecievedFirstAudioFrame = false; //hRequestAudioEvent = CreateSemaphore(NULL, 0, 0x7FFFFFFFL, NULL); hSoundDataMutex = OSCreateMutex(); hSoundThread = OSCreateThread((XTHREAD)OBS::MainAudioThread, NULL); //------------------------------------------------------------- //if (!useInputDevices) // StartBlankSoundPlayback(strPlaybackDevice); //------------------------------------------------------------- colorDesc.fullRange = false; colorDesc.primaries = ColorPrimaries_BT709; colorDesc.transfer = ColorTransfer_IEC6196621; colorDesc.matrix = outputCX >= 1280 || outputCY > 576 ? ColorMatrix_BT709 : ColorMatrix_SMPTE170M; videoEncoder = nullptr; String videoEncoderErrors; String vencoder = AppConfig->GetString(L"Video Encoding", L"Encoder"); if (bDisableEncoding) videoEncoder = CreateNullVideoEncoder(); else if(vencoder == L"QSV") videoEncoder = CreateQSVEncoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR, videoEncoderErrors); else if(vencoder == L"NVENC") videoEncoder = CreateNVENCEncoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR, videoEncoderErrors); else videoEncoder = CreateX264Encoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR); if (!videoEncoder) { Log(L"Couldn't initialize encoder"); Stop(true); if (videoEncoderErrors.IsEmpty()) videoEncoderErrors = Str("Encoder.InitFailed"); else videoEncoderErrors = String(Str("Encoder.InitFailedWithReason")) + videoEncoderErrors; OBSMessageBox(hwndMain, videoEncoderErrors.Array(), nullptr, MB_OK | MB_ICONERROR); //might want to defer localization until here to automatically //output english localization to logfile return; } if ((bStreaming = (!recordingOnly && !replayBufferOnly) && networkMode == 0)) ReportStartStreamingTrigger(); //------------------------------------------------------------- // Ensure that the render frame is properly sized ResizeRenderFrame(true); //------------------------------------------------------------- if ((!replayBufferOnly && !StartRecording(recordingOnly)) && !bStreaming) { Stop(true); return; } //------------------------------------------------------------- curFramePic = NULL; bShutdownVideoThread = false; bShutdownEncodeThread = false; //ResetEvent(hVideoThread); hEncodeThread = OSCreateThread((XTHREAD)OBS::EncodeThread, NULL); hVideoThread = OSCreateThread((XTHREAD)OBS::MainCaptureThread, NULL); EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), TRUE); //------------------------------------------------------------- ReportStartStreamTrigger(); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, 0); SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED | ES_DISPLAY_REQUIRED); UpdateRenderViewMessage(); //update notification icon to reflect current status UpdateNotificationAreaIcon(); OSLeaveMutex (hStartupShutdownMutex); bStartingUp = false; ConfigureStreamButtons(); }
void OBS::Stop(bool overrideKeepRecording) { if((!bStreaming && !bRecording && !bRunning) && (!bTestStream)) return; //ugly hack to prevent hotkeys from being processed while we're stopping otherwise we end up //with callbacks from the ProcessEvents call in DelayedPublisher which causes havoc. OSEnterMutex(hHotkeyMutex); int networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2); if(!overrideKeepRecording && bRecording && bKeepRecording && networkMode == 0) { NetworkStream *tempStream = NULL; videoEncoder->RequestKeyframe(); tempStream = network; network = NULL; Log(TEXT("=====Stream End (recording continues): %s========================="), CurrentDateTimeString().Array()); delete tempStream; bStreaming = false; bSentHeaders = false; ReportStopStreamingTrigger(); ConfigureStreamButtons(); OSLeaveMutex(hHotkeyMutex); return; } OSEnterMutex(hStartupShutdownMutex); //we only want the capture thread to stop first, so we can ensure all packets are flushed bShutdownEncodeThread = true; ShowWindow(hwndProjector, SW_HIDE); if(hEncodeThread) { OSTerminateThread(hEncodeThread, 30000); hEncodeThread = NULL; } bShutdownVideoThread = true; SetEvent(hVideoEvent); if(hVideoThread) { OSTerminateThread(hVideoThread, 30000); hVideoThread = NULL; } bRunning = false; ReportStopStreamTrigger(); for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].source->EndScene(); if(scene) scene->EndScene(); //------------------------------------------------------------- if(hSoundThread) { //ReleaseSemaphore(hRequestAudioEvent, 1, NULL); OSTerminateThread(hSoundThread, 20000); } //if(hRequestAudioEvent) // CloseHandle(hRequestAudioEvent); if(hSoundDataMutex) OSCloseMutex(hSoundDataMutex); hSoundThread = NULL; //hRequestAudioEvent = NULL; hSoundDataMutex = NULL; //------------------------------------------------------------- StopBlankSoundPlayback(); //------------------------------------------------------------- delete network; network = NULL; if (bStreaming) ReportStopStreamingTrigger(); bStreaming = false; if(bRecording) StopRecording(); delete micAudio; micAudio = NULL; delete desktopAudio; desktopAudio = NULL; delete audioEncoder; audioEncoder = NULL; delete videoEncoder; videoEncoder = NULL; //------------------------------------------------------------- for(UINT i=0; i<pendingAudioFrames.Num(); i++) pendingAudioFrames[i].audioData.Clear(); pendingAudioFrames.Clear(); //------------------------------------------------------------- if(GS) GS->UnloadAllData(); //------------------------------------------------------------- delete scene; scene = NULL; for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].FreeData(); globalSources.Clear(); //------------------------------------------------------------- for(UINT i=0; i<auxAudioSources.Num(); i++) delete auxAudioSources[i]; auxAudioSources.Clear(); //------------------------------------------------------------- for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { delete mainRenderTextures[i]; delete yuvRenderTextures[i]; mainRenderTextures[i] = NULL; yuvRenderTextures[i] = NULL; } for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { SafeRelease(copyTextures[i]); } delete transitionTexture; transitionTexture = NULL; //------------------------------------------------------------- delete mainVertexShader; delete mainPixelShader; delete yuvScalePixelShader; delete solidVertexShader; delete solidPixelShader; mainVertexShader = NULL; mainPixelShader = NULL; yuvScalePixelShader = NULL; solidVertexShader = NULL; solidPixelShader = NULL; //------------------------------------------------------------- delete GS; GS = NULL; //------------------------------------------------------------- ResizeRenderFrame(false); RedrawWindow(hwndRenderFrame, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW); //------------------------------------------------------------- AudioDeviceList audioDevices; GetAudioDevices(audioDevices, ADT_RECORDING, false, true); String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL); if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice)) { AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable")); strDevice = TEXT("Disable"); } audioDevices.FreeData(); EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), !strDevice.CompareI(TEXT("Disable"))); //------------------------------------------------------------- ClearStreamInfo(); DumpProfileData(); FreeProfileData(); Log(TEXT("=====Stream End: %s================================================="), CurrentDateTimeString().Array()); //update notification icon to reflect current status UpdateNotificationAreaIcon(); bEditMode = false; SendMessage(GetDlgItem(hwndMain, ID_SCENEEDITOR), BM_SETCHECK, BST_UNCHECKED, 0); EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), FALSE); ClearStatusBar(); InvalidateRect(hwndRenderFrame, NULL, TRUE); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, 0, 0); SetThreadExecutionState(ES_CONTINUOUS); String processPriority = AppConfig->GetString(TEXT("General"), TEXT("Priority"), TEXT("Normal")); if (scmp(processPriority, TEXT("Normal"))) SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); bTestStream = false; ConfigureStreamButtons(); UpdateRenderViewMessage(); DisableMenusWhileStreaming(false); OSLeaveMutex(hStartupShutdownMutex); OSLeaveMutex(hHotkeyMutex); }
void SettingsPublish::SetWarningInfo() { int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0); bool bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR"), 1) != 0; int maxBitRate = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int keyframeInt = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("KeyframeInterval"), 0); int audioBitRate = AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96); String currentx264Profile = AppConfig->GetString(TEXT("Video Encoding"), TEXT("X264Profile"), L"high"); String currentAudioCodec = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC")); float currentAspect = AppConfig->GetInt(L"Video", L"BaseWidth") / (float)max(1, AppConfig->GetInt(L"Video", L"BaseHeight")); //ignore for non-livestreams if (data.mode != 0) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } bool hasErrors = false; bool canOptimize = false; String strWarnings; XConfig serverData; if(serverData.Open(TEXT("services.xconfig"))) { XElement *services = serverData.GetElement(TEXT("services")); if(services) { UINT numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *service = services->GetElementByID(i); if (service->GetInt(TEXT("id")) == serviceID) { strWarnings = FormattedString(Str("Settings.Publish.Warning.BadSettings"), service->GetName()); //check to see if the service we're using has recommendations if (!service->HasItem(TEXT("recommended"))) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } XElement *r = service->GetElement(TEXT("recommended")); if (r->HasItem(TEXT("ratecontrol"))) { CTSTR rc = r->GetString(TEXT("ratecontrol")); if (!scmp (rc, TEXT("cbr")) && !bUseCBR) { hasErrors = true; canOptimize = true; strWarnings << Str("Settings.Publish.Warning.UseCBR"); } } if (r->HasItem(TEXT("max bitrate"))) { int max_bitrate = r->GetInt(TEXT("max bitrate")); if (maxBitRate > max_bitrate) { hasErrors = true; canOptimize = true; strWarnings << FormattedString(Str("Settings.Publish.Warning.Maxbitrate"), max_bitrate); } } if (r->HasItem(L"supported audio codec")) { StringList codecs; r->GetStringList(L"supported audio codec", codecs); if (codecs.FindValueIndex(currentAudioCodec) == INVALID) { String msg = Str("Settings.Publish.Warning.UnsupportedAudioCodec"); //good thing OBS only supports MP3 (and AAC), otherwise I'd have to come up with a better translation solution msg.FindReplace(L"$1", codecs[0].Array()); msg.FindReplace(L"$2", currentAudioCodec.Array()); hasErrors = true; canOptimize = true; strWarnings << msg; } } if (r->HasItem(TEXT("max audio bitrate aac")) && (!scmp(currentAudioCodec, TEXT("AAC")))) { int maxaudioaac = r->GetInt(TEXT("max audio bitrate aac")); if (audioBitRate > maxaudioaac) { hasErrors = true; canOptimize = true; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudioaac); } } if (r->HasItem(TEXT("max audio bitrate mp3")) && (!scmp(currentAudioCodec, TEXT("MP3")))) { int maxaudiomp3 = r->GetInt(TEXT("max audio bitrate mp3")); if (audioBitRate > maxaudiomp3) { hasErrors = true; canOptimize = true; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudiomp3); } } if (r->HasItem(L"video aspect ratio")) { String aspectRatio = r->GetString(L"video aspect ratio"); StringList numbers; aspectRatio.GetTokenList(numbers, ':'); if (numbers.Num() == 2) { float aspect = numbers[0].ToInt() / max(1.f, numbers[1].ToFloat()); if (!CloseFloat(aspect, currentAspect)) { String aspectLocalized = Str("Settings.Video.AspectRatioFormat"); aspectLocalized.FindReplace(L"$1", UIntString(numbers[0].ToInt())); aspectLocalized.FindReplace(L"$2", UIntString(numbers[1].ToInt())); String msg = Str("Settings.Publish.Warning.VideoAspectRatio"); msg.FindReplace(L"$1", aspectLocalized); strWarnings << msg; hasErrors = true; } } } if (r->HasItem(TEXT("profile"))) { String expectedProfile = r->GetString(TEXT("profile")); if (!expectedProfile.CompareI(currentx264Profile)) { hasErrors = true; canOptimize = true; strWarnings << Str("Settings.Publish.Warning.RecommendMainProfile"); } } if (r->HasItem(TEXT("keyint"))) { int keyint = r->GetInt(TEXT("keyint")); if (!keyframeInt || keyframeInt * 1000 > keyint) { hasErrors = true; canOptimize = true; strWarnings << FormattedString(Str("Settings.Publish.Warning.Keyint"), keyint / 1000); } } break; } } } } if (hasErrors) { if (canOptimize) strWarnings << Str("Settings.Publish.Warning.CanOptimize"); SetDlgItemText(hwnd, IDC_WARNINGS, strWarnings.Array()); } else SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); SetCanOptimizeSettings(canOptimize); }
INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam) { HWND hwndTemp; switch(message) { case WM_INITDIALOG: { LocalizeWindow(hwnd); RECT serviceRect, saveToFileRect; GetWindowRect(GetDlgItem(hwnd, IDC_SERVICE), &serviceRect); GetWindowRect(GetDlgItem(hwnd, IDC_SAVEPATH), &saveToFileRect); data.fileControlOffset = saveToFileRect.top-serviceRect.top; //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_MODE); SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)Str("Settings.Publish.Mode.LiveStream")); SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)Str("Settings.Publish.Mode.FileOnly")); int mode = LoadSettingComboInt(hwndTemp, TEXT("Publish"), TEXT("Mode"), 0, 2); data.mode = mode; //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_SERVICE); int itemId = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("Custom")); SendMessage(hwndTemp, CB_SETITEMDATA, itemId, 0); UINT numServices = 0; XConfig serverData; if(serverData.Open(TEXT("services.xconfig"))) { XElement *services = serverData.GetElement(TEXT("services")); if(services) { numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *service = services->GetElementByID(i); itemId = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)service->GetName()); SendMessage(hwndTemp, CB_SETITEMDATA, itemId, service->GetInt(TEXT("id"))); } } } int serviceID = AppConfig->GetInt(TEXT("Publish"), TEXT("Service"), 0); if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_PLAYPATH); LoadSettingEditString(hwndTemp, TEXT("Publish"), TEXT("PlayPath"), NULL); if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); if(serviceID == 0) //custom { ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), SW_HIDE); hwndTemp = GetDlgItem(hwnd, IDC_URL); LoadSettingEditString(hwndTemp, TEXT("Publish"), TEXT("URL"), NULL); SendDlgItemMessage(hwnd, IDC_SERVICE, CB_SETCURSEL, 0, 0); } else { ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_HIDE); hwndTemp = GetDlgItem(hwnd, IDC_SERVERLIST); XElement *services = serverData.GetElement(TEXT("services")); if(services) { XElement *service = NULL; numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *curService = services->GetElementByID(i); if(curService->GetInt(TEXT("id")) == serviceID) { SendDlgItemMessage(hwnd, IDC_SERVICE, CB_SETCURSEL, i+1, 0); service = curService; break; } } if(service) { XElement *servers = service->GetElement(TEXT("servers")); if(servers) { UINT numServers = servers->NumDataItems(); for(UINT i=0; i<numServers; i++) { XDataItem *server = servers->GetDataItemByID(i); SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName()); } } } } LoadSettingComboString(hwndTemp, TEXT("Publish"), TEXT("URL"), NULL); } if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_LOWLATENCYMODE); BOOL bLowLatencyMode = AppConfig->GetInt(TEXT("Publish"), TEXT("LowLatencyMode"), 0); SendMessage(hwndTemp, BM_SETCHECK, bLowLatencyMode ? BST_CHECKED : BST_UNCHECKED, 0); //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_AUTORECONNECT); BOOL bAutoReconnect = AppConfig->GetInt(TEXT("Publish"), TEXT("AutoReconnect"), 1); SendMessage(hwndTemp, BM_SETCHECK, bAutoReconnect ? BST_CHECKED : BST_UNCHECKED, 0); if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); hwndTemp = GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT); EnableWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_EDIT), bAutoReconnect); EnableWindow(hwndTemp, bAutoReconnect); int retryTime = AppConfig->GetInt(TEXT("Publish"), TEXT("AutoReconnectTimeout"), 10); if(retryTime > 60) retryTime = 60; else if(retryTime < 0) retryTime = 0; SendMessage(hwndTemp, UDM_SETRANGE32, 0, 60); SendMessage(hwndTemp, UDM_SETPOS32, 0, retryTime); if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_DELAY); int delayTime = AppConfig->GetInt(TEXT("Publish"), TEXT("Delay"), 0); SendMessage(hwndTemp, UDM_SETRANGE32, 0, 900); SendMessage(hwndTemp, UDM_SETPOS32, 0, delayTime); //-------------------------------------------- if(mode != 0) { ShowWindow(GetDlgItem(hwnd, IDC_SERVICE_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_PLAYPATH_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_URL_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_SERVER_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_LOWLATENCYMODE), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_EDIT), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_DELAY_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_DELAY_EDIT), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_DELAY), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_KEEPRECORDING), SW_HIDE); //ShowWindow(GetDlgItem(hwnd, IDC_DASHBOARDLINK), SW_HIDE); //ShowWindow(GetDlgItem(hwnd, IDC_DASHBOARDLINK_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_SAVETOFILE), SW_HIDE); AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_BROWSE), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTSTREAM), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTRECORDING), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STOPRECORDING), 0, -data.fileControlOffset); } //-------------------------------------------- DWORD startHotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StartStreamHotkey")); SendMessage(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), HKM_SETHOTKEY, startHotkey, 0); //-------------------------------------------- DWORD stopHotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StopStreamHotkey")); SendMessage(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), HKM_SETHOTKEY, stopHotkey, 0); //-------------------------------------------- startHotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StartRecordingHotkey")); SendMessage(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), HKM_SETHOTKEY, startHotkey, 0); //-------------------------------------------- stopHotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StopRecordingHotkey")); SendMessage(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), HKM_SETHOTKEY, stopHotkey, 0); //-------------------------------------------- BOOL bKeepRecording = AppConfig->GetInt(TEXT("Publish"), TEXT("KeepRecording")); SendMessage(GetDlgItem(hwnd, IDC_KEEPRECORDING), BM_SETCHECK, bKeepRecording ? BST_CHECKED : BST_UNCHECKED, 0); BOOL bSaveToFile = AppConfig->GetInt(TEXT("Publish"), TEXT("SaveToFile")); SendMessage(GetDlgItem(hwnd, IDC_SAVETOFILE), BM_SETCHECK, bSaveToFile ? BST_CHECKED : BST_UNCHECKED, 0); String path = OSGetDefaultVideoSavePath(L"\\.flv"); CTSTR lpSavePath = AppConfig->GetStringPtr(TEXT("Publish"), TEXT("SavePath"), path.IsValid() ? path.Array() : nullptr); SetWindowText(GetDlgItem(hwnd, IDC_SAVEPATH), lpSavePath); EnableWindow(GetDlgItem(hwnd, IDC_KEEPRECORDING), true); EnableWindow(GetDlgItem(hwnd, IDC_SAVEPATH), true); EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), true); //-------------------------------------------- //SetWindowText(GetDlgItem(hwnd, IDC_DASHBOARDLINK), App->strDashboard); //-------------------------------------------- SetWarningInfo(); ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_HIDE); SetChangedSettings(false); return TRUE; } case WM_CTLCOLORSTATIC: { switch (GetDlgCtrlID((HWND)lParam)) { case IDC_WARNINGS: SetTextColor((HDC)wParam, RGB(255, 0, 0)); SetBkColor((HDC)wParam, COLORREF(GetSysColor(COLOR_3DFACE))); return (INT_PTR)GetSysColorBrush(COLOR_BTNFACE); } } break; case WM_DESTROY: { } break; case WM_NOTIFY: { NMHDR *nmHdr = (NMHDR*)lParam; if(nmHdr->idFrom == IDC_AUTORECONNECT_TIMEOUT) { if(nmHdr->code == UDN_DELTAPOS) SetChangedSettings(true); } break; } case WM_COMMAND: { bool bDataChanged = false; switch(LOWORD(wParam)) { case IDC_MODE: { if(HIWORD(wParam) != CBN_SELCHANGE) break; int mode = (int)SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0); int swShowControls = (mode == 0) ? SW_SHOW : SW_HIDE; ShowWindow(GetDlgItem(hwnd, IDC_SERVICE), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_PLAYPATH), swShowControls); int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0); if(serviceID == 0) { ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_URL), swShowControls); } else { ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_HIDE); } if(mode == 0 && data.mode == 1) { AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_BROWSE), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTSTREAM), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTRECORDING), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STOPRECORDING), 0, data.fileControlOffset); } else if(mode == 1 && data.mode == 0) { AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_BROWSE), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTSTREAM), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTRECORDING), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STOPRECORDING), 0, -data.fileControlOffset); } data.mode = mode; ShowWindow(GetDlgItem(hwnd, IDC_SERVICE_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_PLAYPATH_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_URL_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_SERVER_STATIC), swShowControls); //ShowWindow(GetDlgItem(hwnd, IDC_DASHBOARDLINK), swShowControls); //ShowWindow(GetDlgItem(hwnd, IDC_DASHBOARDLINK_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_LOWLATENCYMODE), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_EDIT), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_DELAY_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_DELAY_EDIT), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_DELAY), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_SAVETOFILE), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_KEEPRECORDING), swShowControls); SetWarningInfo(); bDataChanged = true; break; } case IDC_SERVICE: if(HIWORD(wParam) == CBN_SELCHANGE) { int serviceID = (int)SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0); if(serviceID == 0) { ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_SHOW); SetWindowText(GetDlgItem(hwnd, IDC_URL), NULL); //SetWindowText(GetDlgItem(hwnd, IDC_DASHBOARDLINK), NULL); } else { ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_HIDE); hwndTemp = GetDlgItem(hwnd, IDC_SERVERLIST); ShowWindow(hwndTemp, SW_SHOW); SendMessage(hwndTemp, CB_RESETCONTENT, 0, 0); XConfig serverData; if(serverData.Open(TEXT("services.xconfig"))) { XElement *services = serverData.GetElement(TEXT("services")); if(services) { XElement *service = services->GetElementByID(serviceID-1); if(service) { XElement *servers = service->GetElement(TEXT("servers")); if(servers) { UINT numServers = servers->NumDataItems(); for(UINT i=0; i<numServers; i++) { XDataItem *server = servers->GetDataItemByID(i); SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName()); } } } } } SendMessage(hwndTemp, CB_SETCURSEL, 0, 0); } SetWindowText(GetDlgItem(hwnd, IDC_PLAYPATH), NULL); bDataChanged = true; } SetWarningInfo(); break; case IDC_AUTORECONNECT: if(HIWORD(wParam) == BN_CLICKED) { BOOL bAutoReconnect = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED; EnableWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT), bAutoReconnect); EnableWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_EDIT), bAutoReconnect); SetChangedSettings(true); } break; case IDC_AUTORECONNECT_TIMEOUT_EDIT: if(HIWORD(wParam) == EN_CHANGE) SetChangedSettings(true); break; case IDC_DELAY_EDIT: if(HIWORD(wParam) == EN_CHANGE) bDataChanged = true; break; case IDC_KEEPRECORDING: if(HIWORD(wParam) == BN_CLICKED) { BOOL bKeepRecording = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED; App->bKeepRecording = bKeepRecording != 0; bDataChanged = true; } break; case IDC_BROWSE: { TCHAR lpFile[512]; OPENFILENAME ofn; zero(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; ofn.lpstrFile = lpFile; ofn.nMaxFile = 511; ofn.lpstrFile[0] = 0; ofn.lpstrFilter = TEXT("MP4 File (*.mp4)\0*.mp4\0Flash Video File (*.flv)\0*.flv\0"); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.nFilterIndex = 1; String path = OSGetDefaultVideoSavePath(); ofn.lpstrInitialDir = AppConfig->GetStringPtr(TEXT("Publish"), TEXT("LastSaveDir"), path.IsValid() ? path.Array() : nullptr); ofn.Flags = OFN_PATHMUSTEXIST; TCHAR curDirectory[512]; GetCurrentDirectory(511, curDirectory); BOOL bChoseFile = GetSaveFileName(&ofn); SetCurrentDirectory(curDirectory); if(*lpFile && bChoseFile) { String strFile = lpFile; strFile.FindReplace(TEXT("\\"), TEXT("/")); String strExtension = GetPathExtension(strFile); if(strExtension.IsEmpty() || (!strExtension.CompareI(TEXT("flv")) && /*!strExtension.CompareI(TEXT("avi")) &&*/ !strExtension.CompareI(TEXT("mp4")))) { switch(ofn.nFilterIndex) { case 1: strFile << TEXT(".mp4"); break; case 2: strFile << TEXT(".flv"); break; /*case 3: strFile << TEXT(".avi"); break;*/ } } String strFilePath = GetPathDirectory(strFile).FindReplace(TEXT("/"), TEXT("\\")) << TEXT("\\"); AppConfig->SetString(TEXT("Publish"), TEXT("LastSaveDir"), strFilePath); strFile.FindReplace(TEXT("/"), TEXT("\\")); SetWindowText(GetDlgItem(hwnd, IDC_SAVEPATH), strFile); bDataChanged = true; } break; } case IDC_LOWLATENCYMODE: case IDC_SAVETOFILE: if(HIWORD(wParam) == BN_CLICKED) bDataChanged = true; break; case IDC_STARTSTREAMHOTKEY: case IDC_STOPSTREAMHOTKEY: //case IDC_DASHBOARDLINK: case IDC_STARTRECORDINGHOTKEY: case IDC_STOPRECORDINGHOTKEY: if(HIWORD(wParam) == EN_CHANGE) SetChangedSettings(true); break; case IDC_PLAYPATH: case IDC_URL: case IDC_SAVEPATH: if(HIWORD(wParam) == EN_CHANGE) bDataChanged = true; break; case IDC_CLEARHOTKEY_STARTSTREAM: if(HIWORD(wParam) == BN_CLICKED) { if(SendMessage(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), HKM_GETHOTKEY, 0, 0)) { SendMessage(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), HKM_SETHOTKEY, 0, 0); SetChangedSettings(true); } } break; case IDC_CLEARHOTKEY: if(HIWORD(wParam) == BN_CLICKED) { if(SendMessage(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), HKM_GETHOTKEY, 0, 0)) { SendMessage(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), HKM_SETHOTKEY, 0, 0); SetChangedSettings(true); } } break; case IDC_CLEARHOTKEY_STARTRECORDING: if (HIWORD(wParam) == BN_CLICKED) { if (SendMessage(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), HKM_GETHOTKEY, 0, 0)) { SendMessage(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), HKM_SETHOTKEY, 0, 0); SetChangedSettings(true); } } break; case IDC_CLEARHOTKEY_STOPRECORDING: if (HIWORD(wParam) == BN_CLICKED) { if (SendMessage(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), HKM_GETHOTKEY, 0, 0)) { SendMessage(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), HKM_SETHOTKEY, 0, 0); SetChangedSettings(true); } } break; case IDC_SERVERLIST: if(HIWORD(wParam) == CBN_EDITCHANGE || HIWORD(wParam) == CBN_SELCHANGE) bDataChanged = true; break; } if(bDataChanged) { ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW); SetChangedSettings(true); } break; } } return FALSE; }
BOOL STDCALL OSFileHasChanged (OSFileChangeData *data) { BOOL hasModified = FALSE; if (!data->hDirectory) { //we lost our directory handle for some reason, try to re-acquire it data->hDirectory = CreateFile(data->strDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL); if(data->hDirectory != INVALID_HANDLE_VALUE) { DWORD test; zero(&data->directoryChange, sizeof(data->directoryChange)); data->directoryChange.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); if(ReadDirectoryChangesW(data->hDirectory, data->changeBuffer, 2048, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE, &test, &data->directoryChange, NULL)) { } else { int i = GetLastError (); CloseHandle(data->directoryChange.hEvent); CloseHandle(data->hDirectory); data->directoryChange.hEvent = NULL; data->hDirectory = NULL; return false; } } } if(HasOverlappedIoCompleted(&data->directoryChange)) { FILE_NOTIFY_INFORMATION *notify = (FILE_NOTIFY_INFORMATION*)data->changeBuffer; //change triggered, process the notifications for (;;) { if (notify->Action == FILE_ACTION_ADDED || notify->Action == FILE_ACTION_MODIFIED || notify->Action == FILE_ACTION_RENAMED_NEW_NAME) { String strFileName; strFileName.SetLength(notify->FileNameLength); scpy_n(strFileName, notify->FileName, notify->FileNameLength/2); strFileName.KillSpaces(); String strFileChanged; strFileChanged << data->strDirectory << strFileName; if(strFileChanged.CompareI(data->targetFileName)) { hasModified = TRUE; break; } } if (!notify->NextEntryOffset) break; notify = (FILE_NOTIFY_INFORMATION*)((BYTE *)notify + notify->NextEntryOffset); } //prepare for next read ResetEvent (data->directoryChange.hEvent); zero(data->changeBuffer, sizeof(data->changeBuffer)); DWORD test; if(ReadDirectoryChangesW(data->hDirectory, data->changeBuffer, 2048, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE, &test, &data->directoryChange, NULL)) { } else { int i = GetLastError (); CloseHandle(data->directoryChange.hEvent); CloseHandle(data->hDirectory); data->directoryChange.hEvent = NULL; data->hDirectory = NULL; return hasModified; } } return hasModified; }
X264Encoder(int fps, int width, int height, int quality, CTSTR preset, bool bUse444, ColorDescription &colorDesc, int maxBitrate, int bufferSize, bool bUseCFR) { curPreset = preset; fps_ms = 1000/fps; StringList paramList; curProfile = AppConfig->GetString(TEXT("Video Encoding"), TEXT("X264Profile"), TEXT("high")); BOOL bUseCustomParams = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCustomSettings")); if(bUseCustomParams) { String strCustomParams = AppConfig->GetString(TEXT("Video Encoding"), TEXT("CustomSettings")); strCustomParams.KillSpaces(); if(strCustomParams.IsValid()) { Log(TEXT("Using custom x264 settings: \"%s\""), strCustomParams.Array()); strCustomParams.GetTokenList(paramList, ' ', FALSE); for(UINT i=0; i<paramList.Num(); i++) { String &strParam = paramList[i]; if(!schr(strParam, '=')) continue; String strParamName = strParam.GetToken(0, '='); String strParamVal = strParam.GetTokenOffset(1, '='); if(strParamName.CompareI(TEXT("preset"))) { if(valid_x264_string(strParamVal, (const char**)x264_preset_names)) curPreset = strParamVal; else Log(TEXT("invalid preset: %s"), strParamVal.Array()); paramList.Remove(i--); } else if(strParamName.CompareI(TEXT("tune"))) { if(valid_x264_string(strParamVal, (const char**)x264_tune_names)) curTune = strParamVal; else Log(TEXT("invalid tune: %s"), strParamVal.Array()); paramList.Remove(i--); } else if(strParamName.CompareI(TEXT("profile"))) { if(valid_x264_string(strParamVal, (const char **)x264_profile_names)) curProfile = strParamVal; else Log(TEXT("invalid profile: %s"), strParamVal.Array()); paramList.Remove(i--); } } } } zero(¶mData, sizeof(paramData)); LPSTR lpPreset = curPreset.CreateUTF8String(); LPSTR lpTune = curTune.CreateUTF8String(); if (x264_param_default_preset(¶mData, lpPreset, lpTune)) Log(TEXT("Failed to set x264 defaults: %s/%s"), curPreset.Array(), curTune.Array()); Free(lpTune); Free(lpPreset); this->width = width; this->height = height; paramData.b_deterministic = false; bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR"), 1) != 0; bPadCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("PadCBR"), 1) != 0; this->bUseCFR = bUseCFR; SetBitRateParams(maxBitrate, bufferSize); if(bUseCBR) { if(bPadCBR) paramData.i_nal_hrd = X264_NAL_HRD_CBR; paramData.rc.i_rc_method = X264_RC_ABR; paramData.rc.f_rf_constant = 0.0f; } else { paramData.rc.i_rc_method = X264_RC_CRF; paramData.rc.f_rf_constant = baseCRF+float(10-quality); } UINT keyframeInterval = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("KeyframeInterval"), 0); paramData.b_vfr_input = !bUseCFR; paramData.i_width = width; paramData.i_height = height; paramData.vui.b_fullrange = colorDesc.fullRange; paramData.vui.i_colorprim = colorDesc.primaries; paramData.vui.i_transfer = colorDesc.transfer; paramData.vui.i_colmatrix = colorDesc.matrix; if (keyframeInterval) paramData.i_keyint_max = fps*keyframeInterval; paramData.i_fps_num = fps; paramData.i_fps_den = 1; paramData.i_timebase_num = 1; paramData.i_timebase_den = 1000; paramData.pf_log = get_x264_log; paramData.i_log_level = X264_LOG_WARNING; for(UINT i=0; i<paramList.Num(); i++) { String &strParam = paramList[i]; if(!schr(strParam, '=')) continue; String strParamName = strParam.GetToken(0, '='); String strParamVal = strParam.GetTokenOffset(1, '='); if( strParamName.CompareI(TEXT("fps")) || strParamName.CompareI(TEXT("force-cfr"))) { Log(TEXT("The custom x264 command '%s' is unsupported, use the application settings instead"), strParam.Array()); continue; } else { LPSTR lpParam = strParamName.CreateUTF8String(); LPSTR lpVal = strParamVal.CreateUTF8String(); if(x264_param_parse(¶mData, lpParam, lpVal) != 0) Log(TEXT("The custom x264 command '%s' failed"), strParam.Array()); Free(lpParam); Free(lpVal); } } if(bUse444) paramData.i_csp = X264_CSP_I444; else paramData.i_csp = X264_CSP_I420; colorDesc.fullRange = paramData.vui.b_fullrange; colorDesc.primaries = paramData.vui.i_colorprim; colorDesc.transfer = paramData.vui.i_transfer; colorDesc.matrix = paramData.vui.i_colmatrix; if (curProfile) { LPSTR lpProfile = curProfile.CreateUTF8String(); if (x264_param_apply_profile (¶mData, lpProfile)) Log(TEXT("Failed to set x264 profile: %s"), curProfile.Array()); Free(lpProfile); } x264 = x264_encoder_open(¶mData); if(!x264) CrashError(TEXT("Could not initialize x264")); Log(TEXT("------------------------------------------")); Log(TEXT("%s"), GetInfoString().Array()); Log(TEXT("------------------------------------------")); DataPacket packet; GetHeaders(packet); }
INT_PTR SettingsGeneral::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: { LocalizeWindow(hwnd); //---------------------------------------------- HWND hwndTemp = GetDlgItem(hwnd, IDC_LANGUAGE); OSFindData ofd; HANDLE hFind; if(hFind = OSFindFirstFile(TEXT("locale/*.txt"), ofd)) { do { if(ofd.bDirectory) continue; String langCode = GetPathFileName(ofd.fileName); LocaleNativeName *langInfo = GetLocaleNativeName(langCode); if(langInfo) { UINT id = (UINT)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)langInfo->lpNative); SendMessage(hwndTemp, CB_SETITEMDATA, id, (LPARAM)langInfo->lpCode); if(App->strLanguage.CompareI(langCode)) SendMessage(hwndTemp, CB_SETCURSEL, id, 0); } } while(OSFindNextFile(hFind, ofd)); OSFindClose(hFind); } //---------------------------------------------- String strCurProfile = GlobalConfig->GetString(TEXT("General"), TEXT("Profile")); hwndTemp = GetDlgItem(hwnd, IDC_PROFILE); StringList profileList; App->GetProfiles(profileList); for(UINT i=0; i<profileList.Num(); i++) { UINT id = (UINT)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)profileList[i].Array()); if(profileList[i].CompareI(strCurProfile)) SendMessage(hwndTemp, CB_SETCURSEL, id, 0); } EnableWindow(hwndTemp, !App->bRunning); EnableWindow(GetDlgItem(hwnd, IDC_ADD), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_RENAME), FALSE); UINT numItems = (UINT)SendMessage(hwndTemp, CB_GETCOUNT, 0, 0); EnableWindow(GetDlgItem(hwnd, IDC_REMOVE), (numItems > 1) && !App->bRunning); //---------------------------------------------- bool bShowNotificationAreaIcon = AppConfig->GetInt(TEXT("General"), TEXT("ShowNotificationAreaIcon"), 0) != 0; SendMessage(GetDlgItem(hwnd, IDC_NOTIFICATIONICON), BM_SETCHECK, bShowNotificationAreaIcon ? BST_CHECKED : BST_UNCHECKED, 0); bool bMinimizeToNotificationArea = AppConfig->GetInt(TEXT("General"), TEXT("MinimizeToNotificationArea"), 0) != 0; SendMessage(GetDlgItem(hwnd, IDC_MINIZENOTIFICATION), BM_SETCHECK, bMinimizeToNotificationArea ? BST_CHECKED : BST_UNCHECKED, 0); //---------------------------------------------- App->bEnableProjectorCursor = GlobalConfig->GetInt(L"General", L"EnableProjectorCursor", 1) != 0; SendMessage(GetDlgItem(hwnd, IDC_ENABLEPROJECTORCURSOR), BM_SETCHECK, App->bEnableProjectorCursor ? BST_CHECKED : BST_UNCHECKED, 0); //---------------------------------------------- bool showLogWindowOnLaunch = GlobalConfig->GetInt(TEXT("General"), TEXT("ShowLogWindowOnLaunch")) != 0; SendMessage(GetDlgItem(hwnd, IDC_SHOWLOGWINDOWONLAUNCH), BM_SETCHECK, showLogWindowOnLaunch ? BST_CHECKED : BST_UNCHECKED, 0); //---------------------------------------------- SetChangedSettings(false); return TRUE; } case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_LANGUAGE: { if(HIWORD(wParam) != CBN_SELCHANGE) break; HWND hwndTemp = (HWND)lParam; SetWindowText(GetDlgItem(hwnd, IDC_INFO), Str("Settings.General.Restart")); ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW); SetChangedSettings(true); break; } case IDC_PROFILE: if (App->bRunning) { HWND cb = (HWND)lParam; String curProfile = GlobalConfig->GetString(TEXT("General"), TEXT("Profile")); UINT numItems = (UINT)SendMessage(cb, CB_GETCOUNT, 0, 0); for (UINT i = 0; i < numItems; i++) { if (GetCBText(cb, i).Compare(curProfile)) SendMessage(cb, CB_SETCURSEL, i, 0); } break; } if(HIWORD(wParam) == CBN_EDITCHANGE) { String strText = GetEditText((HWND)lParam).KillSpaces(); 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)) { OBSMessageBox(hwnd, TEXT("Error - unable to open ini file"), NULL, 0); break; } App->ReloadIniSettings(); SetWindowText(GetDlgItem(hwnd, IDC_INFO), Str("Settings.Info")); ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW); GlobalConfig->SetString(TEXT("General"), TEXT("Profile"), strProfile); App->ResetProfileMenu(); App->ResetApplicationName(); App->UpdateNotificationAreaIcon(); UINT numItems = (UINT)SendMessage(GetDlgItem(hwnd, IDC_PROFILE), CB_GETCOUNT, 0, 0); EnableWindow(GetDlgItem(hwnd, IDC_REMOVE), (numItems > 1)); App->ResizeWindow(false); } break; case IDC_RENAME: case IDC_ADD: if (App->bRunning) break; if(HIWORD(wParam) == BN_CLICKED) { HWND hwndProfileList = GetDlgItem(hwnd, IDC_PROFILE); String strProfile = GetEditText(hwndProfileList).KillSpaces(); SetWindowText(hwndProfileList, strProfile); if(strProfile.IsEmpty()) break; 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)) OBSMessageBox(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)) { OBSMessageBox(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); App->ResetProfileMenu(); App->ResetApplicationName(); } } break; case IDC_REMOVE: if (App->bRunning) break; { 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(OBSMessageBox(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); DialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_PROFILE, CBN_SELCHANGE), (LPARAM)hwndProfileList); String strCurProfilePath; strCurProfilePath << lpAppDataPath << TEXT("\\profiles\\") << strCurProfile << TEXT(".ini"); OSDeleteFile(strCurProfilePath); App->ResetProfileMenu(); } } break; } case IDC_NOTIFICATIONICON: if (SendMessage(GetDlgItem(hwnd, IDC_NOTIFICATIONICON), BM_GETCHECK, 0, 0) == BST_UNCHECKED) { SendMessage(GetDlgItem(hwnd, IDC_MINIZENOTIFICATION), BM_SETCHECK, BST_UNCHECKED, 0); } SetChangedSettings(true); break; case IDC_MINIZENOTIFICATION: if (SendMessage(GetDlgItem(hwnd, IDC_MINIZENOTIFICATION), BM_GETCHECK, 0, 0) == BST_CHECKED) { SendMessage(GetDlgItem(hwnd, IDC_NOTIFICATIONICON), BM_SETCHECK, BST_CHECKED, 0); } SetChangedSettings(true); break; case IDC_ENABLEPROJECTORCURSOR: case IDC_SHOWLOGWINDOWONLAUNCH: SetChangedSettings(true); break; } } return FALSE; }
void OBS::Start() { if(bRunning) return; OSEnterMutex (hStartupShutdownMutex); scenesConfig.Save(); //------------------------------------------------------------- fps = AppConfig->GetInt(TEXT("Video"), TEXT("FPS"), 30); frameTime = 1000/fps; //------------------------------------------------------------- if(!bLoggedSystemStats) { LogSystemStats(); bLoggedSystemStats = TRUE; } //------------------------------------------------------------- if (OSIncompatibleModulesLoaded()) { OSLeaveMutex (hStartupShutdownMutex); MessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR); Log(TEXT("Incompatible modules detected.")); return; } String strPatchesError; if (OSIncompatiblePatchesLoaded(strPatchesError)) { OSLeaveMutex (hStartupShutdownMutex); MessageBox(hwndMain, strPatchesError.Array(), NULL, MB_ICONERROR); Log(TEXT("Incompatible patches detected.")); return; } //------------------------------------------------------------- int networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2); DWORD delayTime = (DWORD)AppConfig->GetInt(TEXT("Publish"), TEXT("Delay")); String strError; if(bTestStream) network = CreateNullNetwork(); else { switch(networkMode) { case 0: network = (delayTime > 0) ? CreateDelayedPublisher(delayTime) : CreateRTMPPublisher(); break; case 1: network = CreateNullNetwork(); break; } } if(!network) { OSLeaveMutex (hStartupShutdownMutex); if(!bReconnecting) MessageBox(hwndMain, strError, NULL, MB_ICONERROR); else DialogBox(hinstMain, MAKEINTRESOURCE(IDD_RECONNECTING), hwndMain, OBS::ReconnectDialogProc); return; } bReconnecting = false; //------------------------------------------------------------- Log(TEXT("=====Stream Start: %s==============================================="), CurrentDateTime().Array()); //------------------------------------------------------------- int monitorID = AppConfig->GetInt(TEXT("Video"), TEXT("Monitor")); if(monitorID >= (int)monitors.Num()) monitorID = 0; RECT &screenRect = monitors[monitorID].rect; int defCX = screenRect.right - screenRect.left; int defCY = screenRect.bottom - screenRect.top; downscaleType = AppConfig->GetInt(TEXT("Video"), TEXT("Filter"), 0); downscale = AppConfig->GetFloat(TEXT("Video"), TEXT("Downscale"), 1.0f); baseCX = AppConfig->GetInt(TEXT("Video"), TEXT("BaseWidth"), defCX); baseCY = AppConfig->GetInt(TEXT("Video"), TEXT("BaseHeight"), defCY); baseCX = MIN(MAX(baseCX, 128), 4096); baseCY = MIN(MAX(baseCY, 128), 4096); scaleCX = UINT(double(baseCX) / double(downscale)); scaleCY = UINT(double(baseCY) / double(downscale)); //align width to 128bit for fast SSE YUV4:2:0 conversion outputCX = scaleCX & 0xFFFFFFFC; outputCY = scaleCY & 0xFFFFFFFE; bUseMultithreadedOptimizations = AppConfig->GetInt(TEXT("General"), TEXT("UseMultithreadedOptimizations"), TRUE) != 0; Log(TEXT(" Multithreaded optimizations: %s"), (CTSTR)(bUseMultithreadedOptimizations ? TEXT("On") : TEXT("Off"))); GlobalConfig->SetInt(TEXT("Audio"), TEXT("GlobalAudioTimeAdjust"), 0); //------------------------------------------------------------------ Log(TEXT(" Base resolution: %ux%u"), baseCX, baseCY); Log(TEXT(" Output resolution: %ux%u"), outputCX, outputCY); Log(TEXT("------------------------------------------")); //------------------------------------------------------------------ GS = new D3D10System; GS->Init(); //------------------------------------------------------------- mainVertexShader = CreateVertexShaderFromFile(TEXT("shaders/DrawTexture.vShader")); mainPixelShader = CreatePixelShaderFromFile(TEXT("shaders/DrawTexture.pShader")); solidVertexShader = CreateVertexShaderFromFile(TEXT("shaders/DrawSolid.vShader")); solidPixelShader = CreatePixelShaderFromFile(TEXT("shaders/DrawSolid.pShader")); //------------------------------------------------------------------ CTSTR lpShader; if(CloseFloat(downscale, 1.0)) lpShader = TEXT("shaders/DrawYUVTexture.pShader"); else if(downscale < 2.01) { switch(downscaleType) { case 0: lpShader = TEXT("shaders/DownscaleBilinear1YUV.pShader"); break; case 1: lpShader = TEXT("shaders/DownscaleBicubicYUV.pShader"); break; case 2: lpShader = TEXT("shaders/DownscaleLanczos6tapYUV.pShader"); break; } } else if(downscale < 3.01) lpShader = TEXT("shaders/DownscaleBilinear9YUV.pShader"); else CrashError(TEXT("Invalid downscale value (must be either 1.0, 1.5, 2.0, 2.25, or 3.0)")); yuvScalePixelShader = CreatePixelShaderFromFile(lpShader); if (!yuvScalePixelShader) CrashError(TEXT("Unable to create shader from file %s"), lpShader); //------------------------------------------------------------- for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { mainRenderTextures[i] = CreateRenderTarget(baseCX, baseCY, GS_BGRA, FALSE); yuvRenderTextures[i] = CreateRenderTarget(outputCX, outputCY, GS_BGRA, FALSE); } //------------------------------------------------------------- D3D10_TEXTURE2D_DESC td; zero(&td, sizeof(td)); td.Width = outputCX; td.Height = outputCY; td.Format = DXGI_FORMAT_B8G8R8A8_UNORM; td.MipLevels = 1; td.ArraySize = 1; td.SampleDesc.Count = 1; td.ArraySize = 1; td.Usage = D3D10_USAGE_STAGING; td.CPUAccessFlags = D3D10_CPU_ACCESS_READ; for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { HRESULT err = GetD3D()->CreateTexture2D(&td, NULL, ©Textures[i]); if(FAILED(err)) { CrashError(TEXT("Unable to create copy texture")); //todo - better error handling } } //------------------------------------------------------------- AudioDeviceList playbackDevices; GetAudioDevices(playbackDevices, ADT_PLAYBACK); String strPlaybackDevice = AppConfig->GetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default")); if(strPlaybackDevice.IsEmpty() || !playbackDevices.HasID(strPlaybackDevice)) { AppConfig->SetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default")); strPlaybackDevice = TEXT("Default"); } Log(TEXT("Playback device %s"), strPlaybackDevice.Array()); playbackDevices.FreeData(); desktopAudio = CreateAudioSource(false, strPlaybackDevice); if(!desktopAudio) { CrashError(TEXT("Cannot initialize desktop audio sound, more info in the log file.")); } AudioDeviceList audioDevices; GetAudioDevices(audioDevices, ADT_RECORDING); String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL); if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice)) { AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable")); strDevice = TEXT("Disable"); } audioDevices.FreeData(); String strDefaultMic; bool bHasDefault = GetDefaultMicID(strDefaultMic); if(strDevice.CompareI(TEXT("Disable"))) EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE); else { bool bUseDefault = strDevice.CompareI(TEXT("Default")) != 0; if(!bUseDefault || bHasDefault) { if(bUseDefault) strDevice = strDefaultMic; micAudio = CreateAudioSource(true, strDevice); if(!micAudio) MessageBox(hwndMain, Str("MicrophoneFailure"), NULL, 0); else micAudio->SetTimeOffset(AppConfig->GetInt(TEXT("Audio"), TEXT("MicTimeOffset"), 0)); EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), micAudio != NULL); } else EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE); } //------------------------------------------------------------- UINT bitRate = (UINT)AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96); String strEncoder = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC")); #ifdef USE_AAC if(strEncoder.CompareI(TEXT("AAC")) && OSGetVersion() >= 7) audioEncoder = CreateAACEncoder(bitRate); else #endif audioEncoder = CreateMP3Encoder(bitRate); //------------------------------------------------------------- desktopVol = AppConfig->GetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 1.0f); micVol = AppConfig->GetFloat(TEXT("Audio"), TEXT("MicVolume"), 1.0f); //------------------------------------------------------------- bRunning = true; if(sceneElement) { scene = CreateScene(sceneElement->GetString(TEXT("class")), sceneElement->GetElement(TEXT("data"))); XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); for(UINT i=0; i<numSources; i++) { SceneItem *item = scene->AddImageSource(sources->GetElementByID(i)); if(item) { if(ListView_GetItemState(GetDlgItem(hwndMain, ID_SOURCES), i, LVIS_SELECTED) > 0) item->Select(true); } } } scene->BeginScene(); } if(scene && scene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); //------------------------------------------------------------- int maxBitRate = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int bufferSize = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("BufferSize"), 1000); int quality = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("Quality"), 8); String preset = AppConfig->GetString(TEXT("Video Encoding"), TEXT("Preset"), TEXT("veryfast")); bUsing444 = AppConfig->GetInt (TEXT("Video Encoding"), TEXT("Use444"), 0) != 0; bDupeFrames = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("DupeFrames"), 1) != 0; if(bUsing444) bDupeFrames = bUseCFR = false; else { bUseCFR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCFR"), 0) != 0; if(bUseCFR) bDupeFrames = true; } //------------------------------------------------------------- bWriteToFile = networkMode == 1 || AppConfig->GetInt(TEXT("Publish"), TEXT("SaveToFile")) != 0; String strOutputFile = AppConfig->GetString(TEXT("Publish"), TEXT("SavePath")); strOutputFile.FindReplace(TEXT("\\"), TEXT("/")); if (bWriteToFile) { OSFindData ofd; HANDLE hFind = NULL; bool bUseDateTimeName = true; if(hFind = OSFindFirstFile(strOutputFile, ofd)) { String strFileExtension = GetPathExtension(strOutputFile); String strFileWithoutExtension = GetPathWithoutExtension(strOutputFile); if(strFileExtension.IsValid() && !ofd.bDirectory) { String strNewFilePath; UINT curFile = 0; do { strNewFilePath.Clear() << strFileWithoutExtension << TEXT(" (") << FormattedString(TEXT("%02u"), ++curFile) << TEXT(").") << strFileExtension; } while(OSFileExists(strNewFilePath)); strOutputFile = strNewFilePath; bUseDateTimeName = false; } if(ofd.bDirectory) strOutputFile.AppendChar('/'); OSFindClose(hFind); } if(bUseDateTimeName) { String strFileName = GetPathFileName(strOutputFile); if(!strFileName.IsValid() || !IsSafeFilename(strFileName)) { SYSTEMTIME st; GetLocalTime(&st); String strDirectory = GetPathDirectory(strOutputFile); strOutputFile = FormattedString(TEXT("%s/%u-%02u-%02u-%02u%02u-%02u.mp4"), strDirectory.Array(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } } } //------------------------------------------------------------- bufferingTime = GlobalConfig->GetInt(TEXT("General"), TEXT("SceneBufferingTime"), 400); //------------------------------------------------------------- bForceMicMono = AppConfig->GetInt(TEXT("Audio"), TEXT("ForceMicMono")) != 0; bRecievedFirstAudioFrame = false; //hRequestAudioEvent = CreateSemaphore(NULL, 0, 0x7FFFFFFFL, NULL); hSoundDataMutex = OSCreateMutex(); hSoundThread = OSCreateThread((XTHREAD)OBS::MainAudioThread, NULL); //------------------------------------------------------------- StartBlankSoundPlayback(strPlaybackDevice); //------------------------------------------------------------- ctsOffset = 0; videoEncoder = CreateX264Encoder(fps, outputCX, outputCY, quality, preset, bUsing444, maxBitRate, bufferSize, bUseCFR, bDupeFrames); //------------------------------------------------------------- // Ensure that the render frame is properly sized ResizeRenderFrame(true); //------------------------------------------------------------- if(!bTestStream && bWriteToFile && strOutputFile.IsValid()) { String strFileExtension = GetPathExtension(strOutputFile); if(strFileExtension.CompareI(TEXT("flv"))) fileStream = CreateFLVFileStream(strOutputFile); else if(strFileExtension.CompareI(TEXT("mp4"))) fileStream = CreateMP4FileStream(strOutputFile); } //------------------------------------------------------------- hMainThread = OSCreateThread((XTHREAD)OBS::MainCaptureThread, NULL); if(bTestStream) { EnableWindow(GetDlgItem(hwndMain, ID_STARTSTOP), FALSE); SetWindowText(GetDlgItem(hwndMain, ID_TESTSTREAM), Str("MainWindow.StopTest")); } else { EnableWindow(GetDlgItem(hwndMain, ID_TESTSTREAM), FALSE); SetWindowText(GetDlgItem(hwndMain, ID_STARTSTOP), Str("MainWindow.StopStream")); } EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), TRUE); //------------------------------------------------------------- ReportStartStreamTrigger(); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, 0); SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED | ES_DISPLAY_REQUIRED); UpdateRenderViewMessage(); //update notification icon to reflect current status UpdateNotificationAreaIcon(); OSLeaveMutex (hStartupShutdownMutex); }
bool OBS::SetScene(CTSTR lpScene) { if(bDisableSceneSwitching) return false; HWND hwndScenes = GetDlgItem(hwndMain, ID_SCENES); UINT curSel = (UINT)SendMessage(hwndScenes, LB_GETCURSEL, 0, 0); //------------------------- if(curSel != LB_ERR) { UINT textLen = (UINT)SendMessage(hwndScenes, LB_GETTEXTLEN, curSel, 0); String strLBName; strLBName.SetLength(textLen); SendMessage(hwndScenes, LB_GETTEXT, curSel, (LPARAM)strLBName.Array()); if(!strLBName.CompareI(lpScene)) { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } } else { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } //------------------------- XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); XElement *newSceneElement = scenes->GetElement(lpScene); if(!newSceneElement) return false; if(sceneElement == newSceneElement) return true; sceneElement = newSceneElement; CTSTR lpClass = sceneElement->GetString(TEXT("class")); if(!lpClass) { AppWarning(TEXT("OBS::SetScene: no class found for scene '%s'"), newSceneElement->GetName()); return false; } DWORD sceneChangeStartTime; if(bRunning) { Log(TEXT("++++++++++++++++++++++++++++++++++++++++++++++++++++++")); Log(TEXT(" New Scene")); sceneChangeStartTime = OSGetTime(); } XElement *sceneData = newSceneElement->GetElement(TEXT("data")); //------------------------- Scene *newScene = NULL; if(bRunning) newScene = CreateScene(lpClass, sceneData); //------------------------- HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)FALSE, (LPARAM) 0); bChangingSources = true; ListView_DeleteAllItems(hwndSources); XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); ListView_SetItemCount(hwndSources, numSources); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); bool render = sourceElement->GetInt(TEXT("render"), 1) > 0; InsertSourceItem(i, (LPWSTR)sourceElement->GetName(), render); if(bRunning && newScene) newScene->AddImageSource(sourceElement); } } bChangingSources = false; SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)TRUE, (LPARAM) 0); RedrawWindow(hwndSources, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); if(scene && newScene && newScene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); if(bRunning) { //todo: cache scenes maybe? undecided. not really as necessary with global sources OSEnterMutex(hSceneMutex); UINT numSources; if (scene) { //shutdown previous scene, if any numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceLeaveScene(); } } } scene->EndScene(); } Scene *previousScene = scene; scene = newScene; scene->BeginScene(); numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceEnterScene(); } } } if(!bTransitioning) { bTransitioning = true; transitionAlpha = 0.0f; } OSLeaveMutex(hSceneMutex); delete previousScene; DWORD sceneChangeTime = OSGetTime() - sceneChangeStartTime; if (sceneChangeTime >= 500) Log(TEXT("PERFORMANCE WARNING: Scene change took %u ms, maybe some sources should be global sources?"), sceneChangeTime); } if(API != NULL) ReportSwitchScenes(lpScene); return true; }
void OBS::ReloadIniSettings() { HWND hwndTemp; //------------------------------------------- // mic volume data hwndTemp = GetDlgItem(hwndMain, ID_MICVOLUME); if(!AppConfig->HasKey(TEXT("Audio"), TEXT("MicVolume"))) AppConfig->SetFloat(TEXT("Audio"), TEXT("MicVolume"), 0.0f); SetVolumeControlValue(hwndTemp, AppConfig->GetFloat(TEXT("Audio"), TEXT("MicVolume"), 0.0f)); AudioDeviceList audioDevices; GetAudioDevices(audioDevices, ADT_RECORDING); String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL); if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice)) { AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable")); strDevice = TEXT("Disable"); } audioDevices.FreeData(); EnableWindow(hwndTemp, !strDevice.CompareI(TEXT("Disable"))); //------------------------------------------- // desktop volume hwndTemp = GetDlgItem(hwndMain, ID_DESKTOPVOLUME); if(!AppConfig->HasKey(TEXT("Audio"), TEXT("DesktopVolume"))) AppConfig->SetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 1.0f); SetVolumeControlValue(hwndTemp, AppConfig->GetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 0.0f)); //------------------------------------------- // mic boost DWORD micBoostPercentage = AppConfig->GetInt(TEXT("Audio"), TEXT("MicBoostMultiple"), 1); if(micBoostPercentage < 1) micBoostPercentage = 1; else if(micBoostPercentage > 20) micBoostPercentage = 20; micBoost = float(micBoostPercentage); //------------------------------------------- // dashboard strDashboard = AppConfig->GetString(TEXT("Publish"), TEXT("Dashboard")); strDashboard.KillSpaces(); //------------------------------------------- // hotkeys QuickClearHotkey(pushToTalkHotkeyID); QuickClearHotkey(muteMicHotkeyID); QuickClearHotkey(muteDesktopHotkeyID); QuickClearHotkey(stopStreamHotkeyID); QuickClearHotkey(startStreamHotkeyID); bUsingPushToTalk = AppConfig->GetInt(TEXT("Audio"), TEXT("UsePushToTalk")) != 0; DWORD hotkey = AppConfig->GetInt(TEXT("Audio"), TEXT("PushToTalkHotkey")); pushToTalkDelay = AppConfig->GetInt(TEXT("Audio"), TEXT("PushToTalkDelay"), 200); if(bUsingPushToTalk && hotkey) pushToTalkHotkeyID = API->CreateHotkey(hotkey, OBS::PushToTalkHotkey, NULL); hotkey = AppConfig->GetInt(TEXT("Audio"), TEXT("MuteMicHotkey")); if(hotkey) muteMicHotkeyID = API->CreateHotkey(hotkey, OBS::MuteMicHotkey, NULL); hotkey = AppConfig->GetInt(TEXT("Audio"), TEXT("MuteDesktopHotkey")); if(hotkey) muteDesktopHotkeyID = API->CreateHotkey(hotkey, OBS::MuteDesktopHotkey, NULL); hotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StopStreamHotkey")); if(hotkey) stopStreamHotkeyID = API->CreateHotkey(hotkey, OBS::StopStreamHotkey, NULL); hotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StartStreamHotkey")); if(hotkey) startStreamHotkeyID = API->CreateHotkey(hotkey, OBS::StartStreamHotkey, NULL); }
void SettingsPublish::SetWarningInfo() { int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0); bool bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR"), 1) != 0; int maxBitRate = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int keyframeInt = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("KeyframeInterval"), 0); int audioBitRate = AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96); String currentx264Profile = AppConfig->GetString(TEXT("Video Encoding"), TEXT("X264Profile"), L"high"); String currentAudioCodec = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC")); //ignore for non-livestreams if (data->mode != 0) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } int errors = 0; String strWarnings; XConfig serverData; if(serverData.Open(TEXT("services.xconfig"))) { XElement *services = serverData.GetElement(TEXT("services")); if(services) { UINT numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *service = services->GetElementByID(i); if (service->GetInt(TEXT("id")) == serviceID) { strWarnings = FormattedString(Str("Settings.Publish.Warning.BadSettings"), service->GetName()); //check to see if the service we're using has recommendations if (!service->HasItem(TEXT("recommended"))) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } XElement *r = service->GetElement(TEXT("recommended")); if (r->HasItem(TEXT("ratecontrol"))) { CTSTR rc = r->GetString(TEXT("ratecontrol")); if (!scmp (rc, TEXT("cbr")) && !bUseCBR) { errors++; strWarnings << Str("Settings.Publish.Warning.UseCBR"); } } if (r->HasItem(TEXT("max bitrate"))) { int max_bitrate = r->GetInt(TEXT("max bitrate")); if (maxBitRate > max_bitrate) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.Maxbitrate"), max_bitrate); } } if (r->HasItem(TEXT("profile"))) { String expectedProfile = r->GetString(TEXT("profile")); if (!expectedProfile.CompareI(currentx264Profile)) { errors++; strWarnings << Str("Settings.Publish.Warning.RecommendMainProfile"); } } if (r->HasItem(TEXT("max audio bitrate aac")) && (!scmp(currentAudioCodec, TEXT("AAC")))) { int maxaudioaac = r->GetInt(TEXT("max audio bitrate aac")); if (audioBitRate > maxaudioaac) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudioaac); } } if (r->HasItem(TEXT("max audio bitrate mp3")) && (!scmp(currentAudioCodec, TEXT("MP3")))) { int maxaudiomp3 = r->GetInt(TEXT("max audio bitrate mp3")); if (audioBitRate > maxaudiomp3) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudiomp3); } } if (r->HasItem(TEXT("keyint"))) { int keyint = r->GetInt(TEXT("keyint")); if (!keyframeInt || keyframeInt * 1000 > keyint) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.Keyint"), keyint / 1000); } } if (r->HasItem(L"supported audio codec")) { StringList codecs; r->GetStringList(L"supported audio codec", codecs); if (codecs.FindValueIndex(currentAudioCodec) == INVALID) { String msg = Str("Settings.Publish.Warning.UnsupportedAudioCodec"); //good thing OBS only supports MP3 (and AAC), otherwise I'd have to come up with a better translation solution msg.FindReplace(L"$1", codecs[0].Array()); msg.FindReplace(L"$2", currentAudioCodec.Array()); errors += 1; strWarnings << msg; } } break; } } } } if (errors) SetDlgItemText(hwnd, IDC_WARNINGS, strWarnings.Array()); else SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); }
void SettingsPublish::OptimizeSettings() { auto refresh_on_exit = GuardScope([&] { SetWarningInfo(); }); XConfig serverData; if (!serverData.Open(L"services.xconfig")) return; XElement *services = serverData.GetElement(L"services"); if (!services) return; UINT numServices = services->NumElements(); int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0); XElement *r = nullptr; for (UINT i = 0; i < numServices; i++) { XElement *service = services->GetElementByID(i); if (service->GetInt(L"id") != serviceID) continue; //check to see if the service we're using has recommendations if (!service->HasItem(L"recommended")) return; r = service->GetElement(L"recommended"); break; } if (!r) return; using optimizers_t = std::vector<std::function<void()>>; optimizers_t optimizers; String changes = Str("Settings.Publish.Optimize.Optimizations"); String currentAudioCodec = AppConfig->GetString(L"Audio Encoding", L"Codec", L"AAC"); int audioBitrate = AppConfig->GetInt(L"Audio Encoding", L"Bitrate", 96); if (r->HasItem(L"ratecontrol")) { bool useCBR = AppConfig->GetInt(L"Video Encoding", L"UseCBR", 1) != 0; CTSTR rc = r->GetString(L"ratecontrol"); if (!scmp(rc, L"cbr") && !useCBR) { optimizers.push_back([] { AppConfig->SetInt(L"Video Encoding", L"UseCBR", 1); }); changes << Str("Settings.Publish.Optimize.UseCBR"); } } if (r->HasItem(L"max bitrate")) { int maxBitrate = AppConfig->GetInt(L"Video Encoding", L"MaxBitrate", 1000); int max_bitrate = r->GetInt(L"max bitrate"); if (maxBitrate > max_bitrate) { optimizers.push_back([max_bitrate] { AppConfig->SetInt(L"Video Encoding", L"MaxBitrate", max_bitrate); }); changes << FormattedString(Str("Settings.Publish.Optimize.Maxbitrate"), max_bitrate); } } if (r->HasItem(L"supported audio codec")) { StringList codecs; r->GetStringList(L"supported audio codec", codecs); if (codecs.FindValueIndex(currentAudioCodec) == INVALID) { String codec = codecs[0]; optimizers.push_back([codec] { AppConfig->SetString(L"Audio Encoding", L"Codec", codec.Array()); AppConfig->SetInt(L"Audio Encoding", L"Format", codec.CompareI(L"AAC") ? 1 : 0); //set to 44.1 kHz in case of MP3, see SettingsEncoding.cpp }); changes << FormattedString(Str("Settings.Publish.Optimize.UnsupportedAudioCodec"), codec.Array()); } } if (r->HasItem(L"max audio bitrate aac") && (!scmp(currentAudioCodec, L"AAC"))) { int maxaudioaac = r->GetInt(L"max audio bitrate aac"); if (audioBitrate > maxaudioaac) { optimizers.push_back([maxaudioaac] { AppConfig->SetInt(L"Audio Encoding", L"Bitrate", maxaudioaac); }); changes << FormattedString(Str("Settings.Publish.Optimize.MaxAudiobitrate"), maxaudioaac); } } if (r->HasItem(L"max audio bitrate mp3") && (!scmp(currentAudioCodec, L"MP3"))) { int maxaudiomp3 = r->GetInt(L"max audio bitrate mp3"); if (audioBitrate > maxaudiomp3) { optimizers.push_back([maxaudiomp3] { AppConfig->SetInt(L"Audio Encoding", L"Bitrate", maxaudiomp3); }); changes << FormattedString(Str("Settings.Publish.Optimize.MaxAudiobitrate"), maxaudiomp3); } } if (r->HasItem(L"profile")) { String currentx264Profile = AppConfig->GetString(L"Video Encoding", L"X264Profile", L"high"); String expectedProfile = r->GetString(L"profile"); if (!expectedProfile.CompareI(currentx264Profile)) { optimizers.push_back([expectedProfile] { AppConfig->SetString(L"Video Encoding", L"X264Profile", expectedProfile); }); changes << FormattedString(Str("Settings.Publish.Optimize.RecommendMainProfile"), expectedProfile.Array()); } } if (r->HasItem(L"keyint")) { int keyframeInt = AppConfig->GetInt(L"Video Encoding", L"KeyframeInterval", 0); int keyint = r->GetInt(L"keyint"); if (!keyframeInt || keyframeInt * 1000 > keyint) { optimizers.push_back([keyint] { AppConfig->SetInt(L"Video Encoding", L"KeyframeInterval", keyint / 1000); }); changes << FormattedString(Str("Settings.Publish.Optimize.Keyint"), keyint / 1000); } } if (OBSMessageBox(hwnd, changes.Array(), Str("Optimize"), MB_OKCANCEL | MB_ICONINFORMATION) != IDOK) return; for (optimizers_t::const_reference i : optimizers) i(); }
bool OBS::SetScene(CTSTR lpScene) { if(bDisableSceneSwitching) return false; HWND hwndScenes = GetDlgItem(hwndMain, ID_SCENES); UINT curSel = (UINT)SendMessage(hwndScenes, LB_GETCURSEL, 0, 0); //------------------------- if(curSel != LB_ERR) { UINT textLen = (UINT)SendMessage(hwndScenes, LB_GETTEXTLEN, curSel, 0); String strLBName; strLBName.SetLength(textLen); SendMessage(hwndScenes, LB_GETTEXT, curSel, (LPARAM)strLBName.Array()); if(!strLBName.CompareI(lpScene)) { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } } else { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } //------------------------- XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); XElement *newSceneElement = scenes->GetElement(lpScene); if(!newSceneElement) return false; if(sceneElement == newSceneElement) return true; sceneElement = newSceneElement; CTSTR lpClass = sceneElement->GetString(TEXT("class")); if(!lpClass) { AppWarning(TEXT("OBS::SetScene: no class found for scene '%s'"), newSceneElement->GetName()); return false; } DWORD sceneChangeStartTime; if(bRunning) { Log(TEXT("++++++++++++++++++++++++++++++++++++++++++++++++++++++")); Log(TEXT(" New Scene")); sceneChangeStartTime = OSGetTime(); } XElement *sceneData = newSceneElement->GetElement(TEXT("data")); //------------------------- Scene *newScene = NULL; if(bRunning) newScene = CreateScene(lpClass, sceneData); //------------------------- HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)FALSE, (LPARAM) 0); App->scaleItem = NULL; bChangingSources = true; ListView_DeleteAllItems(hwndSources); bool bSkipTransition = false; XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); ListView_SetItemCount(hwndSources, numSources); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); String className = sourceElement->GetString(TEXT("class")); if(className == "DeviceCapture") { // There's a capture device in the next scene that isn't a global source, // so let's skip the transition since it won't work anyway. bSkipTransition = true; } } for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); bool render = sourceElement->GetInt(TEXT("render"), 1) > 0; InsertSourceItem(i, (LPWSTR)sourceElement->GetName(), render); // Do not add image sources yet in case we're skipping the transition. // This fixes the issue where capture devices sources that used the // same device as one in the previous scene would just go blank // after switching. if(bRunning && newScene && !bSkipTransition) newScene->AddImageSource(sourceElement); } } bChangingSources = false; SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)TRUE, (LPARAM) 0); RedrawWindow(hwndSources, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); if(scene && newScene && newScene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); if(bRunning) { //todo: cache scenes maybe? undecided. not really as necessary with global sources OSEnterMutex(hSceneMutex); UINT numSources; if (scene) { //shutdown previous scene, if any numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceLeaveScene(); } } } scene->EndScene(); } Scene *previousScene = scene; scene = newScene; if(newScene && bSkipTransition) { // If we're skipping the transition because of a non-global // DirectShow device, delete the scene here and add the // ImageSources at this point instead. delete previousScene; if(sources) { UINT numSources = sources->NumElements(); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); if(newScene) newScene->AddImageSource(sourceElement); } } } scene->BeginScene(); numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceEnterScene(); } } } if(!bTransitioning && !bSkipTransition) { bTransitioning = true; transitionAlpha = 0.0f; } OSLeaveMutex(hSceneMutex); if(!bSkipTransition) { // Do not delete the previous scene here, since it has already // been deleted. delete previousScene; } DWORD sceneChangeTime = OSGetTime() - sceneChangeStartTime; if (sceneChangeTime >= 500) Log(TEXT("PERFORMANCE WARNING: Scene change took %u ms, maybe some sources should be global sources?"), sceneChangeTime); } if(API != NULL) ReportSwitchScenes(lpScene); return true; }
/************************************************** 重置音频参数函数 参数: sAudioParam :设置音频参数,采样率,采样位,声道 ***************************************************/ void CDemandMediaAudio::ResetAudioParam(const AudioParam & sAudioParam) { Log::writeMessage(LOG_RTSPSERV, 1, "%s invoke begin!",__FUNCTION__); EnterCriticalSection(&sampleBufferLock); m_sAudioParam = sAudioParam; m_bisFloat = false; bSameDevice = false; m_uBlockSize = sAudioParam.iChannel * sAudioParam.iBitPerSample / 8; if (m_pAudioWaveOut) { m_pAudioWaveOut->Uninitialize(); } String strReanderName = GetDirectorMonitorDevices(); if (NULL == m_pAudioWaveOut) { if (!strReanderName.Compare(TEXT("停用")) && !m_pAudioWaveOut) { m_pAudioWaveOut = new AudioWaveOut; } } else { if ((strReanderName.Compare(TEXT("Disable")) || strReanderName.Compare(TEXT("停用")))) { delete m_pAudioWaveOut; m_pAudioWaveOut = NULL; } } if (NULL != m_pAudioWaveOut) { if (sAudioParam.iChannel > 2) { m_bisFloat = true; m_pAudioWaveOut->Initialize(strReanderName.Array(), 2, sAudioParam.iSamplesPerSec, sAudioParam.iBitPerSample * 2); } else { m_pAudioWaveOut->Initialize(strReanderName.Array(), 2, sAudioParam.iSamplesPerSec, sAudioParam.iBitPerSample); } } String SecRenderName = GetSecMonitorDevices(); if (m_pSecWaveOut) { m_pSecWaveOut->Uninitialize(); } if (SecRenderName.CompareI(strReanderName.Array()) && (!SecRenderName.Compare(TEXT("Disable")) || !SecRenderName.Compare(TEXT("停用")))) { bSameDevice = true; } else if (!SecRenderName.Compare(TEXT("停用")) && !m_pSecWaveOut) { m_pSecWaveOut = new AudioWaveOut; } else if (m_pSecWaveOut) { if ((SecRenderName.Compare(TEXT("Disable")) || SecRenderName.Compare(TEXT("停用")))) { delete m_pSecWaveOut; m_pSecWaveOut = NULL; } } if (m_pSecWaveOut) { if (sAudioParam.iChannel > 2) { m_bisFloat = true; m_pSecWaveOut->Initialize(SecRenderName.Array(), 2, sAudioParam.iSamplesPerSec, sAudioParam.iBitPerSample * 2); } else { m_pSecWaveOut->Initialize(SecRenderName.Array(), 2, sAudioParam.iSamplesPerSec, sAudioParam.iBitPerSample); } } sampleFrameCount = m_sAudioParam.iSamplesPerSec / 100; if (m_bisFloat) { InitAudioData(m_bisFloat, 2, m_sAudioParam.iSamplesPerSec, m_sAudioParam.iBitPerSample * 2, m_uBlockSize, m_uchannelMask); sampleSegmentSize = 4 * sampleFrameCount * sizeof(float) * 8 / m_sAudioParam.iBitPerSample;//4 又声道的BlockSize,2为转为short转float后扩大2倍 } else { InitAudioData(m_bisFloat, m_sAudioParam.iChannel, m_sAudioParam.iSamplesPerSec, m_sAudioParam.iBitPerSample, m_uBlockSize, m_uchannelMask); sampleSegmentSize = this->m_uBlockSize * sampleFrameCount; } outputBuffer.SetSize(sampleSegmentSize); if (!sampleSegmentSize) { sampleBuffer.RemoveRange(0, sampleBuffer.Num()); } LeaveCriticalSection(&sampleBufferLock); Log::writeMessage(LOG_RTSPSERV, 1, "%s invoke end!",__FUNCTION__); }
void CDemandMediaAudio::OnAudioDeviceChanged(const String &MonitorDevices, const String &SecMonitor) { if (this->MonitorDevices.Compare(MonitorDevices.Array()) && this->SecMonitor.Compare(SecMonitor.Array())) { return; } Log::writeMessage(LOG_RTSPSERV, 1, "%s invoke begin!", __FUNCTION__); EnterCriticalSection(&sampleBufferLock); m_bisFloat = false; bSameDevice = false; if (m_pAudioWaveOut) { m_pAudioWaveOut->Uninitialize(); } if (NULL == m_pAudioWaveOut) { if (!MonitorDevices.Compare(TEXT("停用")) && !m_pAudioWaveOut) { m_pAudioWaveOut = new AudioWaveOut; } } else { if ((MonitorDevices.Compare(TEXT("Disable")) || MonitorDevices.Compare(TEXT("停用")))) { delete m_pAudioWaveOut; m_pAudioWaveOut = NULL; } } if (NULL != m_pAudioWaveOut) { if (m_sAudioParam.iChannel > 2) { m_bisFloat = true; m_pAudioWaveOut->Initialize(MonitorDevices.Array(), 2, m_sAudioParam.iSamplesPerSec, m_sAudioParam.iBitPerSample * 2); } else { m_pAudioWaveOut->Initialize(MonitorDevices.Array(), 2, m_sAudioParam.iSamplesPerSec, m_sAudioParam.iBitPerSample); } } if (m_pSecWaveOut) { m_pSecWaveOut->Uninitialize(); } if (SecMonitor.CompareI(MonitorDevices.Array()) && (!SecMonitor.Compare(TEXT("Disable")) || !SecMonitor.Compare(TEXT("停用")))) { bSameDevice = true; } else if (!SecMonitor.Compare(TEXT("停用")) && !m_pSecWaveOut) { m_pSecWaveOut = new AudioWaveOut; } else if (m_pSecWaveOut) { if ((SecMonitor.Compare(TEXT("Disable")) || SecMonitor.Compare(TEXT("停用")))) { delete m_pSecWaveOut; m_pSecWaveOut = NULL; } } if (m_pSecWaveOut) { if (m_sAudioParam.iChannel > 2) { m_bisFloat = true; m_pSecWaveOut->Initialize(SecMonitor.Array(), 2, m_sAudioParam.iSamplesPerSec, m_sAudioParam.iBitPerSample * 2); } else { m_pSecWaveOut->Initialize(SecMonitor.Array(), 2, m_sAudioParam.iSamplesPerSec, m_sAudioParam.iBitPerSample); } } LeaveCriticalSection(&sampleBufferLock); this->MonitorDevices = MonitorDevices; this->SecMonitor = SecMonitor; Log::writeMessage(LOG_RTSPSERV, 1, "%s invoke end!", __FUNCTION__); }
void OBS::StartRecording() { if (bRecording) return; int networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2); bWriteToFile = networkMode == 1 || AppConfig->GetInt(TEXT("Publish"), TEXT("SaveToFile")) != 0; String strOutputFile = AppConfig->GetString(TEXT("Publish"), TEXT("SavePath")); strOutputFile.FindReplace(TEXT("\\"), TEXT("/")); // Don't request a keyframe while everything is starting up for the first time if(!bStartingUp) videoEncoder->RequestKeyframe(); if (bWriteToFile) { OSFindData ofd; HANDLE hFind = NULL; bool bUseDateTimeName = true; bool bOverwrite = GlobalConfig->GetInt(L"General", L"OverwriteRecordings", false) != 0; if(!bOverwrite && (hFind = OSFindFirstFile(strOutputFile, ofd))) { String strFileExtension = GetPathExtension(strOutputFile); String strFileWithoutExtension = GetPathWithoutExtension(strOutputFile); if(strFileExtension.IsValid() && !ofd.bDirectory) { String strNewFilePath; UINT curFile = 0; do { strNewFilePath.Clear() << strFileWithoutExtension << TEXT(" (") << FormattedString(TEXT("%02u"), ++curFile) << TEXT(").") << strFileExtension; } while(OSFileExists(strNewFilePath)); strOutputFile = strNewFilePath; bUseDateTimeName = false; } if(ofd.bDirectory) strOutputFile.AppendChar('/'); OSFindClose(hFind); } if(bUseDateTimeName) { String strFileName = GetPathFileName(strOutputFile); if(!strFileName.IsValid() || !IsSafeFilename(strFileName)) { SYSTEMTIME st; GetLocalTime(&st); String strDirectory = GetPathDirectory(strOutputFile); String file = strOutputFile.Right(strOutputFile.Length() - strDirectory.Length()); String extension; if (!file.IsEmpty()) extension = GetPathExtension(file.Array()); if(extension.IsEmpty()) extension = TEXT("mp4"); strOutputFile = FormattedString(TEXT("%s/%u-%02u-%02u-%02u%02u-%02u.%s"), strDirectory.Array(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, extension.Array()); } } } if(!bTestStream && bWriteToFile && strOutputFile.IsValid()) { String strFileExtension = GetPathExtension(strOutputFile); if(strFileExtension.CompareI(TEXT("flv"))) fileStream = CreateFLVFileStream(strOutputFile); else if(strFileExtension.CompareI(TEXT("mp4"))) fileStream = CreateMP4FileStream(strOutputFile); if(!fileStream) { Log(TEXT("Warning - OBSCapture::Start: Unable to create the file stream. Check the file path in Broadcast Settings.")); MessageBox(hwndMain, Str("Capture.Start.FileStream.Warning"), Str("Capture.Start.FileStream.WarningCaption"), MB_OK | MB_ICONWARNING); bRecording = false; } else { bRecording = true; ReportStartRecordingTrigger(); } ConfigureStreamButtons(); } }
void NVENCEncoder::init() { NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS stEncodeSessionParams = {0}; NV_ENC_PRESET_CONFIG presetConfig = {0}; GUID clientKey = NV_CLIENT_KEY; CUcontext cuContextCurr; NVENCSTATUS nvStatus = NV_ENC_SUCCESS; int surfaceCount = 0; GUID encoderPreset = NV_ENC_PRESET_HQ_GUID; dontTouchConfig = false; bool is2PassRC = false; String profileString = AppConfig->GetString(TEXT("Video Encoding"), TEXT("X264Profile"), TEXT("high")); String presetString = AppConfig->GetString(TEXT("Video Encoding"), TEXT("NVENCPreset"), TEXT("High Quality")); if (presetString == TEXT("High Performance")) { encoderPreset = NV_ENC_PRESET_HP_GUID; } else if (presetString == TEXT("High Quality")) { encoderPreset = NV_ENC_PRESET_HQ_GUID; } else if (presetString == TEXT("Bluray Disk")) { encoderPreset = NV_ENC_PRESET_BD_GUID; } else if (presetString == TEXT("Low Latency (2pass)")) { encoderPreset = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID; is2PassRC = true; } else if (presetString == TEXT("High Performance Low Latency (2pass)")) { encoderPreset = NV_ENC_PRESET_LOW_LATENCY_HP_GUID; is2PassRC = true; } else if (presetString == TEXT("High Quality Low Latency (2pass)")) { encoderPreset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID; is2PassRC = true; } else if (presetString == TEXT("Low Latency")) { encoderPreset = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID; } else if (presetString == TEXT("High Performance Low Latency")) { encoderPreset = NV_ENC_PRESET_LOW_LATENCY_HP_GUID; } else if (presetString == TEXT("High Quality Low Latency")) { encoderPreset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID; } else if (presetString == TEXT("Lossless")) { encoderPreset = NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID; dontTouchConfig = true; } else if (presetString == TEXT("High Performance Lossless")) { encoderPreset = NV_ENC_PRESET_LOSSLESS_HP_GUID; dontTouchConfig = true; } else if (presetString == TEXT("NVDefault")) { encoderPreset = NV_ENC_PRESET_DEFAULT_GUID; } else if (presetString == TEXT("Streaming")) { encoderPreset = NV_ENC_PRESET_STREAMING; clientKey = NV_ENC_KEY_STREAMING; } else if (presetString == TEXT("Streaming (2pass)")) { encoderPreset = NV_ENC_PRESET_STREAMING; is2PassRC = true; clientKey = NV_ENC_KEY_STREAMING; } else { if (height > 1080 || (height == 1080 && fps > 30)) { encoderPreset = NV_ENC_PRESET_HQ_GUID; } if (height > 720 || (height == 720 && fps > 30)) { encoderPreset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID; } else { encoderPreset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID; is2PassRC = true; } } TCHAR envClientKey[128] = {0}; DWORD envRes = GetEnvironmentVariable(TEXT("NVENC_KEY"), envClientKey, 128); if (envRes > 0 && envRes <= 128) { if (stringToGuid(envClientKey, &clientKey)) { NvLog(TEXT("Got NVENC key from environment")); } else { NvLog(TEXT("NVENC_KEY environment variable has invalid format")); } } mset(&initEncodeParams, 0, sizeof(NV_ENC_INITIALIZE_PARAMS)); mset(&encodeConfig, 0, sizeof(NV_ENC_CONFIG)); encodeConfig.version = NV_ENC_CONFIG_VER; presetConfig.version = NV_ENC_PRESET_CONFIG_VER; presetConfig.presetCfg.version = NV_ENC_CONFIG_VER; initEncodeParams.version = NV_ENC_INITIALIZE_PARAMS_VER; stEncodeSessionParams.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER; stEncodeSessionParams.apiVersion = NVENCAPI_VERSION; stEncodeSessionParams.clientKeyPtr = &clientKey; cuContext = 0; checkCudaErrors(cuCtxCreate(&cuContext, 0, pNvencDevices[iNvencUseDeviceID])); checkCudaErrors(cuCtxPopCurrent(&cuContextCurr)); stEncodeSessionParams.device = (void*)cuContext; stEncodeSessionParams.deviceType = NV_ENC_DEVICE_TYPE_CUDA; nvStatus = pNvEnc->nvEncOpenEncodeSessionEx(&stEncodeSessionParams, &encoder); if (nvStatus != NV_ENC_SUCCESS) { encoder = 0; OBSMessageBox(NULL, Str("Encoder.NVENC.OldDriver"), NULL, MB_OK | MB_ICONERROR); NvLog(TEXT("nvEncOpenEncodeSessionEx failed with 0x%x - outdated driver?"), nvStatus); goto error; } if (!populateEncodePresetGUIDs()) goto error; if (!checkPresetSupport(encoderPreset)) { NvLog(TEXT("Preset is not supported!")); goto error; } nvStatus = pNvEnc->nvEncGetEncodePresetConfig(encoder, NV_ENC_CODEC_H264_GUID, encoderPreset, &presetConfig); if (nvStatus != NV_ENC_SUCCESS) { NvLog(TEXT("nvEncGetEncodePresetConfig failed with 0x%x"), nvStatus); goto error; } initEncodeParams.encodeGUID = NV_ENC_CODEC_H264_GUID; initEncodeParams.encodeHeight = height; initEncodeParams.encodeWidth = width; initEncodeParams.darHeight = height; initEncodeParams.darWidth = width; initEncodeParams.frameRateNum = fps; initEncodeParams.frameRateDen = 1; initEncodeParams.enableEncodeAsync = 0; initEncodeParams.enablePTD = 1; initEncodeParams.presetGUID = encoderPreset; initEncodeParams.encodeConfig = &encodeConfig; memcpy(&encodeConfig, &presetConfig.presetCfg, sizeof(NV_ENC_CONFIG)); encodeConfig.version = NV_ENC_CONFIG_VER; if (!dontTouchConfig) { if (keyint != 0) encodeConfig.gopLength = keyint * fps; if (maxBitRate != -1) { encodeConfig.rcParams.averageBitRate = maxBitRate * 1000; encodeConfig.rcParams.maxBitRate = maxBitRate * 1000; } if (bufferSize != -1) { encodeConfig.rcParams.vbvBufferSize = bufferSize * 1000; encodeConfig.rcParams.vbvInitialDelay = bufferSize * 1000; } if (bUseCBR) { auto filler = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("PadCBR"), 1) != 0; if (is2PassRC) { encodeConfig.rcParams.rateControlMode = filler ? NV_ENC_PARAMS_RC_2_PASS_FRAMESIZE_CAP : NV_ENC_PARAMS_RC_2_PASS_VBR; } else { encodeConfig.rcParams.rateControlMode = filler ? NV_ENC_PARAMS_RC_CBR : NV_ENC_PARAMS_RC_VBR; } encodeConfig.frameIntervalP = 1; encodeConfig.encodeCodecConfig.h264Config.adaptiveTransformMode = NV_ENC_H264_ADAPTIVE_TRANSFORM_ENABLE; encodeConfig.encodeCodecConfig.h264Config.fmoMode = NV_ENC_H264_FMO_DISABLE; } else { encodeConfig.rcParams.rateControlMode = NV_ENC_PARAMS_RC_VBR_MINQP; encodeConfig.rcParams.enableMinQP = 1; encodeConfig.rcParams.minQP.qpInterB = 32 - quality; encodeConfig.rcParams.minQP.qpInterP = 32 - quality; encodeConfig.rcParams.minQP.qpIntra = 32 - quality; encodeConfig.frameIntervalP = 3; } encodeConfig.encodeCodecConfig.h264Config.outputBufferingPeriodSEI = 1; encodeConfig.encodeCodecConfig.h264Config.outputPictureTimingSEI = 1; encodeConfig.encodeCodecConfig.h264Config.disableSPSPPS = 1; encodeConfig.encodeCodecConfig.h264Config.enableVFR = bUseCFR ? 0 : 1; encodeConfig.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME; if(profileString.CompareI(TEXT("main"))) encodeConfig.profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID; else if(profileString.CompareI(TEXT("high"))) encodeConfig.profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID; encodeConfig.encodeCodecConfig.h264Config.disableSPSPPS = 1; encodeConfig.encodeCodecConfig.h264Config.bdirectMode = encodeConfig.frameIntervalP > 1 ? NV_ENC_H264_BDIRECT_MODE_TEMPORAL : NV_ENC_H264_BDIRECT_MODE_DISABLE; encodeConfig.encodeCodecConfig.h264Config.idrPeriod = encodeConfig.gopLength; encodeConfig.encodeCodecConfig.h264Config.h264VUIParameters.videoSignalTypePresentFlag = 1; encodeConfig.encodeCodecConfig.h264Config.h264VUIParameters.colourDescriptionPresentFlag = 1; encodeConfig.encodeCodecConfig.h264Config.h264VUIParameters.colourMatrix = colorDesc.matrix; encodeConfig.encodeCodecConfig.h264Config.h264VUIParameters.videoFullRangeFlag = colorDesc.fullRange; encodeConfig.encodeCodecConfig.h264Config.h264VUIParameters.videoFormat = 5; encodeConfig.encodeCodecConfig.h264Config.h264VUIParameters.colourPrimaries = colorDesc.primaries; encodeConfig.encodeCodecConfig.h264Config.h264VUIParameters.transferCharacteristics = colorDesc.transfer; } nvStatus = pNvEnc->nvEncInitializeEncoder(encoder, &initEncodeParams); if (nvStatus != NV_ENC_SUCCESS) { NvLog(TEXT("nvEncInitializeEncoder failed with 0x%x"), nvStatus); goto error; } for (surfaceCount = 0; surfaceCount < maxSurfaceCount; ++surfaceCount) { NV_ENC_CREATE_INPUT_BUFFER allocSurf = { 0 }; allocSurf.version = NV_ENC_CREATE_INPUT_BUFFER_VER; allocSurf.width = (width + 31) & ~31; allocSurf.height = (height + 31) & ~31; allocSurf.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED; allocSurf.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12_PL; nvStatus = pNvEnc->nvEncCreateInputBuffer(encoder, &allocSurf); if (nvStatus != NV_ENC_SUCCESS) { NvLog(TEXT("nvEncCreateInputBuffer #%d failed with 0x%x"), surfaceCount, nvStatus); goto error; } inputSurfaces[surfaceCount].width = allocSurf.width; inputSurfaces[surfaceCount].height = allocSurf.height; inputSurfaces[surfaceCount].locked = false; inputSurfaces[surfaceCount].useCount = 0; inputSurfaces[surfaceCount].inputSurface = allocSurf.inputBuffer; NV_ENC_CREATE_BITSTREAM_BUFFER allocOut = { 0 }; allocOut.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER; allocOut.size = outBufferSize; allocOut.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED; nvStatus = pNvEnc->nvEncCreateBitstreamBuffer(encoder, &allocOut); if (nvStatus != NV_ENC_SUCCESS) { NvLog(TEXT("Failed allocating bitstream #%d buffer with 0x%x"), surfaceCount, nvStatus); outputSurfaces[surfaceCount].outputSurface = 0; surfaceCount += 1; goto error; } outputSurfaces[surfaceCount].outputSurface = allocOut.bitstreamBuffer; outputSurfaces[surfaceCount].size = allocOut.size; outputSurfaces[surfaceCount].busy = false; } NvLog(TEXT("------------------------------------------")); NvLog(TEXT("%s"), GetInfoString().Array()); NvLog(TEXT("------------------------------------------")); alive = true; return; error: alive = false; for (int i = 0; i < surfaceCount; ++i) { pNvEnc->nvEncDestroyInputBuffer(encoder, inputSurfaces[i].inputSurface); if (outputSurfaces[i].outputSurface != 0) pNvEnc->nvEncDestroyBitstreamBuffer(encoder, outputSurfaces[i].outputSurface); } surfaceCount = 0; if (encoder) pNvEnc->nvEncDestroyEncoder(encoder); encoder = 0; if (cuContext) cuCtxDestroy(cuContext); }
void SettingsAudio::ApplySettings() { UINT iPlaybackDevice = (UINT)SendMessage(GetDlgItem(hwnd, IDC_PLAYBACKDEVICES), CB_GETCURSEL, 0, 0); String strPlaybackDevice; if(iPlaybackDevice == CB_ERR) { strPlaybackDevice = TEXT("Default"); } else { strPlaybackDevice = storage->playbackDevices->devices[iPlaybackDevice].strID; } AppConfig->SetString(TEXT("Audio"), TEXT("PlaybackDevice"), strPlaybackDevice); UINT iDevice = (UINT)SendMessage(GetDlgItem(hwnd, IDC_MICDEVICES), CB_GETCURSEL, 0, 0); String strDevice; if(iDevice == CB_ERR) strDevice = TEXT("Disable"); else strDevice = storage->recordingDevices->devices[iDevice].strID; AppConfig->SetString(TEXT("Audio"), TEXT("Device"), strDevice); if(strDevice.CompareI(TEXT("Disable"))) EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE); else EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), TRUE); //------------------------------------ App->bUsingPushToTalk = SendMessage(GetDlgItem(hwnd, IDC_PUSHTOTALK), BM_GETCHECK, 0, 0) == BST_CHECKED; DWORD hotkey = (DWORD)SendMessage(GetDlgItem(hwnd, IDC_PUSHTOTALKHOTKEY), HKM_GETHOTKEY, 0, 0); DWORD hotkey2 = (DWORD)SendMessage(GetDlgItem(hwnd, IDC_PUSHTOTALKHOTKEY2), HKM_GETHOTKEY, 0, 0); App->pushToTalkDelay = (int)SendMessage(GetDlgItem(hwnd, IDC_PTTDELAY), UDM_GETPOS32, 0, 0); if(App->pushToTalkDelay < 0) App->pushToTalkDelay = 0; else if(App->pushToTalkDelay > 2000) App->pushToTalkDelay = 2000; AppConfig->SetInt(TEXT("Audio"), TEXT("UsePushToTalk"), App->bUsingPushToTalk); AppConfig->SetInt(TEXT("Audio"), TEXT("PushToTalkHotkey"), hotkey); AppConfig->SetInt(TEXT("Audio"), TEXT("PushToTalkHotkey2"), hotkey2); AppConfig->SetInt(TEXT("Audio"), TEXT("PushToTalkDelay"), (int)App->pushToTalkDelay); if(App->pushToTalkHotkeyID) { API->DeleteHotkey(App->pushToTalkHotkeyID); App->pushToTalkHotkeyID = 0; } if(App->bUsingPushToTalk && hotkey) App->pushToTalkHotkeyID = API->CreateHotkey(hotkey, OBS::PushToTalkHotkey, NULL); if(App->bUsingPushToTalk && hotkey2) App->pushToTalkHotkeyID = API->CreateHotkey(hotkey2, OBS::PushToTalkHotkey, NULL); //------------------------------------ hotkey = (DWORD)SendMessage(GetDlgItem(hwnd, IDC_MUTEMICHOTKEY), HKM_GETHOTKEY, 0, 0); AppConfig->SetInt(TEXT("Audio"), TEXT("MuteMicHotkey"), hotkey); if(App->muteMicHotkeyID) { API->DeleteHotkey(App->muteMicHotkeyID); App->muteDesktopHotkeyID = 0; } if(hotkey) App->muteMicHotkeyID = API->CreateHotkey(hotkey, OBS::MuteMicHotkey, NULL); //------------------------------------ hotkey = (DWORD)SendMessage(GetDlgItem(hwnd, IDC_MUTEDESKTOPHOTKEY), HKM_GETHOTKEY, 0, 0); AppConfig->SetInt(TEXT("Audio"), TEXT("MuteDesktopHotkey"), hotkey); if(App->muteDesktopHotkeyID) { API->DeleteHotkey(App->muteDesktopHotkeyID); App->muteDesktopHotkeyID = 0; } if(hotkey) App->muteDesktopHotkeyID = API->CreateHotkey(hotkey, OBS::MuteDesktopHotkey, NULL); //------------------------------------ App->bForceMicMono = SendMessage(GetDlgItem(hwnd, IDC_FORCEMONO), BM_GETCHECK, 0, 0) == BST_CHECKED; AppConfig->SetInt(TEXT("Audio"), TEXT("ForceMicMono"), App->bForceMicMono); //------------------------------------ DWORD desktopBoostMultiple = (DWORD)SendMessage(GetDlgItem(hwnd, IDC_DESKTOPBOOST), UDM_GETPOS32, 0, 0); if(desktopBoostMultiple < 1) desktopBoostMultiple = 1; else if(desktopBoostMultiple > 20) desktopBoostMultiple = 20; GlobalConfig->SetInt(TEXT("Audio"), TEXT("DesktopBoostMultiple"), desktopBoostMultiple); App->desktopBoost = float(desktopBoostMultiple); //------------------------------------ DWORD micBoostMultiple = (DWORD)SendMessage(GetDlgItem(hwnd, IDC_MICBOOST), UDM_GETPOS32, 0, 0); if(micBoostMultiple < 1) micBoostMultiple = 1; else if(micBoostMultiple > 20) micBoostMultiple = 20; AppConfig->SetInt(TEXT("Audio"), TEXT("MicBoostMultiple"), micBoostMultiple); App->micBoost = float(micBoostMultiple); //------------------------------------ int micTimeOffset = (int)SendMessage(GetDlgItem(hwnd, IDC_MICTIMEOFFSET), UDM_GETPOS32, 0, 0); if(micTimeOffset < -150) micTimeOffset = -150; else if(micTimeOffset > 20000) micTimeOffset = 20000; AppConfig->SetInt(TEXT("Audio"), TEXT("MicTimeOffset"), micTimeOffset); if(App->bRunning && App->micAudio) App->micAudio->SetTimeOffset(micTimeOffset); }
bool OBS::SetScene(CTSTR lpScene) { if(bDisableSceneSwitching) return false; HWND hwndScenes = GetDlgItem(hwndMain, ID_SCENES); UINT curSel = (UINT)SendMessage(hwndScenes, LB_GETCURSEL, 0, 0); //------------------------- if(curSel != LB_ERR) { UINT textLen = (UINT)SendMessage(hwndScenes, LB_GETTEXTLEN, curSel, 0); String strLBName; strLBName.SetLength(textLen); SendMessage(hwndScenes, LB_GETTEXT, curSel, (LPARAM)strLBName.Array()); if(!strLBName.CompareI(lpScene)) { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } } else { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } //------------------------- XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); XElement *newSceneElement = scenes->GetElement(lpScene); if(!newSceneElement) return false; if(sceneElement == newSceneElement) return true; sceneElement = newSceneElement; CTSTR lpClass = sceneElement->GetString(TEXT("class")); if(!lpClass) { AppWarning(TEXT("OBS::SetScene: no class found for scene '%s'"), newSceneElement->GetName()); return false; } if(bRunning) { Log(TEXT("++++++++++++++++++++++++++++++++++++++++++++++++++++++")); Log(TEXT(" New Scene")); } XElement *sceneData = newSceneElement->GetElement(TEXT("data")); //------------------------- Scene *newScene = NULL; if(bRunning) newScene = CreateScene(lpClass, sceneData); //------------------------- HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)FALSE, (LPARAM) 0); bChangingSources = true; ListView_DeleteAllItems(hwndSources); XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); ListView_SetItemCount(hwndSources, numSources); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); bool render = sourceElement->GetInt(TEXT("render"), 1) > 0; AddSourceItem((LPWSTR)sourceElement->GetName(), render, i); if(bRunning && newScene) newScene->AddImageSource(sourceElement); } } bChangingSources = false; SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)TRUE, (LPARAM) 0); RedrawWindow(hwndSources, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); if(scene && newScene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); if(bRunning) { //todo: cache scenes maybe? undecided. not really as necessary with global sources OSEnterMutex(hSceneMutex); if(scene) scene->EndScene(); Scene *previousScene = scene; scene = newScene; scene->BeginScene(); if(!bTransitioning) { bTransitioning = true; transitionAlpha = 0.0f; } OSLeaveMutex(hSceneMutex); delete previousScene; } return true; }
void OBS::Stop() { if(!bRunning) return; OSEnterMutex(hStartupShutdownMutex); //we only want the capture thread to stop first, so we can ensure all packets are flushed bShutdownEncodeThread = true; ShowWindow(hwndProjector, SW_HIDE); if(hEncodeThread) { OSTerminateThread(hEncodeThread, 30000); hEncodeThread = NULL; } bShutdownVideoThread = true; SetEvent(hVideoEvent); if(hVideoThread) { OSTerminateThread(hVideoThread, 30000); hVideoThread = NULL; } bRunning = false; ReportStopStreamTrigger(); for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].source->EndScene(); if(scene) scene->EndScene(); //------------------------------------------------------------- if(hSoundThread) { //ReleaseSemaphore(hRequestAudioEvent, 1, NULL); OSTerminateThread(hSoundThread, 20000); } //if(hRequestAudioEvent) // CloseHandle(hRequestAudioEvent); if(hSoundDataMutex) OSCloseMutex(hSoundDataMutex); hSoundThread = NULL; //hRequestAudioEvent = NULL; hSoundDataMutex = NULL; //------------------------------------------------------------- StopBlankSoundPlayback(); //------------------------------------------------------------- delete network; network = NULL; delete fileStream; fileStream = NULL; delete micAudio; micAudio = NULL; delete desktopAudio; desktopAudio = NULL; delete audioEncoder; audioEncoder = NULL; delete videoEncoder; videoEncoder = NULL; //------------------------------------------------------------- for(UINT i=0; i<pendingAudioFrames.Num(); i++) pendingAudioFrames[i].audioData.Clear(); pendingAudioFrames.Clear(); //------------------------------------------------------------- if(GS) GS->UnloadAllData(); //------------------------------------------------------------- delete scene; scene = NULL; for(UINT i=0; i<globalSources.Num(); i++) globalSources[i].FreeData(); globalSources.Clear(); //------------------------------------------------------------- for(UINT i=0; i<auxAudioSources.Num(); i++) delete auxAudioSources[i]; auxAudioSources.Clear(); //------------------------------------------------------------- for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { delete mainRenderTextures[i]; delete yuvRenderTextures[i]; mainRenderTextures[i] = NULL; yuvRenderTextures[i] = NULL; } for(UINT i=0; i<NUM_RENDER_BUFFERS; i++) { SafeRelease(copyTextures[i]); } delete transitionTexture; transitionTexture = NULL; //------------------------------------------------------------- delete mainVertexShader; delete mainPixelShader; delete yuvScalePixelShader; delete solidVertexShader; delete solidPixelShader; mainVertexShader = NULL; mainPixelShader = NULL; yuvScalePixelShader = NULL; solidVertexShader = NULL; solidPixelShader = NULL; //------------------------------------------------------------- delete GS; GS = NULL; //------------------------------------------------------------- ResizeRenderFrame(false); RedrawWindow(hwndRenderFrame, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW); //------------------------------------------------------------- AudioDeviceList audioDevices; GetAudioDevices(audioDevices, ADT_RECORDING); String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL); if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice)) { AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable")); strDevice = TEXT("Disable"); } audioDevices.FreeData(); EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), !strDevice.CompareI(TEXT("Disable"))); //------------------------------------------------------------- ClearStreamInfo(); DumpProfileData(); FreeProfileData(); Log(TEXT("=====Stream End: %s================================================="), CurrentDateTimeString().Array()); //update notification icon to reflect current status UpdateNotificationAreaIcon(); SetWindowText(GetDlgItem(hwndMain, ID_TESTSTREAM), Str("MainWindow.TestStream")); EnableWindow(GetDlgItem(hwndMain, ID_STARTSTOP), TRUE); SetWindowText(GetDlgItem(hwndMain, ID_STARTSTOP), Str("MainWindow.StartStream")); EnableWindow(GetDlgItem(hwndMain, ID_TESTSTREAM), TRUE); bEditMode = false; SendMessage(GetDlgItem(hwndMain, ID_SCENEEDITOR), BM_SETCHECK, BST_UNCHECKED, 0); EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), FALSE); ClearStatusBar(); InvalidateRect(hwndRenderFrame, NULL, TRUE); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, 0, 0); SetThreadExecutionState(ES_CONTINUOUS); String processPriority = AppConfig->GetString(TEXT("General"), TEXT("Priority"), TEXT("Normal")); if (scmp(processPriority, TEXT("Normal"))) SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); bTestStream = false; UpdateRenderViewMessage(); OSLeaveMutex(hStartupShutdownMutex); }
BOOL ShaderProcessor::AddState(SamplerInfo &info, String &stateName, String &stateVal) { if(scmpi_n(stateName, TEXT("Address"), 7) == 0) { int type = stateName[7]-'U'; GSAddressMode *mode; switch(type) { case 0: mode = &info.addressU; break; case 1: mode = &info.addressV; break; case 2: mode = &info.addressW; break; default: CrashError(TEXT("Invalid shader address type %d"), type); } if(stateVal.CompareI(TEXT("Wrap")) || stateVal.CompareI(TEXT("Repeat"))) *mode = GS_ADDRESS_WRAP; else if(stateVal.CompareI(TEXT("Clamp")) || stateVal.CompareI(TEXT("None"))) *mode = GS_ADDRESS_CLAMP; else if(stateVal.CompareI(TEXT("Mirror"))) *mode = GS_ADDRESS_MIRROR; else if(stateVal.CompareI(TEXT("Border"))) *mode = GS_ADDRESS_BORDER; else if(stateVal.CompareI(TEXT("MirrorOnce"))) *mode = GS_ADDRESS_MIRRORONCE; } else if(stateName.CompareI(TEXT("MaxAnisotropy"))) { info.maxAnisotropy = tstoi(stateVal); } else if(stateName.CompareI(TEXT("Filter"))) { if(stateVal.CompareI(TEXT("Anisotropic"))) info.filter = GS_FILTER_ANISOTROPIC; else if(stateVal.CompareI(TEXT("Point")) || stateVal.CompareI(TEXT("MIN_MAG_MIP_POINT"))) info.filter = GS_FILTER_POINT; else if(stateVal.CompareI(TEXT("Linear")) || stateVal.CompareI(TEXT("MIN_MAG_MIP_LINEAR"))) info.filter = GS_FILTER_LINEAR; else if(stateVal.CompareI(TEXT("MIN_MAG_POINT_MIP_LINEAR"))) info.filter = GS_FILTER_MIN_MAG_POINT_MIP_LINEAR; else if(stateVal.CompareI(TEXT("MIN_POINT_MAG_LINEAR_MIP_POINT"))) info.filter = GS_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; else if(stateVal.CompareI(TEXT("MIN_POINT_MAG_MIP_LINEAR"))) info.filter = GS_FILTER_MIN_POINT_MAG_MIP_LINEAR; else if(stateVal.CompareI(TEXT("MIN_LINEAR_MAG_MIP_POINT"))) info.filter = GS_FILTER_MIN_LINEAR_MAG_MIP_POINT; else if(stateVal.CompareI(TEXT("MIN_LINEAR_MAG_POINT_MIP_LINEAR"))) info.filter = GS_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; else if(stateVal.CompareI(TEXT("MIN_MAG_LINEAR_MIP_POINT"))) info.filter = GS_FILTER_MIN_MAG_LINEAR_MIP_POINT; } else if(stateName.CompareI(TEXT("BorderColor"))) { if(stateVal[0] == '{') { String curToken; HandMeAToken(curToken); if(!ValidFloatString(curToken)) {return FALSE;} info.borderColor.x = (float)tstof(curToken); //------------------------------- ExpectToken(TEXT(",")); //------------------------------- HandMeAToken(curToken); if(!ValidFloatString(curToken)) {return FALSE;} info.borderColor.y = (float)tstof(curToken); //------------------------------- ExpectToken(TEXT(",")); //------------------------------- HandMeAToken(curToken); if(!ValidFloatString(curToken)) {return FALSE;} info.borderColor.z = (float)tstof(curToken); //------------------------------- ExpectToken(TEXT(",")); //------------------------------- HandMeAToken(curToken); if(!ValidFloatString(curToken)) {return FALSE;} info.borderColor.w = (float)tstof(curToken); //------------------------------- ExpectToken(TEXT("}")); } else if(ValidIntString(stateVal)) info.borderColor = Color4().MakeFromRGBA(tstoi(stateVal)); } return TRUE; }
void PipeAudioSource::OnAudioDeviceChanged(const String &MonitorDevices, const String &SecMonitor) { if (this->MonitorDevices.Compare(MonitorDevices.Array()) && this->SecMonitor.Compare(SecMonitor.Array())) { return; } Log::writeMessage(LOG_RTSPSERV, 1, "%s invoke begin!", __FUNCTION__); OSEnterMutex(hAudioMutex); bSameDevice = false; if (m_pAudioWaveOut) { m_pAudioWaveOut->Uninitialize(); } if (NULL == m_pAudioWaveOut) { if (!MonitorDevices.Compare(TEXT("停用")) && !m_pAudioWaveOut) { m_pAudioWaveOut = new AudioWaveOut; } } else { if ((MonitorDevices.Compare(TEXT("Disable")) || MonitorDevices.Compare(TEXT("停用")))) { delete m_pAudioWaveOut; m_pAudioWaveOut = NULL; } } if (NULL != m_pAudioWaveOut) { m_pAudioWaveOut->Initialize(MonitorDevices.Array(), 2, Param.samplesPerSec, Param.bitsPerSample); } if (m_pSecWaveOut) { m_pSecWaveOut->Uninitialize(); } if (SecMonitor.CompareI(MonitorDevices.Array()) && (!SecMonitor.Compare(TEXT("Disable")) || !SecMonitor.Compare(TEXT("停用")))) { bSameDevice = true; } else if (!SecMonitor.Compare(TEXT("停用")) && !m_pSecWaveOut) { m_pSecWaveOut = new AudioWaveOut; } else if (m_pSecWaveOut) { if ((SecMonitor.Compare(TEXT("Disable")) || SecMonitor.Compare(TEXT("停用")))) { delete m_pSecWaveOut; m_pSecWaveOut = NULL; } } if (m_pSecWaveOut) { m_pSecWaveOut->Initialize(SecMonitor.Array(), 2, Param.samplesPerSec, Param.bitsPerSample); } OSLeaveMutex(hAudioMutex); this->MonitorDevices = MonitorDevices; this->SecMonitor = SecMonitor; Log::writeMessage(LOG_RTSPSERV, 1, "%s invoke end!", __FUNCTION__); }
X264Encoder(int fps, int width, int height, int quality, CTSTR preset, CTSTR ProFile, bool bUse444, ColorDescription &colorDesc, int maxBitrate, int bufferSize, bool bUseCFR, bool bUesBackConfig) { frameShift = 0; curPreset = preset; FPS = fps; fps_ms = 1000 / fps; StringList paramList; curProfile = ProFile; zero(¶mData, sizeof(paramData)); LPSTR lpPreset = curPreset.CreateUTF8String(); LPSTR lpTune = curTune.CreateUTF8String(); if (x264_param_default_preset(¶mData, lpPreset, lpTune)) Log::writeError(LOG_RTSPSERV,1,"LiveSDK_Log:Failed to set x264 defaults: %s/%s", curPreset.Array(), curTune.Array()); Free(lpTune); Free(lpPreset); this->width = width; this->height = height; paramData.b_deterministic = false; //分主次直播 if (bUesBackConfig) { bUseCBR = CSLiveManager::GetInstance()->BSParam.LiveSetting.bUseCBRSec; } else { bUseCBR = CSLiveManager::GetInstance()->BSParam.LiveSetting.bUseCBR; } bPadCBR = true; this->bUseCFR = bUseCFR; SetBitRateParams(maxBitrate, bufferSize); if (bUseCBR) { if (bPadCBR) paramData.rc.b_filler = 1; //if(bPadCBR) paramData.i_nal_hrd = X264_NAL_HRD_CBR; paramData.rc.i_rc_method = X264_RC_ABR; paramData.rc.f_rf_constant = 0.0f; } else { paramData.i_frame_reference = 5; paramData.rc.i_rc_method = X264_RC_CRF; paramData.rc.f_rf_constant = baseCRF + float(10 - quality); } //分主次直播 UINT keyframeInterval = CSLiveManager::GetInstance()->BSParam.LiveSetting.KeyFrame; if (bUesBackConfig) { keyframeInterval = CSLiveManager::GetInstance()->BSParam.LiveSetting.KeyFrameSec; } paramData.b_vfr_input = !bUseCFR; paramData.i_width = width; paramData.i_height = height; paramData.vui.b_fullrange = colorDesc.fullRange; paramData.vui.i_colorprim = colorDesc.primaries; paramData.vui.i_transfer = colorDesc.transfer; paramData.vui.i_colmatrix = colorDesc.matrix; if (keyframeInterval) paramData.i_keyint_max = fps*keyframeInterval; paramData.i_fps_num = fps; paramData.i_fps_den = 1; paramData.i_timebase_num = 1; paramData.i_timebase_den = 1000; paramData.pf_log = get_x264_log; paramData.i_log_level = X264_LOG_WARNING; //分主次直播 int nBFrameCount = CSLiveManager::GetInstance()->BSParam.LiveSetting.BFrameCount; if (bUesBackConfig) { nBFrameCount = CSLiveManager::GetInstance()->BSParam.LiveSetting.BFrameCountSec; } if (-1 != nBFrameCount) { paramData.i_bframe = nBFrameCount; } //录制高品质不能播放 paramData.b_vfr_input = 0; if (0 == nBFrameCount) { // http://bbs.csdn.net/topics/390922653 paramData.rc.i_lookahead = 0; paramData.i_sync_lookahead = 0; paramData.i_bframe = 0; paramData.b_sliced_threads = 1; paramData.rc.b_mb_tree = 0; } if (scmpi(curProfile, L"main") == 0) paramData.i_level_idc = 41; // to ensure compatibility with portable devices for (UINT i = 0; i<paramList.Num(); i++) { String &strParam = paramList[i]; if (!schr(strParam, '=')) continue; String strParamName = strParam.GetToken(0, '='); String strParamVal = strParam.GetTokenOffset(1, '='); if (strParamName.CompareI(TEXT("fps")) || strParamName.CompareI(TEXT("force-cfr"))) { Log(TEXT("The custom x264 command '%s' is unsupported, use the application settings instead"), strParam.Array()); continue; } else { LPSTR lpParam = strParamName.CreateUTF8String(); LPSTR lpVal = strParamVal.CreateUTF8String(); if (x264_param_parse(¶mData, lpParam, lpVal) != 0) Log(TEXT("The custom x264 command '%s' failed"), strParam.Array()); Free(lpParam); Free(lpVal); } } if (bUse444) paramData.i_csp = X264_CSP_I444; else paramData.i_csp = X264_CSP_I420; colorDesc.fullRange = paramData.vui.b_fullrange; colorDesc.primaries = paramData.vui.i_colorprim; colorDesc.transfer = paramData.vui.i_transfer; colorDesc.matrix = paramData.vui.i_colmatrix; if (curProfile) { LPSTR lpProfile = curProfile.CreateUTF8String(); if (x264_param_apply_profile(¶mData, lpProfile)) Log::writeMessage(LOG_RTSPSERV,1,"LiveSDK_Log:Failed to set x264 profile: %s", curProfile.Array()); Free(lpProfile); } }