Use graphs instead of mappings for filters, use -filter:(a|v) in command line
This commit is contained in:
parent
7639c4de18
commit
a91e86bc66
@ -239,5 +239,5 @@ EncodingSelect.defaultProps = {
|
||||
codecs: [],
|
||||
availableEncoders: [],
|
||||
availableDecoders: [],
|
||||
onChange: function (encoder, decoder) {},
|
||||
onChange: function (encoder, decoder, automatic) {},
|
||||
};
|
||||
|
||||
@ -17,36 +17,38 @@ export default function FilterSelect(props) {
|
||||
// what: Filter name
|
||||
// settings (component settings): {Key: Value}
|
||||
// mapping (FFmpeg -af/-vf args): ['String', ...]
|
||||
const handleFilterSettingsChange = (what) => (settings, mapping, automatic) => {
|
||||
const handleFilterSettingsChange = (what) => (settings, graph, automatic) => {
|
||||
const filter = profile.filter;
|
||||
|
||||
// Store mapping/settings per component
|
||||
filter.settings[what] = {
|
||||
mapping: mapping,
|
||||
settings: settings,
|
||||
graph: graph,
|
||||
};
|
||||
|
||||
// Combine FFmpeg args
|
||||
let settings_mapping = [];
|
||||
for (let i in filter.settings) {
|
||||
if (filter.settings[i].mapping.length !== 0) {
|
||||
settings_mapping.push(filter.settings[i].mapping);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the real filter mapping
|
||||
// ['-af/-vf', 'args,args']
|
||||
if (settings_mapping.length !== 0) {
|
||||
if (props.type === 'video') {
|
||||
filter.mapping = ['-vf', settings_mapping.join(',')];
|
||||
} else if (props.type === 'audio') {
|
||||
filter.mapping = ['-af', settings_mapping.join(',')];
|
||||
}
|
||||
// Get the order of the filters
|
||||
let filterOrder = [];
|
||||
if (props.type === 'video') {
|
||||
filterOrder = Filters.Video.Filters();
|
||||
} else {
|
||||
filter.mapping = [];
|
||||
filterOrder = Filters.Audio.Filters();
|
||||
}
|
||||
|
||||
props.onChange(profile.filter, filter, automatic);
|
||||
// Create the filter graph in the order as the filters are registered
|
||||
const graphs = [];
|
||||
for (let f of filterOrder) {
|
||||
if (!(f in filter.settings)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (filter.settings[f].graph.length !== 0) {
|
||||
graphs.push(filter.settings[f].graph);
|
||||
}
|
||||
}
|
||||
|
||||
filter.graph = graphs.join(',');
|
||||
|
||||
props.onChange(filter, automatic);
|
||||
};
|
||||
|
||||
// Set filterRegistry by type
|
||||
@ -64,8 +66,8 @@ export default function FilterSelect(props) {
|
||||
let hwaccel = false;
|
||||
if (props.type === 'video') {
|
||||
encoderRegistry = Encoders.Video;
|
||||
for (let i in encoderRegistry.List()) {
|
||||
if (encoderRegistry.List()[i].codec === props.videoProfile.encoder.coder && encoderRegistry.List()[i].hwaccel) {
|
||||
for (let encoder of encoderRegistry.List()) {
|
||||
if (encoder.codec === props.profile.encoder.coder && encoder.hwaccel) {
|
||||
hwaccel = true;
|
||||
}
|
||||
}
|
||||
@ -79,12 +81,17 @@ export default function FilterSelect(props) {
|
||||
if (props.availableFilters.includes(c.filter)) {
|
||||
const Settings = c.component;
|
||||
|
||||
if (!(c.filter in profile.filter.settings)) {
|
||||
profile.filter.settings[c.filter] = c.defaults();
|
||||
} else {
|
||||
profile.filter.settings[c.filter] = {
|
||||
...c.defaults(),
|
||||
...profile.filter.settings[c.filter],
|
||||
};
|
||||
}
|
||||
|
||||
filterSettings.push(
|
||||
<Settings
|
||||
key={c.filter}
|
||||
settings={profile.filter.settings[c.filter] ? profile.filter.settings[c.filter].settings : []}
|
||||
onChange={handleFilterSettingsChange(c.filter)}
|
||||
/>
|
||||
<Settings key={c.filter} settings={profile.filter.settings[c.filter].settings} onChange={handleFilterSettingsChange(c.filter)} />
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -121,7 +128,7 @@ export default function FilterSelect(props) {
|
||||
|
||||
FilterSelect.defaultProps = {
|
||||
type: '',
|
||||
filters: [],
|
||||
profile: {},
|
||||
availableFilters: [],
|
||||
onChange: function (filter) {},
|
||||
onChange: function (filter, automatic) {},
|
||||
};
|
||||
|
||||
@ -28,7 +28,7 @@ function createMapping(settings, stream) {
|
||||
layout = stream.layout;
|
||||
}
|
||||
|
||||
const local = ['-codec:a', 'aac', '-b:a', `${settings.bitrate}k`, '-shortest', '-af', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
const local = ['-codec:a', 'aac', '-b:a', `${settings.bitrate}k`, '-shortest', '-filter:a', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
|
||||
if (stream.codec === 'aac') {
|
||||
local.push('-bsf:a', 'aac_adtstoasc');
|
||||
|
||||
@ -28,7 +28,7 @@ function createMapping(settings, stream) {
|
||||
layout = stream.layout;
|
||||
}
|
||||
|
||||
const local = ['-codec:a', 'aac_at', '-b:a', `${settings.bitrate}k`, '-shortest', '-af', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
const local = ['-codec:a', 'aac_at', '-b:a', `${settings.bitrate}k`, '-shortest', '-filter:a', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
|
||||
if (stream.codec === 'aac') {
|
||||
local.push('-bsf:a', 'aac_adtstoasc');
|
||||
|
||||
@ -28,7 +28,7 @@ function createMapping(settings, stream) {
|
||||
layout = stream.layout;
|
||||
}
|
||||
|
||||
const local = ['-codec:a', 'libopus', '-b:a', `${settings.bitrate}k`, '-shortest', '-af', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
const local = ['-codec:a', 'libopus', '-b:a', `${settings.bitrate}k`, '-shortest', '-filter:a', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
|
||||
const mapping = {
|
||||
global: [],
|
||||
|
||||
@ -28,7 +28,7 @@ function createMapping(settings, stream) {
|
||||
layout = stream.layout;
|
||||
}
|
||||
|
||||
const local = ['-codec:a', 'libvorbis', '-b:a', `${settings.bitrate}k`, '-shortest', '-af', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
const local = ['-codec:a', 'libvorbis', '-b:a', `${settings.bitrate}k`, '-shortest', '-filter:a', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
|
||||
const mapping = {
|
||||
global: [],
|
||||
|
||||
@ -29,7 +29,7 @@ function createMapping(settings, stream) {
|
||||
}
|
||||
|
||||
// '-qscale:a', '6'
|
||||
const local = ['-codec:a', 'libmp3lame', '-b:a', `${settings.bitrate}k`, '-shortest', '-af', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
const local = ['-codec:a', 'libmp3lame', '-b:a', `${settings.bitrate}k`, '-shortest', '-filter:a', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
|
||||
const mapping = {
|
||||
global: [],
|
||||
|
||||
@ -34,7 +34,7 @@ function createMapping(settings, stream) {
|
||||
layout = stream.layout;
|
||||
}
|
||||
|
||||
const local = ['-codec:a', 'opus', '-b:a', `${settings.bitrate}k`, '-vbr', 'on', '-shortest', '-af', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
const local = ['-codec:a', 'opus', '-b:a', `${settings.bitrate}k`, '-vbr', 'on', '-shortest', '-filter:a', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
|
||||
if (settings.delay !== 'auto') {
|
||||
local.push('opus_delay', settings.delay);
|
||||
|
||||
@ -28,7 +28,7 @@ function createMapping(settings, stream) {
|
||||
layout = stream.layout;
|
||||
}
|
||||
|
||||
const local = ['-codec:a', 'vorbis', '-b:a', `${settings.bitrate}k`, '-qscale:a', '3', '-shortest', '-af', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
const local = ['-codec:a', 'vorbis', '-b:a', `${settings.bitrate}k`, '-qscale:a', '3', '-shortest', '-filter:a', `aresample=osr=${sampling}:ocl=${layout}`];
|
||||
|
||||
const mapping = {
|
||||
global: [],
|
||||
|
||||
@ -10,21 +10,21 @@ import Checkbox from '../../Checkbox';
|
||||
|
||||
function init(initialState) {
|
||||
const state = {
|
||||
value: false,
|
||||
enabled: false,
|
||||
...initialState,
|
||||
};
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function createMapping(settings) {
|
||||
function createGraph(settings) {
|
||||
const mapping = [];
|
||||
|
||||
if (settings.value) {
|
||||
if (settings.enabled) {
|
||||
mapping.push('loudnorm');
|
||||
}
|
||||
|
||||
return mapping;
|
||||
return mapping.join(',');
|
||||
}
|
||||
|
||||
function Filter(props) {
|
||||
@ -37,15 +37,15 @@ function Filter(props) {
|
||||
automatic = true;
|
||||
}
|
||||
|
||||
props.onChange(newSettings, createMapping(newSettings), automatic);
|
||||
props.onChange(newSettings, createGraph(newSettings), automatic);
|
||||
};
|
||||
|
||||
const update = (what) => (event) => {
|
||||
const newSettings = {
|
||||
...settings,
|
||||
};
|
||||
if (['value'].includes(what)) {
|
||||
newSettings[what] = !settings.value;
|
||||
if (['enabled'].includes(what)) {
|
||||
newSettings[what] = !settings.enabled;
|
||||
} else {
|
||||
newSettings[what] = event.target.value;
|
||||
}
|
||||
@ -61,7 +61,7 @@ function Filter(props) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid item>
|
||||
<Checkbox label={<Trans>Loudness Normalization</Trans>} checked={settings.value} onChange={update('value')} />
|
||||
<Checkbox label={<Trans>Loudness Normalization</Trans>} checked={settings.enabled} onChange={update('enabled')} />
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
@ -86,7 +86,7 @@ function defaults() {
|
||||
|
||||
return {
|
||||
settings: settings,
|
||||
mapping: createMapping(settings),
|
||||
graph: createGraph(settings),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ function init(initialState) {
|
||||
return state;
|
||||
}
|
||||
|
||||
function createMapping(settings) {
|
||||
function createGraph(settings) {
|
||||
const mapping = [];
|
||||
|
||||
switch (settings.level) {
|
||||
@ -34,7 +34,7 @@ function createMapping(settings) {
|
||||
break;
|
||||
}
|
||||
|
||||
return mapping;
|
||||
return mapping.join(',');
|
||||
}
|
||||
|
||||
function VolumeLevel(props) {
|
||||
@ -95,7 +95,7 @@ function Filter(props) {
|
||||
automatic = true;
|
||||
}
|
||||
|
||||
props.onChange(newSettings, createMapping(newSettings), automatic);
|
||||
props.onChange(newSettings, createGraph(newSettings), automatic);
|
||||
};
|
||||
|
||||
const update = (what) => (event) => {
|
||||
@ -143,7 +143,7 @@ function defaults() {
|
||||
|
||||
return {
|
||||
settings: settings,
|
||||
mapping: createMapping(settings),
|
||||
graph: createGraph(settings),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -10,21 +10,21 @@ import Checkbox from '../../Checkbox';
|
||||
|
||||
function init(initialState) {
|
||||
const state = {
|
||||
value: false,
|
||||
enabled: false,
|
||||
...initialState,
|
||||
};
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function createMapping(settings) {
|
||||
function createGraph(settings) {
|
||||
const mapping = [];
|
||||
|
||||
if (settings.value) {
|
||||
if (settings.enabled) {
|
||||
mapping.push('hflip');
|
||||
}
|
||||
|
||||
return mapping;
|
||||
return mapping.join(',');
|
||||
}
|
||||
|
||||
function Filter(props) {
|
||||
@ -37,15 +37,15 @@ function Filter(props) {
|
||||
automatic = true;
|
||||
}
|
||||
|
||||
props.onChange(newSettings, createMapping(newSettings), automatic);
|
||||
props.onChange(newSettings, createGraph(newSettings), automatic);
|
||||
};
|
||||
|
||||
const update = (what) => (event) => {
|
||||
const newSettings = {
|
||||
...settings,
|
||||
};
|
||||
if (['value'].includes(what)) {
|
||||
newSettings[what] = !settings.value;
|
||||
if (['enabled'].includes(what)) {
|
||||
newSettings[what] = !settings.enabled;
|
||||
} else {
|
||||
newSettings[what] = event.target.value;
|
||||
}
|
||||
@ -60,7 +60,7 @@ function Filter(props) {
|
||||
|
||||
return (
|
||||
<Grid item>
|
||||
<Checkbox label={<Trans>Horizontal Flip</Trans>} checked={settings.value} onChange={update('value')} />
|
||||
<Checkbox label={<Trans>Horizontal Flip</Trans>} checked={settings.enabled} onChange={update('enabled')} />
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
@ -84,7 +84,7 @@ function defaults() {
|
||||
|
||||
return {
|
||||
settings: settings,
|
||||
mapping: createMapping(settings),
|
||||
graph: createGraph(settings),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ function init(initialState) {
|
||||
return state;
|
||||
}
|
||||
|
||||
function createMapping(settings) {
|
||||
function createGraph(settings) {
|
||||
const mapping = [];
|
||||
|
||||
switch (settings.value) {
|
||||
@ -35,7 +35,7 @@ function createMapping(settings) {
|
||||
break;
|
||||
}
|
||||
|
||||
return mapping;
|
||||
return mapping.join(',');
|
||||
}
|
||||
|
||||
// filter
|
||||
@ -65,7 +65,7 @@ function Filter(props) {
|
||||
automatic = true;
|
||||
}
|
||||
|
||||
props.onChange(newSettings, createMapping(newSettings), automatic);
|
||||
props.onChange(newSettings, createGraph(newSettings), automatic);
|
||||
};
|
||||
|
||||
const update = (what) => (event) => {
|
||||
@ -108,7 +108,7 @@ function defaults() {
|
||||
|
||||
return {
|
||||
settings: settings,
|
||||
mapping: createMapping(settings),
|
||||
graph: createGraph(settings),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -10,21 +10,21 @@ import Checkbox from '../../Checkbox';
|
||||
|
||||
function init(initialState) {
|
||||
const state = {
|
||||
value: false,
|
||||
enabled: false,
|
||||
...initialState,
|
||||
};
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function createMapping(settings) {
|
||||
function createGraph(settings) {
|
||||
const mapping = [];
|
||||
|
||||
if (settings.value) {
|
||||
if (settings.enabled) {
|
||||
mapping.push('vflip');
|
||||
}
|
||||
|
||||
return mapping;
|
||||
return mapping.join(',');
|
||||
}
|
||||
|
||||
function Filter(props) {
|
||||
@ -37,15 +37,15 @@ function Filter(props) {
|
||||
automatic = true;
|
||||
}
|
||||
|
||||
props.onChange(newSettings, createMapping(newSettings), automatic);
|
||||
props.onChange(newSettings, createGraph(newSettings), automatic);
|
||||
};
|
||||
|
||||
const update = (what) => (event) => {
|
||||
const newSettings = {
|
||||
...settings,
|
||||
};
|
||||
if (['value'].includes(what)) {
|
||||
newSettings[what] = !settings.value;
|
||||
if (['enabled'].includes(what)) {
|
||||
newSettings[what] = !settings.enabled;
|
||||
} else {
|
||||
newSettings[what] = event.target.value;
|
||||
}
|
||||
@ -60,7 +60,7 @@ function Filter(props) {
|
||||
|
||||
return (
|
||||
<Grid item>
|
||||
<Checkbox label={<Trans>Vertical Flip</Trans>} checked={settings.value} onChange={update('value')} />
|
||||
<Checkbox label={<Trans>Vertical Flip</Trans>} checked={settings.enabled} onChange={update('enabled')} />
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
@ -84,7 +84,7 @@ function defaults() {
|
||||
|
||||
return {
|
||||
settings: settings,
|
||||
mapping: createMapping(settings),
|
||||
graph: createGraph(settings),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -597,15 +597,19 @@ const createInputsOutputs = (sources, profiles) => {
|
||||
|
||||
global = [...global, ...profile.video.encoder.mapping.global];
|
||||
|
||||
// Merge video filters
|
||||
for (let i = 0; i < profile.video.encoder.mapping.local.length; i++) {
|
||||
if (profile.video.encoder.mapping.local[i] === '-vf' && profile.video.filter.mapping.length !== 0) {
|
||||
profile.video.encoder.mapping.local[i + 1] = profile.video.encoder.mapping.local[i + 1] + ',' + profile.video.filter.mapping[1];
|
||||
profile.video.filter.mapping = [];
|
||||
const local = profile.video.encoder.mapping.local.slice();
|
||||
|
||||
if (profile.video.filter.graph.length !== 0) {
|
||||
// Check if there's already a video filter in the local mapping
|
||||
let filterIndex = local.indexOf('-filter:v');
|
||||
if (filterIndex !== -1) {
|
||||
local[filterIndex + 1] += ',' + profile.video.filter.graph;
|
||||
} else {
|
||||
local.unshift('-filter:v', profile.video.filter.graph);
|
||||
}
|
||||
}
|
||||
|
||||
const options = ['-map', index + ':' + stream.stream, ...profile.video.filter.mapping, ...profile.video.encoder.mapping.local];
|
||||
const options = ['-map', index + ':' + stream.stream, ...local];
|
||||
|
||||
if (profile.audio.encoder.coder !== 'none' && profile.audio.source !== -1 && profile.audio.stream !== -1) {
|
||||
global = [...global, ...profile.audio.decoder.mapping.global];
|
||||
@ -627,15 +631,19 @@ const createInputsOutputs = (sources, profiles) => {
|
||||
|
||||
global = [...global, ...profile.audio.encoder.mapping.global];
|
||||
|
||||
// Merge audio filters
|
||||
for (let i = 0; i < profile.audio.encoder.mapping.local.length; i++) {
|
||||
if (profile.audio.encoder.mapping.local[i] === '-af' && profile.audio.filter.mapping.length !== 0) {
|
||||
profile.audio.encoder.mapping.local[i + 1] = profile.audio.encoder.mapping.local[i + 1] + ',' + profile.audio.filter.mapping[1];
|
||||
profile.audio.filter.mapping = [];
|
||||
const local = profile.audio.encoder.mapping.local.slice();
|
||||
|
||||
if (profile.audio.filter.graph.length !== 0) {
|
||||
// Check if there's already a audio filter in the local mapping
|
||||
let filterIndex = local.indexOf('-filter:a');
|
||||
if (filterIndex !== -1) {
|
||||
local[filterIndex + 1] += ',' + profile.audio.filter.graph;
|
||||
} else {
|
||||
local.unshift('-filter:a', profile.audio.filter.graph);
|
||||
}
|
||||
}
|
||||
|
||||
options.push('-map', index + ':' + stream.stream, ...profile.audio.filter.mapping, ...profile.audio.encoder.mapping.local);
|
||||
options.push('-map', index + ':' + stream.stream, ...local);
|
||||
} else {
|
||||
options.push('-an');
|
||||
}
|
||||
@ -807,9 +815,8 @@ const initProfile = (initialProfile) => {
|
||||
}
|
||||
|
||||
profile.video.filter = {
|
||||
filter: 'default',
|
||||
graph: '',
|
||||
settings: {},
|
||||
mapping: {},
|
||||
...profile.video.filter,
|
||||
};
|
||||
|
||||
@ -863,9 +870,8 @@ const initProfile = (initialProfile) => {
|
||||
}
|
||||
|
||||
profile.audio.filter = {
|
||||
filter: 'default',
|
||||
graph: '',
|
||||
settings: {},
|
||||
mapping: {},
|
||||
...profile.audio.filter,
|
||||
};
|
||||
|
||||
|
||||
@ -408,12 +408,11 @@ export default function Source(props) {
|
||||
onChange={handleEncoding('video')}
|
||||
/>
|
||||
</Grid>
|
||||
{($profile.video.encoder.coder !== 'none' && $profile.video.encoder.coder !== 'copy') && (
|
||||
{$profile.video.encoder.coder !== 'none' && $profile.video.encoder.coder !== 'copy' && (
|
||||
<Grid item xs={12}>
|
||||
<FilterSelect
|
||||
type="video"
|
||||
profile={$profile.video}
|
||||
videoProfile={$profile.video}
|
||||
availableFilters={props.skills.filter}
|
||||
onChange={handleFilter('video')}
|
||||
/>
|
||||
@ -481,7 +480,7 @@ export default function Source(props) {
|
||||
onChange={handleEncoding('audio')}
|
||||
/>
|
||||
</Grid>
|
||||
{($profile.audio.encoder.coder !== 'none' && $profile.audio.encoder.coder !== 'copy') && (
|
||||
{$profile.audio.encoder.coder !== 'none' && $profile.audio.encoder.coder !== 'copy' && (
|
||||
<Grid item xs={12}>
|
||||
<FilterSelect
|
||||
type="audio"
|
||||
@ -558,7 +557,7 @@ export default function Source(props) {
|
||||
onChange={handleEncoding('audio')}
|
||||
/>
|
||||
</Grid>
|
||||
{($profile.audio.encoder.coder !== 'none' && $profile.audio.encoder.coder !== 'copy') && (
|
||||
{$profile.audio.encoder.coder !== 'none' && $profile.audio.encoder.coder !== 'copy' && (
|
||||
<Grid item xs={12}>
|
||||
<FilterSelect
|
||||
type="audio"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user