aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json55
-rw-r--r--package.json2
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.tsx82
3 files changed, 116 insertions, 23 deletions
diff --git a/package-lock.json b/package-lock.json
index d48e44121..241827de7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -585,6 +585,56 @@
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz",
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
},
+ "@ffmpeg/core": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@ffmpeg/core/-/core-0.10.0.tgz",
+ "integrity": "sha512-qunWJl5PezpXEm31tb8Qu5z37B5KVA1VYZCpXchMhuAb3X9T7PuE3SlhOwphEoRhzaOa3lpofDfzihAUMFaVPQ=="
+ },
+ "@ffmpeg/ffmpeg": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@ffmpeg/ffmpeg/-/ffmpeg-0.10.0.tgz",
+ "integrity": "sha512-W+d0ysYTO6d4vue/0KMYrxaprh9wvmnPqh6qyHXavBWLrDcE7gI3cJ/EQVfwe9nrt2e0Pi7873P2I18VEDgRfA==",
+ "requires": {
+ "is-url": "^1.2.4",
+ "node-fetch": "^2.6.1",
+ "regenerator-runtime": "^0.13.7",
+ "resolve-url": "^0.2.1"
+ },
+ "dependencies": {
+ "node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "requires": {
+ "whatwg-url": "^5.0.0"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.13.9",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
+ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+ },
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
+ },
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+ "requires": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ }
+ }
+ },
"@fortawesome/fontawesome-common-types": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.3.0.tgz",
@@ -9377,6 +9427,11 @@
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
+ "is-url": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
+ "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
+ },
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
diff --git a/package.json b/package.json
index 6185bc0d7..ef646b1d9 100644
--- a/package.json
+++ b/package.json
@@ -112,6 +112,8 @@
"webpack-hot-middleware": "^2.25.1"
},
"dependencies": {
+ "@ffmpeg/core": "0.10.0",
+ "@ffmpeg/ffmpeg": "0.10.0",
"@fortawesome/fontawesome-svg-core": "^1.3.0",
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-regular-svg-icons": "^5.15.4",
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index 87716e9cc..5cfb03414 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -7,12 +7,13 @@ import { FaCheckCircle } from 'react-icons/fa';
import { IconContext } from "react-icons";
import { Networking } from '../../../Network';
import { Upload } from '../../../../server/SharedMediaTypes';
+import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';
import { RecordingApi } from '../../../util/RecordingApi';
interface MediaSegment {
- videoChunks: any[],
- endTime: number
+ videoChunks: any[],
+ endTime: number
}
interface IRecordingViewProps {
@@ -31,7 +32,8 @@ export function RecordingView(props: IRecordingViewProps) {
const [playing, setPlaying] = useState(false);
const [progress, setProgress] = useState(0);
- const [videos, setVideos] = useState<MediaSegment[]>([]);
+ const [videos, setVideos] = useState<MediaSegment[]>([]);
+ // const [order, setOrder] = useState<number[]>([]);
const videoRecorder = useRef<MediaRecorder | null>(null);
const videoElementRef = useRef<HTMLVideoElement | null>(null);
@@ -52,28 +54,52 @@ export function RecordingView(props: IRecordingViewProps) {
}
}
- useEffect(() => {
+ useEffect(() => {
+
+ console.log('in finish useEffect')
- if (finished) {
+ if (finished) {
+ // load ffmpe
+ (async () => {
+ console.log('crossOriginIsolated', crossOriginIsolated)
props.setDuration(recordingTimer * 100)
- let allVideoChunks: any = []
- videos.forEach((vid) => {
- console.log(vid.videoChunks)
- allVideoChunks = allVideoChunks.concat(vid.videoChunks)
- })
-
- const videoFile = new File(allVideoChunks, "video.mkv", { type: allVideoChunks[0].type, lastModified: Date.now() });
-
- Networking.UploadFilesToServer(videoFile)
- .then((data) => {
- const result = data[0].result
- if (!(result instanceof Error)) { // convert this screenshotBox into normal videoBox
- props.setResult(result, trackScreen)
- } else {
- alert("video conversion failed");
- }
- })
+ console.log('Loading ffmpeg-core.js');
+ const ffmpeg = createFFmpeg({ log: true });
+ await ffmpeg.load();
+ console.log('ffmpeg-core.js loaded');
+
+ let allVideoChunks: any = [];
+ const inputPaths: string[] = [];
+ // write each segment into it's indexed file
+ videos.forEach(async (vid, i) => {
+ const vidName = `segvideo${i}.mkv`
+ inputPaths.push(vidName)
+ const videoFile = new File(vid.videoChunks, vidName, { type: allVideoChunks[0].type, lastModified: Date.now() });
+ ffmpeg.FS('writeFile', vidName, await fetchFile(videoFile));
+ })
+ ffmpeg.FS('writeFile', 'order.txt', inputPaths.join('\n'));
+
+ console.log('concat')
+ await ffmpeg.run('-f', 'concat', '-safe', '0', '-i', 'order.txt', 'ouput.mp4');
+
+ const { buffer } = ffmpeg.FS('readFile', 'output.mp4');
+ const concatVideo = new File([buffer], 'concat.mp4', { type: "video/mp4" });
+
+ const data = await Networking.UploadFilesToServer(concatVideo)
+ const result = data[0].result
+ if (!(result instanceof Error)) { // convert this screenshotBox into normal videoBox
+ props.setResult(result, trackScreen)
+ } else {
+ alert("video conversion failed");
+ }
+
+ // delete all files in MEMFS
+ inputPaths.forEach(path => ffmpeg.FS('unlink', path));
+ ffmpeg.FS('unlink', 'order.txt');
+ ffmpeg.FS('unlink', 'output.mp4');
+ })();
+
}
@@ -84,7 +110,7 @@ export function RecordingView(props: IRecordingViewProps) {
if (!navigator.mediaDevices) {
console.log('This browser does not support getUserMedia.')
}
- console.log('This device has the correct media devices.')
+ console.log('This device has the correct media devices.')
}, [])
useEffect(() => {
@@ -222,6 +248,16 @@ export function RecordingView(props: IRecordingViewProps) {
const seconds = Math.floor((milliseconds % (1000 * 60)) / 1000);
return toTwoDigit(minutes) + " : " + toTwoDigit(seconds);
}
+
+ const doTranscode = async () => {
+
+ // console.log('Start transcoding');
+ // ffmpeg.FS('writeFile', 'test.avi', await fetchFile('/flame.avi'));
+ // await ffmpeg.run('-i', 'test.avi', 'test.mp4');
+ // console.log('Complete transcoding');
+ // const data = ffmpeg.FS('readFile', 'test.mp4');
+ // console.log(URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' })));
+ };
return (
<div className="recording-container">