diff options
author | Michael Foiani <sotech117@michaels-mbp-5.devices.brown.edu> | 2022-06-02 11:27:17 -0400 |
---|---|---|
committer | Michael Foiani <sotech117@michaels-mbp-5.devices.brown.edu> | 2022-06-02 11:27:17 -0400 |
commit | 8e0b274fa0fe0a1e8cfa0d3f9d147c3e6a639d38 (patch) | |
tree | 4bba2d9cde724e5929a1b4e2f47b1e355624a1dc | |
parent | 560d7090702c3559724420f3571b11d86c930177 (diff) |
ffmpeg code added, but there is an error with sharedArrayBuffer
-rw-r--r-- | package-lock.json | 55 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/client/views/nodes/RecordingBox/RecordingView.tsx | 82 |
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"> |