diff --git a/src/views/Edit/Sources/ALSA.js b/src/views/Edit/Sources/ALSA.js
index 53c3fff..1d562db 100644
--- a/src/views/Edit/Sources/ALSA.js
+++ b/src/views/Edit/Sources/ALSA.js
@@ -155,7 +155,7 @@ function SourceIcon(props) {
const id = 'alsa';
const name = ALSA;
const capabilities = ['audio'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/AVFoundation.js b/src/views/Edit/Sources/AVFoundation.js
index 5b2e05b..072b7d9 100644
--- a/src/views/Edit/Sources/AVFoundation.js
+++ b/src/views/Edit/Sources/AVFoundation.js
@@ -220,7 +220,7 @@ function SourceIcon(props) {
const id = 'avfoundation';
const name = AVFoundation;
const capabilities = ['audio', 'video'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/AudioLoop.js b/src/views/Edit/Sources/AudioLoop.js
index cd195d6..2220f50 100644
--- a/src/views/Edit/Sources/AudioLoop.js
+++ b/src/views/Edit/Sources/AudioLoop.js
@@ -193,7 +193,7 @@ function SourceIcon(props) {
const id = 'audioloop';
const name = Loop;
const capabilities = ['audio'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/Framebuffer.js b/src/views/Edit/Sources/Framebuffer.js
index 9791939..2f80556 100644
--- a/src/views/Edit/Sources/Framebuffer.js
+++ b/src/views/Edit/Sources/Framebuffer.js
@@ -128,7 +128,7 @@ function SourceIcon(props) {
const id = 'fbdev';
const name = Framebuffer;
const capabilities = ['video'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/Network.js b/src/views/Edit/Sources/Network.js
index eab6091..6bcad4e 100644
--- a/src/views/Edit/Sources/Network.js
+++ b/src/views/Edit/Sources/Network.js
@@ -178,13 +178,15 @@ const initSkills = (initialSkills) => {
};
const createInputs = (settings, config, skills) => {
- settings = initSettings(settings);
config = initConfig(config);
+ settings = initSettings(settings, config);
skills = initSkills(skills);
- let ffmpeg_version = 4;
+ let ffmpeg_version = 6;
if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) {
ffmpeg_version = 5;
+ } else if (SemverSatisfies(skills.ffmpeg.version, '^4.1.0')) {
+ ffmpeg_version = 4;
}
const input = {
@@ -1173,7 +1175,7 @@ function SourceIcon(props) {
const id = 'network';
const name = Network source;
const capabilities = ['audio', 'video'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/Network.test.js b/src/views/Edit/Sources/Network.test.js
index 9204145..e08c888 100644
--- a/src/views/Edit/Sources/Network.test.js
+++ b/src/views/Edit/Sources/Network.test.js
@@ -4,6 +4,18 @@ import '@testing-library/jest-dom';
import * as Network from './Network';
+const $skills_ffmpeg6 = {
+ ffmpeg: {
+ version: '6.1.1',
+ },
+ formats: {
+ demuxers: ['rtsp'],
+ },
+ protocols: {
+ input: ['http', 'https', 'rtmp', 'rtmps', 'srt'],
+ },
+};
+
const $skills_ffmpeg5 = {
ffmpeg: {
version: '5.1.2',
@@ -29,6 +41,7 @@ const $skills_ffmpeg4 = {
};
const $config = {
+ channelid: 'external',
rtmp: {
enabled: true,
app: '/live',
@@ -64,9 +77,17 @@ test('source:network pull', async () => {
expect(queryByText(`This protocol is unknown or not supported by the available FFmpeg binary.`)).toBeInTheDocument();
+ rerender();
+
+ expect(queryByText(`This protocol is unknown or not supported by the available FFmpeg binary.`)).toBe(null);
+
rerender();
expect(queryByText(`This protocol is unknown or not supported by the available FFmpeg binary.`)).toBe(null);
+
+ rerender();
+
+ expect(queryByText(`This protocol is unknown or not supported by the available FFmpeg binary.`)).toBe(null);
});
const pullmatrix = {
@@ -205,6 +226,56 @@ pullmatrix.tests = [
options: ['-fflags', '+genpts', '-thread_queue_size', 512],
},
},
+ {
+ name: 'RTSP',
+ settings: { ...pullmatrix.settings, address: 'rtsp://127.0.0.1/live/stream' },
+ skills: $skills_ffmpeg6,
+ input: {
+ address: 'rtsp://admin:foobar@127.0.0.1/live/stream',
+ options: ['-fflags', '+genpts', '-thread_queue_size', 512, '-timeout', 5000000, '-rtsp_transport', 'tcp'],
+ },
+ },
+ {
+ name: 'RTMP',
+ settings: { ...pullmatrix.settings, address: 'rtmp://127.0.0.1/live/stream' },
+ skills: $skills_ffmpeg6,
+ input: {
+ address: 'rtmp://admin:foobar@127.0.0.1/live/stream',
+ options: ['-fflags', '+genpts', '-thread_queue_size', 512, '-analyzeduration', 3000000],
+ },
+ },
+ {
+ name: 'HTTP',
+ settings: { ...pullmatrix.settings, address: 'http://127.0.0.1/live/stream.m3u8' },
+ skills: $skills_ffmpeg6,
+ input: {
+ address: 'http://admin:foobar@127.0.0.1/live/stream.m3u8',
+ options: [
+ '-fflags',
+ '+genpts',
+ '-thread_queue_size',
+ 512,
+ '-analyzeduration',
+ 20000000,
+ '-re',
+ '-r',
+ 25,
+ '-user_agent',
+ 'foobaz/1',
+ '-referer',
+ 'http://example.com',
+ ],
+ },
+ },
+ {
+ name: 'SRT',
+ settings: { ...pullmatrix.settings, address: 'srt://127.0.0.1?mode=caller&streamid=foobar' },
+ skills: $skills_ffmpeg6,
+ input: {
+ address: 'srt://127.0.0.1?mode=caller&streamid=foobar',
+ options: ['-fflags', '+genpts', '-thread_queue_size', 512],
+ },
+ },
];
test.each(pullmatrix.tests)('source:network pull $name input with ffmpeg $skills.ffmpeg.version', async (data) => {
@@ -231,6 +302,7 @@ test('source:network push', async () => {
mode: 'push',
push: {
type: 'rtmp',
+ name: 'external',
},
};
const handleChange = (settings) => {
@@ -244,9 +316,17 @@ test('source:network push', async () => {
expect(queryByText(`The available FFmpeg binary doesn't support any of the required protocols.`)).toBeInTheDocument();
+ rerender();
+
+ expect(queryByText(`The available FFmpeg binary doesn't support any of the required protocols.`)).toBe(null);
+
rerender();
expect(queryByText(`The available FFmpeg binary doesn't support any of the required protocols.`)).toBe(null);
+
+ rerender();
+
+ expect(queryByText(`The available FFmpeg binary doesn't support any of the required protocols.`)).toBe(null);
});
test('source:network push RTMP', async () => {
@@ -254,6 +334,7 @@ test('source:network push RTMP', async () => {
mode: 'push',
push: {
type: 'rtmp',
+ name: 'external',
},
};
const handleChange = (settings) => {
@@ -278,6 +359,7 @@ test('source:network push SRT', async () => {
mode: 'push',
push: {
type: 'srt',
+ name: 'external',
},
};
const handleChange = (settings) => {
@@ -302,6 +384,7 @@ const pushmatrix = {
mode: 'push',
push: {
type: '',
+ name: 'external',
},
},
tests: [],
@@ -348,6 +431,26 @@ pushmatrix.tests = [
options: ['-fflags', '+genpts', '-thread_queue_size', 512],
},
},
+ {
+ name: 'RTMP',
+ settings: { ...pushmatrix.settings, push: { ...pushmatrix.push, type: 'rtmp' } },
+ skills: $skills_ffmpeg6,
+ config: $config,
+ input: {
+ address: '{rtmp,name=external.stream}',
+ options: ['-fflags', '+genpts', '-thread_queue_size', 512, '-analyzeduration', 3000000],
+ },
+ },
+ {
+ name: 'SRT',
+ settings: { ...pushmatrix.settings, push: { ...pushmatrix.push, type: 'srt' } },
+ skills: $skills_ffmpeg6,
+ config: $config,
+ input: {
+ address: '{srt,name=external.stream,mode=request}',
+ options: ['-fflags', '+genpts', '-thread_queue_size', 512],
+ },
+ },
];
test.each(pushmatrix.tests)('source:network push $name input with ffmpeg $skills.ffmpeg.version', async (data) => {
diff --git a/src/views/Edit/Sources/NoAudio.js b/src/views/Edit/Sources/NoAudio.js
index 3583118..b6f7668 100644
--- a/src/views/Edit/Sources/NoAudio.js
+++ b/src/views/Edit/Sources/NoAudio.js
@@ -44,7 +44,7 @@ function SourceIcon(props) {
const id = 'noaudio';
const name = No audio;
const capabilities = ['audio'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/Raspicam.js b/src/views/Edit/Sources/Raspicam.js
index 682942b..471704f 100644
--- a/src/views/Edit/Sources/Raspicam.js
+++ b/src/views/Edit/Sources/Raspicam.js
@@ -143,7 +143,7 @@ function SourceIcon(props) {
const id = 'raspicam';
const name = Raspberry Pi camera;
const capabilities = ['video'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/V4L.js b/src/views/Edit/Sources/V4L.js
index b01f29e..003c166 100644
--- a/src/views/Edit/Sources/V4L.js
+++ b/src/views/Edit/Sources/V4L.js
@@ -153,7 +153,7 @@ function SourceIcon(props) {
const id = 'video4linux2';
const name = Hardware device;
const capabilities = ['video'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/VideoAudio.js b/src/views/Edit/Sources/VideoAudio.js
index 8279e34..47b3ec0 100644
--- a/src/views/Edit/Sources/VideoAudio.js
+++ b/src/views/Edit/Sources/VideoAudio.js
@@ -44,7 +44,7 @@ function SourceIcon(props) {
const id = 'videoaudio';
const name = Video source;
const capabilities = ['audio'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/VideoLoop.js b/src/views/Edit/Sources/VideoLoop.js
index f532547..9350f33 100644
--- a/src/views/Edit/Sources/VideoLoop.js
+++ b/src/views/Edit/Sources/VideoLoop.js
@@ -201,7 +201,7 @@ function SourceIcon(props) {
const id = 'videoloop';
const name = Loop;
const capabilities = ['video'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/VirtualAudio.js b/src/views/Edit/Sources/VirtualAudio.js
index 3885a43..de0b0d5 100644
--- a/src/views/Edit/Sources/VirtualAudio.js
+++ b/src/views/Edit/Sources/VirtualAudio.js
@@ -186,7 +186,7 @@ function SourceIcon(props) {
const id = 'virtualaudio';
const name = Virtual source;
const capabilities = ['audio'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Sources/VirtualVideo.js b/src/views/Edit/Sources/VirtualVideo.js
index f2b3c69..aeb8dfa 100644
--- a/src/views/Edit/Sources/VirtualVideo.js
+++ b/src/views/Edit/Sources/VirtualVideo.js
@@ -205,7 +205,7 @@ function SourceIcon(props) {
const id = 'virtualvideo';
const name = Virtual source;
const capabilities = ['video'];
-const ffversion = '^4.1.0 || ^5.0.0';
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0';
const func = {
initSettings,
diff --git a/src/views/Edit/Wizard/Sources/InternalHLS.js b/src/views/Edit/Wizard/Sources/InternalHLS.js
index ae4942e..929153f 100644
--- a/src/views/Edit/Wizard/Sources/InternalHLS.js
+++ b/src/views/Edit/Wizard/Sources/InternalHLS.js
@@ -9,9 +9,9 @@ import * as S from '../../Sources/Network';
import BoxTextarea from '../../../../misc/BoxTextarea';
import Textarea from '../../../../misc/Textarea';
-const initSettings = (initialSettings) => {
+const initSettings = (initialSettings, config) => {
const settings = {
- ...S.func.initSettings(initialSettings),
+ ...S.func.initSettings(initialSettings, config),
mode: 'push',
};
@@ -21,8 +21,8 @@ const initSettings = (initialSettings) => {
};
function Source(props) {
- const settings = initSettings(props.settings);
const config = S.func.initConfig(props.config);
+ const settings = initSettings(props.settings, config);
const skills = S.func.initSkills(props.skills);
const handleChange = (newSettings) => {
diff --git a/src/views/Edit/Wizard/Sources/InternalRTMP.js b/src/views/Edit/Wizard/Sources/InternalRTMP.js
index 0cb3e0b..fb6622c 100644
--- a/src/views/Edit/Wizard/Sources/InternalRTMP.js
+++ b/src/views/Edit/Wizard/Sources/InternalRTMP.js
@@ -11,9 +11,9 @@ import * as S from '../../Sources/Network';
import BoxTextarea from '../../../../misc/BoxTextarea';
import Textarea from '../../../../misc/Textarea';
-const initSettings = (initialSettings) => {
+const initSettings = (initialSettings, config) => {
const settings = {
- ...S.func.initSettings(initialSettings),
+ ...S.func.initSettings(initialSettings, config),
mode: 'push',
};
@@ -24,8 +24,8 @@ const initSettings = (initialSettings) => {
function Source(props) {
const navigate = useNavigate();
- const settings = initSettings(props.settings);
const config = S.func.initConfig(props.config);
+ const settings = initSettings(props.settings, config);
const skills = S.func.initSkills(props.skills);
const handleChange = (newSettings) => {
diff --git a/src/views/Edit/Wizard/Sources/InternalSRT.js b/src/views/Edit/Wizard/Sources/InternalSRT.js
index cf1b89d..c5e0bbd 100644
--- a/src/views/Edit/Wizard/Sources/InternalSRT.js
+++ b/src/views/Edit/Wizard/Sources/InternalSRT.js
@@ -11,9 +11,9 @@ import * as S from '../../Sources/Network';
import BoxTextarea from '../../../../misc/BoxTextarea';
import Textarea from '../../../../misc/Textarea';
-const initSettings = (initialSettings) => {
+const initSettings = (initialSettings, config) => {
const settings = {
- ...S.func.initSettings(initialSettings),
+ ...S.func.initSettings(initialSettings, config),
mode: 'push',
};
@@ -24,8 +24,8 @@ const initSettings = (initialSettings) => {
function Source(props) {
const navigate = useNavigate();
- const settings = initSettings(props.settings);
const config = S.func.initConfig(props.config);
+ const settings = initSettings(props.settings, config);
const skills = S.func.initSkills(props.skills);
const handleChange = (newSettings) => {
diff --git a/src/views/Edit/Wizard/Sources/Network.js b/src/views/Edit/Wizard/Sources/Network.js
index 4a352f7..88578c0 100644
--- a/src/views/Edit/Wizard/Sources/Network.js
+++ b/src/views/Edit/Wizard/Sources/Network.js
@@ -10,9 +10,9 @@ import * as S from '../../Sources/Network';
import Checkbox from '../../../../misc/Checkbox';
import Password from '../../../../misc/Password';
-const initSettings = (initialSettings) => {
+const initSettings = (initialSettings, config) => {
const settings = {
- ...S.func.initSettings(initialSettings),
+ ...S.func.initSettings(initialSettings, config),
mode: 'pull',
};
@@ -20,8 +20,8 @@ const initSettings = (initialSettings) => {
};
function Source(props) {
- const settings = initSettings(props.settings);
const config = S.func.initConfig(props.config);
+ const settings = initSettings(props.settings, config);
const skills = S.func.initSkills(props.skills);
const handleChange = (newSettings) => {
diff --git a/src/views/Edit/Wizard/Sources/V4L.js b/src/views/Edit/Wizard/Sources/V4L.js
index 055742b..7417a08 100644
--- a/src/views/Edit/Wizard/Sources/V4L.js
+++ b/src/views/Edit/Wizard/Sources/V4L.js
@@ -97,7 +97,7 @@ function Source(props) {
options.push(
+ ,
);
}