示例#1
0
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;
}
示例#2
0
INT_PTR SettingsAdvanced::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case WM_INITDIALOG:
    {
        LocalizeWindow(hwnd);

        bool invalidSettings = false;

        //--------------------------------------------

        HWND hwndToolTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL, WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP,
                                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                                          hwnd, NULL, hinstMain, NULL);

        TOOLINFO ti;
        zero(&ti, sizeof(ti));
        ti.cbSize = sizeof(ti);
        ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND;
        ti.hwnd = hwnd;

        if (LocaleIsRTL())
            ti.uFlags |= TTF_RTLREADING;

        SendMessage(hwndToolTip, TTM_SETMAXTIPWIDTH, 0, 500);
        SendMessage(hwndToolTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, 14000);

        //------------------------------------

        UINT sceneBufferingTime = GlobalConfig->GetInt(TEXT("General"), TEXT("SceneBufferingTime"), 700);
        SendMessage(GetDlgItem(hwnd, IDC_SCENEBUFFERTIME), UDM_SETRANGE32, 60, 20000);
        SendMessage(GetDlgItem(hwnd, IDC_SCENEBUFFERTIME), UDM_SETPOS32, 0, sceneBufferingTime);

        //------------------------------------

        bool bUseMTOptimizations = AppConfig->GetInt(TEXT("General"), TEXT("UseMultithreadedOptimizations"), TRUE) != 0;
        SendMessage(GetDlgItem(hwnd, IDC_USEMULTITHREADEDOPTIMIZATIONS), BM_SETCHECK, bUseMTOptimizations ? BST_CHECKED : BST_UNCHECKED, 0);

        HWND hwndTemp = GetDlgItem(hwnd, IDC_PRIORITY);
        SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)Str("Settings.Advanced.Priority.High"));
        SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)Str("Settings.Advanced.Priority.AboveNormal"));
        SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)Str("Settings.Advanced.Priority.Normal"));
        SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)Str("Settings.Advanced.Priority.Idle"));

        CTSTR pStr = AppConfig->GetStringPtr(TEXT("General"), TEXT("Priority"), TEXT("Normal"));
        if (scmpi(pStr, TEXT("Idle")) == 0)
            SendMessage(hwndTemp, CB_SETCURSEL, 3, 0);
        else if (scmpi(pStr, TEXT("Above Normal")) == 0)
            SendMessage(hwndTemp, CB_SETCURSEL, 1, 0);
        else if (scmpi(pStr, TEXT("High")) == 0)
            SendMessage(hwndTemp, CB_SETCURSEL, 0, 0);
        else //Normal
            SendMessage(hwndTemp, CB_SETCURSEL, 2, 0);

        //------------------------------------

        bool bDisablePreviewEncoding = GlobalConfig->GetInt(TEXT("General"), TEXT("DisablePreviewEncoding"), false) != 0;
        SendMessage(GetDlgItem(hwnd, IDC_DISABLEPREVIEWENCODING), BM_SETCHECK, bDisablePreviewEncoding ? BST_CHECKED : BST_UNCHECKED, 0);

        //------------------------------------

        bool bAllowOtherHotkeyModifiers = GlobalConfig->GetInt(TEXT("General"), TEXT("AllowOtherHotkeyModifiers"), true) != 0;
        SendMessage(GetDlgItem(hwnd, IDC_ALLOWOTHERHOTKEYMODIFIERS), BM_SETCHECK, bAllowOtherHotkeyModifiers ? BST_CHECKED : BST_UNCHECKED, 0);

        //--------------------------------------------

        hwndTemp = GetDlgItem(hwnd, IDC_X264PROFILE);
        static const CTSTR profile_names[3] = {TEXT("main"), TEXT("high")};
        for(int i=0; i<2; i++)
            SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)profile_names[i]);

        LoadSettingComboString(hwndTemp, TEXT("Video Encoding"), TEXT("X264Profile"), TEXT("high"));

        //--------------------------------------------

        hwndTemp = GetDlgItem(hwnd, IDC_PRESET);
        static const CTSTR preset_names[8] = {TEXT("ultrafast"), TEXT("superfast"), TEXT("veryfast"), TEXT("faster"), TEXT("fast"), TEXT("medium"), TEXT("slow"), TEXT("slower")};
        for(int i=0; i<8; i++)
            SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)preset_names[i]);

        LoadSettingComboString(hwndTemp, TEXT("Video Encoding"), TEXT("Preset"), TEXT("veryfast"));

        ti.lpszText = (LPWSTR)Str("Settings.Advanced.VideoEncoderCPUTradeoffTooltip");
        ti.uId = (UINT_PTR)hwndTemp;
        SendMessage(hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);

        //------------------------------------

        bool bUseCFR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCFR"), 1) != 0;
        SendMessage(GetDlgItem(hwnd, IDC_USECFR), BM_SETCHECK, bUseCFR ? BST_CHECKED : BST_UNCHECKED, 0);

        //------------------------------------

        bool bUseCustomX264Settings = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCustomSettings")) != 0;
        String strX264Settings = AppConfig->GetString(TEXT("Video Encoding"), TEXT("CustomSettings"));

        SendMessage(GetDlgItem(hwnd, IDC_USEVIDEOENCODERSETTINGS), BM_SETCHECK, bUseCustomX264Settings ? BST_CHECKED : BST_UNCHECKED, 0);
        SetWindowText(GetDlgItem(hwnd, IDC_VIDEOENCODERSETTINGS), strX264Settings);

        ti.lpszText = (LPWSTR)Str("Settings.Advanced.VideoEncoderSettingsTooltip");
        ti.uId = (UINT_PTR)GetDlgItem(hwnd, IDC_VIDEOENCODERSETTINGS);
        SendMessage(hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);

        ti.uId = (UINT_PTR)GetDlgItem(hwnd, IDC_USEVIDEOENCODERSETTINGS);
        SendMessage(hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);

        EnableWindow(GetDlgItem(hwnd, IDC_VIDEOENCODERSETTINGS), bUseCustomX264Settings);

        //--------------------------------------------

        UINT keyframeInt = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("KeyframeInterval"), 0);
        SendMessage(GetDlgItem(hwnd, IDC_KEYFRAMEINTERVAL), UDM_SETRANGE32, 0, 20);
        SendMessage(GetDlgItem(hwnd, IDC_KEYFRAMEINTERVAL), UDM_SETPOS32, 0, keyframeInt);

        //--------------------------------------------

        bool bUnlockFPS = AppConfig->GetInt(TEXT("Video"), TEXT("UnlockFPS")) != 0;
        SendMessage(GetDlgItem(hwnd, IDC_UNLOCKHIGHFPS), BM_SETCHECK, bUnlockFPS ? BST_CHECKED : BST_UNCHECKED, 0);

        //------------------------------------

        String vencoder = AppConfig->GetString(L"Video Encoding", L"Encoder");

        bool bUseQSV = !!(vencoder == L"QSV");

        bool bUseNVENC = !!(vencoder == L"NVENC");

        SelectPresetDialog(bUseQSV, bUseNVENC);

        bool bQSVUseVideoEncoderSettings = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("QSVUseVideoEncoderSettings")) != 0;
        SendMessage(GetDlgItem(hwnd, IDC_QSVUSEVIDEOENCODERSETTINGS), BM_SETCHECK, bQSVUseVideoEncoderSettings ? BST_CHECKED : BST_UNCHECKED, 0);

        String qsvSettings = AppConfig->GetString(TEXT("Video Encoding"), TEXT("CustomQSVSettings"));
        SetWindowText(GetDlgItem(hwnd, IDC_QSVVIDEOENCODERSETTINGS), qsvSettings);
        EnableWindow(GetDlgItem(hwnd, IDC_QSVVIDEOENCODERSETTINGS), bQSVUseVideoEncoderSettings);

        ti.lpszText = (LPWSTR)Str("Settings.Advanced.QSVUseVideoEncoderSettingsTooltip");
        ti.uId = (UINT_PTR)GetDlgItem(hwnd, IDC_QSVUSEVIDEOENCODERSETTINGS);
        SendMessage(hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
        ti.uId = (UINT_PTR)GetDlgItem(hwnd, IDC_QSVVIDEOENCODERSETTINGS);
        SendMessage(hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);

        hwndTemp = GetDlgItem(hwnd, IDC_NVENCPRESET);
        static const CTSTR nv_preset_names[16] = {
            TEXT("Automatic"),
            TEXT("Streaming"),
            TEXT("Streaming (2pass)"),
            TEXT("High Quality"),
            TEXT("High Performance"),
            TEXT("Bluray Disk"),
            TEXT("Low Latency"),
            TEXT("High Performance Low Latency"),
            TEXT("High Quality Low Latency"),
            TEXT("Low Latency (2pass)"),
            TEXT("High Performance Low Latency (2pass)"),
            TEXT("High Quality Low Latency (2pass)"),
            TEXT("Lossless"),
            TEXT("High Performance Lossless"),
            TEXT("NVDefault"),
            NULL
        };
        for (int i = 0; nv_preset_names[i]; i++)
            SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)nv_preset_names[i]);

        LoadSettingComboString(hwndTemp, TEXT("Video Encoding"), TEXT("NVENCPreset"), nv_preset_names[0]);

        hwndTemp = GetDlgItem(hwnd, IDC_QSVPRESET);
        static const struct {
            CTSTR name;
            int id;
        } qsv_presets[] = {
            { L"1 (Best Quality)", 1 },
            { L"2", 2 },
            { L"3", 3 },
            { L"4 (Balanced)", 4 },
            { L"5", 5 },
            { L"6", 6 },
            { L"7 (Best Speed)", 7 }
        };
        for (int i = 0; i < _countof(qsv_presets); i++)
        {
            SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)qsv_presets[i].name);
            SendMessage(hwndTemp, CB_SETITEMDATA, i, qsv_presets[i].id);
        }
        int qsvPreset = AppConfig->GetInt(L"Video Encoding", L"QSVPreset", 1);
        if (qsvPreset < 1 || qsvPreset > 7) qsvPreset = 1;
        SendMessage(hwndTemp, CB_SETCURSEL, qsvPreset - 1, 0);

        //------------------------------------

        bool bSyncToVideoTime = AppConfig->GetInt(TEXT("Audio"), TEXT("SyncToVideoTime")) != 0;
        SendMessage(GetDlgItem(hwnd, IDC_SYNCTOVIDEOTIME), BM_SETCHECK, bSyncToVideoTime ? BST_CHECKED : BST_UNCHECKED, 0);

        //------------------------------------

        bool bUseMicQPC = GlobalConfig->GetInt(TEXT("Audio"), TEXT("UseMicQPC")) != 0;
        SendMessage(GetDlgItem(hwnd, IDC_USEMICQPC), BM_SETCHECK, bUseMicQPC ? BST_CHECKED : BST_UNCHECKED, 0);

        //------------------------------------

        BOOL bMicSyncFixHack = GlobalConfig->GetInt(TEXT("Audio"), TEXT("UseMicSyncFixHack"));
        SendMessage(GetDlgItem(hwnd, IDC_MICSYNCFIX), BM_SETCHECK, bMicSyncFixHack ? BST_CHECKED : BST_UNCHECKED, 0);

        //------------------------------------

        int bufferTime = GlobalConfig->GetInt(TEXT("General"), TEXT("SceneBufferingTime"), 700);

        int globalAudioTimeAdjust = GlobalConfig->GetInt(TEXT("Audio"), TEXT("GlobalAudioTimeAdjust"));
        SendMessage(GetDlgItem(hwnd, IDC_AUDIOTIMEADJUST), UDM_SETRANGE32, -bufferTime, 5000);
        SendMessage(GetDlgItem(hwnd, IDC_AUDIOTIMEADJUST), UDM_SETPOS32, 0, globalAudioTimeAdjust);

        //------------------------------------

        int lowLatencyFactor = AppConfig->GetInt(TEXT("Publish"), TEXT("LatencyFactor"), 20);
        SetDlgItemInt(hwnd, IDC_LATENCYTUNE, lowLatencyFactor, TRUE);

        int bLowLatencyAutoMethod = AppConfig->GetInt(TEXT("Publish"), TEXT("LowLatencyMethod"), 0);
        SendMessage(GetDlgItem(hwnd, IDC_LATENCYMETHOD), BM_SETCHECK, bLowLatencyAutoMethod ? BST_CHECKED : BST_UNCHECKED, 0);

        //------------------------------------

        MIB_IPADDRTABLE tempTable;
        DWORD dwSize = 0;
        if (GetIpAddrTable (&tempTable, &dwSize, TRUE) == ERROR_INSUFFICIENT_BUFFER)
        {
            PMIB_IPADDRTABLE ipTable;

            ipTable = (PMIB_IPADDRTABLE)Allocate(dwSize);

            if (GetIpAddrTable (ipTable, &dwSize, TRUE) == NO_ERROR)
            {
                DWORD i;

                hwndTemp = GetDlgItem(hwnd, IDC_BINDIP);
                SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("Default"));

                for (i=0; i < ipTable->dwNumEntries; i++)
                {
                    String strAddress;
                    DWORD strLength = 32;

                    // don't allow binding to localhost
                    if ((ipTable->table[i].dwAddr & 0xFF) == 127)
                        continue;

                    strAddress.SetLength(strLength);

                    SOCKADDR_IN IP;

                    IP.sin_addr.S_un.S_addr = ipTable->table[i].dwAddr;
                    IP.sin_family = AF_INET;
                    IP.sin_port = 0;
                    zero(&IP.sin_zero, sizeof(IP.sin_zero));

                    WSAAddressToString ((LPSOCKADDR)&IP, sizeof(IP), NULL, strAddress.Array(), &strLength);
                    SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)strAddress.Array());
                }

                LoadSettingComboString(hwndTemp, TEXT("Publish"), TEXT("BindToIP"), TEXT("Default"));
            }

            Free(ipTable);
        }

        //need this as some of the dialog item sets above trigger the notifications
        ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_HIDE);
        SetChangedSettings(invalidSettings);
        return TRUE;
    }

    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case IDC_USEVIDEOENCODERSETTINGS:
            if(HIWORD(wParam) == BN_CLICKED)
            {
                BOOL bUseVideoEncoderSettings = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
                EnableWindow(GetDlgItem(hwnd, IDC_VIDEOENCODERSETTINGS), bUseVideoEncoderSettings);

                if (App->GetVideoEncoder())
                    ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
                SetChangedSettings(true);
            }
            break;

        case IDC_QSVUSEVIDEOENCODERSETTINGS:
            if (HIWORD(wParam) == BN_CLICKED)
            {
                bool useSettings = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
                EnableWindow(GetDlgItem(hwnd, IDC_QSVVIDEOENCODERSETTINGS), useSettings);

                if (App->GetVideoEncoder())
                    ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
                SetChangedSettings(true);
            }
            break;

        case IDC_KEYFRAMEINTERVAL_EDIT:
        case IDC_SCENEBUFFERTIME_EDIT:
        case IDC_AUDIOTIMEADJUST_EDIT:
        case IDC_VIDEOENCODERSETTINGS:
        case IDC_QSVVIDEOENCODERSETTINGS:
        case IDC_LATENCYTUNE:
            if(HIWORD(wParam) == EN_CHANGE)
            {
                if (App->GetVideoEncoder())
                    ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
                SetChangedSettings(true);
            }
            break;

        /*case IDC_TIMER1:
        case IDC_TIMER2:
        case IDC_TIMER3:
        case IDC_DISABLED3DCOMPATIBILITY:
            if(HIWORD(wParam) == BN_CLICKED)
            {
                ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
                SetChangedSettings(true);
            }
            break;*/

        case IDC_USESENDBUFFER:
            if(HIWORD(wParam) == BN_CLICKED)
            {
                BOOL bUseSendBuffer = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
                EnableWindow(GetDlgItem(hwnd, IDC_SENDBUFFERSIZE), bUseSendBuffer);

                if (App->GetVideoEncoder())
                    ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
                SetChangedSettings(true);
            }
            break;

        case IDC_PRESET:
            if(HIWORD(wParam) == CBN_SELCHANGE)
            {
                HWND hwndTemp = (HWND)lParam;

                String strNewPreset = GetCBText(hwndTemp);
                if (scmp(strNewPreset.Array(), TEXT("veryfast")))
                {
                    static BOOL bHasWarned = FALSE;
                    if (!bHasWarned && OBSMessageBox(hwnd, Str("Settings.Advanced.PresetWarning"), NULL, MB_ICONEXCLAMATION | MB_YESNO) == IDNO)
                        LoadSettingComboString(hwndTemp, TEXT("Video Encoding"), TEXT("Preset"), TEXT("veryfast"));
                    else
                        bHasWarned = TRUE;
                }

                SetChangedSettings(true);
                if (App->GetVideoEncoder())
                    ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
            }
            break;

        case IDC_X264PROFILE:
        case IDC_SENDBUFFERSIZE:
        case IDC_PRIORITY:
        case IDC_BINDIP:
        case IDC_NVENCPRESET:
        case IDC_QSVPRESET:
            if(HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE)
            {
                if (App->GetVideoEncoder())
                    ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
                SetChangedSettings(true);
            }
            break;

        case IDC_DISABLEPREVIEWENCODING:
        case IDC_ALLOWOTHERHOTKEYMODIFIERS:
        case IDC_MICSYNCFIX:
        case IDC_USEMICQPC:
        case IDC_SYNCTOVIDEOTIME:
        case IDC_USECFR:
        case IDC_USEMULTITHREADEDOPTIMIZATIONS:
        case IDC_UNLOCKHIGHFPS:
        case IDC_LATENCYMETHOD:
            if(HIWORD(wParam) == BN_CLICKED)
            {
                if (App->GetVideoEncoder())
                    ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW);
                SetChangedSettings(true);
            }
            break;
        }

    }
    return FALSE;
}
示例#3
0
INT_PTR CALLBACK OBS::SettingsDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
        case WM_INITDIALOG:
            {
                App->hwndSettings = hwnd;

                LocalizeWindow(hwnd);

                // Add setting categories from the pane list
                for(unsigned int i = 0; i < App->settingsPanes.Num(); i++)
                {
                    SettingsPane *pane = App->settingsPanes[i];
                    if(pane == NULL)
                        continue;
                    SendMessage(GetDlgItem(hwnd, IDC_SETTINGSLIST), LB_ADDSTRING, 0, (LPARAM)pane->GetCategory());
                }

                RECT subDialogRect;
                GetWindowRect(GetDlgItem(hwnd, IDC_SUBDIALOG), &subDialogRect);
                MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&subDialogRect, 2);

                SendMessage(GetDlgItem(hwnd, IDC_SETTINGSLIST), LB_SETCURSEL, 0, 0);

                // Load the first settings pane from the list
                App->curSettingsSelection = 0;
                App->hwndCurrentSettings = NULL;
                App->currentSettingsPane = NULL;

                if(App->settingsPanes.Num() >= 1)
                    App->currentSettingsPane = App->settingsPanes[0];

                if(App->currentSettingsPane != NULL)
                    App->hwndCurrentSettings = App->currentSettingsPane->CreatePane(hwnd);

                if(App->hwndCurrentSettings != NULL)
                {
                    SetWindowPos(App->hwndCurrentSettings, NULL,
                        subDialogRect.left, subDialogRect.top,
                        subDialogRect.right - subDialogRect.left,
                        subDialogRect.bottom - subDialogRect.top,
                        SWP_NOZORDER);
                    ShowWindow(App->hwndCurrentSettings, SW_SHOW);
                    ShowWindow(GetDlgItem(hwnd, IDC_DEFAULTS), App->currentSettingsPane->HasDefaults());
                    ShowWindow(GetDlgItem(hwnd, IDC_OPTIMIZE), false);
                }

                return TRUE;
            }

        case WM_DRAWITEM:
            PDRAWITEMSTRUCT pdis;
            pdis = (PDRAWITEMSTRUCT) lParam;

            if(pdis->CtlID != IDC_SETTINGSLIST || pdis->itemID == -1)
                break;

            switch(pdis->itemAction)
            {
                case ODA_SELECT:
                case ODA_DRAWENTIRE:
                    {
                        int cy, bkMode;
                        TEXTMETRIC tm;
                        COLORREF oldTextColor;
                        TCHAR itemText[MAX_PATH];

                        oldTextColor = GetTextColor(pdis->hDC);

                        if(pdis->itemState & ODS_SELECTED)
                        {
                            FillRect(pdis->hDC, &pdis->rcItem, (HBRUSH)(COLOR_HIGHLIGHT + 1));
                            SetTextColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
                        }
                        else
                        {
                            FillRect(pdis->hDC, &pdis->rcItem, (HBRUSH)(COLOR_WINDOW + 1));
                            SetTextColor(pdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
                        }

                        SendMessage(pdis->hwndItem, LB_GETTEXT, pdis->itemID, (LPARAM)itemText);

                        GetTextMetrics(pdis->hDC, &tm);
                        cy = (pdis->rcItem.bottom + pdis->rcItem.top - tm.tmHeight) / 2;

                        bkMode = SetBkMode(pdis->hDC, TRANSPARENT);

                        if(slen(itemText) > 0)
                            TextOut(pdis->hDC, 6, cy, itemText, slen(itemText));

                        SetBkMode(pdis->hDC, bkMode);
                        SetTextColor(pdis->hDC, oldTextColor);

                        UINT builtinAndEncoderPanes = App->numberOfBuiltInSettingsPanes + App->numberOfEncoderSettingsPanes;

                        if ((App->settingsPanes.Num() > (UINT)App->numberOfBuiltInSettingsPanes && pdis->itemID == App->numberOfBuiltInSettingsPanes)
                            || (App->settingsPanes.Num() > (UINT)builtinAndEncoderPanes && pdis->itemID == builtinAndEncoderPanes))
                        {
                            HGDIOBJ origPen;
                            origPen = SelectObject(pdis->hDC, GetStockObject(DC_PEN));
                            SetDCPenColor(pdis->hDC, GetSysColor(COLOR_BTNSHADOW));

                            MoveToEx(pdis->hDC, pdis->rcItem.left, pdis->rcItem.top, NULL);
                            LineTo(pdis->hDC, pdis->rcItem.right, pdis->rcItem.top);

                            SelectObject(pdis->hDC, origPen);
                        }

                        break;
                    }

                case ODA_FOCUS:
                    break;
            }

            break;

        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case IDC_SETTINGSLIST:
                    {
                        if(HIWORD(wParam) != LBN_SELCHANGE)
                            break;

                        int sel = (int)SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);

                        // No need to continue if we're on the same panel
                        if(sel == App->curSettingsSelection)
                            break;

                        if(App->bSettingsChanged)
                        {
                            int id = OBSMessageBox(hwnd, Str("Settings.SaveChangesPrompt"), Str("Settings.SaveChangesTitle"), MB_YESNOCANCEL);

                            if (id == IDNO)
                                App->CancelSettings();

                            if(id == IDCANCEL)
                            {
                                SendMessage((HWND)lParam, LB_SETCURSEL, App->curSettingsSelection, 0);
                                break;
                            }
                            else if(id == IDYES)
                                App->ApplySettings();
                        }

                        App->curSettingsSelection = sel;

                        if(App->currentSettingsPane != NULL)
                            App->currentSettingsPane->DestroyPane();
                        App->currentSettingsPane = NULL;
                        App->hwndCurrentSettings = NULL;
                        ShowWindow(GetDlgItem(hwnd, IDC_OPTIMIZE), false);

                        RECT subDialogRect;
                        GetWindowRect(GetDlgItem(hwnd, IDC_SUBDIALOG), &subDialogRect);
                        MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&subDialogRect, 2);

                        if(sel >= 0 && sel < (int)App->settingsPanes.Num())
                            App->currentSettingsPane = App->settingsPanes[sel];
                        if(App->currentSettingsPane != NULL)
                            App->hwndCurrentSettings = App->currentSettingsPane->CreatePane(hwnd);
                        if(App->hwndCurrentSettings)
                        {
                            SetWindowPos(App->hwndCurrentSettings, NULL,
                                subDialogRect.left, subDialogRect.top,
                                subDialogRect.right - subDialogRect.left,
                                subDialogRect.bottom - subDialogRect.top,
                                SWP_NOZORDER);
                            ShowWindow(App->hwndCurrentSettings, SW_SHOW);

                            ShowWindow(GetDlgItem(hwnd, IDC_DEFAULTS), App->currentSettingsPane->HasDefaults());
                            SetFocus(GetDlgItem(hwnd, IDC_SETTINGSLIST));
                        }

                        break;
                    }

                case IDC_DEFAULTS:
                    App->currentSettingsPane->SetDefaults();
                    break;

                case IDOK:
                    if(App->bSettingsChanged)
                        App->ApplySettings();
                    if (App->bApplySettingsAborted)
                        break;
                    EndDialog(hwnd, IDOK);
                    App->hwndSettings = NULL;
                    break;

                case IDCANCEL:
                    if(App->bSettingsChanged)
                        App->CancelSettings();
                    EndDialog(hwnd, IDCANCEL);
                    App->hwndSettings = NULL;
                    break;

                case IDC_APPLY:
                    if(App->bSettingsChanged)
                        App->ApplySettings();
                    break;

                case IDC_OPTIMIZE:
                    App->OptimizeSettings();
                    break;
            }
            break;
    }

    return FALSE;
}
示例#4
0
void SettingsEncoding::ApplySettings()
{
    bool useQSV   = SendMessage(GetDlgItem(hwnd, IDC_ENCODERQSV), BM_GETCHECK, 0, 0) == BST_CHECKED;
    bool useNVENC = SendMessage(GetDlgItem(hwnd, IDC_ENCODERNVENC), BM_GETCHECK, 0, 0) == BST_CHECKED;
    bool usex264 = !useQSV && !useNVENC;

    String vcodec = AppConfig->GetString(L"Video Encoding", L"Encoder");

    bool useQSV_prev   = !!(vcodec == L"QSV");
    bool useNVENC_prev = !!(vcodec == L"NVENC");

    if (!hasQSV && !useQSV && useQSV_prev &&
        OBSMessageBox(hwnd, Str("Settings.Encoding.Video.EncoderQSVDisabledAfterApply"), Str("MessageBoxWarningCaption"), MB_ICONEXCLAMATION | MB_OKCANCEL) != IDOK)
    {
        SetAbortApplySettings(true);
        return;
    }

    if (!hasNVENC && !useNVENC && useNVENC_prev &&
        OBSMessageBox(hwnd, Str("Settings.Encoding.Video.EncoderNVENCDisabledAfterApply"), Str("MessageBoxWarningCaption"), MB_ICONEXCLAMATION | MB_OKCANCEL) != IDOK)
    {
        SetAbortApplySettings(true);
        return;
    }

    EnableWindow(GetDlgItem(hwnd, IDC_ENCODERQSV), hasQSV || useQSV);
    EnableWindow(GetDlgItem(hwnd, IDC_ENCODERNVENC), hasNVENC || useNVENC);

    AppConfig->SetString(L"Video Encoding", L"Encoder", useQSV ? L"QSV" : useNVENC ? L"NVENC" : L"x264");

    int quality = (int)SendMessage(GetDlgItem(hwnd, IDC_QUALITY), CB_GETCURSEL, 0, 0);
    if(quality != CB_ERR)
        AppConfig->SetInt(TEXT("Video Encoding"), TEXT("Quality"), quality);

    static const int minBitRate = 64;

    UINT bitrate = GetEditText(GetDlgItem(hwnd, IDC_MAXBITRATE)).ToInt();
    if (bitrate < minBitRate) bitrate = minBitRate;
    AppConfig->SetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), bitrate);

    UINT bufSize = GetEditText(GetDlgItem(hwnd, IDC_BUFFERSIZE)).ToInt();
    //if(bufSize < minBitRate) bufSize = bitrate;  //R1CH: Allow users to enter 0 buffer size to disable VBV, its protected by checkbox anyway
    AppConfig->SetInt(TEXT("Video Encoding"), TEXT("BufferSize"), bufSize);

    if(App->GetVideoEncoder() != NULL) {
        if(App->GetVideoEncoder()->DynamicBitrateSupported())
        {
            int oldBitrate = App->GetVideoEncoder()->GetBitRate();
            App->GetVideoEncoder()->SetBitRate(bitrate, bufSize);
            if(oldBitrate != bitrate)
                Log(FormattedString(TEXT("Settings::Encoding: Changing bitrate from %dkb/s to %dkb/s"), oldBitrate, bitrate));
        }
    }

    String strTemp = GetCBText(GetDlgItem(hwnd, IDC_AUDIOCODEC));
    AppConfig->SetString(TEXT("Audio Encoding"), TEXT("Codec"), strTemp);

    strTemp = GetCBText(GetDlgItem(hwnd, IDC_AUDIOBITRATE));
    AppConfig->SetString(TEXT("Audio Encoding"), TEXT("Bitrate"), strTemp);

    int curSel = (int)SendMessage(GetDlgItem(hwnd, IDC_AUDIOFORMAT), CB_GETCURSEL, 0, 0);
    if(curSel != CB_ERR)
        AppConfig->SetInt(TEXT("Audio Encoding"), TEXT("Format"), curSel);

    int curSelCh = (int)SendMessage(GetDlgItem(hwnd, IDC_AUDIOCHANNEL), CB_GETCURSEL, 0, 0);
    if(curSelCh != CB_ERR)
        AppConfig->SetInt(TEXT("Audio Encoding"), TEXT("isStereo"), curSelCh);

    bool bUseCBR = SendMessage(GetDlgItem(hwnd, IDC_USECBR), BM_GETCHECK, 0, 0) == BST_CHECKED;
    AppConfig->SetInt(TEXT("Video Encoding"), TEXT("UseCBR"), bUseCBR);

    bool bPadCBR = SendMessage(GetDlgItem(hwnd, IDC_PADCBR), BM_GETCHECK, 0, 0) == BST_CHECKED;
    AppConfig->SetInt(TEXT("Video Encoding"), TEXT("PadCBR"), bPadCBR);

    bool bCustomBuffer = SendMessage(GetDlgItem(hwnd, IDC_CUSTOMBUFFER), BM_GETCHECK, 0, 0) == BST_CHECKED;
    AppConfig->SetInt(TEXT("Video Encoding"), TEXT("UseBufferSize"), bCustomBuffer);
}
示例#5
0
INT_PTR CALLBACK IVASendiCloudInfoProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_INITDIALOG:
    {
        ConfigIVAInfo *configInfo = (ConfigIVAInfo*)lParam;
        SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)configInfo);
        LocalizeWindow(hwnd);

        ICP_MODE eMode = g_pCloudData->GetICPMode();
        SendMessage(GetDlgItem(hwnd, IDC_MODEIVA), BM_SETCHECK, eMode==ICP_INTERACTIVE_MODE, 0);
        SendMessage(GetDlgItem(hwnd, IDC_MODEEDIT), BM_SETCHECK, eMode == ICP_EDIT_MODE, 0);
        EnableWindow(GetDlgItem(hwnd, IDC_SENDCLOUD), eMode == ICP_INTERACTIVE_MODE);

        return 0;
    }

    case WM_NEWIVACLOUD:
    {
        int nIndex = wParam;
        int nSourceID = lParam;
        HWND hwndLCI = GetDlgItem(hwnd, IDC_LISTCLOUDINFO);

        std::wstring name;
        StringToWString(g_pCloudData->m_vIPicDesc[nIndex].strTitle, name);

        UINT id = (UINT)SendMessage(hwndLCI, LB_ADDSTRING, 0, (LPARAM)name.c_str());
        SendMessage(hwndLCI, LB_SETITEMDATA, id, (LPARAM)nSourceID);
        break;
    }
    case WM_DELETEIVACLOUD:
    {
        int nIndex = wParam;
        int nSourceID = lParam;
        HWND hwndLCI = GetDlgItem(hwnd, IDC_LISTCLOUDINFO);

        std::wstring name;
        StringToWString(g_pCloudData->m_vIPicDesc[nIndex].strTitle, name);
        int iNum = SendMessage(hwndLCI, LB_FINDSTRINGEXACT, -1, (LPARAM)name.c_str());
        SendMessage(hwndLCI, LB_DELETESTRING, iNum, 0);
        break;
    }

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {
        case IDC_SENDCLOUD:
        {
            HWND hwndLCI = GetDlgItem(hwnd, IDC_LISTCLOUDINFO);
            int id = (int)SendMessage((HWND)hwndLCI, LB_GETCURSEL, 0, 0);
            if (id == LB_ERR)
            {
                OBSMessageBox(hwnd, L"请选择一个云信息操作", NULL, 0);
                break;
            }
            int nSourceID = (UINT)SendMessage((HWND)hwndLCI, LB_GETITEMDATA, id, 0);
            if (g_pCloudData->SendCloud(nSourceID) != 0)
                OBSMessageBox(hwnd, L"发送成功", L"成功", 0);
            else
                OBSMessageBox(hwnd, L"发送失败", L"失败", 0);
            break;
        }
        case IDC_MODEIVA:
        case IDC_MODEEDIT:
        {
            int bEditMode = SendMessage(GetDlgItem(hwnd, IDC_MODEEDIT), BM_GETCHECK, 0, 0) == BST_CHECKED;
            int bIVAMode = SendMessage(GetDlgItem(hwnd, IDC_MODEIVA), BM_GETCHECK, 0, 0) == BST_CHECKED;
            ICP_MODE eMode;
            if (bIVAMode != 0)
                eMode = ICP_INTERACTIVE_MODE;
            else
                eMode = ICP_EDIT_MODE;
            EnableWindow(GetDlgItem(hwnd, IDC_SENDCLOUD), bIVAMode);
            g_pCloudData->SetICPMode(eMode);
            break;
        }
        case IDOK:
        {

        }
        case IDCANCEL:
            EndDialog(hwnd, LOWORD(wParam));
            break;
        }
        break;
    }
    }

    return 0;
}
示例#6
0
INT_PTR CALLBACK IVACloudProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_INITDIALOG:
    {
        ConfigIVAInfo *configInfo = (ConfigIVAInfo*)lParam;
        SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)configInfo);
        LocalizeWindow(hwnd);

        HWND hwndPic = GetDlgItem(hwnd, IDC_LISTPIC);
        int i;
        for (i = 0; i < g_pCloudData->m_vIPicDesc.size(); i++)
        {
            std::wstring name;
            StringToWString(g_pCloudData->m_vIPicDesc[i].strTitle, name);

            UINT id = (UINT)SendMessage(hwndPic, LB_ADDSTRING, 0, (LPARAM)name.c_str());
            SendMessage(hwndPic, LB_SETITEMDATA, id, (LPARAM)i);
        }

        CTSTR wszSelPic = configInfo->data->GetString(TEXT("SelCloud"));
        if (wszSelPic != NULL)
        {
            int iNum = SendMessage(hwndPic, LB_FINDSTRINGEXACT, 2, (LPARAM)wszSelPic);
            SendMessage(hwndPic, LB_SETCURSEL, iNum, 0);
            UINT nIndex = (UINT)SendMessage((HWND)hwndPic, LB_GETITEMDATA, iNum, 0);

            std::wstring wstrFilename;
            StringToWString(g_pCloudData->m_vIPicDesc[nIndex].strFileName, wstrFilename);
            DrawImage(hwnd, wstrFilename.c_str(), IDC_PICZONE);
        }

        return 0;
    }

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {
        case IDC_LISTPIC:
        {
            if (HIWORD(wParam) == LBN_SELCHANGE)
            {
                UINT id = (UINT)SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);
                if (id == LB_ERR)
                    break;
                UINT nIndex = (UINT)SendMessage((HWND)lParam, LB_GETITEMDATA, id, 0);
                std::wstring wstrFilename;
                StringToWString(g_pCloudData->m_vIPicDesc[nIndex].strFileName, wstrFilename);
                DrawImage(hwnd, wstrFilename.c_str(), IDC_PICZONE);
            }
            break;
        }
        case IDTEST:
        {
#if 0
            CImage *img = new CImage;
            HDC dc = GetDC(hwnd);
            img->Load(L"D:\\sss.jpg");
            RECT rect = { 10, 10, 100, 100 };
            img->Draw(GetDC(hwnd), rect);
            delete img;
#endif
            break;
        }
        case IDOK:
        {
            HWND hwndPic = GetDlgItem(hwnd, IDC_LISTPIC);
            UINT id = (UINT)SendMessage((HWND)hwndPic, LB_GETCURSEL, 0, 0);
            if (id == LB_ERR)
            {
                OBSMessageBox(hwnd, L"请选择云图", NULL, 0);
                break;
            }
            UINT nIndex = (UINT)SendMessage((HWND)hwndPic, LB_GETITEMDATA, id, 0);
            ConfigIVAInfo *configInfo = (ConfigIVAInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
            configInfo->data->SetString(TEXT("SelCloud"), g_pCloudData->m_vIPicDesc[nIndex].wstrTitle.c_str());
            configInfo->data->SetInt(TEXT("SelIndex"), nIndex);
        }
        case IDCANCEL:
            EndDialog(hwnd, LOWORD(wParam));
            break;
        }
        break;
    }
    }

    return 0;
}
示例#7
0
文件: API.cpp 项目: Aslai/OBS
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 = !performTransition;

    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())
        OBSMessageBox(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;
}
示例#8
0
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();
}
LONG CALLBACK OBSExceptionHandler (PEXCEPTION_POINTERS exceptionInfo)
{
    HANDLE  hProcess;

    HMODULE hDbgHelp;

    MINIDUMP_EXCEPTION_INFORMATION miniInfo;

    STACKFRAME64        frame = {0};
    CONTEXT             context = *exceptionInfo->ContextRecord;
    SYMBOL_INFO         *symInfo;
    DWORD64             fnOffset;
    TCHAR               logPath[MAX_PATH];

    OSVERSIONINFOEX     osInfo;
    SYSTEMTIME          timeInfo;

    ENUMERATELOADEDMODULES64    fnEnumerateLoadedModules64;
    SYMSETOPTIONS               fnSymSetOptions;
    SYMINITIALIZE               fnSymInitialize;
    STACKWALK64                 fnStackWalk64;
    SYMFUNCTIONTABLEACCESS64    fnSymFunctionTableAccess64;
    SYMGETMODULEBASE64          fnSymGetModuleBase64;
    SYMFROMADDR                 fnSymFromAddr;
    SYMCLEANUP                  fnSymCleanup;
    MINIDUMPWRITEDUMP           fnMiniDumpWriteDump;
    SYMGETMODULEINFO64          fnSymGetModuleInfo64;

    DWORD                       i;
    DWORD64                     InstructionPtr;
    DWORD                       imageType;

    TCHAR                       searchPath[MAX_PATH], *p;

    static BOOL                 inExceptionHandler = FALSE;

    moduleinfo_t                moduleInfo;

    //always break into a debugger if one is present
    if (IsDebuggerPresent ())
        return EXCEPTION_CONTINUE_SEARCH;

    //exception codes < 0x80000000 are typically informative only and not crash worthy
    //0xe06d7363 indicates a c++ exception was thrown, let's just hope it was caught.
    //this is no longer needed since we're an unhandled handler vs a vectored handler
    
    /*if (exceptionInfo->ExceptionRecord->ExceptionCode < 0x80000000 || exceptionInfo->ExceptionRecord->ExceptionCode == 0xe06d7363 ||
        exceptionInfo->ExceptionRecord->ExceptionCode == 0x800706b5)
        return EXCEPTION_CONTINUE_SEARCH;*/

    //uh oh, we're crashing inside ourselves... this is really bad!
    if (inExceptionHandler)
        return EXCEPTION_CONTINUE_SEARCH;

    inExceptionHandler = TRUE;

    //load dbghelp dynamically
    hDbgHelp = LoadLibrary (TEXT("DBGHELP"));

    if (!hDbgHelp)
        return EXCEPTION_CONTINUE_SEARCH;

    fnEnumerateLoadedModules64 = (ENUMERATELOADEDMODULES64)GetProcAddress (hDbgHelp, "EnumerateLoadedModulesW64");
    fnSymSetOptions = (SYMSETOPTIONS)GetProcAddress (hDbgHelp, "SymSetOptions");
    fnSymInitialize = (SYMINITIALIZE)GetProcAddress (hDbgHelp, "SymInitialize");
    fnSymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESS64)GetProcAddress (hDbgHelp, "SymFunctionTableAccess64");
    fnSymGetModuleBase64 = (SYMGETMODULEBASE64)GetProcAddress (hDbgHelp, "SymGetModuleBase64");
    fnStackWalk64 = (STACKWALK64)GetProcAddress (hDbgHelp, "StackWalk64");
    fnSymFromAddr = (SYMFROMADDR)GetProcAddress (hDbgHelp, "SymFromAddrW");
    fnSymCleanup = (SYMCLEANUP)GetProcAddress (hDbgHelp, "SymCleanup");
    fnSymGetModuleInfo64 = (SYMGETMODULEINFO64)GetProcAddress (hDbgHelp, "SymGetModuleInfo64");
    fnMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress (hDbgHelp, "MiniDumpWriteDump");

    if (!fnEnumerateLoadedModules64 || !fnSymSetOptions || !fnSymInitialize || !fnSymFunctionTableAccess64 ||
        !fnSymGetModuleBase64 || !fnStackWalk64 || !fnSymFromAddr || !fnSymCleanup || !fnSymGetModuleInfo64)
    {
        FreeLibrary (hDbgHelp);
        return EXCEPTION_CONTINUE_SEARCH;
    }

    hProcess = GetCurrentProcess();

    fnSymSetOptions (SYMOPT_UNDNAME | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_ANYTHING);

    GetModuleFileName (NULL, searchPath, _countof(searchPath)-1);
    p = srchr (searchPath, '\\');
    if (p)
        *p = 0;

    //create a log file
    GetSystemTime (&timeInfo);
    for (i = 1;;)
    {
        tsprintf_s (logPath, _countof(logPath)-1, TEXT("%s\\crashDumps\\OBSCrashLog%.4d-%.2d-%.2d_%d.txt"), lpAppDataPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, i);
        if (GetFileAttributes(logPath) == INVALID_FILE_ATTRIBUTES)
            break;
        i++;
    }

    XFile   crashDumpLog;

    if (!crashDumpLog.Open(logPath, XFILE_WRITE, XFILE_CREATENEW))
    {
        FreeLibrary (hDbgHelp);
        return EXCEPTION_CONTINUE_SEARCH;
    }

    //initialize debug symbols
    fnSymInitialize (hProcess, NULL, TRUE);

