diff --git a/src/misc/coders/Encoders/index.js b/src/misc/coders/Encoders/index.js index ec5380b..0b25fd6 100644 --- a/src/misc/coders/Encoders/index.js +++ b/src/misc/coders/Encoders/index.js @@ -22,6 +22,7 @@ import * as VideoCopy from './video/Copy'; import * as VideoNone from './video/None'; import * as VideoRaw from './video/Raw'; import * as VP9 from './video/VP9'; +import * as AV1Rav1e from './video/AV1Rav1e'; class Registry { constructor(type) { @@ -135,5 +136,6 @@ videoRegistry.Register(HEVCVideoToolbox); videoRegistry.Register(VP9VAAPI); videoRegistry.Register(VP9); videoRegistry.Register(VideoRaw); +videoRegistry.Register(AV1Rav1e); export { audioRegistry as Audio, videoRegistry as Video }; diff --git a/src/misc/coders/Encoders/video/AV1Rav1e.js b/src/misc/coders/Encoders/video/AV1Rav1e.js new file mode 100644 index 0000000..0c8db86 --- /dev/null +++ b/src/misc/coders/Encoders/video/AV1Rav1e.js @@ -0,0 +1,255 @@ +import React from 'react'; + +import Grid from '@mui/material/Grid'; +import MenuItem from '@mui/material/MenuItem'; +import TextField from '@mui/material/TextField'; +import Typography from '@mui/material/Typography'; + +import { Trans } from '@lingui/macro'; + +import Select from '../../../Select'; +import Video from '../../settings/Video'; +import Helper from '../../helper'; + +function init(initialState) { + const state = { + bitrate: '4096', + fps: '25', + fps_mode: 'auto', + gop: '2', + qp: '-1', + speed: '-1', + tiles: '0', + tile_rows: '0', + tile_columns: '0', + params: '', + ...initialState, + }; + + return state; +} + +function createMapping(settings, stream, skills) { + stream = Helper.InitStream(stream); + skills = Helper.InitSkills(skills); + + const local = [ + '-codec:v', + 'librav1e', + '-b:v', + `${settings.bitrate}k`, + '-maxrate:v', + `${settings.bitrate}k`, + '-bufsize:v', + `${settings.bitrate}k`, + '-r', + `${settings.fps}`, + '-pix_fmt', + 'yuv420p', + '-qp', + `${settings.qp}`, + '-speed', + `${settings.speed}`, + '-tiles', + `${settings.tiles}`, + '-tile-rows', + `${settings.tile_rows}`, + '-tile-columns', + `${settings.tile_columns}`, + ]; + + if (settings.params.length !== 0) { + local.push('-rav1e-params', `${settings.params}`); + } + + if (settings.gop !== 'auto') { + local.push( + '-g', + `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`, + '-keyint_min', + `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`, + ); + } + + if (skills.ffmpeg.version_major >= 5) { + local.push('-fps_mode', `${settings.fps_mode}`); + } + + const mapping = { + global: [], + local: local, + }; + + return mapping; +} + +function Speed(props) { + return ( + + + + What speed preset to use. + + + ); +} + +Speed.defaultProps = { + value: '-1', + onChange: function (event) {}, +}; + +function Coder(props) { + const settings = init(props.settings); + const stream = Helper.InitStream(props.stream); + const skills = Helper.InitSkills(props.skills); + + const handleChange = (newSettings) => { + let automatic = false; + if (!newSettings) { + newSettings = settings; + automatic = true; + } + + props.onChange(newSettings, createMapping(newSettings, stream, skills), 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 ( + + + + + + + + + + + {skills.ffmpeg.version_major >= 5 && ( + + + + )} + + + + + QP} + value={settings.qp} + onChange={update('qp')} + /> + + Constant Quantizer Mode (-1 to 255). + + + + Tiles} + value={settings.tiles} + onChange={update('tiles')} + /> + + Number of tiles encode with. + + + + Tile Rows} + value={settings.tile_rows} + onChange={update('tile_rows')} + /> + + Number of tiles rows to encode with. + + + + Tile Columns} + value={settings.tile_columns} + onChange={update('tile_columns')} + /> + + Number of tiles columns to encode with. + + + + rav1e Parameters} value={settings.params} onChange={update('params')} /> + + Set the rav1e configuration using a :-separated list of key=value parameters. + + + + ); +} + +Coder.defaultProps = { + stream: {}, + settings: {}, + skills: {}, + onChange: function (settings, mapping) {}, +}; + +const coder = 'librav1e'; +const name = 'AV1 (librav1e)'; +const codec = 'av1'; +const type = 'video'; +const hwaccel = false; + +function summarize(settings) { + return `${name}, ${settings.bitrate} kbit/s, ${settings.fps} FPS, Speed: ${settings.speed}, QP: ${settings.qp}`; +} + +function defaults(stream, skills) { + const settings = init({}); + + return { + settings: settings, + mapping: createMapping(settings, stream, skills), + }; +} + +export { coder, name, codec, type, hwaccel, summarize, defaults, Coder as component }; diff --git a/src/misc/coders/Encoders/video/H264V4L2M2M.js b/src/misc/coders/Encoders/video/H264V4L2M2M.js index 85e32d7..9f36211 100644 --- a/src/misc/coders/Encoders/video/H264V4L2M2M.js +++ b/src/misc/coders/Encoders/video/H264V4L2M2M.js @@ -1,5 +1,4 @@ import React from 'react'; -import SemverSatisfies from 'semver/functions/satisfies'; import Grid from '@mui/material/Grid'; import Typography from '@mui/material/Typography'; @@ -80,10 +79,6 @@ function createMapping(settings, stream, skills) { stream = Helper.InitStream(stream); skills = Helper.InitSkills(skills); - let ffversion = 4; - if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) { - ffversion = 5; - } const local = [ '-codec:v', 'h264_v4l2m2m', @@ -119,7 +114,7 @@ function createMapping(settings, stream, skills) { local.push('-keyint_min', `${parseInt(settings.fps)}`); } - if (ffversion === 5) { + if (skills.ffmpeg.version_major >= 5) { local.push('-fps_mode', `${settings.fps_mode}`); } @@ -140,11 +135,6 @@ function Coder(props) { const stream = Helper.InitStream(props.stream); const skills = Helper.InitSkills(props.skills); - let ffversion = 4; - if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) { - ffversion = 5; - } - const handleChange = (newSettings) => { let automatic = false; if (!newSettings) { @@ -190,7 +180,7 @@ function Coder(props) { To stabilize the system, increase the HLS segment length for the keyframe interval by 2-3 * (Processing and Control). - {ffversion === 5 && ( + {skills.ffmpeg.version_major >= 5 && ( diff --git a/src/misc/coders/Encoders/video/VP9.js b/src/misc/coders/Encoders/video/VP9.js index 54843c3..32cf359 100644 --- a/src/misc/coders/Encoders/video/VP9.js +++ b/src/misc/coders/Encoders/video/VP9.js @@ -1,5 +1,4 @@ import React from 'react'; -import SemverSatisfies from 'semver/functions/satisfies'; import Grid from '@mui/material/Grid'; @@ -22,11 +21,6 @@ function createMapping(settings, stream, skills) { stream = Helper.InitStream(stream); skills = Helper.InitSkills(skills); - let ffversion = 4; - if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) { - ffversion = 5; - } - const local = [ '-codec:v', 'libvpx-vp9', @@ -49,11 +43,11 @@ function createMapping(settings, stream, skills) { '-g', `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`, '-keyint_min', - `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}` + `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`, ); } - if (ffversion === 5) { + if (skills.ffmpeg.version_major >= 5) { local.push('-fps_mode', `${settings.fps_mode}`); } @@ -70,11 +64,6 @@ function Coder(props) { const stream = Helper.InitStream(props.stream); const skills = Helper.InitSkills(props.skills); - let ffversion = 4; - if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) { - ffversion = 5; - } - const handleChange = (newSettings) => { let automatic = false; if (!newSettings) { @@ -110,7 +99,7 @@ function Coder(props) { - {ffversion === 5 && ( + {skills.ffmpeg.version_major >= 5 && ( diff --git a/src/misc/coders/Encoders/video/X264.js b/src/misc/coders/Encoders/video/X264.js index 8cc2d1c..920891c 100644 --- a/src/misc/coders/Encoders/video/X264.js +++ b/src/misc/coders/Encoders/video/X264.js @@ -1,5 +1,4 @@ import React from 'react'; -import SemverSatisfies from 'semver/functions/satisfies'; import Grid from '@mui/material/Grid'; import MenuItem from '@mui/material/MenuItem'; @@ -29,11 +28,6 @@ function createMapping(settings, stream, skills) { stream = Helper.InitStream(stream); skills = Helper.InitSkills(skills); - let ffversion = 4; - if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) { - ffversion = 5; - } - const local = [ '-codec:v', 'libx264', @@ -58,11 +52,11 @@ function createMapping(settings, stream, skills) { '-g', `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`, '-keyint_min', - `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}` + `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`, ); } - if (ffversion === 5) { + if (skills.ffmpeg.version_major >= 5) { local.push('-fps_mode', `${settings.fps_mode}`); } @@ -127,11 +121,6 @@ function Coder(props) { const stream = Helper.InitStream(props.stream); const skills = Helper.InitSkills(props.skills); - let ffversion = 4; - if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) { - ffversion = 5; - } - const handleChange = (newSettings) => { let automatic = false; if (!newSettings) { @@ -167,7 +156,7 @@ function Coder(props) { - {ffversion === 5 && ( + {skills.ffmpeg.version_major >= 5 && ( diff --git a/src/misc/coders/Encoders/video/X265.js b/src/misc/coders/Encoders/video/X265.js index 05cbc48..fd83cbd 100644 --- a/src/misc/coders/Encoders/video/X265.js +++ b/src/misc/coders/Encoders/video/X265.js @@ -1,5 +1,4 @@ import React from 'react'; -import SemverSatisfies from 'semver/functions/satisfies'; import Grid from '@mui/material/Grid'; import MenuItem from '@mui/material/MenuItem'; @@ -29,11 +28,6 @@ function createMapping(settings, stream, skills) { stream = Helper.InitStream(stream); skills = Helper.InitSkills(skills); - let ffversion = 4; - if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) { - ffversion = 5; - } - const local = [ '-codec:v', 'libx265', @@ -62,7 +56,7 @@ function createMapping(settings, stream, skills) { ); } - if (ffversion === 5) { + if (skills.ffmpeg.version_major >= 5) { local.push('-fps_mode', `${settings.fps_mode}`); } @@ -127,11 +121,6 @@ function Coder(props) { const stream = Helper.InitStream(props.stream); const skills = Helper.InitSkills(props.skills); - let ffversion = 4; - if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) { - ffversion = 5; - } - const handleChange = (newSettings) => { let automatic = false; if (!newSettings) { @@ -167,7 +156,7 @@ function Coder(props) { - {ffversion === 5 && ( + {skills.ffmpeg.version_major >= 5 && ( @@ -193,7 +182,7 @@ Coder.defaultProps = { }; const coder = 'libx265'; -const name = 'H.265 (libx265)'; +const name = 'HEVC (libx265)'; const codec = 'hevc'; const type = 'video'; const hwaccel = false;