diff --git a/web/components/config/cpu-usage.tsx b/web/components/config/cpu-usage.tsx deleted file mode 100644 index b75aa8bc4..000000000 --- a/web/components/config/cpu-usage.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, { useContext, useState, useEffect } from 'react'; -import { Typography, Slider } from 'antd'; -import { ServerStatusContext } from '../../utils/server-status-context'; - -const { Title } = Typography; - -const SLIDER_MARKS = { - 1: 'lowest', - 2: '', - 3: '', - 4: '', - 5: 'highest', -}; - -const TOOLTIPS = { - 1: 'Lowest CPU usage - lowest quality video', - 2: 'Low CPU usage - low quality video', - 3: 'Medium CPU usage - average quality video', - 4: 'High CPU usage - high quality video', - 5: 'Highest CPU usage - higher quality video', -}; -interface Props { - defaultValue: number; - disabled: boolean; - onChange: (arg: number) => void; -} -export default function CPUUsageSelector({ defaultValue, disabled, onChange }: Props) { - const [selectedOption, setSelectedOption] = useState(null); - - const serverStatusData = useContext(ServerStatusContext); - const { serverConfig } = serverStatusData || {}; - const { videoSettings } = serverConfig || {}; - - if (!videoSettings) { - return null; - } - - useEffect(() => { - setSelectedOption(defaultValue); - }, [videoSettings]); - - const handleChange = value => { - setSelectedOption(value); - onChange(value); - }; - - const cpuUsageNote = () => { - if (disabled) { - return 'CPU usage selection is disabled when Video Passthrough is enabled.'; - } - - return TOOLTIPS[selectedOption]; - }; - - return ( -
- CPU Usage -

- Reduce to improve server performance, or increase it to improve video quality. -

-
- TOOLTIPS[value]} - onChange={handleChange} - min={1} - max={Object.keys(SLIDER_MARKS).length} - marks={SLIDER_MARKS} - defaultValue={selectedOption} - value={selectedOption} - disabled={disabled} - /> -

{cpuUsageNote()}

-
-
- ); -} diff --git a/web/components/config/video-variant-form.tsx b/web/components/config/video-variant-form.tsx index a8550f91e..4ead753be 100644 --- a/web/components/config/video-variant-form.tsx +++ b/web/components/config/video-variant-form.tsx @@ -1,62 +1,25 @@ -// This content populates the video variant modal, which is spawned from the variants table. +// This content populates the video variant modal, which is spawned from the variants table. This relies on the `dataState` prop fed in by the table. import React from 'react'; import { Popconfirm, Row, Col, Slider, Collapse, Typography } from 'antd'; import { ExclamationCircleFilled } from '@ant-design/icons'; +import classNames from 'classnames'; import { FieldUpdaterFunc, VideoVariant, UpdateArgs } from '../../types/config-section'; import TextField from './form-textfield'; -import { DEFAULT_VARIANT_STATE } from '../../utils/config-constants'; -import CPUUsageSelector from './cpu-usage'; +import { + DEFAULT_VARIANT_STATE, + VIDEO_VARIANT_SETTING_DEFAULTS, + ENCODER_PRESET_SLIDER_MARKS, + ENCODER_PRESET_TOOLTIPS, + VIDEO_BITRATE_DEFAULTS, + VIDEO_BITRATE_SLIDER_MARKS, + FRAMERATE_SLIDER_MARKS, + FRAMERATE_DEFAULTS, + FRAMERATE_TOOLTIPS, +} from '../../utils/config-constants'; import ToggleSwitch from './form-toggleswitch'; const { Panel } = Collapse; -const VIDEO_VARIANT_DEFAULTS = { - framerate: { - min: 24, - max: 120, - defaultValue: 24, - unit: 'fps', - incrementBy: null, - tip: - 'Reducing your framerate will decrease the amount of video that needs to be encoded and sent to your viewers, saving CPU and bandwidth at the expense of smoothness. A lower value is generally is fine for most content.', - }, - videoBitrate: { - min: 600, - max: 6000, - defaultValue: 1200, - unit: 'kbps', - incrementBy: 100, - tip: 'The overall quality of your stream is generally impacted most by bitrate.', - }, - audioBitrate: { - min: 600, - max: 1200, - defaultValue: 800, - unit: 'kbps', - incrementBy: 100, - tip: 'nothing to see here', - }, - videoPassthrough: { - tip: 'If enabled, all other settings will be disabled. Otherwise configure as desired.', - }, - audioPassthrough: { - tip: 'If No is selected, then you should set your desired Audio Bitrate.', - }, - scaledWidth: { - fieldName: 'scaledWidth', - label: 'Resized Width', - maxLength: 4, - placeholder: '1080', - tip: "Optionally resize this content's width.", - }, - scaledHeight: { - fieldName: 'scaledHeight', - label: 'Resized Height', - maxLength: 4, - placeholder: '720', - tip: "Optionally resize this content's height.", - }, -}; interface VideoVariantFormProps { dataState: VideoVariant; onUpdateField: FieldUpdaterFunc; @@ -66,6 +29,8 @@ export default function VideoVariantForm({ dataState = DEFAULT_VARIANT_STATE, onUpdateField, }: VideoVariantFormProps) { + const videoPassthroughEnabled = dataState.videoPassthrough; + const handleFramerateChange = (value: number) => { onUpdateField({ fieldName: 'framerate', value }); }; @@ -99,40 +64,17 @@ export default function VideoVariantForm({ // If passthrough is currently on, set it back to false on toggle. // Else let the Popconfirm turn it on. const handleVideoPassthroughToggle = (value: boolean) => { - if (dataState.videoPassthrough) { + if (videoPassthroughEnabled) { onUpdateField({ fieldName: 'videoPassthrough', value }); } }; - const framerateDefaults = VIDEO_VARIANT_DEFAULTS.framerate; - const framerateMin = framerateDefaults.min; - const framerateMax = framerateDefaults.max; - const framerateUnit = framerateDefaults.unit; - const framerateMarks = { - [framerateMin]: `${framerateMin} ${framerateUnit}`, - 30: '', - 60: '', - 90: '', - [framerateMax]: `${framerateMax} ${framerateUnit}`, - }; - - const videoBitrateDefaults = VIDEO_VARIANT_DEFAULTS.videoBitrate; - const videoBRMin = videoBitrateDefaults.min; - const videoBRMax = videoBitrateDefaults.max; - const videoBRUnit = videoBitrateDefaults.unit; - const videoBRMarks = { - [videoBRMin]: `${videoBRMin} ${videoBRUnit}`, - 3000: 3000, - 4500: 4500, - [videoBRMax]: `${videoBRMax} ${videoBRUnit}`, - }; - + // Slider notes const selectedVideoBRnote = () => { - if (dataState.videoPassthrough) { + if (videoPassthroughEnabled) { return 'Bitrate selection is disabled when Video Passthrough is enabled.'; } - - let note = `${dataState.videoBitrate}${videoBRUnit}`; + let note = `${dataState.videoBitrate}${VIDEO_BITRATE_DEFAULTS.unit}`; if (dataState.videoBitrate < 2000) { note = `${note} - Good for low bandwidth environments.`; } else if (dataState.videoBitrate < 3500) { @@ -143,35 +85,24 @@ export default function VideoVariantForm({ return note; }; const selectedFramerateNote = () => { - if (dataState.videoPassthrough) { + if (videoPassthroughEnabled) { return 'Framerate selection is disabled when Video Passthrough is enabled.'; } - - let note = `Selected: ${dataState.framerate}${framerateUnit}`; - switch (dataState.framerate) { - case 24: - note = `${note} - Good for film, presentations, music, low power/bandwidth servers.`; - break; - case 30: - note = `${note} - Good for slow/casual games, chat, general purpose.`; - break; - case 60: - note = `${note} - Good for fast/action games, sports, HD video.`; - break; - case 90: - note = `${note} - Good for newer fast games and hardware.`; - break; - case 120: - note = `${note} - Experimental, use at your own risk!`; - break; - default: - note = ''; + return FRAMERATE_TOOLTIPS[dataState.framerate] || ''; + }; + const cpuUsageNote = () => { + if (videoPassthroughEnabled) { + return 'CPU usage selection is disabled when Video Passthrough is enabled.'; } - return note; + return ENCODER_PRESET_TOOLTIPS[dataState.cpuUsageLevel] || ''; }; + const classes = classNames({ + 'config-variant-form': true, + 'video-passthrough-enabled': videoPassthroughEnabled, + }); return ( -
+