#ifdef _WIN64
    InstructionPtr = context.Rip;
    frame.AddrPC.Offset = InstructionPtr;
    frame.AddrFrame.Offset = context.Rbp;
    frame.AddrStack.Offset = context.Rsp;
    imageType = IMAGE_FILE_MACHINE_AMD64;
#else
    InstructionPtr = context.Eip;
    frame.AddrPC.Offset = InstructionPtr;
    frame.AddrFrame.Offset = context.Ebp;
    frame.AddrStack.Offset = context.Esp;
    imageType = IMAGE_FILE_MACHINE_I386;
#endif

    frame.AddrFrame.Mode = AddrModeFlat;
    frame.AddrPC.Mode = AddrModeFlat;
    frame.AddrStack.Mode = AddrModeFlat;

    symInfo = (SYMBOL_INFO *)LocalAlloc (LPTR, sizeof(*symInfo) + 256);
    symInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
    symInfo->MaxNameLen = 256;
    fnOffset = 0;

    //get os info
    memset (&osInfo, 0, sizeof(osInfo));
    osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    if (!GetVersionEx ((OSVERSIONINFO *)&osInfo))
    {
        osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
        GetVersionEx ((OSVERSIONINFO *)&osInfo);
    }

    String cpuInfo;
    HKEY key;

    // get cpu info
    if(RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), &key) == ERROR_SUCCESS)
    {
        DWORD dwSize = 1024;
        cpuInfo.SetLength(dwSize);
        if (RegQueryValueEx(key, TEXT("ProcessorNameString"), NULL, NULL, (LPBYTE)cpuInfo.Array(), &dwSize) != ERROR_SUCCESS)
            cpuInfo = TEXT("<unable to query>");
        RegCloseKey(key);
    }
    else
        cpuInfo = TEXT("<unable to query>");

    //determine which module the crash occured in
    scpy (moduleInfo.moduleName, TEXT("<unknown>"));
    moduleInfo.faultAddress = InstructionPtr;
    fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)&moduleInfo);
    slwr (moduleInfo.moduleName);

    BOOL isPlugin = FALSE;

    if (sstr (moduleInfo.moduleName, TEXT("plugins\\")))
        isPlugin = TRUE;

    String strModuleInfo;
    String crashMessage;

    fnEnumerateLoadedModules64(hProcess, (PENUMLOADED_MODULES_CALLBACK64)RecordAllLoadedModules, (VOID *)&strModuleInfo);

    crashMessage << 
        TEXT("OBS has encountered an unhandled exception and has terminated. If you are able to\r\n")
        TEXT("reproduce this crash, please submit this crash report on the forums at\r\n")
        TEXT("https://obsproject.com/ - include the contents of this crash log and the\r\n")
        TEXT("minidump .dmp file (if available) as well as your regular OBS log files and\r\n")
        TEXT("a description of what you were doing at the time of the crash.\r\n")
        TEXT("\r\n")
        TEXT("This crash appears to have occured in the '") << moduleInfo.moduleName << TEXT("' module.\r\n\r\n");

    crashDumpLog.WriteStr(crashMessage.Array());

    crashDumpLog.WriteStr(FormattedString(TEXT("**** UNHANDLED EXCEPTION: %x\r\nFault address: %I64p (%s)\r\n"), exceptionInfo->ExceptionRecord->ExceptionCode, InstructionPtr, moduleInfo.moduleName));

    crashDumpLog.WriteStr(TEXT("OBS version: ") OBS_VERSION_STRING TEXT("\r\n"));
    crashDumpLog.WriteStr(FormattedString(TEXT("Windows version: %d.%d (Build %d) %s\r\nCPU: %s\r\n\r\n"), osInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.dwBuildNumber, osInfo.szCSDVersion, cpuInfo.Array()));

    crashDumpLog.WriteStr(TEXT("Crashing thread stack trace:\r\n"));
