Browse Source

UI: Add Multitrack Video settings

Ruwen Hahn 1 year ago
parent
commit
3f1362f7e7

+ 11 - 0
UI/data/locale/en-US.ini

@@ -935,6 +935,7 @@ Basic.Settings.Appearance.General.NoVariant="No Styles Available"
 
 # basic mode 'stream' settings
 Basic.Settings.Stream="Stream"
+Basic.Settings.Stream.Destination="Destination"
 Basic.Settings.Stream.Custom.UseAuthentication="Use authentication"
 Basic.Settings.Stream.Custom.Username="Username"
 Basic.Settings.Stream.Custom.Password="Password"
@@ -960,6 +961,16 @@ Basic.Settings.Stream.Recommended.MaxResolution="Maximum Resolution: %1"
 Basic.Settings.Stream.Recommended.MaxFPS="Maximum FPS: %1"
 Basic.Settings.Stream.SpecifyCustomServer="Specify Custom Server..."
 Basic.Settings.Stream.ServiceCustomServer="Custom Server"
+Basic.Settings.Stream.EnableMultitrackVideo="Enable %1"
+Basic.Settings.Stream.MultitrackVideoMaximumAggregateBitrate="Maximum Streaming Bandwidth"
+Basic.Settings.Stream.MultitrackVideoMaximumAggregateBitrateAuto="Auto"
+Basic.Settings.Stream.MultitrackVideoMaximumVideoTracks="Maximum Video Tracks"
+Basic.Settings.Stream.MultitrackVideoMaximumVideoTracksAuto="Auto"
+Basic.Settings.Stream.MultitrackVideoStreamDumpEnable="Enable stream dump to FLV (uses simple recording file settings)"
+Basic.Settings.Stream.MultitrackVideoConfigOverride="Config Override (JSON)"
+Basic.Settings.Stream.MultitrackVideoConfigOverrideEnable="Enable Config Override"
+Basic.Settings.Stream.MultitrackVideoLabel="Multitrack Video"
+Basic.Settings.Stream.AdvancedOptions="Advanced Options"
 
 # basic mode 'output' settings
 Basic.Settings.Output="Output"

+ 577 - 329
UI/forms/OBSBasicSettings.ui

@@ -1204,366 +1204,614 @@
              </item>
             </layout>
            </widget>
-           <widget class="QWidget" name="streamKeyPage">
-            <layout class="QFormLayout" name="streamkeyPageLayout">
-             <property name="fieldGrowthPolicy">
-              <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
-             </property>
-             <property name="labelAlignment">
-              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           <widget class="QScrollArea" name="streamKeyScrollArea">
+            <property name="frameShape">
+             <enum>QFrame::NoFrame</enum>
+            </property>
+            <property name="frameShadow">
+             <enum>QFrame::Plain</enum>
+            </property>
+            <property name="widgetResizable">
+             <bool>true</bool>
+            </property>
+            <widget class="QWidget" name="streamKeyPage">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
              </property>
-             <item row="0" column="0">
-              <widget class="QLabel" name="serverLabel">
-               <property name="text">
-                <string>Basic.AutoConfig.StreamPage.Server</string>
-               </property>
-              </widget>
-             </item>
-             <item row="0" column="1">
-              <widget class="QStackedWidget" name="serverStackedWidget">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="currentIndex">
-                <number>1</number>
-               </property>
-               <widget class="QWidget" name="servicePage">
-                <layout class="QHBoxLayout" name="horizontalLayout_21">
+             <layout class="QVBoxLayout" name="streamkeyPageLayout">
+              <item>
+               <widget class="QGroupBox" name="destinationGroupBox">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="title">
+                 <string>Basic.Settings.Stream.Destination</string>
+                </property>
+                <layout class="QFormLayout" name="destinationLayout">
+                 <property name="fieldGrowthPolicy">
+                  <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+                 </property>
+                 <property name="labelAlignment">
+                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                 </property>
                  <property name="leftMargin">
-                  <number>0</number>
+                  <number>9</number>
                  </property>
                  <property name="topMargin">
-                  <number>0</number>
+                  <number>2</number>
                  </property>
                  <property name="rightMargin">
-                  <number>0</number>
+                  <number>9</number>
                  </property>
                  <property name="bottomMargin">
-                  <number>0</number>
+                  <number>9</number>
                  </property>
