BOOL CreatePath(CTSTR lpPath) { if(OSFileExists(lpPath)) return true; if(OSCreateDirectory(lpPath)) return true; else if(!CreatePath(GetPathDirectory(lpPath))) return false; return OSCreateDirectory(lpPath); }
BOOL CreatePath(CTSTR lpPath) { if(OSFileExists(lpPath)) return true; if(OSCreateDirectory(lpPath)) return true; else { String parent = GetPathDirectory(lpPath); if (parent == lpPath) return false; if (!CreatePath(parent)) return false; } return OSCreateDirectory(lpPath); }
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); }
INT_PTR CALLBACK ConfigureBitmapTransitionProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: { ConfigBitmapInfo *configInfo = (ConfigBitmapInfo*)lParam; SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)configInfo); LocalizeWindow(hwnd); //-------------------------- HWND hwndTemp = GetDlgItem(hwnd, IDC_BITMAPS); StringList bitmapList; configInfo->data->GetStringList(TEXT("bitmap"), bitmapList); for(UINT i=0; i<bitmapList.Num(); i++) { CTSTR lpBitmap = bitmapList[i]; if(OSFileExists(lpBitmap)) SendMessage(hwndTemp, LB_ADDSTRING, 0, (LPARAM)lpBitmap); } //-------------------------- hwndTemp = GetDlgItem(hwnd, IDC_TRANSITIONTIME); UINT transitionTime = configInfo->data->GetInt(TEXT("transitionTime")); SendMessage(hwndTemp, UDM_SETRANGE32, MIN_TRANSITION_TIME, MAX_TRANSITION_TIME); if(!transitionTime) transitionTime = 10; SendMessage(hwndTemp, UDM_SETPOS32, 0, transitionTime); EnableWindow(GetDlgItem(hwnd, IDC_REPLACE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_REMOVE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_MOVEUPWARD), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_MOVEDOWNWARD), FALSE); //-------------------------- BOOL bFadeInOnly = configInfo->data->GetInt(TEXT("fadeInOnly"), 1); BOOL bDisableFading = configInfo->data->GetInt(TEXT("disableFading")); BOOL bRandomize = configInfo->data->GetInt(TEXT("randomize")); SendMessage(GetDlgItem(hwnd, IDC_FADEINONLY), BM_SETCHECK, bFadeInOnly ? BST_CHECKED : BST_UNCHECKED, 0); SendMessage(GetDlgItem(hwnd, IDC_DISABLEFADING), BM_SETCHECK, bDisableFading ? BST_CHECKED : BST_UNCHECKED, 0); SendMessage(GetDlgItem(hwnd, IDC_RANDOMIZE), BM_SETCHECK, bRandomize ? BST_CHECKED : BST_UNCHECKED, 0); EnableWindow(GetDlgItem(hwnd, IDC_FADEINONLY), !bDisableFading); return TRUE; } case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_ADD: { TSTR lpFile = (TSTR)Allocate(32*1024*sizeof(TCHAR)); zero(lpFile, 32*1024*sizeof(TCHAR)); OPENFILENAME ofn; zero(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.lpstrFile = lpFile; ofn.hwndOwner = hwnd; ofn.nMaxFile = 32*1024*sizeof(TCHAR); ofn.lpstrFilter = TEXT("All Formats (*.bmp;*.dds;*.jpg;*.png;*.gif)\0*.bmp;*.dds;*.jpg;*.png;*.gif\0"); ofn.nFilterIndex = 1; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER; TCHAR curDirectory[MAX_PATH+1]; GetCurrentDirectory(MAX_PATH, curDirectory); BOOL bOpenFile = GetOpenFileName(&ofn); TCHAR newDirectory[MAX_PATH+1]; GetCurrentDirectory(MAX_PATH, newDirectory); SetCurrentDirectory(curDirectory); if(bOpenFile) { TSTR lpCurFile = lpFile+ofn.nFileOffset; while(lpCurFile && *lpCurFile) { String strPath; strPath << newDirectory << TEXT("\\") << lpCurFile; SendMessage(GetDlgItem(hwnd, IDC_BITMAPS), LB_ADDSTRING, 0, (LPARAM)strPath.Array()); lpCurFile += slen(lpCurFile)+1; } } Free(lpFile); break; } case IDC_BITMAPS: if(HIWORD(wParam) == LBN_SELCHANGE) { EnableWindow(GetDlgItem(hwnd, IDC_REPLACE), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_REMOVE), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_MOVEUPWARD), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_MOVEDOWNWARD), TRUE); } break; case IDC_REMOVE: { UINT curSel = (UINT)SendMessage(GetDlgItem(hwnd, IDC_BITMAPS), LB_GETCURSEL, 0, 0); if(curSel != LB_ERR) { SendMessage(GetDlgItem(hwnd, IDC_BITMAPS), LB_DELETESTRING, curSel, 0); EnableWindow(GetDlgItem(hwnd, IDC_REPLACE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_REMOVE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_MOVEUPWARD), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_MOVEDOWNWARD), FALSE); } } break; case IDC_MOVEUPWARD: { HWND hwndBitmaps = GetDlgItem(hwnd, IDC_BITMAPS); UINT curSel = (UINT)SendMessage(hwndBitmaps, LB_GETCURSEL, 0, 0); if(curSel != LB_ERR) { if(curSel > 0) { String strText = GetLBText(hwndBitmaps, curSel); SendMessage(hwndBitmaps, LB_DELETESTRING, curSel, 0); SendMessage(hwndBitmaps, LB_INSERTSTRING, --curSel, (LPARAM)strText.Array()); PostMessage(hwndBitmaps, LB_SETCURSEL, curSel, 0); } } } break; case IDC_MOVEDOWNWARD: { HWND hwndBitmaps = GetDlgItem(hwnd, IDC_BITMAPS); UINT numBitmaps = (UINT)SendMessage(hwndBitmaps, LB_GETCOUNT, 0, 0); UINT curSel = (UINT)SendMessage(hwndBitmaps, LB_GETCURSEL, 0, 0); if(curSel != LB_ERR) { if(curSel < (numBitmaps-1)) { String strText = GetLBText(hwndBitmaps, curSel); SendMessage(hwndBitmaps, LB_DELETESTRING, curSel, 0); SendMessage(hwndBitmaps, LB_INSERTSTRING, ++curSel, (LPARAM)strText.Array()); PostMessage(hwndBitmaps, LB_SETCURSEL, curSel, 0); } } } break; case IDC_DISABLEFADING: { BOOL bDisableFading = SendMessage(GetDlgItem(hwnd, IDC_DISABLEFADING), BM_GETCHECK, 0, 0) == BST_CHECKED; EnableWindow(GetDlgItem(hwnd, IDC_FADEINONLY), !bDisableFading); } break; case IDOK: { HWND hwndBitmaps = GetDlgItem(hwnd, IDC_BITMAPS); UINT numBitmaps = (UINT)SendMessage(hwndBitmaps, LB_GETCOUNT, 0, 0); if(!numBitmaps) { OBSMessageBox(hwnd, Str("Sources.TransitionSource.Empty"), NULL, 0); break; } //--------------------------- StringList bitmapList; for(UINT i=0; i<numBitmaps; i++) bitmapList << GetLBText(hwndBitmaps, i); ConfigBitmapInfo *configInfo = (ConfigBitmapInfo*)GetWindowLongPtr(hwnd, DWLP_USER); D3DX11_IMAGE_INFO ii; if(SUCCEEDED(D3DX11GetImageInfoFromFile(bitmapList[0], NULL, &ii, NULL))) { configInfo->cx = ii.Width; configInfo->cy = ii.Height; } else { configInfo->cx = configInfo->cy = 32; AppWarning(TEXT("ConfigureBitmapTransitionSource: could not get image info for bitmap '%s'"), bitmapList[0].Array()); } configInfo->data->SetStringList(TEXT("bitmap"), bitmapList); UINT transitionTime = (UINT)SendMessage(GetDlgItem(hwnd, IDC_TRANSITIONTIME), UDM_GETPOS32, 0, 0); configInfo->data->SetInt(TEXT("transitionTime"), transitionTime); BOOL bFadeInOnly = SendMessage(GetDlgItem(hwnd, IDC_FADEINONLY), BM_GETCHECK, 0, 0) == BST_CHECKED; BOOL bDisableFading = SendMessage(GetDlgItem(hwnd, IDC_DISABLEFADING), BM_GETCHECK, 0, 0) == BST_CHECKED; BOOL bRandomize = SendMessage(GetDlgItem(hwnd, IDC_RANDOMIZE), BM_GETCHECK, 0, 0) == BST_CHECKED; configInfo->data->SetInt(TEXT("fadeInOnly"), bFadeInOnly); configInfo->data->SetInt(TEXT("disableFading"), bDisableFading); configInfo->data->SetInt(TEXT("randomize"), bRandomize); } case IDCANCEL: EndDialog(hwnd, LOWORD(wParam)); break; } break; } return 0; }
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(); } }
String GetOutputFilename(bool replayBuffer=false) { String path = OSGetDefaultVideoSavePath(replayBuffer ? L"\\Replay-$T.flv" : L"\\.flv"); String strOutputFile = AppConfig->GetString(TEXT("Publish"), replayBuffer ? L"ReplayBufferSavePath" : L"SavePath", path.IsValid() ? path.Array() : nullptr); strOutputFile.FindReplace(TEXT("\\"), TEXT("/")); OSFindData ofd; HANDLE hFind = NULL; bool bUseDateTimeName = true; bool bOverwrite = GlobalConfig->GetInt(L"General", L"OverwriteRecordings", false) != 0; strOutputFile = ExpandRecordingFilename(strOutputFile); CreatePath(GetPathDirectory(strOutputFile)); 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()); } } return strOutputFile; }
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 ParseUpdateManifest (TCHAR *path, BOOL *updatesAvailable, String &description) { XConfig manifest; XElement *root; if (!manifest.Open(path)) return FALSE; root = manifest.GetRootElement(); DWORD numPackages = root->NumElements(); DWORD totalUpdatableFiles = 0; int priority, bestPriority = 999; for (DWORD i = 0; i < numPackages; i++) { XElement *package; package = root->GetElementByID(i); CTSTR packageName = package->GetName(); //find out if this package is relevant to us String platform = package->GetString(TEXT("platform")); if (!platform) continue; if (scmp(platform, TEXT("all"))) { #ifndef _WIN64 if (scmp(platform, TEXT("Win32"))) continue; #else if (scmp(platform, TEXT("Win64"))) continue; #endif } //what is it? String name = package->GetString(TEXT("name")); String version = package->GetString(TEXT("version")); //figure out where the files belong XDataItem *pathElement = package->GetDataItem(TEXT("path")); if (!pathElement) continue; CTSTR path = pathElement->GetData(); if (path == NULL) path = TEXT(""); if (!IsSafePath(path)) continue; priority = package->GetInt(TEXT("priority"), 999); //get the file list for this package XElement *files = package->GetElement(TEXT("files")); if (!files) continue; DWORD numFiles = files->NumElements(); DWORD numUpdatableFiles = 0; for (DWORD j = 0; j < numFiles; j++) { XElement *file = files->GetElementByID(j); String hash = file->GetString(TEXT("hash")); if (!hash || hash.Length() != 40) continue; String fileName = file->GetName(); if (!fileName) continue; if (!IsSafeFilename(fileName)) continue; String filePath; filePath << path; filePath << fileName; BYTE fileHash[20]; TCHAR fileHashString[41]; if (OSFileExists(filePath)) { if (!CalculateFileHash(filePath, fileHash)) continue; HashToString(fileHash, fileHashString); if (!scmp(fileHashString, hash)) continue; } numUpdatableFiles++; } if (numUpdatableFiles) { if (version.Length()) description << name << TEXT(" (") << version << TEXT(")\r\n"); else description << name << TEXT("\r\n"); if (priority < bestPriority) bestPriority = priority; } totalUpdatableFiles += numUpdatableFiles; numUpdatableFiles = 0; } manifest.Close(); if (totalUpdatableFiles) { if (!FetchUpdaterModule()) return FALSE; } if (bestPriority <= 5) *updatesAvailable = TRUE; else *updatesAvailable = FALSE; return TRUE; }
Shader* D3D10VertexShader::CreateVertexShader(CTSTR lpShader, CTSTR lpFileName) { String errorString; ShaderProcessor shaderProcessor; if(!shaderProcessor.ProcessShader(lpShader, lpFileName)) AppWarning(TEXT("Unable to process vertex shader '%s'"), lpFileName); //don't exit, leave it to the actual shader compiler to tell the errors //----------------------------------------------- D3D10System *d3d10Sys = static_cast<D3D10System*>(GS); LPCSTR lpVSType = d3d10Sys->bDisableCompatibilityMode ? "vs_4_0" : "vs_4_0_level_9_3"; String cacheFilename = FormattedString(TEXT("%s/shaderCache/%s.blob"), OBSGetAppDataPath(), lpFileName).FindReplace(TEXT("\\"), TEXT("/")); List<BYTE> shaderBuffer; LPVOID shaderData; SIZE_T shaderDataSize; ID3D10Blob *errorMessages = NULL, *shaderBlob = NULL; HRESULT err; if(!OSFileExists(cacheFilename) || OSGetFileModificationTime(lpFileName) > OSGetFileModificationTime(cacheFilename)) { LPSTR lpAnsiShader = tstr_createUTF8(lpShader); LPSTR lpAnsiFileName = tstr_createUTF8(lpFileName); err = D3DX10CompileFromMemory(lpAnsiShader, strlen(lpAnsiShader), lpAnsiFileName, NULL, NULL, "main", lpVSType, D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, &shaderBlob, &errorMessages, NULL); Free(lpAnsiFileName); Free(lpAnsiShader); if(FAILED(err)) { if(errorMessages) { if(errorMessages->GetBufferSize()) { LPSTR lpErrors = (LPSTR)errorMessages->GetBufferPointer(); Log(TEXT("Error compiling vertex shader '%s':\r\n\r\n%S\r\n"), lpFileName, lpErrors); } errorMessages->Release(); } CrashError(TEXT("Compilation of vertex shader '%s' failed, result = %08lX"), lpFileName, err); return NULL; } shaderData = shaderBlob->GetBufferPointer(); shaderDataSize = shaderBlob->GetBufferSize(); CreatePath(GetPathDirectory(cacheFilename)); XFile cacheFile(cacheFilename, XFILE_WRITE, XFILE_CREATEALWAYS); cacheFile.Write(shaderData, (DWORD)shaderDataSize); } else { XFile cacheFile(cacheFilename, XFILE_READ | XFILE_SHARED, XFILE_OPENEXISTING); shaderBuffer.SetSize((unsigned)cacheFile.GetFileSize()); cacheFile.Read(shaderBuffer.Array(), shaderBuffer.Num()); shaderData = shaderBuffer.Array(); shaderDataSize = shaderBuffer.Num(); } //----------------------------------------------- ID3D10VertexShader *vShader; ID3D10InputLayout *vShaderLayout; err = GetD3D()->CreateVertexShader(shaderData, shaderDataSize, &vShader); if(FAILED(err)) { CrashError(TEXT("Unable to create vertex shader '%s', result = %08lX"), lpFileName, err); SafeRelease(shaderBlob); return NULL; } err = GetD3D()->CreateInputLayout(shaderProcessor.generatedLayout.Array(), shaderProcessor.generatedLayout.Num(), shaderData, shaderDataSize, &vShaderLayout); if(FAILED(err)) { CrashError(TEXT("Unable to create vertex layout for vertex shader '%s', result = %08lX"), lpFileName, err); SafeRelease(shaderBlob); SafeRelease(vShader); return NULL; } SafeRelease(shaderBlob); //----------------------------------------------- D3D10VertexShader *shader = new D3D10VertexShader; shader->vertexShader = vShader; shader->inputLayout = vShaderLayout; if(!shader->ProcessData(shaderProcessor, lpFileName)) { delete shader; return NULL; } shader->bHasNormals = shaderProcessor.bHasNormals; shader->bHasColors = shaderProcessor.bHasColors; shader->bHasTangents = shaderProcessor.bHasTangents; shader->nTextureCoords = shaderProcessor.numTextureCoords; shader->hViewProj = shader->GetParameterByName(TEXT("ViewProj")); return shader; }