#ifdef _WIN64
    crashDumpLog.WriteStr(TEXT("Stack            EIP              Arg0             Arg1             Arg2             Arg3             Address\r\n"));
#else
    crashDumpLog.WriteStr(TEXT("Stack    EIP      Arg0     Arg1     Arg2     Arg3     Address\r\n"));
#endif
    crashDumpLog.FlushFileBuffers();

    while (fnStackWalk64 (imageType, hProcess, GetCurrentThread(), &frame, &context, NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE64)fnSymFunctionTableAccess64, (PGET_MODULE_BASE_ROUTINE64)fnSymGetModuleBase64, NULL))
    {
        scpy (moduleInfo.moduleName, TEXT("<unknown>"));
        moduleInfo.faultAddress = frame.AddrPC.Offset;
        fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)&moduleInfo);
        slwr (moduleInfo.moduleName);

        p = srchr (moduleInfo.moduleName, '\\');
        if (p)
            p++;
        else
            p = moduleInfo.moduleName;

#ifdef _WIN64
        if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT))
        {
            crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!%s+0x%I64x\r\n"),
                frame.AddrStack.Offset,
                frame.AddrPC.Offset,
                frame.Params[0],
                frame.Params[1],
                frame.Params[2],
                frame.Params[3],
                p,
                symInfo->Name,
                fnOffset));
        }
        else
        {
            crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!0x%I64x\r\n"),
                frame.AddrStack.Offset,
                frame.AddrPC.Offset,
                frame.Params[0],
                frame.Params[1],
                frame.Params[2],
                frame.Params[3],
                p,
                frame.AddrPC.Offset));
        }