-                 <item>
-                  <widget class="QComboBox" name="server"/>
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="serverLabel">
+                   <property name="text">
+                    <string>Basic.AutoConfig.StreamPage.Server</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QStackedWidget" name="serverStackedWidget">
+                   <property name="sizePolicy">
+                    <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+                     <horstretch>0</horstretch>
+                     <verstretch>0</verstretch>
+                    </sizepolicy>
+                   </property>
+                   <property name="currentIndex">
+                    <number>1</number>
+                   </property>
+                   <widget class="QWidget" name="servicePage">
+                    <layout class="QHBoxLayout" name="horizontalLayout_21">
+                     <property name="leftMargin">
+                      <number>0</number>
+                     </property>
+                     <property name="topMargin">
+                      <number>0</number>
+                     </property>
+                     <property name="rightMargin">
+                      <number>0</number>
+                     </property>
+                     <property name="bottomMargin">
+                      <number>0</number>
+                     </property>
+                     <item>
+                      <widget class="QComboBox" name="server"/>
+                     </item>
+                    </layout>
+                   </widget>
+                   <widget class="QWidget" name="customPage">
+                    <layout class="QHBoxLayout" name="horizontalLayout_22">
+                     <property name="leftMargin">
+                      <number>0</number>
+                     </property>
+                     <property name="topMargin">
+                      <number>0</number>
+                     </property>
+                     <property name="rightMargin">
+                      <number>0</number>
+                     </property>
+                     <property name="bottomMargin">
+                      <number>0</number>
+                     </property>
+                     <item>
+                      <widget class="QLineEdit" name="customServer"/>
+                     </item>
+                    </layout>
+                   </widget>
+                  </widget>
+                 </item>
+                 <item row="1" column="0">
+                  <widget class="QLabel" name="serviceCustomServerLabel">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.ServiceCustomServer</string>
+                   </property>
+                   <property name="buddy">
+                    <cstring>serviceCustomServer</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QLineEdit" name="serviceCustomServer"/>
+                 </item>
+                 <item row="2" column="0">
+                  <widget class="QLabel" name="streamKeyLabel">
+                   <property name="text">
+                    <string>Basic.AutoConfig.StreamPage.StreamKey</string>
+                   </property>
+                   <property name="openExternalLinks">
+                    <bool>true</bool>
+                   </property>
+                   <property name="buddy">
+                    <cstring>key</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="2" column="1">
+                  <widget class="QFrame" name="streamKeyWidget">
+                   <layout class="QHBoxLayout" name="horizontalLayout_11">
+                    <property name="leftMargin">
+                     <number>0</number>
+                    </property>
+                    <property name="topMargin">
+                     <number>0</number>
+                    </property>
+                    <property name="rightMargin">
+                     <number>0</number>
+                    </property>
+                    <property name="bottomMargin">
+                     <number>0</number>
+                    </property>
+                    <item>
+                     <widget class="QLineEdit" name="key">
+                      <property name="inputMask">
+                       <string notr="true"/>
+                      </property>
+                      <property name="text">
+                       <string notr="true"/>
+                      </property>
+                      <property name="echoMode">
+                       <enum>QLineEdit::Password</enum>
+                      </property>
+                     </widget>
+                    </item>
+                    <item>
+                     <widget class="QPushButton" name="show">
+                      <property name="text">
+                       <string>Show</string>
+                      </property>
+                     </widget>
+                    </item>
+                    <item>
+                     <widget class="UrlPushButton" name="getStreamKeyButton">
+                      <property name="toolTip">
+                       <string/>
+                      </property>
+                      <property name="toolTipDuration">
+                       <number>-4</number>
+                      </property>
+                      <property name="text">
+                       <string>Basic.AutoConfig.StreamPage.GetStreamKey</string>
+                      </property>
+                     </widget>
+                    </item>
+                   </layout>
+                  </widget>
+                 </item>
+                 <item row="3" column="0">
+                  <spacer name="horizontalSpacer_18">
+                   <property name="orientation">
+                    <enum>Qt::Horizontal</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>170</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item row="3" column="1">
+                  <layout class="QHBoxLayout" name="horizontalLayout_15">
+                   <item>
+                    <widget class="QPushButton" name="connectAccount2">
+                     <property name="cursor">
+                      <cursorShape>PointingHandCursor</cursorShape>
+                     </property>
+                     <property name="text">
+                      <string>Basic.AutoConfig.StreamPage.ConnectAccount</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <spacer name="horizontalSpacer_19">
+                     <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                     </property>
+                     <property name="sizeHint" stdset="0">
+                      <size>
+                       <width>40</width>
+                       <height>0</height>
+                      </size>
+                     </property>
+                    </spacer>
+                   </item>
+                  </layout>
+                 </item>
+                 <item row="4" column="0">
+                  <widget class="QLabel" name="connectedAccountLabel">
+                   <property name="text">
+                    <string>Basic.AutoConfig.StreamPage.ConnectedAccount</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="4" column="1">
+                  <layout class="QHBoxLayout" name="horizontalLayout_23">
+                   <property name="spacing">
+                    <number>8</number>
+                   </property>
+                   <property name="leftMargin">
+                    <number>7</number>
+                   </property>
+                   <property name="rightMargin">
+                    <number>7</number>
+                   </property>
+                   <item>
+                    <widget class="QLabel" name="connectedAccountText">
+                     <property name="styleSheet">
+                      <string notr="true">font-weight: bold</string>
+                     </property>
+                     <property name="text">
+                      <string>Auth.LoadingChannel.Title</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <widget class="QPushButton" name="disconnectAccount">
+                     <property name="text">
+                      <string>Basic.AutoConfig.StreamPage.DisconnectAccount</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <spacer name="horizontalSpacer_24">
+                     <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                     </property>
+                     <property name="sizeHint" stdset="0">
+                      <size>
+                       <width>40</width>
+                       <height>20</height>
+                      </size>
+                     </property>
+                    </spacer>
+                   </item>
+                  </layout>
+                 </item>
+                 <item row="5" column="1">
+                  <layout class="QHBoxLayout" name="horizontalLayout_28">
+                   <item>
+                    <widget class="QPushButton" name="useStreamKeyAdv">
+                     <property name="text">
+                      <string>Basic.AutoConfig.StreamPage.UseStreamKeyAdvanced</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <spacer name="horizontalSpacer_28">
+                     <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                     </property>
+                     <property name="sizeHint" stdset="0">
+                      <size>
+                       <width>40</width>
+                       <height>0</height>
+                      </size>
+                     </property>
+                    </spacer>
+                   </item>
+                  </layout>
+                 </item>
+                 <item row="6" column="1">
+                  <widget class="QCheckBox" name="useAuth">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.Custom.UseAuthentication</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="7" column="0">
+                  <widget class="QLabel" name="authUsernameLabel">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.Custom.Username</string>
+                   </property>
+                   <property name="buddy">
+                    <cstring>authUsername</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="7" column="1">
+                  <widget class="QLineEdit" name="authUsername"/>
+                 </item>
+                 <item row="8" column="0">
+                  <widget class="QLabel" name="authPwLabel">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.Custom.Password</string>
+                   </property>
+                   <property name="buddy">
+                    <cstring>authPw</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="8" column="1">
+                  <widget class="QFrame" name="authPwWidget">
+                   <layout class="QHBoxLayout" name="horizontalLayout_25">
+                    <property name="leftMargin">
+                     <number>0</number>
+                    </property>
+                    <property name="topMargin">
+                     <number>0</number>
+                    </property>
+                    <property name="rightMargin">
+                     <number>0</number>
+                    </property>
+                    <property name="bottomMargin">
+                     <number>0</number>
+                    </property>
+                    <item>
+                     <widget class="QLineEdit" name="authPw">
+                      <property name="echoMode">
+                       <enum>QLineEdit::Password</enum>
+                      </property>
+                     </widget>
+                    </item>
+                    <item>
+                     <widget class="QPushButton" name="authPwShow">
+                      <property name="text">
+                       <string>Show</string>
+                      </property>
+                     </widget>
+                    </item>
+                   </layout>
+                  </widget>
                  </item>
                 </layout>
                </widget>
