From 1aa43fff4d6da24d9ba2ea4ea24960414b735ec2 Mon Sep 17 00:00:00 2001 From: Ingo Oppermann Date: Thu, 14 Jul 2022 17:56:30 +0200 Subject: [PATCH] Add aresample filter to replace filter in encoders (WIP) --- src/misc/filters/audio/Resample.js | 224 ++++++++++++++++++++++++++++ src/misc/filters/audio/Volume.js | 14 +- src/misc/filters/index.js | 2 + src/misc/filters/video/Transpose.js | 2 +- 4 files changed, 239 insertions(+), 3 deletions(-) create mode 100644 src/misc/filters/audio/Resample.js diff --git a/src/misc/filters/audio/Resample.js b/src/misc/filters/audio/Resample.js new file mode 100644 index 0000000..5cd7e1b --- /dev/null +++ b/src/misc/filters/audio/Resample.js @@ -0,0 +1,224 @@ +import React from 'react'; + +import { useLingui } from '@lingui/react'; +import { Trans, t } from '@lingui/macro'; +import Grid from '@mui/material/Grid'; +import Typography from '@mui/material/Typography'; + +import SelectCustom from '../../../misc/SelectCustom'; + +// Resample Filter +// https://ffmpeg.org/ffmpeg-filters.html#toc-aresample-1 + +function init(initialState) { + const state = { + channels: '2', + layout: 'stereo', + sampling: '44100', + ...initialState, + }; + + return state; +} + +function createGraph(settings) { + const mapping = []; + + const sampling = settings.sampling; + const layout = settings.layout; + + if (sampling !== 'inherit') { + mapping.push(`osr=${sampling}`); + } + + if (layout !== 'inherit') { + mapping.push(`ocl=${layout}`); + } + + if (mapping.length === 0) { + return ''; + } + + return 'aresample=' + mapping.join(':'); +} + +function Layout(props) { + const { i18n } = useLingui(); + const options = [ + { value: 'mono', label: 'mono' }, + { value: 'stereo', label: 'stereo' }, + ]; + + if (props.allowAuto === true) { + options.unshift({ value: 'auto', label: 'auto' }); + } + + if (props.allowInherit === true) { + options.unshift({ value: 'inherit', label: i18n._(t`Inherit`) }); + } + + if (props.allowCustom === true) { + options.push({ value: 'custom', label: i18n._(t`Custom ...`) }); + } + + return ( + + + + The layout of the audio stream. + + + ); +} + +Layout.defaultProps = { + variant: 'outlined', + allowAuto: false, + allowInherit: false, + allowCustom: false, + label: Layout, + customLabel: Custom layout, + onChange: function () {}, +}; + +function Sampling(props) { + const { i18n } = useLingui(); + const options = [ + { value: '96000', label: '96000 Hz' }, + { value: '88200', label: '88200 Hz' }, + { value: '48000', label: '48000 Hz' }, + { value: '44100', label: '44100 Hz' }, + { value: '22050', label: '22050 Hz' }, + { value: '8000', label: '8000 Hz' }, + ]; + + if (props.allowAuto === true) { + options.unshift({ value: 'auto', label: 'auto' }); + } + + if (props.allowInherit === true) { + options.unshift({ value: 'inherit', label: i18n._(t`Inherit`) }); + } + + if (props.allowCustom === true) { + options.push({ value: 'custom', label: i18n._(t`Custom ...`) }); + } + + return ( + + + + The sample rate of the audio stream. + + + ); +} + +Sampling.defaultProps = { + variant: 'outlined', + allowAuto: false, + allowInherit: false, + allowCustom: false, + label: Sampling, + customLabel: Custom sampling (Hz), + onChange: function () {}, +}; + +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 value = event.target.value; + + const newSettings = { + ...settings, + [what]: value, + }; + + if (what === 'layout') { + let channels = 2; + + switch (value) { + case 'mono': + channels = 1; + break; + case 'stereo': + channels = 2; + break; + default: + break; + } + + newSettings.channels = channels; + } + + handleChange(newSettings); + }; + + React.useEffect(() => { + handleChange(null); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + + + + + + + + ); +} + +Filter.defaultProps = { + settings: {}, + onChange: function (settings, mapping) {}, +}; + +const filter = 'aresample'; +const name = 'Resample'; +const type = 'audio'; +const hwaccel = false; + +function summarize(settings) { + return `${name} (${settings.layout}, ${settings.sampling}Hz)`; +} + +function defaults() { + const settings = init({}); + + return { + settings: settings, + graph: createGraph(settings), + }; +} + +export { name, filter, type, hwaccel, summarize, defaults, Filter as component }; diff --git a/src/misc/filters/audio/Volume.js b/src/misc/filters/audio/Volume.js index 06cc660..8aeb750 100644 --- a/src/misc/filters/audio/Volume.js +++ b/src/misc/filters/audio/Volume.js @@ -130,12 +130,22 @@ Filter.defaultProps = { }; const filter = 'volume'; -const name = 'Volume level'; +const name = 'Volume'; const type = 'audio'; const hwaccel = false; function summarize(settings) { - return `${name}`; + let summary = `${name} (`; + + if (settings.level === 'custom') { + summary += `${settings.db}dB`; + } else { + summary += `${settings.level}%`; + } + + summary += ')'; + + return summary; } function defaults() { diff --git a/src/misc/filters/index.js b/src/misc/filters/index.js index f4f0b90..eebc322 100644 --- a/src/misc/filters/index.js +++ b/src/misc/filters/index.js @@ -1,4 +1,5 @@ // Audio Filter +import * as AResample from './audio/Resample'; import * as Volume from './audio/Volume'; import * as Loudnorm from './audio/Loudnorm'; @@ -42,6 +43,7 @@ class Registry { // Audio Filters const audioRegistry = new Registry('audio'); +audioRegistry.Register(AResample); audioRegistry.Register(Volume); audioRegistry.Register(Loudnorm); diff --git a/src/misc/filters/video/Transpose.js b/src/misc/filters/video/Transpose.js index 2c5157b..80eb338 100644 --- a/src/misc/filters/video/Transpose.js +++ b/src/misc/filters/video/Transpose.js @@ -100,7 +100,7 @@ const type = 'video'; const hwaccel = false; function summarize(settings) { - return `${name}`; + return `${name} (${settings.value}° clockwise)`; } function defaults() {