// This content populates the video variant modal, which is spawned from the variants table. import React from 'react'; import { Popconfirm, Row, Col, Slider, Collapse, Typography } from 'antd'; import { ExclamationCircleFilled } from '@ant-design/icons'; 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 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; } export default function VideoVariantForm({ dataState = DEFAULT_VARIANT_STATE, onUpdateField, }: VideoVariantFormProps) { const handleFramerateChange = (value: number) => { onUpdateField({ fieldName: 'framerate', value }); }; const handleVideoBitrateChange = (value: number) => { onUpdateField({ fieldName: 'videoBitrate', value }); }; const handleVideoCpuUsageLevelChange = (value: number) => { onUpdateField({ fieldName: 'cpuUsageLevel', value }); }; const handleScaledWidthChanged = (args: UpdateArgs) => { const value = Number(args.value); // eslint-disable-next-line no-restricted-globals if (isNaN(value)) { return; } onUpdateField({ fieldName: 'scaledWidth', value: value || '' }); }; const handleScaledHeightChanged = (args: UpdateArgs) => { const value = Number(args.value); // eslint-disable-next-line no-restricted-globals if (isNaN(value)) { return; } onUpdateField({ fieldName: 'scaledHeight', value: value || '' }); }; // Video passthrough handling const handleVideoPassConfirm = () => { onUpdateField({ fieldName: 'videoPassthrough', value: true }); }; // 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) { 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}`, }; const selectedVideoBRnote = () => { if (dataState.videoPassthrough) { return 'Bitrate selection is disabled when Video Passthrough is enabled.'; } let note = `${dataState.videoBitrate}${videoBRUnit}`; if (dataState.videoBitrate < 2000) { note = `${note} - Good for low bandwidth environments.`; } else if (dataState.videoBitrate < 3500) { note = `${note} - Good for most bandwidth environments.`; } else { note = `${note} - Good for high bandwidth environments.`; } return note; }; const selectedFramerateNote = () => { if (dataState.videoPassthrough) { 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 note; }; return (

Learn more about how each of these settings can impact the performance of your server.

{/* ENCODER PRESET FIELD */}

Read more about CPU usage.

{/* VIDEO BITRATE FIELD */}
Video Bitrate

{VIDEO_VARIANT_DEFAULTS.videoBitrate.tip}

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

{selectedVideoBRnote()}

Read more about bitrates.

Resolution

Resizing your content will take additional resources on your server. If you wish to optionally resize your content for this stream output then you should either set the width or the height to keep your aspect ratio.{' '} Read more about resolutions.


{/* VIDEO PASSTHROUGH FIELD */}
Video Passthrough

Enabling video passthrough may allow for less hardware utilization, but may also make your stream unplayable.

All other settings for this stream output will be disabled if passthrough is used.

Read the documentation before enabling, as it impacts your stream.

} onConfirm={handleVideoPassConfirm} okText="Yes" cancelText="No" > {/* adding an tag to force Popcofirm to register click on toggle */} {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
{/* FRAME RATE FIELD */}
Frame rate

{VIDEO_VARIANT_DEFAULTS.framerate.tip}

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

{selectedFramerateNote()}

Read more about framerates.

); }