-               <widget class="QWidget" name="customPage">
-                <layout class="QHBoxLayout" name="horizontalLayout_22">
+              </item>
+              <item>
+               <widget class="QGroupBox" name="multitrackVideoGroupBox">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="title">
+                 <string>Basic.Settings.Stream.MultitrackVideoLabel</string>
+                </property>
+                <layout class="QFormLayout" name="multitrackVideoLayout">
+                 <property name="fieldGrowthPolicy">
+                  <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+                 </property>
+                 <property name="labelAlignment">
+                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                 </property>
                  <property name="leftMargin">
-                  <number>0</number>
+                  <number>9</number>
                  </property>
                  <property name="topMargin">
-                  <number>0</number>
+                  <number>2</number>
                  </property>
                  <property name="rightMargin">
-                  <number>0</number>
+                  <number>9</number>
                  </property>
                  <property name="bottomMargin">
-                  <number>0</number>
+                  <number>9</number>
                  </property>
-                 <item>
-                  <widget class="QLineEdit" name="customServer"/>
+                 <item row="0" column="1">
+                  <widget class="QCheckBox" name="enableMultitrackVideo">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.EnableMultitrackVideo</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QLabel" name="multitrackVideoInfo">
+                   <property name="text">
+                    <string>MultitrackVideo.Info</string>
+                   </property>
+                   <property name="textFormat">
+                    <enum>Qt::RichText</enum>
+                   </property>
+                   <property name="wordWrap">
+                    <bool>true</bool>
+                   </property>
+                   <property name="openExternalLinks">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="2" column="0">
+                  <widget class="QLabel" name="multitrackVideoMaximumAggregateBitrateLabel">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.MultitrackVideoMaximumAggregateBitrate</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="2" column="1">
+                  <layout class="QHBoxLayout">
+                   <item>
+                    <widget class="QCheckBox" name="multitrackVideoMaximumAggregateBitrateAuto">
+                     <property name="text">
+                      <string>Basic.Settings.Stream.MultitrackVideoMaximumAggregateBitrateAuto</string>
+                     </property>
+                     <property name="sizePolicy">
+                      <enum>QSizePolicy::Minimum, QSizePolicy::Minimum</enum>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <widget class="QSpinBox" name="multitrackVideoMaximumAggregateBitrate">
+                     <property name="sizePolicy">
+                      <enum>QSizePolicy::MinimumExpanding, QSizePolicy::Minimum</enum>
+                     </property>
+                     <property name="minimum">
+                      <number>500</number>
+                     </property>
+                     <property name="maximum">
+                      <number>1000000</number>
+                     </property>
+                     <property name="value">
+                      <number>8000</number>
+                     </property>
+                    </widget>
+                   </item>
+                  </layout>
+                 </item>
+                 <item row="3" column="0">
+                  <widget class="QLabel" name="multitrackVideoMaximumVideoTracksLabel">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.MultitrackVideoMaximumVideoTracks</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="3" column="1">
+                  <layout class="QHBoxLayout">
+                   <item>
+                    <widget class="QCheckBox" name="multitrackVideoMaximumVideoTracksAuto">
+                     <property name="text">
+                      <string>Basic.Settings.Stream.MultitrackVideoMaximumVideoTracksAuto</string>
+                     </property>
+                     <property name="sizePolicy">
+                      <enum>QSizePolicy::Minimum, QSizePolicy::Minimum</enum>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <widget class="QSpinBox" name="multitrackVideoMaximumVideoTracks">
+                     <property name="sizePolicy">
+                      <enum>QSizePolicy::MinimumExpanding, QSizePolicy::Minimum</enum>
+                     </property>
+                     <property name="minimum">
+                      <number>0</number>
+                     </property>
+                     <property name="maximum">
+                      <number>100</number>
+                     </property>
+                     <property name="value">
+                      <number>0</number>
+                     </property>
+                    </widget>
+                   </item>
+                  </layout>
+                 </item>
+                 <item row="4" column="1">
+                  <widget class="QCheckBox" name="multitrackVideoStreamDumpEnable">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.MultitrackVideoStreamDumpEnable</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="5" column="1">
+                  <widget class="QCheckBox" name="multitrackVideoConfigOverrideEnable">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.MultitrackVideoConfigOverrideEnable</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="6" column="0">
+                  <widget class="QLabel" name="multitrackVideoConfigOverrideLabel">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.MultitrackVideoConfigOverride</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="7" column="1">
+                  <widget class="QPlainTextEdit" name="multitrackVideoConfigOverride">
+                   <property name="sizePolicy">
+                    <enum>QSizePolicy::Preferred, QSizePolicy::MinimumExpanding</enum>
+                   </property>
+                  </widget>
                  </item>
                 </layout>
                </widget>