#else
        if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT))
        {
            crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!%s+0x%I64x\r\n"),
                frame.AddrStack.Offset,
                frame.AddrPC.Offset,
                (DWORD)frame.Params[0],
                (DWORD)frame.Params[1],
                (DWORD)frame.Params[2],
                (DWORD)frame.Params[3],
                p,
                symInfo->Name,
                fnOffset));
        }
        else
        {
            crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!0x%I64x\r\n"),
                frame.AddrStack.Offset,
                frame.AddrPC.Offset,
                (DWORD)frame.Params[0],
                (DWORD)frame.Params[1],
                (DWORD)frame.Params[2],
                (DWORD)frame.Params[3],
                p,
                frame.AddrPC.Offset
                ));
        }
#endif

        crashDumpLog.FlushFileBuffers();
    }

    //if we manually crashed due to a deadlocked thread, record some extra info
    if (exceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
    {
        HANDLE hVideoThread = NULL, hEncodeThread = NULL;
        if (App)
            App->GetThreadHandles (&hVideoThread, &hEncodeThread);

        if (hVideoThread)
        {
            crashDumpLog.WriteStr(TEXT("\r\nVideo thread stack trace:\r\n"));
#ifdef _WIN64
            crashDumpLog.WriteStr(TEXT("Stack            EIP              Arg0             Arg1             Arg2             Arg3             Address\r\n"));
#else
            crashDumpLog.WriteStr(TEXT("Stack    EIP      Arg0     Arg1     Arg2     Arg3     Address\r\n"));
#endif
            crashDumpLog.FlushFileBuffers();

            context.ContextFlags = CONTEXT_ALL;
            GetThreadContext (hVideoThread, &context);
            ZeroMemory (&frame, sizeof(frame));
#ifdef _WIN64
            InstructionPtr = context.Rip;
            frame.AddrPC.Offset = InstructionPtr;
            frame.AddrFrame.Offset = context.Rbp;
            frame.AddrStack.Offset = context.Rsp;
            imageType = IMAGE_FILE_MACHINE_AMD64;
#else
            InstructionPtr = context.Eip;
            frame.AddrPC.Offset = InstructionPtr;
            frame.AddrFrame.Offset = context.Ebp;
            frame.AddrStack.Offset = context.Esp;
            imageType = IMAGE_FILE_MACHINE_I386;
#endif

            frame.AddrFrame.Mode = AddrModeFlat;
            frame.AddrPC.Mode = AddrModeFlat;
            frame.AddrStack.Mode = AddrModeFlat;
            while (fnStackWalk64 (imageType, hProcess, hVideoThread, &frame, &context, NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE64)fnSymFunctionTableAccess64, (PGET_MODULE_BASE_ROUTINE64)fnSymGetModuleBase64, NULL))
            {
                scpy (moduleInfo.moduleName, TEXT("<unknown>"));
                moduleInfo.faultAddress = frame.AddrPC.Offset;
                fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)&moduleInfo);
                slwr (moduleInfo.moduleName);

                p = srchr (moduleInfo.moduleName, '\\');
                if (p)
                    p++;
                else
                    p = moduleInfo.moduleName;

#ifdef _WIN64
                if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT))
                {
                    crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!%s+0x%I64x\r\n"),
                        frame.AddrStack.Offset,
                        frame.AddrPC.Offset,
                        frame.Params[0],
                        frame.Params[1],
                        frame.Params[2],
                        frame.Params[3],
                        p,
                        symInfo->Name,
                        fnOffset));
                }
                else
                {
                    crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!0x%I64x\r\n"),
                        frame.AddrStack.Offset,
                        frame.AddrPC.Offset,
                        frame.Params[0],
                        frame.Params[1],
                        frame.Params[2],
                        frame.Params[3],
                        p,
                        frame.AddrPC.Offset));
                }
