Merge branch 'dev' into dev-internal-srt-latency
This commit is contained in:
commit
e0744f8e07
@ -114,36 +114,23 @@
|
||||
var player = videojs('player', config);
|
||||
|
||||
if(playerConfig.logo.image.length != 0) {
|
||||
var overlay = null;
|
||||
|
||||
var imgTag = new Image();
|
||||
imgTag.onLoad = function () {
|
||||
imgTag.setAttribute('width', this.width);
|
||||
imgTag.setAttribute('height'.this.height);
|
||||
const imgTag = new Image();
|
||||
imgTag.src = playerConfig.logo.image;
|
||||
imgTag.onload = function () {
|
||||
const logoWidth = imgTag.width;
|
||||
const logoHeight = imgTag.height;
|
||||
const overlayPosition = playerConfig.logo.position || 'top-left';
|
||||
const overlayLink = playerConfig.logo.link || '#';
|
||||
player.overlay({
|
||||
overlays: [{
|
||||
content: `<a href="${overlayLink}" target="_blank"><img src="${playerConfig.logo.image + '?' + Math.random()}" alt="Logo" width="${logoWidth}" height="${logoHeight}"></a>`,
|
||||
start: 'play',
|
||||
end: 'pause',
|
||||
align: overlayPosition,
|
||||
showBackground: false
|
||||
}]
|
||||
});
|
||||
};
|
||||
imgTag.src = playerConfig.logo.image + '?' + Math.random();
|
||||
|
||||
if (playerConfig.logo.link.length !== 0) {
|
||||
var aTag = document.createElement('a');
|
||||
aTag.setAttribute('href', playerConfig.logo.link);
|
||||
aTag.setAttribute('target', '_blank');
|
||||
aTag.appendChild(imgTag);
|
||||
overlay = aTag.outerHTML;
|
||||
} else {
|
||||
overlay = imgTag.outerHTML;
|
||||
}
|
||||
|
||||
player.overlay({
|
||||
align: playerConfig.logo.position,
|
||||
overlays: [
|
||||
{
|
||||
showBackground: false,
|
||||
content: overlay,
|
||||
start: 'play',
|
||||
end: 'pause',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
player.ready(function() {
|
||||
|
||||
@ -43,6 +43,8 @@ function createMapping(settings, stream, skills) {
|
||||
`${settings.fps}`,
|
||||
'-sc_threshold',
|
||||
'0',
|
||||
'-forced-idr',
|
||||
'1',
|
||||
'-pix_fmt',
|
||||
'yuv420p',
|
||||
];
|
||||
|
||||
@ -381,9 +381,9 @@ class Restreamer {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._initSkills();
|
||||
await this._initConfig();
|
||||
await this._discoverChannels();
|
||||
await this._initSkills();
|
||||
}
|
||||
|
||||
_setTokenRefresh(expiresIn) {
|
||||
@ -514,6 +514,9 @@ class Restreamer {
|
||||
virtualvideo: [],
|
||||
videoloop: [],
|
||||
audioloop: [],
|
||||
channel: [],
|
||||
noaudio: [],
|
||||
sdp: [],
|
||||
},
|
||||
sinks: {},
|
||||
};
|
||||
@ -677,6 +680,15 @@ class Restreamer {
|
||||
|
||||
skills.sources['network'].push(...channels);
|
||||
|
||||
channels = this.ListChannels().map((channel) => {
|
||||
return {
|
||||
id: channel.channelid,
|
||||
name: channel.name,
|
||||
};
|
||||
});
|
||||
|
||||
skills.sources['channel'].push(...channels);
|
||||
|
||||
this.skills = skills;
|
||||
}
|
||||
|
||||
|
||||
@ -78,10 +78,6 @@ export default function Profile({
|
||||
}, []);
|
||||
|
||||
const load = async () => {
|
||||
// Add pseudo sources
|
||||
skills.sources.noaudio = [];
|
||||
skills.sources.sdp = [];
|
||||
|
||||
let audio = $sources.audio;
|
||||
|
||||
let hasAudio = false;
|
||||
|
||||
125
src/views/Edit/Sources/Channel.js
Normal file
125
src/views/Edit/Sources/Channel.js
Normal file
@ -0,0 +1,125 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans, t } from '@lingui/macro';
|
||||
import VideocamIcon from '@mui/icons-material/Videocam';
|
||||
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 Typography from '@mui/material/Typography';
|
||||
|
||||
import FormInlineButton from '../../../misc/FormInlineButton';
|
||||
import SelectCustom from '../../../misc/SelectCustom';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
gridContainer: {
|
||||
marginTop: '0.5em',
|
||||
},
|
||||
}));
|
||||
|
||||
const initSettings = (initialSettings) => {
|
||||
if (!initialSettings) {
|
||||
initialSettings = {};
|
||||
}
|
||||
|
||||
const settings = {
|
||||
channelid: 'none',
|
||||
...initialSettings,
|
||||
};
|
||||
|
||||
return settings;
|
||||
};
|
||||
|
||||
const createInputs = (settings) => {
|
||||
const address = `{fs:mem}/${settings.channelid}.m3u8`;
|
||||
const input = {
|
||||
address: address,
|
||||
options: [],
|
||||
};
|
||||
|
||||
return [input];
|
||||
};
|
||||
|
||||
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 (['channelid'].includes(what)) {
|
||||
data[what] = event.target.value;
|
||||
}
|
||||
|
||||
onChange({
|
||||
...settings,
|
||||
...data,
|
||||
});
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
onRefresh();
|
||||
};
|
||||
|
||||
const handleProbe = () => {
|
||||
onProbe(settings, createInputs(settings));
|
||||
};
|
||||
|
||||
const options = knownDevices.map((device) => {
|
||||
return {
|
||||
value: device.id,
|
||||
label: device.name + ' (' + device.id + ')',
|
||||
};
|
||||
});
|
||||
|
||||
options.unshift({
|
||||
value: 'none',
|
||||
label: i18n._(t`Choose an input channel ...`),
|
||||
disabled: true,
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid container alignItems="flex-start" spacing={2} className={classes.gridContainer}>
|
||||
<Grid item xs={12}>
|
||||
<Typography>
|
||||
<Trans>Select a channel:</Trans>
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SelectCustom
|
||||
options={options}
|
||||
label={<Trans>Video device</Trans>}
|
||||
value={settings.channelid}
|
||||
onChange={handleChange('channelid')}
|
||||
variant="outlined"
|
||||
/>
|
||||
<Button size="small" startIcon={<RefreshIcon />} onClick={handleRefresh} sx={{ float: 'right' }}>
|
||||
<Trans>Refresh</Trans>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FormInlineButton onClick={handleProbe} disabled={settings.channelid === 'none'}>
|
||||
<Trans>Probe</Trans>
|
||||
</FormInlineButton>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
function SourceIcon(props) {
|
||||
return <VideocamIcon style={{ color: '#FFF' }} {...props} />;
|
||||
}
|
||||
|
||||
const id = 'channel';
|
||||
const name = <Trans>Channel</Trans>;
|
||||
const capabilities = ['audio', '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 };
|
||||
@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useLingui } from '@lingui/react';
|
||||
import ScreenshotMonitorIcon from '@mui/icons-material/ScreenshotMonitor';
|
||||
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';
|
||||
|
||||
@ -11,6 +11,7 @@ import * as VideoLoop from './VideoLoop';
|
||||
import * as VirtualAudio from './VirtualAudio';
|
||||
import * as VirtualVideo from './VirtualVideo';
|
||||
import * as X11grab from './X11grab';
|
||||
import * as Channel from './Channel';
|
||||
|
||||
class Registry {
|
||||
constructor() {
|
||||
@ -54,5 +55,6 @@ registry.Register(VideoLoop);
|
||||
registry.Register(AudioLoop);
|
||||
registry.Register(SDP);
|
||||
registry.Register(X11grab);
|
||||
registry.Register(Channel);
|
||||
|
||||
export default registry;
|
||||
|
||||
@ -112,6 +112,7 @@ export default function Edit({ restreamer = null }) {
|
||||
});
|
||||
|
||||
const skills = await restreamer.Skills();
|
||||
skills.sources['channel'] = skills.sources['channel'].filter((channel) => channel.id !== _channelid);
|
||||
setSkills(skills);
|
||||
|
||||
const config = await restreamer.ConfigActive();
|
||||
@ -208,6 +209,7 @@ export default function Edit({ restreamer = null }) {
|
||||
await restreamer.RefreshSkills();
|
||||
|
||||
const skills = await restreamer.Skills();
|
||||
skills.sources['channel'] = skills.sources['channel'].filter((channel) => channel.id !== _channelid);
|
||||
setSkills(skills);
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user