-              </widget>
-             </item>
-             <item row="1" column="0">
-              <widget class="QLabel" name="serviceCustomServerLabel">
-               <property name="text">
-                <string>Basic.Settings.Stream.ServiceCustomServer</string>
-               </property>
-               <property name="buddy">
-                <cstring>serviceCustomServer</cstring>
-               </property>
-              </widget>
-             </item>
-             <item row="1" column="1">
-              <widget class="QLineEdit" name="serviceCustomServer"/>
-             </item>
-             <item row="3" column="0">
-              <widget class="QLabel" name="streamKeyLabel">
-               <property name="text">
-                <string>Basic.AutoConfig.StreamPage.StreamKey</string>
-               </property>
-               <property name="openExternalLinks">
-                <bool>true</bool>
-               </property>
-               <property name="buddy">
-                <cstring>key</cstring>
-               </property>
-              </widget>
-             </item>
-             <item row="3" column="1">
-              <widget class="QFrame" name="streamKeyWidget">
-               <layout class="QHBoxLayout" name="horizontalLayout_11">
-                <property name="leftMargin">
-                 <number>0</number>
+              </item>
+              <item>
+               <widget class="QGroupBox" name="serviceAdvancedOptionsGroupBox">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
                 </property>
-                <property name="topMargin">
-                 <number>0</number>
-                </property>
-                <property name="rightMargin">
-                 <number>0</number>
-                </property>
-                <property name="bottomMargin">
-                 <number>0</number>
+                <property name="title">
+                 <string>Basic.Settings.Stream.AdvancedOptions</string>
                 </property>
-                <item>
-                 <widget class="QLineEdit" name="key">
-                  <property name="inputMask">
-                   <string notr="true"/>
-                  </property>
-                  <property name="text">
-                   <string notr="true"/>
-                  </property>
-                  <property name="echoMode">
-                   <enum>QLineEdit::Password</enum>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QPushButton" name="show">
-                  <property name="text">
-                   <string>Show</string>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="UrlPushButton" name="getStreamKeyButton">
-                  <property name="toolTip">
-                   <string/>
-                  </property>
-                  <property name="toolTipDuration">
-                   <number>-4</number>
-                  </property>
-                  <property name="text">
-                   <string>Basic.AutoConfig.StreamPage.GetStreamKey</string>
-                  </property>
-                 </widget>
-                </item>
-               </layout>
-              </widget>
-             </item>
-             <item row="4" column="0">
-              <spacer name="horizontalSpacer_18">
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-               <property name="sizeHint" stdset="0">
-                <size>
-                 <width>170</width>
-                 <height>8</height>
-                </size>
-               </property>
-              </spacer>
-             </item>
-             <item row="5" column="1">
-              <layout class="QHBoxLayout" name="horizontalLayout_23">
-               <property name="spacing">
-                <number>8</number>
-               </property>
-               <property name="leftMargin">
-                <number>7</number>
-               </property>
-               <property name="rightMargin">
-                <number>7</number>
-               </property>
-               <item>
-                <widget class="QLabel" name="connectedAccountText">
-                 <property name="styleSheet">
-                  <string notr="true">font-weight: bold</string>
-                 </property>
-                 <property name="text">
-                  <string>Auth.LoadingChannel.Title</string>
-                 </property>
-                </widget>
-               </item>
-               <item>
-                <widget class="QPushButton" name="disconnectAccount">
-                 <property name="text">
-                  <string>Basic.AutoConfig.StreamPage.DisconnectAccount</string>
+                <layout class="QFormLayout" name="serviceAdvancedOptionsLayout">
+                 <property name="fieldGrowthPolicy">
+                  <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
                  </property>
