From c008fb1eef9e65c28986490a3bc001e856b92c7d Mon Sep 17 00:00:00 2001 From: Jan Stabenow Date: Fri, 21 Oct 2022 00:31:41 +0200 Subject: [PATCH] Add scale filter to non-hwaccel encoders --- CHANGELOG.md | 1 + src/misc/coders/settings/Video.js | 48 ++++++++++++++++ src/misc/filters/index.js | 2 + src/misc/filters/video/Scale.js | 91 +++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+) create mode 100644 src/misc/filters/video/Scale.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 296d86a..81a52dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### v1.4.0 > v1.5.0 +- Add scale filter to non-hwaccel encoders - Add PeerTube and Media Network to publication services (plattforms, software) - Add reset button to hide a player logo (datarhei/restreamer#431) - Mod adds Istafeed.me as StreamKey service to Instagram's publishing service diff --git a/src/misc/coders/settings/Video.js b/src/misc/coders/settings/Video.js index 2c038cf..5aacc1c 100644 --- a/src/misc/coders/settings/Video.js +++ b/src/misc/coders/settings/Video.js @@ -203,6 +203,53 @@ Size.defaultProps = { onChange: function (event) {}, }; +function Height(props) { + const { i18n } = useLingui(); + const height = [ + { value: '4320', label: '4320' }, + { value: '2880', label: '2880' }, + { value: '2160', label: '2160' }, + { value: '1800', label: '1800' }, + { value: '1600', label: '1600' }, + { value: '1440', label: '1440' }, + { value: '1080', label: '1080' }, + { value: '900', label: '900' }, + { value: '720', label: '720' }, + { value: '540', label: '540' }, + { value: '360', label: '360' }, + ]; + + if (props.allowNone === true) { + height.unshift({ value: 'none', label: 'none' }); + } + + if (props.allowCustom === true) { + height.push({ value: 'custom', label: i18n._(t`Custom ...`) }); + } + + return ( + + ); +} + +Height.defaultProps = { + allowNone: false, + allowCustom: false, + variant: 'outlined', + label: Height, + customLabel: Custom size, + onChange: function (event) {}, +}; + function Format(props) { const { i18n } = useLingui(); const sizes = [ @@ -248,5 +295,6 @@ export default { Framerate, Profile, Size, + Height, Format, }; diff --git a/src/misc/filters/index.js b/src/misc/filters/index.js index 8ace2f7..382f0d0 100644 --- a/src/misc/filters/index.js +++ b/src/misc/filters/index.js @@ -5,6 +5,7 @@ import * as Volume from './audio/Volume'; import * as Loudnorm from './audio/Loudnorm'; // Video Filter +import * as Scale from './video/Scale'; import * as Transpose from './video/Transpose'; import * as HFlip from './video/HFlip'; import * as VFlip from './video/VFlip'; @@ -51,6 +52,7 @@ audioRegistry.Register(Loudnorm); // Video Filters const videoRegistry = new Registry('video'); +videoRegistry.Register(Scale); videoRegistry.Register(Transpose); videoRegistry.Register(HFlip); videoRegistry.Register(VFlip); diff --git a/src/misc/filters/video/Scale.js b/src/misc/filters/video/Scale.js new file mode 100644 index 0000000..49f7859 --- /dev/null +++ b/src/misc/filters/video/Scale.js @@ -0,0 +1,91 @@ +import React from 'react'; + +import { Trans } from '@lingui/macro'; +import Grid from '@mui/material/Grid'; + +import Video from '../../coders/settings/Video'; + +// Scale Filter +// https://ffmpeg.org/ffmpeg-all.html#scale-1 + +function init(initialState) { + const state = { + value: 'none', + ...initialState, + }; + + return state; +} + +function createGraph(settings) { + settings = init(settings); + + const mapping = []; + + if (settings.value !== 'none') { + mapping.push(`scale=-1:${settings.value}`); + } + + return mapping.join(','); +} + +function Filter(props) { + const settings = init(props.settings); + + const handleChange = (newSettings) => { + let automatic = false; + if (!newSettings) { + newSettings = settings; + automatic = true; + } + + props.onChange(newSettings, createGraph(newSettings), automatic); + }; + + const update = (what) => (event) => { + const newSettings = { + ...settings, + [what]: event.target.value, + }; + + handleChange(newSettings); + }; + + React.useEffect(() => { + handleChange(null); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + + Scale by height} value={settings.value} onChange={update('value')}> + + + ); +} + +Filter.defaultProps = { + settings: {}, + onChange: function (settings, mapping) {}, +}; + +const filter = 'scale'; +const name = 'Scale'; +const type = 'video'; +const hwaccel = false; + +function summarize(settings) { + return `${name} (-1:${settings.value})`; +} + +function defaults() { + const settings = init({}); + + return { + settings: settings, + graph: createGraph(settings), + }; +} + +export { name, filter, type, hwaccel, summarize, defaults, createGraph, Filter as component };