#else
                if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT))
                {
                    crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!%s+0x%I64x\r\n"),
                        frame.AddrStack.Offset,
                        frame.AddrPC.Offset,
                        (DWORD)frame.Params[0],
                        (DWORD)frame.Params[1],
                        (DWORD)frame.Params[2],
                        (DWORD)frame.Params[3],
                        p,
                        symInfo->Name,
                        fnOffset));
                }
                else
                {
                    crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!0x%I64x\r\n"),
                        frame.AddrStack.Offset,
                        frame.AddrPC.Offset,
                        (DWORD)frame.Params[0],
                        (DWORD)frame.Params[1],
                        (DWORD)frame.Params[2],
                        (DWORD)frame.Params[3],
                        p,
                        frame.AddrPC.Offset
                        ));
                }
#endif

                crashDumpLog.FlushFileBuffers();
            }
        }

        if (hEncodeThread)
        {
            crashDumpLog.WriteStr(TEXT("\r\nEncode thread stack trace:\r\n"));
#ifdef _WIN64
            crashDumpLog.WriteStr(TEXT("Stack            EIP              Arg0             Arg1             Arg2             Arg3             Address\r\n"));
#else
            crashDumpLog.WriteStr(TEXT("Stack    EIP      Arg0     Arg1     Arg2     Arg3     Address\r\n"));
#endif
            crashDumpLog.FlushFileBuffers();

            context.ContextFlags = CONTEXT_ALL;
            GetThreadContext (hEncodeThread, &context);
            ZeroMemory (&frame, sizeof(frame));
#ifdef _WIN64
            InstructionPtr = context.Rip;
            frame.AddrPC.Offset = InstructionPtr;
            frame.AddrFrame.Offset = context.Rbp;
            frame.AddrStack.Offset = context.Rsp;
            imageType = IMAGE_FILE_MACHINE_AMD64;
#else
            InstructionPtr = context.Eip;
            frame.AddrPC.Offset = InstructionPtr;
            frame.AddrFrame.Offset = context.Ebp;
            frame.AddrStack.Offset = context.Esp;
            imageType = IMAGE_FILE_MACHINE_I386;
#endif

            frame.AddrFrame.Mode = AddrModeFlat;
            frame.AddrPC.Mode = AddrModeFlat;
            frame.AddrStack.Mode = AddrModeFlat;
            while (fnStackWalk64 (imageType, hProcess, hEncodeThread, &frame, &context, NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE64)fnSymFunctionTableAccess64, (PGET_MODULE_BASE_ROUTINE64)fnSymGetModuleBase64, NULL))
            {
                scpy (moduleInfo.moduleName, TEXT("<unknown>"));
                moduleInfo.faultAddress = frame.AddrPC.Offset;
                fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)&moduleInfo);
                slwr (moduleInfo.moduleName);

                p = srchr (moduleInfo.moduleName, '\\');
                if (p)
                    p++;
                else
                    p = moduleInfo.moduleName;