-                </widget>
-               </item>
-               <item>
-                <spacer name="horizontalSpacer_24">
-                 <property name="orientation">
-                  <enum>Qt::Horizontal</enum>
-                 </property>
-                 <property name="sizeHint" stdset="0">
-                  <size>
-                   <width>40</width>
-                   <height>20</height>
-                  </size>
-                 </property>
-                </spacer>
-               </item>
-              </layout>
-             </item>
-             <item row="7" column="1">
-              <widget class="QCheckBox" name="bandwidthTestEnable">
-               <property name="text">
-                <string>Basic.Settings.Stream.BandwidthTestMode</string>
-               </property>
-              </widget>
-             </item>
-             <item row="8" column="1">
-              <widget class="QCheckBox" name="useAuth">
-               <property name="text">
-                <string>Basic.Settings.Stream.Custom.UseAuthentication</string>
-               </property>
-              </widget>
-             </item>
-             <item row="10" column="0">
-              <widget class="QLabel" name="authUsernameLabel">
-               <property name="text">
-                <string>Basic.Settings.Stream.Custom.Username</string>
-               </property>
-               <property name="buddy">
-                <cstring>authUsername</cstring>
-               </property>
-              </widget>
-             </item>
-             <item row="10" column="1">
-              <widget class="QLineEdit" name="authUsername"/>
-             </item>
-             <item row="11" column="0">
-              <widget class="QLabel" name="authPwLabel">
-               <property name="text">
-                <string>Basic.Settings.Stream.Custom.Password</string>
-               </property>
-               <property name="buddy">
-                <cstring>authPw</cstring>
-               </property>
-              </widget>
-             </item>
-             <item row="11" column="1">
-              <widget class="QFrame" name="authPwWidget">
-               <layout class="QHBoxLayout" name="horizontalLayout_25">
-                <property name="leftMargin">
-                 <number>0</number>
-                </property>
-                <property name="topMargin">
-                 <number>0</number>
-                </property>
-                <property name="rightMargin">
-                 <number>0</number>
-                </property>
-                <property name="bottomMargin">
-                 <number>0</number>
-                </property>
-                <item>
-                 <widget class="QLineEdit" name="authPw">
-                  <property name="echoMode">
-                   <enum>QLineEdit::Password</enum>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QPushButton" name="authPwShow">
-                  <property name="text">
-                   <string>Show</string>
-                  </property>
-                 </widget>
-                </item>
-               </layout>
-              </widget>
-             </item>
-             <item row="9" column="1">
-              <widget class="QComboBox" name="twitchAddonDropdown"/>
-             </item>
-             <item row="9" column="0">
-              <widget class="QLabel" name="twitchAddonLabel">
-               <property name="text">
-                <string>Basic.Settings.Stream.TTVAddon</string>
-               </property>
-               <property name="buddy">
-                <cstring>twitchAddonDropdown</cstring>
-               </property>
-              </widget>
-             </item>
-             <item row="12" column="1">
-              <widget class="QCheckBox" name="ignoreRecommended">
-               <property name="text">
-                <string>Basic.Settings.Stream.IgnoreRecommended</string>
-               </property>
-              </widget>
-             </item>
-             <item row="13" column="1">
-              <widget class="QLabel" name="enforceSettingsLabel">
-               <property name="text">
-                <string notr="true"/>
-               </property>
-               <property name="textFormat">
-                <enum>Qt::RichText</enum>
-               </property>
-               <property name="openExternalLinks">
-                <bool>true</bool>
-               </property>
-              </widget>
-             </item>
-             <item row="6" column="1">
-              <layout class="QHBoxLayout" name="horizontalLayout_28">
-               <item>
-                <widget class="QPushButton" name="useStreamKeyAdv">
-                 <property name="text">
-                  <string>Basic.AutoConfig.StreamPage.UseStreamKeyAdvanced</string>
-                 </property>
-                </widget>
-               </item>
-               <item>
-                <spacer name="horizontalSpacer_28">
-                 <property name="orientation">
-                  <enum>Qt::Horizontal</enum>
-                 </property>
-                 <property name="sizeHint" stdset="0">
-                  <size>
-                   <width>40</width>
-                   <height>20</height>
-                  </size>
+                 <property name="labelAlignment">
+                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
                  </property>
-                </spacer>
-               </item>
-              </layout>
-             </item>
-             <item row="5" column="0">
-              <widget class="QLabel" name="connectedAccountLabel">
-               <property name="text">
-                <string>Basic.AutoConfig.StreamPage.ConnectedAccount</string>
-               </property>
-              </widget>
-             </item>
-             <item row="4" column="1">
-              <layout class="QHBoxLayout" name="horizontalLayout_15">
-               <item>
-                <widget class="QPushButton" name="connectAccount2">
-                 <property name="cursor">
-                  <cursorShape>PointingHandCursor</cursorShape>
+                 <property name="leftMargin">
+                  <number>9</number>
                  </property>
-                 <property name="text">
-                  <string>Basic.AutoConfig.StreamPage.ConnectAccount</string>
+                 <property name="topMargin">
+                  <number>2</number>
                  </property>
-                </widget>
-               </item>
-               <item>
-                <spacer name="horizontalSpacer_19">
-                 <property name="orientation">
-                  <enum>Qt::Horizontal</enum>
+                 <property name="rightMargin">
+                  <number>9</number>
                  </property>
-                 <property name="sizeHint" stdset="0">
-                  <size>
-                   <width>40</width>
-                   <height>20</height>
-                  </size>
+                 <property name="bottomMargin">
+                  <number>9</number>
                  </property>
-                </spacer>
-               </item>
-              </layout>
-             </item>
-            </layout>
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="twitchAddonLabel">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.TTVAddon</string>
+                   </property>
+                   <property name="buddy">
+                    <cstring>twitchAddonDropdown</cstring>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="QComboBox" name="twitchAddonDropdown"/>
+                 </item>
+                 <item row="1" column="0">
+                  <spacer name="horizontalSpacer_18_1">
+                   <property name="orientation">
+                    <enum>Qt::Horizontal</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>170</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QCheckBox" name="bandwidthTestEnable">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.BandwidthTestMode</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="2" column="1">
+                  <widget class="QCheckBox" name="ignoreRecommended">
+                   <property name="text">
+                    <string>Basic.Settings.Stream.IgnoreRecommended</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="3" column="1">
+                  <widget class="QLabel" name="enforceSettingsLabel">
+                   <property name="text">
+                    <string notr="true"/>
+                   </property>
+                   <property name="textFormat">
+                    <enum>Qt::RichText</enum>
+                   </property>
+                   <property name="openExternalLinks">
+                    <bool>true</bool>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+             </layout>
+            </widget>
            </widget>
           </widget>
          </item>

+ 101 - 3
UI/window-basic-settings-stream.cpp

@@ -45,7 +45,7 @@ enum class Section : int {
 	StreamKey,
 };
 
-inline bool OBSBasicSettings::IsCustomService() const
+bool OBSBasicSettings::IsCustomService() const
 {
 	return ui->service->currentData().toInt() == (int)ListOpt::Custom;
 }
@@ -96,6 +96,16 @@ void OBSBasicSettings::InitStreamPage()
 		&OBSBasicSettings::DisplayEnforceWarning);
 	connect(ui->ignoreRecommended, &QCheckBox::toggled, this,
 		&OBSBasicSettings::UpdateResFPSLimits);
