diff --git a/src/misc/EncodingSelect.js b/src/misc/EncodingSelect.js
index e15be0c..0ef6838 100644
--- a/src/misc/EncodingSelect.js
+++ b/src/misc/EncodingSelect.js
@@ -239,5 +239,5 @@ EncodingSelect.defaultProps = {
codecs: [],
availableEncoders: [],
availableDecoders: [],
- onChange: function (encoder, decoder) {},
+ onChange: function (encoder, decoder, automatic) {},
};
diff --git a/src/misc/FilterSelect.js b/src/misc/FilterSelect.js
index 0d6ccc8..516a40e 100644
--- a/src/misc/FilterSelect.js
+++ b/src/misc/FilterSelect.js
@@ -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(
-
+
);
}
}
@@ -121,7 +128,7 @@ export default function FilterSelect(props) {
FilterSelect.defaultProps = {
type: '',
- filters: [],
+ profile: {},
availableFilters: [],
- onChange: function (filter) {},
+ onChange: function (filter, automatic) {},
};
diff --git a/src/misc/coders/Encoders/audio/AAC.js b/src/misc/coders/Encoders/audio/AAC.js
index a3eea58..4784c7b 100644
--- a/src/misc/coders/Encoders/audio/AAC.js
+++ b/src/misc/coders/Encoders/audio/AAC.js
@@ -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');
diff --git a/src/misc/coders/Encoders/audio/AACAudioToolbox.js b/src/misc/coders/Encoders/audio/AACAudioToolbox.js
index f8e0525..94fe217 100644
--- a/src/misc/coders/Encoders/audio/AACAudioToolbox.js
+++ b/src/misc/coders/Encoders/audio/AACAudioToolbox.js
@@ -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');
diff --git a/src/misc/coders/Encoders/audio/Libopus.js b/src/misc/coders/Encoders/audio/Libopus.js
index bb6d9d9..a7bd2ce 100644
--- a/src/misc/coders/Encoders/audio/Libopus.js
+++ b/src/misc/coders/Encoders/audio/Libopus.js
@@ -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: [],
diff --git a/src/misc/coders/Encoders/audio/Libvorbis.js b/src/misc/coders/Encoders/audio/Libvorbis.js
index 4ceafbc..bb7aa4b 100644
--- a/src/misc/coders/Encoders/audio/Libvorbis.js
+++ b/src/misc/coders/Encoders/audio/Libvorbis.js
@@ -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: [],
diff --git a/src/misc/coders/Encoders/audio/MP3.js b/src/misc/coders/Encoders/audio/MP3.js
index 7a394c7..0e7fc49 100644
--- a/src/misc/coders/Encoders/audio/MP3.js
+++ b/src/misc/coders/Encoders/audio/MP3.js
@@ -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: [],
diff --git a/src/misc/coders/Encoders/audio/Opus.js b/src/misc/coders/Encoders/audio/Opus.js
index 17f62ed..c5fe8a6 100644
--- a/src/misc/coders/Encoders/audio/Opus.js
+++ b/src/misc/coders/Encoders/audio/Opus.js
@@ -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);
diff --git a/src/misc/coders/Encoders/audio/Vorbis.js b/src/misc/coders/Encoders/audio/Vorbis.js
index c484720..462a508 100644
--- a/src/misc/coders/Encoders/audio/Vorbis.js
+++ b/src/misc/coders/Encoders/audio/Vorbis.js
@@ -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: [],
diff --git a/src/misc/filters/audio/Loudnorm.js b/src/misc/filters/audio/Loudnorm.js
index 5b2c70a..7b0ec22 100644
--- a/src/misc/filters/audio/Loudnorm.js
+++ b/src/misc/filters/audio/Loudnorm.js
@@ -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 (
- Loudness Normalization} checked={settings.value} onChange={update('value')} />
+ Loudness Normalization} checked={settings.enabled} onChange={update('enabled')} />
);
@@ -86,7 +86,7 @@ function defaults() {
return {
settings: settings,
- mapping: createMapping(settings),
+ graph: createGraph(settings),
};
}
diff --git a/src/misc/filters/audio/Volume.js b/src/misc/filters/audio/Volume.js
index ab2bffc..06cc660 100644
--- a/src/misc/filters/audio/Volume.js
+++ b/src/misc/filters/audio/Volume.js
@@ -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),
};
}
diff --git a/src/misc/filters/video/HFlip.js b/src/misc/filters/video/HFlip.js
index 34b8fff..52d8ff2 100644
--- a/src/misc/filters/video/HFlip.js
+++ b/src/misc/filters/video/HFlip.js
@@ -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 (
- Horizontal Flip} checked={settings.value} onChange={update('value')} />
+ Horizontal Flip} checked={settings.enabled} onChange={update('enabled')} />
);
}
@@ -84,7 +84,7 @@ function defaults() {
return {
settings: settings,
- mapping: createMapping(settings),
+ graph: createGraph(settings),
};
}
diff --git a/src/misc/filters/video/Transpose.js b/src/misc/filters/video/Transpose.js
index 8f99731..2c5157b 100644
--- a/src/misc/filters/video/Transpose.js
+++ b/src/misc/filters/video/Transpose.js
@@ -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),
};
}
diff --git a/src/misc/filters/video/VFlip.js b/src/misc/filters/video/VFlip.js
index 4d74c20..9c76f94 100644
--- a/src/misc/filters/video/VFlip.js
+++ b/src/misc/filters/video/VFlip.js
@@ -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 (
- Vertical Flip} checked={settings.value} onChange={update('value')} />
+ Vertical Flip} checked={settings.enabled} onChange={update('enabled')} />
);
}
@@ -84,7 +84,7 @@ function defaults() {
return {
settings: settings,
- mapping: createMapping(settings),
+ graph: createGraph(settings),
};
}
diff --git a/src/utils/metadata.js b/src/utils/metadata.js
index e99be7b..3bfda79 100644
--- a/src/utils/metadata.js
+++ b/src/utils/metadata.js
@@ -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,
};
diff --git a/src/views/Edit/Profile.js b/src/views/Edit/Profile.js
index 4afb778..02f644c 100644
--- a/src/views/Edit/Profile.js
+++ b/src/views/Edit/Profile.js
@@ -408,12 +408,11 @@ export default function Source(props) {
onChange={handleEncoding('video')}
/>
- {($profile.video.encoder.coder !== 'none' && $profile.video.encoder.coder !== 'copy') && (
+ {$profile.video.encoder.coder !== 'none' && $profile.video.encoder.coder !== 'copy' && (
@@ -481,7 +480,7 @@ export default function Source(props) {
onChange={handleEncoding('audio')}
/>
- {($profile.audio.encoder.coder !== 'none' && $profile.audio.encoder.coder !== 'copy') && (
+ {$profile.audio.encoder.coder !== 'none' && $profile.audio.encoder.coder !== 'copy' && (
- {($profile.audio.encoder.coder !== 'none' && $profile.audio.encoder.coder !== 'copy') && (
+ {$profile.audio.encoder.coder !== 'none' && $profile.audio.encoder.coder !== 'copy' && (