#ifdef _WIN64
                if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT))
                {
                    crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!%s+0x%I64x\r\n"),
                        frame.AddrStack.Offset,
                        frame.AddrPC.Offset,
                        frame.Params[0],
                        frame.Params[1],
                        frame.Params[2],
                        frame.Params[3],
                        p,
                        symInfo->Name,
                        fnOffset));
                }
                else
                {
                    crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!0x%I64x\r\n"),
                        frame.AddrStack.Offset,
                        frame.AddrPC.Offset,
                        frame.Params[0],
                        frame.Params[1],
                        frame.Params[2],
                        frame.Params[3],
                        p,
                        frame.AddrPC.Offset));
                }
#else
                if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT))
                {
                    crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!%s+0x%I64x\r\n"),
                        frame.AddrStack.Offset,
                        frame.AddrPC.Offset,
                        (DWORD)frame.Params[0],
                        (DWORD)frame.Params[1],
                        (DWORD)frame.Params[2],
                        (DWORD)frame.Params[3],
                        p,
                        symInfo->Name,
                        fnOffset));
                }
                else
                {
                    crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!0x%I64x\r\n"),
                        frame.AddrStack.Offset,
                        frame.AddrPC.Offset,
                        (DWORD)frame.Params[0],
                        (DWORD)frame.Params[1],
                        (DWORD)frame.Params[2],
                        (DWORD)frame.Params[3],
                        p,
                        frame.AddrPC.Offset
                        ));
                }