Learn more @@ -179,15 +110,34 @@ export default function VideoVariantForm({ about how each of these settings can impact the performance of your server.

+ {videoPassthroughEnabled && ( +

+ NOTE: Video Passthrough for this output stream variant is enabled, disabling the + below video encoding settings. +

+ )} + - {/* ENCODER PRESET FIELD */} + {/* ENCODER PRESET (CPU USAGE) FIELD */}
- + CPU Usage +

+ Reduce to improve server performance, or increase it to improve video quality. +

+
+ ENCODER_PRESET_TOOLTIPS[value]} + onChange={handleVideoCpuUsageLevelChange} + min={1} + max={Object.keys(ENCODER_PRESET_SLIDER_MARKS).length} + marks={ENCODER_PRESET_SLIDER_MARKS} + defaultValue={dataState.cpuUsageLevel} + value={dataState.cpuUsageLevel} + disabled={dataState.videoPassthrough} + /> +

{cpuUsageNote()}

+

Video Bitrate -

{VIDEO_VARIANT_DEFAULTS.videoBitrate.tip}

+

{VIDEO_BITRATE_DEFAULTS.tip}

`${value} ${videoBRUnit}`} + tipFormatter={value => `${value} ${VIDEO_BITRATE_DEFAULTS.unit}`} disabled={dataState.videoPassthrough} defaultValue={dataState.videoBitrate} value={dataState.videoBitrate} onChange={handleVideoBitrateChange} - step={videoBitrateDefaults.incrementBy} - min={videoBRMin} - max={videoBRMax} - marks={videoBRMarks} + step={VIDEO_BITRATE_DEFAULTS.incrementBy} + min={VIDEO_BITRATE_DEFAULTS.min} + max={VIDEO_BITRATE_DEFAULTS.max} + marks={VIDEO_BITRATE_SLIDER_MARKS} />