+
+	connect(ui->enableMultitrackVideo, &QCheckBox::toggled, this,
+		&OBSBasicSettings::UpdateMultitrackVideo);
+	connect(ui->multitrackVideoMaximumAggregateBitrateAuto,
+		&QCheckBox::toggled, this,
+		&OBSBasicSettings::UpdateMultitrackVideo);
+	connect(ui->multitrackVideoMaximumVideoTracksAuto, &QCheckBox::toggled,
+		this, &OBSBasicSettings::UpdateMultitrackVideo);
+	connect(ui->multitrackVideoConfigOverrideEnable, &QCheckBox::toggled,
+		this, &OBSBasicSettings::UpdateMultitrackVideo);
 }
 
 void OBSBasicSettings::LoadStream1Settings()
@@ -155,6 +165,44 @@ void OBSBasicSettings::LoadStream1Settings()
 		ui->twitchAddonDropdown->setCurrentIndex(idx);
 	}
 
+	ui->enableMultitrackVideo->setChecked(config_get_bool(
+		main->Config(), "Stream1", "EnableMultitrackVideo"));
+
+	ui->multitrackVideoMaximumAggregateBitrateAuto->setChecked(
+		config_get_bool(main->Config(), "Stream1",
+				"MultitrackVideoMaximumAggregateBitrateAuto"));
+	if (config_has_user_value(main->Config(), "Stream1",
+				  "MultitrackVideoMaximumAggregateBitrate")) {
+		ui->multitrackVideoMaximumAggregateBitrate->setValue(
+			config_get_int(
+				main->Config(), "Stream1",
+				"MultitrackVideoMaximumAggregateBitrate"));
+	}
+
+	ui->multitrackVideoMaximumVideoTracksAuto->setChecked(
+		config_get_bool(main->Config(), "Stream1",
+				"MultitrackVideoMaximumVideoTracksAuto"));
+	if (config_has_user_value(main->Config(), "Stream1",
+				  "MultitrackVideoMaximumVideoTracks"))
+		ui->multitrackVideoMaximumVideoTracks->setValue(
+			config_get_int(main->Config(), "Stream1",
+				       "MultitrackVideoMaximumVideoTracks"));
+
+	ui->multitrackVideoStreamDumpEnable->setChecked(config_get_bool(
+		main->Config(), "Stream1", "MultitrackVideoStreamDumpEnabled"));
+
+	ui->multitrackVideoConfigOverrideEnable->setChecked(
+		config_get_bool(main->Config(), "Stream1",
+				"MultitrackVideoConfigOverrideEnabled"));
+	if (config_has_user_value(main->Config(), "Stream1",
+				  "MultitrackVideoConfigOverride"))
+		ui->multitrackVideoConfigOverride->setPlainText(
+			DeserializeConfigText(
+				config_get_string(
+					main->Config(), "Stream1",
+					"MultitrackVideoConfigOverride"))
+				.c_str());
+
 	UpdateServerList();
 
 	if (is_rtmp_common) {
@@ -187,6 +235,7 @@ void OBSBasicSettings::LoadStream1Settings()
 	UpdateMoreInfoLink();
 	UpdateVodTrackSetting();
 	UpdateServiceRecommendations();
+	UpdateMultitrackVideo();
 
 	bool streamActive = obs_frontend_streaming_active();
 	ui->streamPage->setEnabled(!streamActive);
@@ -315,6 +364,49 @@ void OBSBasicSettings::SaveStream1Settings()
 	}
 
 	SaveCheckBox(ui->ignoreRecommended, "Stream1", "IgnoreRecommended");
+
+	auto oldMultitrackVideoSetting = config_get_bool(
+		main->Config(), "Stream1", "EnableMultitrackVideo");
+
+	if (!IsCustomService()) {
+		OBSDataAutoRelease settings = obs_data_create();
+		obs_data_set_string(settings, "service",
+				    QT_TO_UTF8(ui->service->currentText()));
+		OBSServiceAutoRelease temp_service = obs_service_create_private(
+			"rtmp_common", "auto config query service", settings);
+		settings = obs_service_get_settings(temp_service);
+		auto available = obs_data_has_user_value(
+			settings, "multitrack_video_configuration_url");
+
+		if (available) {
+			SaveCheckBox(ui->enableMultitrackVideo, "Stream1",
+				     "EnableMultitrackVideo");
+		} else {
+			config_remove_value(main->Config(), "Stream1",
+					    "EnableMultitrackVideo");
+		}
+	} else {
+		SaveCheckBox(ui->enableMultitrackVideo, "Stream1",
+			     "EnableMultitrackVideo");
+	}
+	SaveCheckBox(ui->multitrackVideoMaximumAggregateBitrateAuto, "Stream1",
+		     "MultitrackVideoMaximumAggregateBitrateAuto");
+	SaveSpinBox(ui->multitrackVideoMaximumAggregateBitrate, "Stream1",
+		    "MultitrackVideoMaximumAggregateBitrate");
+	SaveCheckBox(ui->multitrackVideoMaximumVideoTracksAuto, "Stream1",
+		     "MultitrackVideoMaximumVideoTracksAuto");
+	SaveSpinBox(ui->multitrackVideoMaximumVideoTracks, "Stream1",
+		    "MultitrackVideoMaximumVideoTracks");
+	SaveCheckBox(ui->multitrackVideoStreamDumpEnable, "Stream1",
+		     "MultitrackVideoStreamDumpEnabled");
+	SaveCheckBox(ui->multitrackVideoConfigOverrideEnable, "Stream1",
+		     "MultitrackVideoConfigOverrideEnabled");
+	SaveText(ui->multitrackVideoConfigOverride, "Stream1",
+		 "MultitrackVideoConfigOverride");
+
+	if (oldMultitrackVideoSetting != ui->enableMultitrackVideo->isChecked())
+		main->ResetOutputs();
+
 	SwapMultiTrack(QT_TO_UTF8(protocol));
 }
 
