diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui
index 0265e9cec..27fbedaa1 100644
--- a/UI/forms/OBSBasicSettings.ui
+++ b/UI/forms/OBSBasicSettings.ui
@@ -666,106 +666,20 @@
0
-
-
-
- true
-
-
-
-
- 0
- 0
- 818
- 697
-
+
+
+ true
-
-
- 0
+
+
+
+ 0
+ 0
+ 818
+ 697
+
-
- 0
-
-
- 0
-
-
- 9
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.Mode
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- outputMode
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
- 0
-
-
-
-
- Basic.Settings.Output.Mode.Simple
-
-
- -
-
- Basic.Settings.Output.Mode.Adv
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- 0
-
-
-
+
0
@@ -776,28 +690,22 @@
0
- 0
+ 9
- -
-
+
-
+
-
+
0
0
-
- Basic.Settings.Output.Adv.Streaming
-
-
+
QFormLayout::AllNonFixedFieldsGrow
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
+
170
@@ -805,496 +713,526 @@
- Basic.Settings.Output.VideoBitrate
+ Basic.Settings.Output.Mode
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- simpleOutputVBitrate
+ outputMode
-
-
-
- 200
-
-
- 1000000
-
-
- 2000
-
-
-
- -
-
-
- Basic.Settings.Output.AudioBitrate
-
-
- simpleOutputABitrate
-
-
-
- -
-
-
- 8
-
-
-
-
- 32
-
-
- -
-
- 48
-
-
- -
-
- 64
-
-
- -
-
- 80
-
-
- -
-
- 96
-
-
- -
-
- 112
-
-
- -
-
- 128
-
-
- -
-
- 160
-
-
- -
-
- 192
-
-
- -
-
- 256
-
-
- -
-
- 320
-
-
-
-
- -
-
-
- Basic.Settings.Output.Advanced
-
-
- true
-
-
-
- -
-
-
- -
-
+
true
-
- Basic.Settings.Output.EncoderPreset
+
+
+ 0
+ 0
+
-
- simpleOutPreset
-
-
-
- -
-
-
- Basic.Settings.Output.CustomEncoderSettings
-
-
- simpleOutCustom
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.EnforceBitrate
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.Encoder
-
-
- simpleOutRecEncoder
+
+ 0
+
-
+
+ Basic.Settings.Output.Mode.Simple
+
+
+ -
+
+ Basic.Settings.Output.Mode.Adv
+
+
-
-
-
-
- 0
- 0
-
-
-
- Basic.Settings.Output.Adv.Recording
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.Simple.SavePath
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- simpleOutputPath
-
-
-
- -
-
-
-
-
-
- true
-
-
-
- -
-
-
- true
-
-
- Browse
-
-
-
-
-
- -
-
-
- Basic.Settings.Output.NoSpaceFileName
-
-
- true
-
-
-
- -
-
-
- Basic.Settings.Output.Simple.RecordingQuality
-
-
- simpleOutRecQuality
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.Format
-
-
- simpleOutRecFormat
-
-
-
- -
-
-
-
-
- flv
-
-
- -
-
- mp4
-
-
- -
-
- mov
-
-
- -
-
- mkv
-
-
- -
-
- ts
-
-
- -
-
- m3u8
-
-
-
-
- -
-
-
- Basic.Settings.Output.Encoder
-
-
- simpleOutRecEncoder
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.CustomMuxerSettings
-
-
- simpleOutMuxCustom
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.UseReplayBuffer
-
-
- true
-
-
-
-
-
-
- -
-
-
- ReplayBuffer
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
- Basic.Settings.Output.ReplayBuffer.SecondsMax
-
-
-
- -
-
-
- sec
-
-
- 5
-
-
- 21600
-
-
- 15
-
-
-
- -
-
-
- Basic.Settings.Output.ReplayBuffer.MegabytesMax
-
-
-
- -
-
-
- MB
-
-
- 20
-
-
- 8192
-
-
- 512
-
-
-
- -
-
-
- Basic.Settings.Output.ReplayBuffer.HotkeyMessage
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- 10
-
-
- 10
-
-
- 10
-
-
- 10
-
-
-
- -
-
+
- Qt::Vertical
+ Qt::Horizontal
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
+
0
-
- true
-
-
-
- Basic.Settings.Output.Adv.Streaming
-
-
+
+
- 9
+ 0
0
- 9
+ 0
- 9
+ 0
-
-
-
-
-
- 0
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Output.Adv.Streaming
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.VideoBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ simpleOutputVBitrate
+
+
+
+ -
+
+
+ 200
+
+
+ 1000000
+
+
+ 2000
+
+
+
+ -
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ simpleOutputABitrate
+
+
+
+ -
+
+
+ 8
+
+
-
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.Advanced
+
+
+ true
+
+
+
+ -
+
+
+ -
+
+
+ true
+
+
+ Basic.Settings.Output.EncoderPreset
+
+
+ simpleOutPreset
+
+
+
+ -
+
+
+ Basic.Settings.Output.CustomEncoderSettings
+
+
+ simpleOutCustom
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.EnforceBitrate
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.Encoder
+
+
+ simpleOutRecEncoder
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Output.Adv.Recording
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.Simple.SavePath
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ simpleOutputPath
+
+
+
+ -
+
+
-
+
+
+ true
+
+
+
+ -
+
+
+ true
+
+
+ Browse
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.NoSpaceFileName
+
+
+ true
+
+
+
+ -
+
+
+ Basic.Settings.Output.Simple.RecordingQuality
+
+
+ simpleOutRecQuality
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.Format
+
+
+ simpleOutRecFormat
+
+
+
+ -
+
+
-
+
+ flv
+
+
+ -
+
+ mp4
+
+
+ -
+
+ mov
+
+
+ -
+
+ mkv
+
+
+ -
+
+ ts
+
+
+ -
+
+ m3u8
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.Encoder
+
+
+ simpleOutRecEncoder
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.CustomMuxerSettings
+
+
+ simpleOutMuxCustom
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.UseReplayBuffer
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ ReplayBuffer
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+ Basic.Settings.Output.ReplayBuffer.SecondsMax
+
+
+
+ -
+
+
+ sec
+
+
+ 5
+
+
+ 21600
+
+
+ 15
+
+
+
+ -
+
+
+ Basic.Settings.Output.ReplayBuffer.MegabytesMax
+
+
+
+ -
+
+
+ MB
+
+
+ 20
+
+
+ 8192
+
+
+ 512
+
+
+
+ -
+
+
+ Basic.Settings.Output.ReplayBuffer.HotkeyMessage
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
0
@@ -1307,260 +1245,56 @@
0
-
-
-
-
-
- 0
- 0
-
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.Adv.AudioTrack
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- 1
-
-
- true
-
-
-
- -
-
-
- 2
-
-
-
- -
-
-
- 3
-
-
-
- -
-
-
- 4
-
-
-
- -
-
-
- 5
-
-
-
- -
-
-
- 6
-
-
-
-
-
-
- -
-
-
- Basic.Settings.Output.Encoder
-
-
- advOutEncoder
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.Adv.ApplyServiceSettings
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::RightToLeft
-
-
- Basic.Settings.Output.Adv.Rescale
-
-
-
- -
-
-
- false
-
-
- true
-
-
-
-
-
-
-
-
- Basic.Settings.Output.Adv.Recording
-
-
+
+
- 9
+ 0
- 9
+ 0
- 9
+ 0
- 9
+ 0
-
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.Adv.Recording.Type
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- advOutRecType
-
-
-
- -
-
-
-
-
- Basic.Settings.Output.Adv.Recording.Type.Standard
-
-
- -
-
- Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
+
0
-
-
+
+ true
+
+
+
+ Basic.Settings.Output.Adv.Streaming
+
+
- 0
+ 9
0
- 0
+ 9
- 0
+ 9
-
-
-
+
+
+
+ 0
+
0
@@ -1574,31 +1308,22 @@
0
-
-
+
0
0
-
+
QFormLayout::AllNonFixedFieldsGrow
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
- 0
-
-
-
-
-
-
- 0
- 0
-
-
+
-
+
170
@@ -1606,107 +1331,22 @@
- Basic.Settings.Output.Simple.SavePath
+ Basic.Settings.Output.Adv.AudioTrack
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
- advOutRecPath
-
- -
-
-
-
-
-
- true
-
-
-
- -
-
-
- true
-
-
- Browse
-
-
-
-
-
-
-
-
- Basic.Settings.Output.NoSpaceFileName
-
-
- true
-
-
-
- -
-
-
- Basic.Settings.Output.Format
-
-
- advOutRecFormat
-
-
-
- -
-
-
-
-
- flv
-
-
- -
-
- mp4
-
-
- -
-
- mov
-
-
- -
-
- mkv
-
-
- -
-
- ts
-
-
- -
-
- m3u8
-
-
-
-
- -
-
-
- Basic.Settings.Output.Adv.AudioTrack
-
-
-
- -
-
+
0
0
-
+
0
@@ -1720,42 +1360,45 @@
0
-
-
+
1
+
+ true
+
-
-
+
2
-
-
+
3
-
-
+
4
-
-
+
5
-
-
+
6
@@ -1764,21 +1407,31 @@
- -
-
+
-
+
Basic.Settings.Output.Encoder
- advOutRecEncoder
+ advOutEncoder
- -
-
+
-
+
- -
-
+
-
+
+
+ Basic.Settings.Output.Adv.ApplyServiceSettings
+
+
+ true
+
+
+
+ -
+
0
@@ -1793,47 +1446,16 @@
- -
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- false
-
-
- true
-
-
-
-
-
-
- -
-
-
- Basic.Settings.Output.CustomMuxerSettings
+
-
+
+
+ false
-
- advOutMuxCustom
+
+ true
- -
-
-
@@ -1842,423 +1464,1641 @@
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ Basic.Settings.Output.Adv.Recording
+
+
+
+ 9
- 0
+ 9
- -
-
-
-
- 0
- 0
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.Adv.FFmpeg.SavePathURL
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- 0
-
-
-
-
- 3
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- true
-
-
-
- -
-
-
- Browse
-
-
-
-
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
-
-
- true
-
-
-
-
-
-
-
- -
-
-
- Basic.Settings.Output.Adv.FFmpeg.Format
-
-
- advOutFFFormat
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.Adv.FFmpeg.FormatDesc
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- Basic.Settings.Output.VideoBitrate
-
-
- advOutFFVBitrate
-
-
-
- -
-
-
- 0
-
-
- 1000000000
-
-
- 2500
-
-
-
- -
-
-
- 1000000000
-
-
- 250
-
-
-
- -
-
-
- Basic.Settings.Output.Adv.FFmpeg.GOPSize
-
-
- advOutFFVGOPSize
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::RightToLeft
-
-
- Basic.Settings.Output.Adv.Rescale
-
-
-
- -
-
-
- false
-
-
- true
-
-
-
- -
-
-
- Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat
-
-
-
- -
-
-
- Basic.Settings.Output.Adv.FFmpeg.VEncoder
-
-
- advOutFFVEncoder
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings
-
-
- advOutFFVCfg
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.AudioBitrate
-
-
- advOutFFABitrate
-
-
-
- -
-
-
- 32
-
-
- 4096
-
-
- 16
-
-
- 128
-
-
-
- -
-
-
- Basic.Settings.Output.Adv.AudioTrack
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
+
+ 9
+
+
+ 9
+
+
-
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
0
-
- 0
-
0
-
-
-
-
- 1
+
-
+
+
+
+ 170
+ 0
+
-
- true
+
+ Basic.Settings.Output.Adv.Recording.Type
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutRecType
+ -
+
+
-
+
+ Basic.Settings.Output.Adv.Recording.Type.Standard
+
+
+ -
+
+ Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.Simple.SavePath
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutRecPath
+
+
+
+ -
+
+
-
+
+
+ true
+
+
+
+ -
+
+
+ true
+
+
+ Browse
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.NoSpaceFileName
+
+
+ true
+
+
+
+ -
+
+
+ Basic.Settings.Output.Format
+
+
+ advOutRecFormat
+
+
+
+ -
+
+
-
+
+ flv
+
+
+ -
+
+ mp4
+
+
+ -
+
+ mov
+
+
+ -
+
+ mkv
+
+
+ -
+
+ ts
+
+
+ -
+
+ m3u8
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.AudioTrack
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ 1
+
+
+
+ -
+
+
+ 2
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ 4
+
+
+
+ -
+
+
+ 5
+
+
+
+ -
+
+
+ 6
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.Encoder
+
+
+ advOutRecEncoder
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::RightToLeft
+
+
+ Basic.Settings.Output.Adv.Rescale
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ false
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.CustomMuxerSettings
+
+
+ advOutMuxCustom
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.Adv.FFmpeg.SavePathURL
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ 1
+
+
+
+
+ 3
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ true
+
+
+
+ -
+
+
+ Browse
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ true
+
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.Format
+
+
+ advOutFFFormat
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.FormatDesc
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.VideoBitrate
+
+
+ advOutFFVBitrate
+
+
+
+ -
+
+
+ 0
+
+
+ 1000000000
+
+
+ 2500
+
+
+
+ -
+
+
+ 1000000000
+
+
+ 250
+
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.GOPSize
+
+
+ advOutFFVGOPSize
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::RightToLeft
+
+
+ Basic.Settings.Output.Adv.Rescale
+
+
+
+ -
+
+
+ false
+
+
+ true
+
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat
+
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.VEncoder
+
+
+ advOutFFVEncoder
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings
+
+
+ advOutFFVCfg
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ advOutFFABitrate
+
+
+
+ -
+
+
+ 32
+
+
+ 4096
+
+
+ 16
+
+
+ 128
+
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.AudioTrack
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ 1
+
+
+ true
+
+
+
+ -
+
+
+ 2
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ 4
+
+
+
+ -
+
+
+ 5
+
+
+
+ -
+
+
+ 6
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.AEncoder
+
+
+ advOutFFAEncoder
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings
+
+
+ advOutFFACfg
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.Adv.FFmpeg.Type
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutFFType
+
+
+
+ -
+
+
-
+
+ Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile
+
+
+ -
+
+ Basic.Settings.Output.Adv.FFmpeg.Type.URL
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.MuxerSettings
+
+
+ advOutFFMCfg
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.NoSpaceFileName
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+ Basic.Settings.Audio
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
-
-
-
- 2
+
+
+
+ 0
+ 0
+
+
+ Basic.Settings.Output.Adv.Audio.Track1
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+ 8
+
+
-
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutTrack1Bitrate
+
+
+
+ -
+
+
+ Name
+
+
+ advOutTrack1Name
+
+
+
+ -
+
+
+
-
-
-
- 3
+
+
+
+ 0
+ 0
+
+
+ Basic.Settings.Output.Adv.Audio.Track2
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutTrack2Bitrate
+
+
+
+ -
+
+
+ 8
+
+
-
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+ Name
+
+
+ advOutTrack2Name
+
+
+
+ -
+
+
+
-
-
-
- 4
+
+
+
+ 0
+ 0
+
+
+ Basic.Settings.Output.Adv.Audio.Track3
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutTrack3Bitrate
+
+
+
+ -
+
+
+ 8
+
+
-
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+ Name
+
+
+ advOutTrack3Name
+
+
+
+ -
+
+
+
-
-
-
- 5
+
+
+
+ 0
+ 0
+
+
+ Basic.Settings.Output.Adv.Audio.Track4
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutTrack4Bitrate
+
+
+
+ -
+
+
+ 8
+
+
-
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+ Name
+
+
+ advOutTrack4Name
+
+
+
+ -
+
+
+
-
-
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Output.Adv.Audio.Track5
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutTrack5Bitrate
+
+
+
+ -
+
+
+ 8
+
+
-
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+ Name
+
+
+ advOutTrack5Name
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Output.Adv.Audio.Track6
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutTrack6Bitrate
+
+
+
+ -
+
+
+ 8
+
+
-
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+ Name
+
+
+ advOutTrack6Name
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ ReplayBuffer
+
+
+ -
+
+
+ Basic.Settings.Output.UseReplayBuffer
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ ReplayBuffer
+
+
+ false
+
+
+ false
+
+
+
-
+
- 6
+ Basic.Settings.Output.ReplayBuffer.SecondsMax
+
+
+
+ -
+
+
+ sec
+
+
+ 5
+
+
+ 21600
+
+
+ 15
+
+
+
+ -
+
+
+ Basic.Settings.Output.ReplayBuffer.HotkeyMessage
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ MB
+
+
+ 20
+
+
+ 8192
+
+
+ 512
+
+
+
+ -
+
+
+ Basic.Settings.Output.ReplayBuffer.MegabytesMax
- -
-
-
- Basic.Settings.Output.Adv.FFmpeg.AEncoder
+
-
+
+
+ Qt::Vertical
-
- advOutFFAEncoder
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings
-
-
- advOutFFACfg
-
-
-
- -
-
-
- -
-
-
-
- 0
- 0
-
-
-
+
- 170
- 0
+ 20
+ 40
-
- Basic.Settings.Output.Adv.FFmpeg.Type
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- advOutFFType
-
-
-
- -
-
-
-
-
- Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile
-
-
- -
-
- Basic.Settings.Output.Adv.FFmpeg.Type.URL
-
-
-
-
- -
-
-
- Basic.Settings.Output.Adv.FFmpeg.MuxerSettings
-
-
- advOutFFMCfg
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.NoSpaceFileName
-
-
- true
-
-
+
@@ -2266,737 +3106,12 @@
-
-
- Basic.Settings.Audio
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Basic.Settings.Output.Adv.Audio.Track1
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
- 8
-
-
-
-
- 32
-
-
- -
-
- 48
-
-
- -
-
- 64
-
-
- -
-
- 80
-
-
- -
-
- 96
-
-
- -
-
- 112
-
-
- -
-
- 128
-
-
- -
-
- 160
-
-
- -
-
- 192
-
-
- -
-
- 256
-
-
- -
-
- 320
-
-
-
-
- -
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.AudioBitrate
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- advOutTrack1Bitrate
-
-
-
- -
-
-
- Name
-
-
- advOutTrack1Name
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Basic.Settings.Output.Adv.Audio.Track2
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.AudioBitrate
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- advOutTrack2Bitrate
-
-
-
- -
-
-
- 8
-
-
-
-
- 32
-
-
- -
-
- 48
-
-
- -
-
- 64
-
-
- -
-
- 80
-
-
- -
-
- 96
-
-
- -
-
- 112
-
-
- -
-
- 128
-
-
- -
-
- 160
-
-
- -
-
- 192
-
-
- -
-
- 256
-
-
- -
-
- 320
-
-
-
-
- -
-
-
- Name
-
-
- advOutTrack2Name
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Basic.Settings.Output.Adv.Audio.Track3
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.AudioBitrate
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- advOutTrack3Bitrate
-
-
-
- -
-
-
- 8
-
-
-
-
- 32
-
-
- -
-
- 48
-
-
- -
-
- 64
-
-
- -
-
- 80
-
-
- -
-
- 96
-
-
- -
-
- 112
-
-
- -
-
- 128
-
-
- -
-
- 160
-
-
- -
-
- 192
-
-
- -
-
- 256
-
-
- -
-
- 320
-
-
-
-
- -
-
-
- Name
-
-
- advOutTrack3Name
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Basic.Settings.Output.Adv.Audio.Track4
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.AudioBitrate
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- advOutTrack4Bitrate
-
-
-
- -
-
-
- 8
-
-
-
-
- 32
-
-
- -
-
- 48
-
-
- -
-
- 64
-
-
- -
-
- 80
-
-
- -
-
- 96
-
-
- -
-
- 112
-
-
- -
-
- 128
-
-
- -
-
- 160
-
-
- -
-
- 192
-
-
- -
-
- 256
-
-
- -
-
- 320
-
-
-
-
- -
-
-
- Name
-
-
- advOutTrack4Name
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Basic.Settings.Output.Adv.Audio.Track5
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.AudioBitrate
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- advOutTrack5Bitrate
-
-
-
- -
-
-
- 8
-
-
-
-
- 32
-
-
- -
-
- 48
-
-
- -
-
- 64
-
-
- -
-
- 80
-
-
- -
-
- 96
-
-
- -
-
- 112
-
-
- -
-
- 128
-
-
- -
-
- 160
-
-
- -
-
- 192
-
-
- -
-
- 256
-
-
- -
-
- 320
-
-
-
-
- -
-
-
- Name
-
-
- advOutTrack5Name
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Basic.Settings.Output.Adv.Audio.Track6
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.AudioBitrate
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- advOutTrack6Bitrate
-
-
-
- -
-
-
- 8
-
-
-
-
- 32
-
-
- -
-
- 48
-
-
- -
-
- 64
-
-
- -
-
- 80
-
-
- -
-
- 96
-
-
- -
-
- 112
-
-
- -
-
- 128
-
-
- -
-
- 160
-
-
- -
-
- 192
-
-
- -
-
- 256
-
-
- -
-
- 320
-
-
-
-
- -
-
-
- Name
-
-
- advOutTrack6Name
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -3174,8 +3289,8 @@
0
0
- 98
- 28
+ 800
+ 69
@@ -3545,7 +3660,7 @@
0
0
- 593
+ 803
761
diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp
index dbe2cd22a..bc28469ad 100644
--- a/UI/window-basic-main-outputs.cpp
+++ b/UI/window-basic-main-outputs.cpp
@@ -991,6 +991,7 @@ struct AdvancedOutput : BasicOutputHandler {
bool ffmpegOutput;
bool ffmpegRecording;
bool useStreamEncoder;
+ bool usesBitrate = false;
string aacEncoderID[MAX_AUDIO_MIXES];
@@ -1009,10 +1010,13 @@ struct AdvancedOutput : BasicOutputHandler {
virtual bool StartStreaming(obs_service_t *service) override;
virtual bool StartRecording() override;
+ virtual bool StartReplayBuffer() override;
virtual void StopStreaming(bool force) override;
virtual void StopRecording(bool force) override;
+ virtual void StopReplayBuffer(bool force) override;
virtual bool StreamingActive() const override;
virtual bool RecordingActive() const override;
+ virtual bool ReplayBufferActive() const override;
};
static OBSData GetDataFromJsonFile(const char *jsonFile)
@@ -1050,6 +1054,15 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
OBSData streamEncSettings = GetDataFromJsonFile("streamEncoder.json");
OBSData recordEncSettings = GetDataFromJsonFile("recordEncoder.json");
+ const char *rate_control = obs_data_get_string(
+ useStreamEncoder ? streamEncSettings : recordEncSettings,
+ "rate_control");
+ if (!rate_control)
+ rate_control = "";
+ usesBitrate = astrcmpi(rate_control, "CBR") == 0 ||
+ astrcmpi(rate_control, "VBR") == 0 ||
+ astrcmpi(rate_control, "ABR") == 0;
+
if (ffmpegOutput) {
fileOutput = obs_output_create("ffmpeg_output",
"adv_ffmpeg_output", nullptr, nullptr);
@@ -1058,6 +1071,33 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
"(advanced output)";
obs_output_release(fileOutput);
} else {
+ bool useReplayBuffer = config_get_bool(main->Config(),
+ "AdvOut", "RecRB");
+ if (useReplayBuffer) {
+ const char *str = config_get_string(main->Config(),
+ "Hotkeys", "ReplayBuffer");
+ obs_data_t *hotkey = obs_data_create_from_json(str);
+ replayBuffer = obs_output_create("replay_buffer",
+ Str("ReplayBuffer"), nullptr, hotkey);
+
+ obs_data_release(hotkey);
+ if (!replayBuffer)
+ throw "Failed to create replay buffer output "
+ "(simple output)";
+ obs_output_release(replayBuffer);
+
+ signal_handler_t *signal =
+ obs_output_get_signal_handler(
+ replayBuffer);
+
+ startReplayBuffer.Connect(signal, "start",
+ OBSStartReplayBuffer, this);
+ stopReplayBuffer.Connect(signal, "stop",
+ OBSStopReplayBuffer, this);
+ replayBufferStopping.Connect(signal, "stopping",
+ OBSReplayBufferStopping, this);
+ }
+
fileOutput = obs_output_create("ffmpeg_muxer",
"adv_file_output", nullptr, nullptr);
if (!fileOutput)
@@ -1174,6 +1214,9 @@ inline void AdvancedOutput::SetupRecording()
if (useStreamEncoder) {
obs_output_set_video_encoder(fileOutput, h264Streaming);
+ if (replayBuffer)
+ obs_output_set_video_encoder(replayBuffer,
+ h264Streaming);
} else {
if (rescale && rescaleRes && *rescaleRes) {
if (sscanf(rescaleRes, "%ux%u", &cx, &cy) != 2) {
@@ -1185,18 +1228,27 @@ inline void AdvancedOutput::SetupRecording()
obs_encoder_set_scaled_size(h264Recording, cx, cy);
obs_encoder_set_video(h264Recording, obs_get_video());
obs_output_set_video_encoder(fileOutput, h264Recording);
+ if (replayBuffer)
+ obs_output_set_video_encoder(replayBuffer,
+ h264Recording);
}
for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
if ((tracks & (1<Config(), "AdvOut",
+ ffmpegRecording ? "FFFilePath" : "RecFilePath");
+ recFormat = config_get_string(main->Config(), "AdvOut",
+ ffmpegRecording ? "FFExtension" : "RecFormat");
+ filenameFormat = config_get_string(main->Config(), "Output",
+ "FilenameFormatting");
+ overwriteIfExists = config_get_bool(main->Config(), "Output",
+ "OverwriteIfExists");
+ noSpace = config_get_bool(main->Config(), "AdvOut",
+ ffmpegRecording ?
+ "FFFileNameWithoutSpace" :
+ "RecFileNameWithoutSpace");
+ rbPrefix = config_get_string(main->Config(), "SimpleOutput",
+ "RecRBPrefix");
+ rbSuffix = config_get_string(main->Config(), "SimpleOutput",
+ "RecRBSuffix");
+ rbTime = config_get_int(main->Config(), "AdvOut",
+ "RecRBTime");
+ rbSize = config_get_int(main->Config(), "AdvOut",
+ "RecRBSize");
+
+ os_dir_t *dir = path && path[0] ? os_opendir(path) : nullptr;
+
+ if (!dir) {
+ if (main->isVisible())
+ OBSMessageBox::information(main,
+ QTStr("Output.BadPath.Title"),
+ QTStr("Output.BadPath.Text"));
+ else
+ main->SysTrayNotify(QTStr("Output.BadPath.Text"),
+ QSystemTrayIcon::Warning);
+ return false;
+ }
+
+ os_closedir(dir);
+
+ string strPath;
+ strPath += path;
+
+ char lastChar = strPath.back();
+ if (lastChar != '/' && lastChar != '\\')
+ strPath += "/";
+
+ strPath += GenerateSpecifiedFilename(recFormat, noSpace,
+ filenameFormat);
+ ensure_directory_exists(strPath);
+ if (!overwriteIfExists)
+ FindBestFilename(strPath, noSpace);
+
+ obs_data_t *settings = obs_data_create();
+ string f;
+
+ if (rbPrefix && *rbPrefix) {
+ f += rbPrefix;
+ if (f.back() != ' ')
+ f += " ";
+ }
+
+ f += filenameFormat;
+
+ if (rbSuffix && *rbSuffix) {
+ if (*rbSuffix != ' ')
+ f += " ";
+ f += rbSuffix;
+ }
+
+ remove_reserved_file_characters(f);
+
+ obs_data_set_string(settings, "directory", path);
+ obs_data_set_string(settings, "format", f.c_str());
+ obs_data_set_string(settings, "extension", recFormat);
+ obs_data_set_int(settings, "max_time_sec", rbTime);
+ obs_data_set_int(settings, "max_size_mb",
+ usesBitrate ? 0 : rbSize);
+
+ obs_output_update(replayBuffer, settings);
+
+ obs_data_release(settings);
+ }
+
+ if (!obs_output_start(replayBuffer)) {
+ QMessageBox::critical(main,
+ QTStr("Output.StartRecordingFailed"),
+ QTStr("Output.StartFailedGeneric"));
+ return false;
+ }
+
+ return true;
+}
+
void AdvancedOutput::StopStreaming(bool force)
{
if (force)
@@ -1565,6 +1732,14 @@ void AdvancedOutput::StopRecording(bool force)
obs_output_stop(fileOutput);
}
+void AdvancedOutput::StopReplayBuffer(bool force)
+{
+ if (force)
+ obs_output_force_stop(replayBuffer);
+ else
+ obs_output_stop(replayBuffer);
+}
+
bool AdvancedOutput::StreamingActive() const
{
return obs_output_active(streamOutput);
@@ -1575,6 +1750,11 @@ bool AdvancedOutput::RecordingActive() const
return obs_output_active(fileOutput);
}
+bool AdvancedOutput::ReplayBufferActive() const
+{
+ return obs_output_active(replayBuffer);
+}
+
/* ------------------------------------------------------------------------ */
BasicOutputHandler *CreateSimpleOutputHandler(OBSBasic *main)
diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
index b954764d5..eade3813f 100644
--- a/UI/window-basic-main.cpp
+++ b/UI/window-basic-main.cpp
@@ -1057,6 +1057,10 @@ bool OBSBasic::InitBasicConfigDefaults()
config_set_default_uint (basicConfig, "AdvOut", "Track5Bitrate", 160);
config_set_default_uint (basicConfig, "AdvOut", "Track6Bitrate", 160);
+ config_set_default_bool (basicConfig, "AdvOut", "RecRB", false);
+ config_set_default_uint (basicConfig, "AdvOut", "RecRBTime", 20);
+ config_set_default_int (basicConfig, "AdvOut", "RecRBSize", 512);
+
config_set_default_uint (basicConfig, "Video", "BaseCX", cx);
config_set_default_uint (basicConfig, "Video", "BaseCY", cy);
diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
index a25ba24eb..cf9772ace 100644
--- a/UI/window-basic-settings.cpp
+++ b/UI/window-basic-settings.cpp
@@ -387,6 +387,9 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
HookWidget(ui->advOutTrack5Name, EDIT_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->advOutTrack6Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->advOutTrack6Name, EDIT_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->advReplayBuf, CHECK_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->advRBSecMax, SCROLL_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->advRBMegsMax, SCROLL_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->channelSetup, COMBO_CHANGED, AUDIO_RESTART);
HookWidget(ui->sampleRate, COMBO_CHANGED, AUDIO_RESTART);
HookWidget(ui->desktopAudioDevice1, COMBO_CHANGED, AUDIO_CHANGED);
@@ -612,6 +615,38 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
this, SLOT(SimpleReplayBufferChanged()));
connect(ui->simpleRBSecMax, SIGNAL(valueChanged(int)),
this, SLOT(SimpleReplayBufferChanged()));
+ connect(ui->advReplayBuf, SIGNAL(toggled(bool)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutRecTrack1, SIGNAL(toggled(bool)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutRecTrack2, SIGNAL(toggled(bool)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutRecTrack3, SIGNAL(toggled(bool)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutRecTrack4, SIGNAL(toggled(bool)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutRecTrack5, SIGNAL(toggled(bool)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutRecTrack6, SIGNAL(toggled(bool)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutTrack1Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutTrack2Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutTrack3Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutTrack4Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutTrack5Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutTrack6Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutRecType, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advOutRecEncoder, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(AdvReplayBufferChanged()));
+ connect(ui->advRBSecMax, SIGNAL(valueChanged(int)),
+ this, SLOT(AdvReplayBufferChanged()));
connect(ui->listWidget, SIGNAL(currentRowChanged(int)),
this, SLOT(SimpleRecordingEncoderChanged()));
@@ -1491,6 +1526,8 @@ void OBSBasicSettings::LoadAdvOutputStreamingEncoderProperties()
connect(streamEncoderProps, SIGNAL(Changed()),
this, SLOT(UpdateStreamDelayEstimate()));
+ connect(streamEncoderProps, SIGNAL(Changed()),
+ this, SLOT(AdvReplayBufferChanged()));
curAdvStreamEncoder = type;
@@ -1557,6 +1594,8 @@ void OBSBasicSettings::LoadAdvOutputRecordingEncoderProperties()
recordEncoderProps = CreateEncoderPropertyView(type,
"recordEncoder.json");
ui->advOutRecStandard->layout()->addWidget(recordEncoderProps);
+ connect(recordEncoderProps, SIGNAL(Changed()),
+ this, SLOT(AdvReplayBufferChanged()));
}
curAdvRecordEncoder = type;
@@ -2050,6 +2089,13 @@ void OBSBasicSettings::LoadAdvancedSettings()
"RecRBPrefix");
const char *rbSuffix = config_get_string(main->Config(), "SimpleOutput",
"RecRBSuffix");
+ bool replayBuf = config_get_bool(main->Config(), "AdvOut",
+ "RecRB");
+ int rbTime = config_get_int(main->Config(), "AdvOut",
+ "RecRBTime");
+ int rbSize = config_get_int(main->Config(), "AdvOut",
+ "RecRBSize");
+
loading = true;
LoadRendererList();
@@ -2064,6 +2110,10 @@ void OBSBasicSettings::LoadAdvancedSettings()
ui->simpleRBPrefix->setText(rbPrefix);
ui->simpleRBSuffix->setText(rbSuffix);
+ ui->advReplayBuf->setChecked(replayBuf);
+ ui->advRBSecMax->setValue(rbTime);
+ ui->advRBMegsMax->setValue(rbSize);
+
ui->reconnectEnable->setChecked(reconnect);
ui->reconnectRetryDelay->setValue(retryDelay);
ui->reconnectMaxRetries->setValue(maxRetries);
@@ -2854,6 +2904,10 @@ void OBSBasicSettings::SaveOutputSettings()
SaveEdit(ui->advOutTrack5Name, "AdvOut", "Track5Name");
SaveEdit(ui->advOutTrack6Name, "AdvOut", "Track6Name");
+ SaveCheckBox(ui->advReplayBuf, "AdvOut", "RecRB");
+ SaveSpinBox(ui->advRBSecMax, "AdvOut", "RecRBTime");
+ SaveSpinBox(ui->advRBMegsMax, "AdvOut", "RecRBSize");
+
WriteJsonData(streamEncoderProps, "streamEncoder.json");
WriteJsonData(recordEncoderProps, "recordEncoder.json");
main->ResetOutputs();
@@ -3184,6 +3238,8 @@ void OBSBasicSettings::on_advOutRecEncoder_currentIndexChanged(int idx)
loadSettings ? "recordEncoder.json" : nullptr,
true);
ui->advOutRecStandard->layout()->addWidget(recordEncoderProps);
+ connect(recordEncoderProps, SIGNAL(Changed()),
+ this, SLOT(AdvReplayBufferChanged()));
}
}
@@ -3730,8 +3786,15 @@ void OBSBasicSettings::SimpleStreamingEncoderChanged()
void OBSBasicSettings::UpdateAutomaticReplayBufferCheckboxes()
{
- bool state = ui->simpleReplayBuf->isChecked() &&
- ui->outputMode->currentIndex() == 0;
+ bool state = false;
+ switch (ui->outputMode->currentIndex()) {
+ case 0:
+ state = ui->simpleReplayBuf->isChecked();
+ break;
+ case 1:
+ state = ui->advReplayBuf->isChecked();
+ break;
+ }
ui->replayWhileStreaming->setEnabled(state);
ui->keepReplayStreamStops->setEnabled(state &&
ui->replayWhileStreaming->isChecked());
@@ -3766,7 +3829,89 @@ void OBSBasicSettings::SimpleReplayBufferChanged()
ui->simpleReplayBuf->setVisible(!lossless);
UpdateAutomaticReplayBufferCheckboxes();
+}
+void OBSBasicSettings::AdvReplayBufferChanged()
+{
+ obs_data_t *settings;
+ QString encoder = ui->advOutRecEncoder->currentText();
+ bool useStream = QString::compare(encoder, TEXT_USE_STREAM_ENC) == 0;
+
+ if (useStream && streamEncoderProps) {
+ settings = streamEncoderProps->GetSettings();
+ } else if (!useStream && recordEncoderProps) {
+ settings = recordEncoderProps->GetSettings();
+ } else {
+ if (useStream)
+ encoder = GetComboData(ui->advOutEncoder);
+ settings = obs_encoder_defaults(encoder.toUtf8().constData());
+
+ if (!settings)
+ return;
+
+ char encoderJsonPath[512];
+ int ret = GetProfilePath(encoderJsonPath,
+ sizeof(encoderJsonPath), "recordEncoder.json");
+ if (ret > 0) {
+ obs_data_t *data = obs_data_create_from_json_file_safe(
+ encoderJsonPath, "bak");
+ obs_data_apply(settings, data);
+ obs_data_release(data);
+ }
+ }
+
+ int vbitrate = (int)obs_data_get_int(settings, "bitrate");
+ const char *rateControl = obs_data_get_string(settings, "rate_control");
+
+ bool lossless = strcmp(rateControl, "lossless") == 0 ||
+ ui->advOutRecType->currentIndex() == 1;
+ bool replayBufferEnabled = ui->advReplayBuf->isChecked();
+
+ int abitrate = 0;
+ if (ui->advOutRecTrack1->isChecked())
+ abitrate += ui->advOutTrack1Bitrate->currentText().toInt();
+ if (ui->advOutRecTrack2->isChecked())
+ abitrate += ui->advOutTrack2Bitrate->currentText().toInt();
+ if (ui->advOutRecTrack3->isChecked())
+ abitrate += ui->advOutTrack3Bitrate->currentText().toInt();
+ if (ui->advOutRecTrack4->isChecked())
+ abitrate += ui->advOutTrack4Bitrate->currentText().toInt();
+ if (ui->advOutRecTrack5->isChecked())
+ abitrate += ui->advOutTrack5Bitrate->currentText().toInt();
+ if (ui->advOutRecTrack6->isChecked())
+ abitrate += ui->advOutTrack6Bitrate->currentText().toInt();
+
+ int seconds = ui->advRBSecMax->value();
+
+ int64_t memMB = int64_t(seconds) * int64_t(vbitrate + abitrate) *
+ 1000 / 8 / 1024 / 1024;
+ if (memMB < 1)
+ memMB = 1;
+
+ if (!rateControl)
+ rateControl = "";
+
+ bool varRateControl = (astrcmpi(rateControl, "CBR") == 0 ||
+ astrcmpi(rateControl, "VBR") == 0 ||
+ astrcmpi(rateControl, "ABR") == 0);
+ if (vbitrate == 0)
+ varRateControl = false;
+
+ ui->advRBMegsMax->setVisible(!varRateControl);
+ ui->advRBMegsMaxLabel->setVisible(!varRateControl);
+
+ if (varRateControl)
+ ui->advRBEstimate->setText(
+ QTStr(ESTIMATE_STR).arg(
+ QString::number(int(memMB))));
+ else
+ ui->advRBEstimate->setText(QTStr(ESTIMATE_UNKNOWN_STR));
+
+ ui->advReplayBufferGroupBox->setVisible(!lossless && replayBufferEnabled);
+ ui->line_4->setVisible(!lossless && replayBufferEnabled);
+ ui->advReplayBuf->setEnabled(!lossless);
+
+ UpdateAutomaticReplayBufferCheckboxes();
}
#define SIMPLE_OUTPUT_WARNING(str) \
diff --git a/UI/window-basic-settings.hpp b/UI/window-basic-settings.hpp
index 5e56ec75c..1eb810427 100644
--- a/UI/window-basic-settings.hpp
+++ b/UI/window-basic-settings.hpp
@@ -295,6 +295,7 @@ private slots:
void SimpleRecordingQualityLosslessWarning(int idx);
void SimpleReplayBufferChanged();
+ void AdvReplayBufferChanged();
void SimpleStreamingEncoderChanged();