{selectedVideoBRnote()}

@@ -256,14 +206,14 @@ export default function VideoVariantForm({
{/* VIDEO PASSTHROUGH FIELD */} -
+
Video Passthrough

@@ -307,7 +257,7 @@ export default function VideoVariantForm({ @@ -320,17 +270,17 @@ export default function VideoVariantForm({ {/* FRAME RATE FIELD */}

Frame rate -

{VIDEO_VARIANT_DEFAULTS.framerate.tip}

+

{FRAMERATE_DEFAULTS.tip}

`${value} ${framerateUnit}`} + tipFormatter={value => `${value} ${FRAMERATE_DEFAULTS.unit}`} defaultValue={dataState.framerate} value={dataState.framerate} onChange={handleFramerateChange} - step={framerateDefaults.incrementBy} - min={framerateMin} - max={framerateMax} - marks={framerateMarks} + step={FRAMERATE_DEFAULTS.incrementBy} + min={FRAMERATE_DEFAULTS.min} + max={FRAMERATE_DEFAULTS.max} + marks={FRAMERATE_SLIDER_MARKS} disabled={dataState.videoPassthrough} />

{selectedFramerateNote()}

diff --git a/web/styles/config-video-variants.scss b/web/styles/config-video-variants.scss index 340f6bb93..9d3e556c9 100644 --- a/web/styles/config-video-variants.scss +++ b/web/styles/config-video-variants.scss @@ -15,6 +15,15 @@ .description { margin-top: 0; } + .passthrough-warning { + text-align: center; + padding: 1em; + color: var(--ant-warning); + font-size: 0.88em; + font-weight: 500; + background-color: var(--black-50); + border-radius: var(--container-border-radius); + } .cpu-usage-container, .bitrate-container { @@ -25,10 +34,17 @@ margin-top: 1em; .resolution-module, - .video-passthroug-module { + .video-passthrough-module { min-height: 30em; } } + // make some things look disabled when passthrough is on + &.video-passthrough-enabled { + .form-module:not(.video-passthrough-module) { + opacity: 0.25; + cursor: not-allowed; + } + } } .variants-table { diff --git a/web/utils/config-constants.tsx b/web/utils/config-constants.tsx index 4bd3d636f..30f107785 100644 --- a/web/utils/config-constants.tsx +++ b/web/utils/config-constants.tsx @@ -144,8 +144,7 @@ export const FIELD_PROPS_YP = { apiPath: API_YP_SWITCH, configPath: 'yp', label: 'Enable directory', - tip: - 'Turn this ON if you want to show up in the directory.', + tip: 'Turn this ON if you want to show up in the directory.', }; export const DEFAULT_VARIANT_STATE: VideoVariant = { @@ -159,6 +158,94 @@ export const DEFAULT_VARIANT_STATE: VideoVariant = { scaledWidth: null, }; +export const VIDEO_VARIANT_SETTING_DEFAULTS = { + // this one is currently unused + audioBitrate: { + min: 600, + max: 1200, + defaultValue: 800, + unit: 'kbps', + incrementBy: 100, + tip: 'nothing to see here', + }, + videoPassthrough: { + tip: 'If enabled, all other settings will be disabled. Otherwise configure as desired.', + }, + audioPassthrough: { + tip: 'If No is selected, then you should set your desired Audio Bitrate.', + }, + scaledWidth: { + fieldName: 'scaledWidth', + label: 'Resized Width', + maxLength: 4, + placeholder: '1080', + tip: "Optionally resize this content's width.", + }, + scaledHeight: { + fieldName: 'scaledHeight', + label: 'Resized Height', + maxLength: 4, + placeholder: '720', + tip: "Optionally resize this content's height.", + }, +}; + +// VIDEO VARIANT FORM - framerate +export const FRAMERATE_DEFAULTS = { + min: 24, + max: 120, + defaultValue: 24, + unit: 'fps', + incrementBy: null, + tip: + 'Reducing your framerate will decrease the amount of video that needs to be encoded and sent to your viewers, saving CPU and bandwidth at the expense of smoothness. A lower value is generally is fine for most content.', +}; +export const FRAMERATE_SLIDER_MARKS = { + [FRAMERATE_DEFAULTS.min]: `${FRAMERATE_DEFAULTS.min} ${FRAMERATE_DEFAULTS.unit}`, + 30: '', + 60: '', + 90: '', + [FRAMERATE_DEFAULTS.max]: `${FRAMERATE_DEFAULTS.max} ${FRAMERATE_DEFAULTS.unit}`, +}; +export const FRAMERATE_TOOLTIPS = { + [FRAMERATE_DEFAULTS.min]: `${FRAMERATE_DEFAULTS.min}fps - Good for film, presentations, music, low power/bandwidth servers.`, + 30: '30fps - Good for slow/casual games, chat, general purpose.', + 60: '60fps - Good for fast/action games, sports, HD video.', + 90: '90fps - Good for newer fast games and hardware.', + [FRAMERATE_DEFAULTS.max]: `${FRAMERATE_DEFAULTS.max}fps - Experimental, use at your own risk!`, +}; +// VIDEO VARIANT FORM - bitrate +export const VIDEO_BITRATE_DEFAULTS = { + min: 600, + max: 6000, + defaultValue: 1200, + unit: 'kbps', + incrementBy: 100, + tip: 'The overall quality of your stream is generally impacted most by bitrate.', +}; +export const VIDEO_BITRATE_SLIDER_MARKS = { + [VIDEO_BITRATE_DEFAULTS.min]: `${VIDEO_BITRATE_DEFAULTS.min} ${VIDEO_BITRATE_DEFAULTS.unit}`, + 3000: 3000, + 4500: 4500, + [VIDEO_BITRATE_DEFAULTS.max]: `${VIDEO_BITRATE_DEFAULTS.max} ${VIDEO_BITRATE_DEFAULTS.unit}`, +}; +// VIDEO VARIANT FORM - encoder preset +// CPU +export const ENCODER_PRESET_SLIDER_MARKS = { + 1: 'lowest', + 2: '', + 3: '', + 4: '', + 5: 'highest', +}; +export const ENCODER_PRESET_TOOLTIPS = { + 1: 'Lowest CPU usage - lowest quality video', + 2: 'Low CPU usage - low quality video', + 3: 'Medium CPU usage - average quality video', + 4: 'High CPU usage - high quality video', + 5: 'Highest CPU usage - higher quality video', +}; + export const DEFAULT_SOCIAL_HANDLE: SocialHandle = { url: '', platform: '',