@@ -555,6 +647,7 @@ void OBSBasicSettings::on_service_currentIndexChanged(int idx)
 
 	protocol = FindProtocol();
 	UpdateAdvNetworkGroup();
+	UpdateMultitrackVideo();
 
 	if (ServiceSupportsCodecCheck() && UpdateResFPSLimits()) {
 		lastServiceIdx = idx;
@@ -576,6 +669,7 @@ void OBSBasicSettings::on_customServer_textChanged(const QString &)
 
 	protocol = FindProtocol();
 	UpdateAdvNetworkGroup();
+	UpdateMultitrackVideo();
 
 	if (ServiceSupportsCodecCheck())
 		lastCustomServer = ui->customServer->text();
@@ -596,6 +690,10 @@ void OBSBasicSettings::ServiceChanged(bool resetFields)
 
 	if (resetFields || lastService != service.c_str()) {
 		reset_service_ui_fields(ui.get(), service, loading);
+
+		ui->enableMultitrackVideo->setChecked(config_get_bool(
+			main->Config(), "Stream1", "EnableMultitrackVideo"));
+		UpdateMultitrackVideo();
 	}
 
 	ui->useAuth->setVisible(custom);
@@ -605,8 +703,8 @@ void OBSBasicSettings::ServiceChanged(bool resetFields)
 	ui->authPwWidget->setVisible(custom);
 
 	if (custom || whip) {
-		ui->streamkeyPageLayout->insertRow(1, ui->serverLabel,
-						   ui->serverStackedWidget);
+		ui->destinationLayout->insertRow(1, ui->serverLabel,
+						 ui->serverStackedWidget);
 
 		ui->serverStackedWidget->setCurrentIndex(1);
 		ui->serverStackedWidget->setVisible(true);

+ 134 - 0
UI/window-basic-settings.cpp

@@ -337,6 +337,7 @@ void RestrictResetBitrates(initializer_list<QComboBox *> boxes, int maxbitrate);
 #define GROUP_CHANGED   &QGroupBox::toggled
 #define SCROLL_CHANGED  &QSpinBox::valueChanged
 #define DSCROLL_CHANGED &QDoubleSpinBox::valueChanged
+#define TEXT_CHANGED    &QPlainTextEdit::textChanged
 
 #define GENERAL_CHANGED &OBSBasicSettings::GeneralChanged
 #define STREAM1_CHANGED &OBSBasicSettings::Stream1Changed
@@ -419,6 +420,14 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
 	HookWidget(ui->authUsername,         EDIT_CHANGED,   STREAM1_CHANGED);
 	HookWidget(ui->authPw,               EDIT_CHANGED,   STREAM1_CHANGED);
 	HookWidget(ui->ignoreRecommended,    CHECK_CHANGED,  STREAM1_CHANGED);
+	HookWidget(ui->enableMultitrackVideo,      CHECK_CHANGED,  STREAM1_CHANGED);
+	HookWidget(ui->multitrackVideoMaximumAggregateBitrateAuto, CHECK_CHANGED,  STREAM1_CHANGED);
+	HookWidget(ui->multitrackVideoMaximumAggregateBitrate,     SCROLL_CHANGED, STREAM1_CHANGED);
+	HookWidget(ui->multitrackVideoMaximumVideoTracksAuto, CHECK_CHANGED,  STREAM1_CHANGED);
+	HookWidget(ui->multitrackVideoMaximumVideoTracks,     SCROLL_CHANGED, STREAM1_CHANGED);
+	HookWidget(ui->multitrackVideoStreamDumpEnable,            CHECK_CHANGED,  STREAM1_CHANGED);
+	HookWidget(ui->multitrackVideoConfigOverrideEnable,        CHECK_CHANGED,  STREAM1_CHANGED);
+	HookWidget(ui->multitrackVideoConfigOverride,              TEXT_CHANGED,   STREAM1_CHANGED);
 	HookWidget(ui->outputMode,           COMBO_CHANGED,  OUTPUTS_CHANGED);
 	HookWidget(ui->simpleOutputPath,     EDIT_CHANGED,   OUTPUTS_CHANGED);
 	HookWidget(ui->simpleNoSpace,        CHECK_CHANGED,  OUTPUTS_CHANGED);
@@ -1068,6 +1077,21 @@ void OBSBasicSettings::SaveSpinBox(QSpinBox *widget, const char *section,
 		config_set_int(main->Config(), section, value, widget->value());
 }
 
+void OBSBasicSettings::SaveText(QPlainTextEdit *widget, const char *section,
+				const char *value)
+{
+	if (!WidgetChanged(widget))
+		return;
+
+	auto utf8 = widget->toPlainText().toUtf8();
+
+	OBSDataAutoRelease safe_text = obs_data_create();
+	obs_data_set_string(safe_text, "text", utf8.constData());
+
+	config_set_string(main->Config(), section, value,
+			  obs_data_get_json(safe_text));
+}
+
 std::string DeserializeConfigText(const char *value)
 {
 	OBSDataAutoRelease data = obs_data_create_from_json(value);
@@ -6253,6 +6277,116 @@ void OBSBasicSettings::UpdateAdvNetworkGroup()
 #endif
 }
 
+extern bool MultitrackVideoDeveloperModeEnabled();
+
+void OBSBasicSettings::UpdateMultitrackVideo()
+{
+	// Technically, it should currently be safe to toggle multitrackVideo
+	// while not streaming (recording should be irrelevant), but practically
+	// output settings aren't currently being tracked with that degree of
+	// flexibility, so just disable everything while outputs are active.
+	auto toggle_available = !main->Active();
+
+	// FIXME: protocol is not updated properly for WHIP; what do?
+	auto available = protocol.startsWith("RTMP");
+
+	if (available && !IsCustomService()) {
+		OBSDataAutoRelease settings = obs_data_create();
+		obs_data_set_string(settings, "service",
+				    QT_TO_UTF8(ui->service->currentText()));
+		OBSServiceAutoRelease temp_service = obs_service_create_private(
+			"rtmp_common", "auto config query service", settings);
+		settings = obs_service_get_settings(temp_service);
+		available = obs_data_has_user_value(
+			settings, "multitrack_video_configuration_url");
+		if (!available && ui->enableMultitrackVideo->isChecked())
+			ui->enableMultitrackVideo->setChecked(false);
+	}
+
+	ui->multitrackVideoGroupBox->setVisible(available);
+
+	ui->enableMultitrackVideo->setEnabled(toggle_available);
+
+	ui->multitrackVideoMaximumAggregateBitrateLabel->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked());
+	ui->multitrackVideoMaximumAggregateBitrateAuto->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked());
+	ui->multitrackVideoMaximumAggregateBitrate->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked() &&
+		!ui->multitrackVideoMaximumAggregateBitrateAuto->isChecked());
+
+	ui->multitrackVideoMaximumVideoTracksLabel->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked());
+	ui->multitrackVideoMaximumVideoTracksAuto->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked());
+	ui->multitrackVideoMaximumVideoTracks->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked() &&
+		!ui->multitrackVideoMaximumVideoTracksAuto->isChecked());
+
+	ui->multitrackVideoStreamDumpEnable->setVisible(
+		available && MultitrackVideoDeveloperModeEnabled());
+	ui->multitrackVideoConfigOverrideEnable->setVisible(
+		available && MultitrackVideoDeveloperModeEnabled());
+	ui->multitrackVideoConfigOverrideLabel->setVisible(
+		available && MultitrackVideoDeveloperModeEnabled());
+	ui->multitrackVideoConfigOverride->setVisible(
+		available && MultitrackVideoDeveloperModeEnabled());
+
+	ui->multitrackVideoStreamDumpEnable->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked());
+	ui->multitrackVideoConfigOverrideEnable->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked());
+	ui->multitrackVideoConfigOverrideLabel->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked() &&
+		ui->multitrackVideoConfigOverrideEnable->isChecked());
+	ui->multitrackVideoConfigOverride->setEnabled(
+		toggle_available && ui->enableMultitrackVideo->isChecked() &&
+		ui->multitrackVideoConfigOverrideEnable->isChecked());
+
+	if (available) {
+		OBSDataAutoRelease settings;
+		{
+			auto service_name = ui->service->currentText();
+			auto custom_server = ui->customServer->text().trimmed();
+
+			obs_properties_t *props =
+				obs_get_service_properties("rtmp_common");
+			obs_property_t *service =
+				obs_properties_get(props, "service");
+
+			settings = obs_data_create();
+
+			obs_data_set_string(settings, "service",
+					    QT_TO_UTF8(service_name));
+			obs_property_modified(service, settings);
+
+			obs_properties_destroy(props);
+		}
+
+		auto multitrack_video_name =
+			QTStr("Basic.Settings.Stream.MultitrackVideoLabel");
+		if (obs_data_has_user_value(settings, "multitrack_video_name"))
+			multitrack_video_name = obs_data_get_string(
+				settings, "multitrack_video_name");
+
+		ui->enableMultitrackVideo->setText(
+			QTStr("Basic.Settings.Stream.EnableMultitrackVideo")
+				.arg(multitrack_video_name));
+
+		if (obs_data_has_user_value(settings,
+					    "multitrack_video_disclaimer")) {
+			ui->multitrackVideoInfo->setVisible(true);
+			ui->multitrackVideoInfo->setText(obs_data_get_string(
+				settings, "multitrack_video_disclaimer"));
+		} else {
+			ui->multitrackVideoInfo->setText(
+				QTStr("MultitrackVideo.Info")
+					.arg(multitrack_video_name,
+					     ui->service->currentText()));
+		}
+	}
+}
+
 void OBSBasicSettings::SimpleStreamAudioEncoderChanged()
 {
 	PopulateSimpleBitrates(

+ 4 - 1
UI/window-basic-settings.hpp

@@ -195,6 +195,8 @@ private:
 		      const char *value);
 	void SaveSpinBox(QSpinBox *widget, const char *section,
 			 const char *value);
+	void SaveText(QPlainTextEdit *widget, const char *section,
+		      const char *value);
 	void SaveFormat(QComboBox *combo);
 	void SaveEncoder(QComboBox *combo, const char *section,
 			 const char *value);
@@ -275,7 +277,7 @@ private:
 
 	/* stream */
 	void InitStreamPage();
-	inline bool IsCustomService() const;
+	bool IsCustomService() const;
 	inline bool IsWHIP() const;
 	void LoadServices(bool showAll);
 	void OnOAuthStreamKeyConnected();
@@ -301,6 +303,7 @@ private:
 	bool IsCustomServer();
 
 private slots:
+	void UpdateMultitrackVideo();
 	void RecreateOutputResolutionWidget();
 	bool UpdateResFPSLimits();
 	void DisplayEnforceWarning(bool checked);