248 lines
6.5 KiB
JavaScript
248 lines
6.5 KiB
JavaScript
import React from 'react';
|
|
|
|
import { useLingui } from '@lingui/react';
|
|
import { Trans, t } from '@lingui/macro';
|
|
import ScreenshotMonitorIcon from '@mui/icons-material/ScreenshotMonitor';
|
|
import makeStyles from '@mui/styles/makeStyles';
|
|
import Button from '@mui/material/Button';
|
|
import Grid from '@mui/material/Grid';
|
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
import TextField from '@mui/material/TextField';
|
|
import Typography from '@mui/material/Typography';
|
|
|
|
import FormInlineButton from '../../../misc/FormInlineButton';
|
|
import MultiSelect from '../../../misc/MultiSelect';
|
|
import SelectCustom from '../../../misc/SelectCustom';
|
|
import Checkbox from '../../../misc/Checkbox';
|
|
import Video from '../../../misc/coders/settings/Video';
|
|
|
|
const useStyles = makeStyles((theme) => ({
|
|
gridContainer: {
|
|
marginTop: '0.5em',
|
|
},
|
|
}));
|
|
|
|
const initSettings = (initialSettings) => {
|
|
if (!initialSettings) {
|
|
initialSettings = {};
|
|
}
|
|
|
|
const settings = {
|
|
probesize: 42_000_000, // bytes
|
|
fflags: ['nobuffer'],
|
|
thread_queue_size: 1024,
|
|
video_size: '1280x720',
|
|
framerate: '25',
|
|
device: ':1',
|
|
draw_mouse: false,
|
|
follow_mouse: 'centered',
|
|
...initialSettings,
|
|
};
|
|
|
|
return settings;
|
|
};
|
|
|
|
const createInputs = (settings) => {
|
|
const address = settings.device === 'custom' || settings.device === 'none' ? settings.deviceCustom : settings.device;
|
|
const input = {
|
|
address: address,
|
|
options: [],
|
|
};
|
|
|
|
input.options.push('-thread_queue_size', settings.thread_queue_size);
|
|
input.options.push('-probesize', '' + settings.probesize);
|
|
if (settings.fflags.length !== 0) {
|
|
input.options.push('-fflags', '+' + settings.fflags.join('+'));
|
|
}
|
|
input.options.push('-f', 'x11grab');
|
|
input.options.push('-video_size', settings.video_size);
|
|
input.options.push('-framerate', settings.framerate);
|
|
if (settings.follow_mouse === true) {
|
|
input.options.push('-draw_mouse', '1');
|
|
input.options.push('-follow_mouse', settings.follow_mouse);
|
|
} else {
|
|
input.options.push('-draw_mouse', '0');
|
|
}
|
|
|
|
return [input];
|
|
};
|
|
|
|
function FollowMouse({ value = '', allowCustom = false, onChange = function (event) {}, disabled = false }) {
|
|
const { i18n } = useLingui();
|
|
const values = [{ value: 'centered', label: 'Centered' }];
|
|
|
|
values.push({ value: 'custom', label: i18n._(t`Custom ...`) });
|
|
|
|
return (
|
|
<SelectCustom
|
|
disabled={disabled}
|
|
options={values}
|
|
label={<Trans>Follow mouse</Trans>}
|
|
customLabel={<Trans>Follow mouse</Trans>}
|
|
value={value}
|
|
onChange={onChange}
|
|
variant={'outlined'}
|
|
allowCustom={allowCustom}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function Source({ knownDevices = [], settings = {}, onChange = function (settings) {}, onProbe = function (settings, inputs) {}, onRefresh = function () {} }) {
|
|
const classes = useStyles();
|
|
const { i18n } = useLingui();
|
|
settings = initSettings(settings);
|
|
|
|
const handleChange = (what) => (event) => {
|
|
let data = {};
|
|
|
|
if (['device', 'probesize', 'fflags', 'framerate', 'video_size', 'thread_queue_size', 'follow_mouse'].includes(what)) {
|
|
data[what] = event.target.value;
|
|
}
|
|
|
|
if (['draw_mouse'].includes(what)) {
|
|
data[what] = !settings.draw_mouse;
|
|
}
|
|
|
|
onChange({
|
|
...settings,
|
|
...data,
|
|
});
|
|
};
|
|
|
|
const handleRefresh = () => {
|
|
onRefresh();
|
|
};
|
|
|
|
const handleProbe = () => {
|
|
onProbe(settings, createInputs(settings));
|
|
};
|
|
|
|
const filteredDevices = knownDevices.filter((device) => device.media === 'video');
|
|
const options = filteredDevices.map((device) => {
|
|
return {
|
|
value: device.id,
|
|
label: device.name + ' (' + device.id + ')',
|
|
};
|
|
});
|
|
|
|
options.unshift({
|
|
value: 'none',
|
|
label: i18n._(t`Choose an input device ...`),
|
|
disabled: true,
|
|
});
|
|
|
|
options.push({
|
|
value: 'custom',
|
|
label: i18n._(t`Custom ...`),
|
|
});
|
|
|
|
return (
|
|
<Grid container alignItems="flex-start" spacing={2} className={classes.gridContainer}>
|
|
<Grid item xs={12}>
|
|
<Typography>
|
|
<Trans>Select a device:</Trans>
|
|
</Typography>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<SelectCustom
|
|
options={options}
|
|
label={<Trans>Video device</Trans>}
|
|
customLabel={<Trans>Custom video device</Trans>}
|
|
value={settings.device}
|
|
onChange={handleChange('device')}
|
|
variant="outlined"
|
|
allowCustom
|
|
/>
|
|
<Button size="small" startIcon={<RefreshIcon />} onClick={handleRefresh} sx={{ float: 'right' }}>
|
|
<Trans>Refresh</Trans>
|
|
</Button>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<TextField
|
|
variant="outlined"
|
|
type="number"
|
|
min="0"
|
|
step="1"
|
|
fullWidth
|
|
label="thread_queue_size"
|
|
value={settings.thread_queue_size}
|
|
onChange={handleChange('thread_queue_size')}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<TextField
|
|
variant="outlined"
|
|
type="number"
|
|
min="32"
|
|
step="1"
|
|
fullWidth
|
|
label="probesize (bytes)"
|
|
value={settings.probesize}
|
|
onChange={handleChange('probesize')}
|
|
/>
|
|
<Typography variant="caption">
|
|
<Trans>
|
|
Mininum {32}, default {5000000}
|
|
</Trans>
|
|
</Typography>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<MultiSelect
|
|
type="select"
|
|
label="flags"
|
|
value={settings.fflags}
|
|
onChange={handleChange('fflags')}
|
|
items={[
|
|
{ value: 'discardcorrupt' },
|
|
{ value: 'fastseek' },
|
|
{ value: 'genpts' },
|
|
{ value: 'igndts' },
|
|
{ value: 'ignidx' },
|
|
{ value: 'nobuffer' },
|
|
{ value: 'nofillin' },
|
|
{ value: 'noparse' },
|
|
{ value: 'sortdts' },
|
|
]}
|
|
></MultiSelect>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<Video.Framerate value={settings.framerate} onChange={handleChange('framerate')} allowCustom />
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<Video.Size value={settings.video_size} onChange={handleChange('video_size')} allowCustom />
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<Grid item>
|
|
<Checkbox label={<Trans>Draw mouse</Trans>} checked={settings.draw_mouse} onChange={handleChange('draw_mouse')} />
|
|
</Grid>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<Grid item>
|
|
<FollowMouse disabled={!settings.draw_mouse} value={settings.follow_mouse} onChange={handleChange('follow_mouse')} allowCustom />
|
|
</Grid>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<FormInlineButton onClick={handleProbe}>
|
|
<Trans>Probe</Trans>
|
|
</FormInlineButton>
|
|
</Grid>
|
|
</Grid>
|
|
);
|
|
}
|
|
|
|
function SourceIcon(props) {
|
|
return <ScreenshotMonitorIcon style={{ color: '#FFF' }} {...props} />;
|
|
}
|
|
|
|
const id = 'x11grab';
|
|
const name = <Trans>X11 Screen Capture</Trans>;
|
|
const capabilities = ['video'];
|
|
const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0 || ^7.0.0';
|
|
|
|
const func = {
|
|
initSettings,
|
|
createInputs,
|
|
};
|
|
|
|
export { id, name, capabilities, ffversion, SourceIcon as icon, Source as component, func };
|