#endif

                crashDumpLog.FlushFileBuffers();
            }
        }

    }

    //generate a minidump if possible
    if (fnMiniDumpWriteDump)
    {
        TCHAR     dumpPath[MAX_PATH];
        HANDLE    hFile;

        tsprintf_s (dumpPath, _countof(dumpPath)-1, TEXT("%s\\crashDumps\\OBSCrashDump%.4d-%.2d-%.2d_%d.dmp"), lpAppDataPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, i);

        hFile = CreateFile (dumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile != INVALID_HANDLE_VALUE)
        {
            MINIDUMP_TYPE dumpFlags = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData);

            miniInfo.ClientPointers = TRUE;
            miniInfo.ExceptionPointers = exceptionInfo;
            miniInfo.ThreadId = GetCurrentThreadId ();

            if (fnMiniDumpWriteDump (hProcess, GetCurrentProcessId(), hFile, dumpFlags, &miniInfo, NULL, NULL))
            {
                crashDumpLog.WriteStr(FormattedString(TEXT("\r\nA minidump was saved to %s.\r\nPlease include this file when posting a crash report.\r\n"), dumpPath));
            }
            else
            {
                CloseHandle (hFile);
                DeleteFile (dumpPath);
            }
        }
    }
    else
    {
        crashDumpLog.WriteStr(TEXT("\r\nA minidump could not be created. Please check dbghelp.dll is present.\r\n"));
    }

    crashDumpLog.WriteStr("\r\nList of loaded modules:\r\n");
#ifdef _WIN64
    crashDumpLog.WriteStr("Base Address                      Module\r\n");
#else
    crashDumpLog.WriteStr("Base Address      Module\r\n");
#endif
    crashDumpLog.WriteStr(strModuleInfo);

    crashDumpLog.Close();

    LocalFree (symInfo);

    fnSymCleanup (hProcess);

    if (OBSMessageBox(hwndMain, TEXT("Woops! OBS has crashed. Would you like to view a crash report?"), NULL, MB_ICONERROR | MB_YESNO) == IDYES)
        ShellExecute(NULL, NULL, logPath, NULL, searchPath, SW_SHOWDEFAULT);

    FreeLibrary (hDbgHelp);

    //we really shouldn't be returning here, if we're at the bottom of the VEH chain this is a pretty legitimate crash
    //and if we return we could end up invoking a second crash handler or other weird / annoying things
    //ExitProcess(exceptionInfo->ExceptionRecord->ExceptionCode);
    return EXCEPTION_CONTINUE_SEARCH;
}