// 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, { FC } from 'react'; import { Popconfirm, Row, Col, Slider, Collapse, Typography, Alert, Button } from 'antd'; import classNames from 'classnames'; import dynamic from 'next/dynamic'; import { FieldUpdaterFunc, VideoVariant, UpdateArgs } from '../../types/config-section'; import { TextField } from './TextField'; import { DEFAULT_VARIANT_STATE, VIDEO_VARIANT_SETTING_DEFAULTS, VIDEO_NAME_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 './ToggleSwitch'; const { Panel } = Collapse; // Lazy loaded components const ExclamationCircleFilled = dynamic(() => import('@ant-design/icons/ExclamationCircleFilled'), { ssr: false, }); export type VideoVariantFormProps = { dataState: VideoVariant; onUpdateField: FieldUpdaterFunc; }; export const VideoVariantForm: FC = ({ dataState = DEFAULT_VARIANT_STATE, onUpdateField, }) => { const videoPassthroughEnabled = dataState.videoPassthrough; 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 || 0 }); }; 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 || 0 }); }; // 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 (videoPassthroughEnabled) { onUpdateField({ fieldName: 'videoPassthrough', value }); } }; const handleNameChanged = (args: UpdateArgs) => { onUpdateField({ fieldName: 'name', value: args.value }); }; // Slider notes const selectedVideoBRnote = () => { if (videoPassthroughEnabled) { return 'Bitrate selection is disabled when Video Passthrough is enabled.'; } let note = `${dataState.videoBitrate}${VIDEO_BITRATE_DEFAULTS.unit}`; 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 (videoPassthroughEnabled) { return 'Framerate selection is disabled when Video Passthrough is enabled.'; } return FRAMERATE_TOOLTIPS[dataState.framerate] || ''; }; const cpuUsageNote = () => { if (videoPassthroughEnabled) { return 'CPU usage selection is disabled when Video Passthrough is enabled.'; } return ENCODER_PRESET_TOOLTIPS[dataState.cpuUsageLevel] || ''; }; const classes = classNames({ 'config-variant-form': true, 'video-passthrough-enabled': videoPassthroughEnabled, }); return (
} />
{videoPassthroughEnabled && (

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

)}
CPU or GPU Utilization

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()}

This could mean GPU or CPU usage depending on your server environment.

Read more about hardware performance.

{/* VIDEO BITRATE FIELD */}
Video Bitrate

{VIDEO_BITRATE_DEFAULTS.tip}

`${value} ${VIDEO_BITRATE_DEFAULTS.unit}`} disabled={dataState.videoPassthrough} defaultValue={dataState.videoBitrate} value={dataState.videoBitrate} onChange={handleVideoBitrateChange} step={VIDEO_BITRATE_DEFAULTS.incrementBy} min={VIDEO_BITRATE_DEFAULTS.min} max={VIDEO_BITRATE_DEFAULTS.max} marks={VIDEO_BITRATE_SLIDER_MARKS} />

{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" getPopupContainer={triggerNode => triggerNode} placement="topLeft" > {/* adding an tag to force Popcofirm to register click on toggle */} {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}

Use Video Passthrough?

*{VIDEO_VARIANT_SETTING_DEFAULTS.videoPassthrough.tip}

{/* FRAME RATE FIELD */}
Frame rate

{FRAMERATE_DEFAULTS.tip}

`${value} ${FRAMERATE_DEFAULTS.unit}`} defaultValue={dataState.framerate} value={dataState.framerate} onChange={handleFramerateChange} step={FRAMERATE_DEFAULTS.incrementBy} min={FRAMERATE_DEFAULTS.min} max={FRAMERATE_DEFAULTS.max} marks={FRAMERATE_SLIDER_MARKS} disabled={dataState.videoPassthrough} />

{selectedFramerateNote()}

Read more about framerates.

); };