├── .eslintignore ├── README.md ├── .eslintrc.json ├── src ├── worker.js ├── components │ ├── style.css │ ├── Excalidraw.js │ ├── TimelinePreview.js │ ├── Video.js │ └── Timeline.js ├── styles.css ├── index.js ├── atoms.js ├── utils.js ├── App.js └── mp4.js ├── .editorconfig ├── .gitignore ├── .codesandbox └── workspace.json ├── public └── index.html ├── package.json └── LICENSE.md /.eslintignore: -------------------------------------------------------------------------------- 1 | src/mp4.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # video-editor 2 | Created with CodeSandbox 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@excalidraw/eslint-config", "react-app"], 3 | "rules": { 4 | "import/no-anonymous-default-export": "off", 5 | "no-restricted-globals": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /src/worker.js: -------------------------------------------------------------------------------- 1 | 2 | var CALLS = { 3 | processFrame: ({frameID}) => { 4 | self.postMessage('42'); 5 | } 6 | } 7 | 8 | self.onmessage = ({ data: {call, ...args} }) => { 9 | CALLS[call](args); 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0; 3 | margin: 0; 4 | } 5 | 6 | .excalidraw-wrapper { 7 | width: 1200px; 8 | height: 500px; 9 | } 10 | 11 | .excalidraw .App-menu_top .Stack_vertical .Island { 12 | min-width: 204px; 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://EditorConfig.org 2 | 3 | # top-level EditorConfig file 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | end_of_line = lf 9 | indent_size = 2 10 | indent_style = space 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .eslintcache 3 | .history 4 | .idea 5 | .vercel 6 | .vscode 7 | .yarn 8 | *.log 9 | *.tgz 10 | build 11 | dist 12 | logs 13 | node_modules 14 | npm-debug.log* 15 | package-lock.json 16 | static 17 | yarn-debug.log* 18 | yarn-error.log* 19 | -------------------------------------------------------------------------------- /.codesandbox/workspace.json: -------------------------------------------------------------------------------- 1 | { 2 | "responsive-preview": { 3 | "Mobile": [ 4 | 320, 5 | 675 6 | ], 7 | "Tablet": [ 8 | 1024, 9 | 765 10 | ], 11 | "Desktop": [ 12 | 1400, 13 | 800 14 | ], 15 | "Desktop HD": [ 16 | 1920, 17 | 1080 18 | ] 19 | } 20 | } -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: rgb(13, 17, 23); 3 | } 4 | 5 | .App { 6 | font-family: sans-serif; 7 | text-align: center; 8 | width: 100vw; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | /* overflow: hidden; */ 14 | } 15 | 16 | .cursor { 17 | display: inline-block; 18 | width: 4px; 19 | height: 140px; 20 | background-color: green; 21 | position: absolute; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/Excalidraw.js: -------------------------------------------------------------------------------- 1 | import { Excalidraw as ExcalidrawComponent } from "@excalidraw/excalidraw"; 2 | 3 | import "./style.css"; 4 | 5 | export const Excalidraw = () => { 6 | return ( 7 |
8 | {}} 16 | onLinkOpen={() => {}} 17 | /> 18 |
19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { StrictMode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | import { RecoilRoot } from "recoil"; 4 | 5 | import App from "./App"; 6 | 7 | const worker = new Worker(new URL('./worker.js', import.meta.url)); 8 | 9 | /* 10 | worker.postMessage({ call: 'processFrame' }); 11 | 12 | worker.onmessage = ({ data: { answer } }) => { 13 | console.log(answer); 14 | }; 15 | */ 16 | 17 | const rootElement = document.getElementById("root"); 18 | const root = createRoot(rootElement); 19 | 20 | root.render( 21 | 22 | 23 | 24 | ); 25 | -------------------------------------------------------------------------------- /src/atoms.js: -------------------------------------------------------------------------------- 1 | import { atom, atomFamily, selectorFamily } from "recoil"; 2 | 3 | export const loadingStateAtom = atom({ 4 | key: "loadingState", 5 | default: "idle", 6 | }); 7 | 8 | export const durationStateAtom = atom({ 9 | key: "durationStateAtom", 10 | default: 0, 11 | }); 12 | 13 | export const rangeStateAtom = atomFamily({ 14 | key: "rangeStateAtom", 15 | default: selectorFamily({ 16 | key: "rangeStateAtom/Default", 17 | get: (data) => () => { 18 | return data; 19 | }, 20 | }), 21 | }); 22 | 23 | export const cursorPositionStateAtom = atom({ 24 | key: "cursorPositionStateAtom", 25 | default: 0, 26 | }); 27 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | React App 9 | 10 | 11 | 12 | 15 |
16 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | export const generateRange = (duration) => { 2 | return { 3 | [Symbol.iterator]: function* rangeGenerator() { 4 | let x = 0; 5 | const step = 1; 6 | 7 | while (x < duration) { 8 | let hours = Math.floor(x / 3600); 9 | let minutes = Math.floor((x - hours * 3600) / 60); 10 | let seconds = Math.ceil(parseInt(x - hours * 3600 - minutes * 60, 10)); 11 | if (hours < 10) { 12 | hours = `0${hours}`; 13 | } 14 | if (minutes < 10) { 15 | minutes = `0${minutes}`; 16 | } 17 | if (seconds < 10) { 18 | seconds = `0${seconds}`; 19 | } 20 | x += step; 21 | yield `${hours}:${minutes}:${seconds}`; 22 | } 23 | }, 24 | }; 25 | }; 26 | 27 | export const getSeconds = (duration) => { 28 | const [hours, minutes, seconds] = duration.split(":"); 29 | const totalSeconds = +hours * 60 * 60 + +minutes * 60 + +seconds; 30 | return totalSeconds; 31 | }; 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react", 3 | "version": "1.0.0", 4 | "description": "React example starter project", 5 | "keywords": [ 6 | "react", 7 | "starter" 8 | ], 9 | "main": "src/index.js", 10 | "dependencies": { 11 | "@excalidraw/excalidraw": "^0.12.0", 12 | "idb-keyval": "^6.2.0", 13 | "react": "18.0.0", 14 | "react-dom": "18.0.0", 15 | "react-scripts": "^5.0.1", 16 | "react-window": "^1.8.8", 17 | "recoil": "^0.7.6" 18 | }, 19 | "devDependencies": { 20 | "@babel/runtime": "7.13.8", 21 | "@excalidraw/eslint-config": "^1.0.3", 22 | "@excalidraw/prettier-config": "^1.0.2", 23 | "eslint-config-prettier": "^8.5.0", 24 | "eslint-plugin-prettier": "^4.2.1", 25 | "prettier": "^2.7.1", 26 | "typescript": "4.1.3" 27 | }, 28 | "scripts": { 29 | "start": "react-scripts --openssl-legacy-provider start", 30 | "build": "react-scripts build", 31 | "test": "react-scripts test --env=jsdom", 32 | "eject": "react-scripts eject" 33 | }, 34 | "browserslist": [ 35 | ">0.2%", 36 | "not dead", 37 | "not ie <= 11", 38 | "not op_mini all" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Christopher Chedeau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/TimelinePreview.js: -------------------------------------------------------------------------------- 1 | import { get } from "idb-keyval"; 2 | import { useCallback, useEffect, useRef } from "react"; 3 | import { getSeconds } from "../utils"; 4 | 5 | export const TimelinePreview = ({ data, index, style }) => { 6 | const canvasRef = useRef(); 7 | const imgRef = useRef(); 8 | const ref = useRef(); 9 | const range = data[index]; 10 | const tempo = getSeconds(range); 11 | 12 | const setFrame = useCallback(async () => { 13 | const file = await get("file"); 14 | const video = document.createElement("video"); 15 | const source = document.createElement("source"); 16 | video.appendChild(source); 17 | source.src = URL.createObjectURL(file); 18 | 19 | const img = imgRef.current; 20 | const canvas = canvasRef.current; 21 | 22 | video.currentTime = tempo; 23 | video.load(); 24 | video.ontimeupdate = async function () { 25 | const context = canvas.getContext("2d"); 26 | context.drawImage(video, 0, 0, canvas.width, canvas.height); 27 | img.src = canvas.toDataURL(); 28 | }; 29 | }, [tempo]); 30 | 31 | const onMouseMove = useCallback(() => { 32 | const video = document.querySelector("#video"); 33 | video.currentTime = tempo; 34 | }, [tempo]); 35 | 36 | useEffect(() => { 37 | const div = ref.current; 38 | div.addEventListener("mousemove", onMouseMove); 39 | return () => div.removeEventListener("mousemove", onMouseMove); 40 | }, [onMouseMove]); 41 | 42 | useEffect(() => { 43 | // setFrame().then(); 44 | }, []); 45 | 46 | // return null; 47 | return ( 48 |
60 | {/* */} 64 |

{range}

65 | {/* */} 66 |
67 | ); 68 | }; 69 | -------------------------------------------------------------------------------- /src/components/Video.js: -------------------------------------------------------------------------------- 1 | import { get } from "idb-keyval"; 2 | import { useCallback } from "react"; 3 | import { loadingStateAtom } from "../atoms"; 4 | import { useRecoilValue } from "recoil"; 5 | import { Excalidraw } from "./Excalidraw"; 6 | 7 | export const Video = () => { 8 | const loadingState = useRecoilValue(loadingStateAtom); 9 | 10 | const onVideoLoad = useCallback( 11 | async (video) => { 12 | if (loadingState === "loaded") { 13 | const file = await get("file"); 14 | const source = document.querySelector("#source"); 15 | source.src = URL.createObjectURL(file); 16 | 17 | video.load(); 18 | video.ontimeupdate = async function () { 19 | const stream = video.captureStream(); 20 | const tracks = stream.getTracks(); 21 | const track = tracks.find((track) => track.kind === "video"); 22 | if (!track) { 23 | return; 24 | } 25 | 26 | const trackProcessor = new window.MediaStreamTrackProcessor(track); 27 | 28 | const reader = trackProcessor.readable.getReader(); 29 | const result = await reader.read(); 30 | if (result.done) { 31 | return; 32 | } 33 | const frame = result.value; 34 | 35 | const [canvas] = document.getElementsByTagName("canvas"); 36 | const context = canvas.getContext("2d"); 37 | context.drawImage( 38 | frame, 39 | 0, 40 | 0, 41 | frame.codedWidth, 42 | frame.codedHeight, 43 | 0, 44 | 0, 45 | canvas.width, 46 | canvas.height 47 | ); 48 | frame.close(); 49 | }; 50 | } 51 | }, 52 | [loadingState] 53 | ); 54 | 55 | return ( 56 |
57 | 58 | 68 |
69 | ); 70 | }; 71 | -------------------------------------------------------------------------------- /src/components/Timeline.js: -------------------------------------------------------------------------------- 1 | import { cursorPositionStateAtom, rangeStateAtom } from "../atoms"; 2 | import { useCallback, useEffect, useRef } from "react"; 3 | 4 | import { useRecoilState, useRecoilValue } from "recoil"; 5 | 6 | import { TimelinePreview } from "./TimelinePreview"; 7 | import { generateRange } from "../utils"; 8 | import { FixedSizeList as List } from "react-window"; 9 | 10 | const ITEM_SIZE = 100; 11 | const LIST_WIDTH = 800; 12 | 13 | export const Timeline = ({ duration }) => { 14 | const cursorDivRef = useRef(); 15 | const timelineDivRef = useRef(); 16 | const range = useRecoilValue(rangeStateAtom([...generateRange(duration)])); 17 | const [, setCursorPosition] = useRecoilState(cursorPositionStateAtom); 18 | 19 | const onMouseMove = useCallback( 20 | (e) => { 21 | const video = document.querySelector("#video"); 22 | const rect = timelineDivRef.current.getBoundingClientRect(); 23 | const cursorPosition = e.clientX - rect.x; 24 | cursorDivRef.current.style.transform = `translateX(${cursorPosition}px)`; 25 | const percentage = cursorPosition / rect.width; 26 | // video.currentTime = video.duration * percentage; 27 | setCursorPosition(cursorPosition); 28 | }, 29 | [setCursorPosition] 30 | ); 31 | 32 | useEffect(() => { 33 | const listElement = document.querySelector(".list"); 34 | listElement.addEventListener("mousemove", onMouseMove); 35 | return () => listElement.removeEventListener("mousemove", onMouseMove); 36 | }, [onMouseMove]); 37 | 38 | return ( 39 |
50 |
60 | 70 | {TimelinePreview} 71 | 72 |
73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react"; 2 | import { set } from "idb-keyval"; 3 | import { loadingStateAtom, durationStateAtom } from "./atoms"; 4 | import { useRecoilState } from "recoil"; 5 | import { Video } from "./components/Video"; 6 | import "./styles.css"; 7 | import { Timeline } from "./components/Timeline"; 8 | 9 | import { useState, useEffect, useRef } from 'react'; 10 | import loadMP4Module from "./mp4.js"; 11 | 12 | 13 | function createVideoFile(file) { 14 | const videoElement = document.createElement('video'); 15 | videoElement.style = 'display: none'; 16 | const sourceElement = document.createElement('source'); 17 | sourceElement.src = URL.createObjectURL(file); 18 | videoElement.appendChild(sourceElement); 19 | document.body.appendChild(videoElement); 20 | 21 | return { 22 | file, 23 | videoElement, 24 | sourceElement 25 | }; 26 | } 27 | 28 | function asyncGetDuration(videoFile) { 29 | return new Promise((resolve, reject) => { 30 | const videoElement = videoFile.videoElement; 31 | const listener = (event) => { 32 | videoElement.removeEventListener('durationchange', listener); 33 | resolve(videoElement.duration); 34 | }; 35 | videoElement.addEventListener('durationchange', listener); 36 | }); 37 | } 38 | 39 | var RANDOM_COLORS = ['red', 'green', 'blue', 'orange', 'yellow']; 40 | function getRandomColor() { 41 | const randomColor = RANDOM_COLORS.shift(); 42 | RANDOM_COLORS.push(randomColor); 43 | return randomColor; 44 | } 45 | 46 | function getReaderFromVideoElement(videoElement) { 47 | const stream = videoElement.captureStream(); 48 | const tracks = stream.getVideoTracks(); 49 | const track = tracks[0]; 50 | if (!track) { 51 | return null; 52 | } 53 | const trackProcessor = new window.MediaStreamTrackProcessor(track); 54 | return trackProcessor.readable.getReader(); 55 | } 56 | 57 | async function extractFrameFromVideoFile(videoFile, time, targetCanvas) { 58 | await new Promise((resolve) => { 59 | const videoElement = videoFile.videoElement; 60 | 61 | const listener = async function() { 62 | videoElement.removeEventListener('timeupdate', listener); 63 | 64 | const reader = getReaderFromVideoElement(videoElement); 65 | if (!reader) { 66 | return; 67 | } 68 | 69 | const result = await reader.read(); 70 | if (result.done) { 71 | return; 72 | } 73 | const frame = result.value; 74 | 75 | const context = targetCanvas.getContext('2d'); 76 | 77 | context.imageSmoothingEnabled = true; 78 | context.imageSmoothingQuality = 'high'; 79 | context.drawImage( 80 | frame, 81 | 0, 82 | 0, 83 | frame.codedWidth, 84 | frame.codedHeight, 85 | 0, 86 | 0, 87 | targetCanvas.width, 88 | targetCanvas.height 89 | ); 90 | frame.close(); 91 | resolve(); 92 | } 93 | videoElement.addEventListener('timeupdate', listener); 94 | 95 | videoElement.currentTime = time; 96 | }) 97 | } 98 | 99 | // https://medium.com/@karenmarkosyan/how-to-manage-promises-into-dynamic-queue-with-vanilla-javascript-9d0d1f8d4df5 100 | class PromiseQueue { 101 | static queue = []; 102 | static pendingPromise = false; 103 | 104 | static enqueue(promise) { 105 | return new Promise((resolve, reject) => { 106 | this.queue.push({ 107 | promise, 108 | resolve, 109 | reject, 110 | }); 111 | this.dequeue(); 112 | }); 113 | } 114 | 115 | static dequeue() { 116 | if (this.workingOnPromise) { 117 | return false; 118 | } 119 | const item = this.queue.shift(); 120 | if (!item) { 121 | return false; 122 | } 123 | try { 124 | this.workingOnPromise = true; 125 | item.promise() 126 | .then((value) => { 127 | this.workingOnPromise = false; 128 | item.resolve(value); 129 | this.dequeue(); 130 | }) 131 | .catch(err => { 132 | this.workingOnPromise = false; 133 | item.reject(err); 134 | this.dequeue(); 135 | }) 136 | } catch (err) { 137 | this.workingOnPromise = false; 138 | item.reject(err); 139 | this.dequeue(); 140 | } 141 | return true; 142 | } 143 | } 144 | 145 | function Preview({clip, time}) { 146 | const canvasElement = useRef(null); 147 | 148 | useEffect(() => { 149 | // PromiseQueue.enqueue(() => extractFrameFromVideoFile(clip.videoFile, time, canvasElement.current)); 150 | }, [clip, time]); 151 | 152 | return ( 153 | 159 | ); 160 | } 161 | 162 | async function record(videoElement) { 163 | const reader = getReaderFromVideoElement(videoElement); 164 | if (!reader) { 165 | return; 166 | } 167 | 168 | const width = 1920; 169 | const height = 1080; 170 | const fps = 30; 171 | const MP4 = await loadMP4Module(); 172 | const encoder = MP4.createWebCodecsEncoder({ 173 | width, 174 | height, 175 | fps 176 | }); 177 | const duration = videoElement.duration; 178 | console.log(videoElement.duration); 179 | 180 | let currentTime = 0; 181 | let frameCount = 0; 182 | const startNow = performance.now(); 183 | 184 | const listener = async () => { 185 | reader.read().then(async (frame) => { 186 | if (frame.value) { 187 | const bitmap = await createImageBitmap(frame.value); 188 | await encoder.addFrame(bitmap); 189 | frameCount++; 190 | 191 | if (frameCount % 10 === 0) { 192 | console.log("Encoding " + Math.round(100 * currentTime / duration) + "% " + Math.round(1000 * frameCount / (performance.now() - startNow)) + " fps"); 193 | } 194 | frame.value.close(); 195 | } 196 | if (currentTime < duration) { 197 | currentTime += 1/fps; 198 | videoElement.currentTime = currentTime; 199 | } else { 200 | videoElement.removeEventListener('timeupdate', listener); 201 | const data = await encoder.end(); 202 | const url = URL.createObjectURL(new Blob([data], { type: "video/mp4" })); 203 | 204 | const anchor = document.createElement("a"); 205 | anchor.href = url; 206 | anchor.download = "download.mp4"; 207 | anchor.click(); 208 | } 209 | }); 210 | } 211 | videoElement.addEventListener('timeupdate', listener); 212 | videoElement.currentTime = currentTime; 213 | } 214 | 215 | export default function App({worker}) { 216 | const [tracks, setTracks] = useState( 217 | [ 218 | { 219 | clips: [] 220 | } 221 | ] 222 | ); 223 | 224 | const windowStart = 0; 225 | const windowEnd = Math.max(0, ...tracks[0].clips.map(clip => clip.end)); 226 | const windowWidth = document.body.clientWidth; 227 | 228 | return ( 229 |
230 |

Video Editor

231 |

232 | Select a video:{" "} 233 | clip.end)); 245 | const duration = await asyncGetDuration(videoFile); 246 | newTracks[0].clips.push({ 247 | start: start, 248 | end: start + duration, 249 | videoFile, 250 | backgroundColor: getRandomColor() 251 | }); 252 | } 253 | setTracks(newTracks); 254 | }} 255 | /> 256 |

257 | 258 |
259 |

Tracks

260 | {tracks.map((track, i) => 261 |
262 | {track.clips.map(clip => { 263 | const width = ((clip.end - clip.start) / (windowEnd - windowStart)) * windowWidth; 264 | return ( 265 |
277 | {Array.from({length: Math.ceil(width / 70)}).map((_, i) => 278 | 283 | )} 284 |
285 | ); 286 | })} 287 |
288 | )} 289 |
290 | 291 |
292 | 299 |
300 |
301 | ); 302 | }; 303 | -------------------------------------------------------------------------------- /src/mp4.js: -------------------------------------------------------------------------------- 1 | // https://unpkg.com/mp4-wasm@1.0.6/build/mp4.js 2 | // With the path to the wasm file changed. Search for CHANGED 3 | 4 | var Module = (function () { 5 | var _ = import.meta.url; 6 | return function (t) { 7 | t = t || {}; 8 | var t = typeof t != "undefined" ? t : {}, 9 | u, 10 | h; 11 | (t.ready = new Promise(function (r, n) { 12 | (u = r), (h = n); 13 | })), 14 | (t.create_buffer = function (n) { 15 | return t._malloc(n); 16 | }), 17 | (t.free_buffer = function (n) { 18 | return t._free(n); 19 | }), 20 | (t.locateFile = function (n, e) { 21 | return ( 22 | t.simd && (n = n.replace(/\.wasm$/i, ".simd.wasm")), 23 | t.getWasmPath ? t.getWasmPath(n, e, t.simd) : e + n 24 | ); 25 | }), 26 | (t.createWebCodecsEncoder = function (n) { 27 | return createWebCodecsEncoderWithModule(t, n); 28 | }); 29 | var m = {}, 30 | l; 31 | for (l in t) t.hasOwnProperty(l) && (m[l] = t[l]); 32 | var p = [], 33 | j = "./this.program", 34 | N = function (r, n) { 35 | throw n; 36 | }, 37 | W = !1, 38 | k = !1, 39 | x = !1, 40 | L = !1; 41 | (W = typeof window == "object"), 42 | (k = typeof importScripts == "function"), 43 | (x = 44 | typeof process == "object" && 45 | typeof process.versions == "object" && 46 | typeof process.versions.node == "string"), 47 | (L = !W && !x && !k); 48 | var y = ""; 49 | function z(r) { 50 | return t.locateFile ? t.locateFile(r, y) : y + r; 51 | } 52 | var sr, nr, J, lr; 53 | (W || k) && 54 | (k 55 | ? (y = self.location.href) 56 | : typeof document != "undefined" && 57 | document.currentScript && 58 | (y = document.currentScript.src), 59 | _ && (y = _), 60 | y.indexOf("blob:") !== 0 61 | ? (y = y.substr(0, y.lastIndexOf("/") + 1)) 62 | : (y = ""), 63 | (sr = function (r) { 64 | var n = new XMLHttpRequest(); 65 | return n.open("GET", r, !1), n.send(null), n.responseText; 66 | }), 67 | k && 68 | (J = function (r) { 69 | var n = new XMLHttpRequest(); 70 | return ( 71 | n.open("GET", r, !1), 72 | (n.responseType = "arraybuffer"), 73 | n.send(null), 74 | new Uint8Array(n.response) 75 | ); 76 | }), 77 | (nr = function (r, n, e) { 78 | var i = new XMLHttpRequest(); 79 | i.open("GET", r, !0), 80 | (i.responseType = "arraybuffer"), 81 | (i.onload = function () { 82 | if (i.status == 200 || (i.status == 0 && i.response)) { 83 | n(i.response); 84 | return; 85 | } 86 | e(); 87 | }), 88 | (i.onerror = e), 89 | i.send(null); 90 | }), 91 | (lr = function (r) { 92 | document.title = r; 93 | })); 94 | var er = t.print || console.log.bind(console), 95 | P = t.printErr || console.warn.bind(console); 96 | for (l in m) m.hasOwnProperty(l) && (t[l] = m[l]); 97 | (m = null), 98 | t.arguments && (p = t.arguments), 99 | t.thisProgram && (j = t.thisProgram), 100 | t.quit && (N = t.quit); 101 | var X; 102 | t.wasmBinary && (X = t.wasmBinary); 103 | var Wr = t.noExitRuntime || !0; 104 | typeof WebAssembly != "object" && ar("no native wasm support detected"); 105 | var K, 106 | w = !1, 107 | b; 108 | function I(r, n, e) { 109 | for (var i = n + e, a = ""; !(n >= i); ) { 110 | var f = r[n++]; 111 | if (!f) return a; 112 | if (!(f & 128)) { 113 | a += String.fromCharCode(f); 114 | continue; 115 | } 116 | var c = r[n++] & 63; 117 | if ((f & 224) == 192) { 118 | a += String.fromCharCode(((f & 31) << 6) | c); 119 | continue; 120 | } 121 | var o = r[n++] & 63; 122 | if ( 123 | ((f & 240) == 224 124 | ? (f = ((f & 15) << 12) | (c << 6) | o) 125 | : (f = ((f & 7) << 18) | (c << 12) | (o << 6) | (r[n++] & 63)), 126 | f < 65536) 127 | ) 128 | a += String.fromCharCode(f); 129 | else { 130 | var s = f - 65536; 131 | a += String.fromCharCode(55296 | (s >> 10), 56320 | (s & 1023)); 132 | } 133 | } 134 | return a; 135 | } 136 | function A(r, n) { 137 | return r ? I(U, r, n) : ""; 138 | } 139 | function O(r, n, e, i) { 140 | if (!(i > 0)) return 0; 141 | for (var a = e, f = e + i - 1, c = 0; c < r.length; ++c) { 142 | var o = r.charCodeAt(c); 143 | if (o >= 55296 && o <= 57343) { 144 | var s = r.charCodeAt(++c); 145 | o = (65536 + ((o & 1023) << 10)) | (s & 1023); 146 | } 147 | if (o <= 127) { 148 | if (e >= f) break; 149 | n[e++] = o; 150 | } else if (o <= 2047) { 151 | if (e + 1 >= f) break; 152 | (n[e++] = 192 | (o >> 6)), (n[e++] = 128 | (o & 63)); 153 | } else if (o <= 65535) { 154 | if (e + 2 >= f) break; 155 | (n[e++] = 224 | (o >> 12)), 156 | (n[e++] = 128 | ((o >> 6) & 63)), 157 | (n[e++] = 128 | (o & 63)); 158 | } else { 159 | if (e + 3 >= f) break; 160 | (n[e++] = 240 | (o >> 18)), 161 | (n[e++] = 128 | ((o >> 12) & 63)), 162 | (n[e++] = 128 | ((o >> 6) & 63)), 163 | (n[e++] = 128 | (o & 63)); 164 | } 165 | } 166 | return (n[e] = 0), e - a; 167 | } 168 | function E(r, n, e) { 169 | return O(r, U, n, e); 170 | } 171 | function vr(r) { 172 | for (var n = 0, e = 0; e < r.length; ++e) { 173 | var i = r.charCodeAt(e); 174 | i >= 55296 && 175 | i <= 57343 && 176 | (i = (65536 + ((i & 1023) << 10)) | (r.charCodeAt(++e) & 1023)), 177 | i <= 127 178 | ? ++n 179 | : i <= 2047 180 | ? (n += 2) 181 | : i <= 65535 182 | ? (n += 3) 183 | : (n += 4); 184 | } 185 | return n; 186 | } 187 | function Zr(r, n) { 188 | for (var e = "", i = 0; !(i >= n / 2); ++i) { 189 | var a = Z[(r + i * 2) >> 1]; 190 | if (a == 0) break; 191 | e += String.fromCharCode(a); 192 | } 193 | return e; 194 | } 195 | function Qr(r, n, e) { 196 | if ((e === void 0 && (e = 2147483647), e < 2)) return 0; 197 | e -= 2; 198 | for ( 199 | var i = n, a = e < r.length * 2 ? e / 2 : r.length, f = 0; 200 | f < a; 201 | ++f 202 | ) { 203 | var c = r.charCodeAt(f); 204 | (Z[n >> 1] = c), (n += 2); 205 | } 206 | return (Z[n >> 1] = 0), n - i; 207 | } 208 | function Mr(r) { 209 | return r.length * 2; 210 | } 211 | function rn(r, n) { 212 | for (var e = 0, i = ""; !(e >= n / 4); ) { 213 | var a = V[(r + e * 4) >> 2]; 214 | if (a == 0) break; 215 | if ((++e, a >= 65536)) { 216 | var f = a - 65536; 217 | i += String.fromCharCode(55296 | (f >> 10), 56320 | (f & 1023)); 218 | } else i += String.fromCharCode(a); 219 | } 220 | return i; 221 | } 222 | function nn(r, n, e) { 223 | if ((e === void 0 && (e = 2147483647), e < 4)) return 0; 224 | for (var i = n, a = i + e - 4, f = 0; f < r.length; ++f) { 225 | var c = r.charCodeAt(f); 226 | if (c >= 55296 && c <= 57343) { 227 | var o = r.charCodeAt(++f); 228 | c = (65536 + ((c & 1023) << 10)) | (o & 1023); 229 | } 230 | if (((V[n >> 2] = c), (n += 4), n + 4 > a)) break; 231 | } 232 | return (V[n >> 2] = 0), n - i; 233 | } 234 | function en(r) { 235 | for (var n = 0, e = 0; e < r.length; ++e) { 236 | var i = r.charCodeAt(e); 237 | i >= 55296 && i <= 57343 && ++e, (n += 4); 238 | } 239 | return n; 240 | } 241 | function tn(r, n) { 242 | return r % n > 0 && (r += n - (r % n)), r; 243 | } 244 | var pr, _r, U, Z, hr, V, D, kr, Ir; 245 | function Or(r) { 246 | (pr = r), 247 | (t.HEAP8 = _r = new Int8Array(r)), 248 | (t.HEAP16 = Z = new Int16Array(r)), 249 | (t.HEAP32 = V = new Int32Array(r)), 250 | (t.HEAPU8 = U = new Uint8Array(r)), 251 | (t.HEAPU16 = hr = new Uint16Array(r)), 252 | (t.HEAPU32 = D = new Uint32Array(r)), 253 | (t.HEAPF32 = kr = new Float32Array(r)), 254 | (t.HEAPF64 = Ir = new Float64Array(r)); 255 | } 256 | var me = t.INITIAL_MEMORY || 16777216, 257 | tr, 258 | Lr = [], 259 | Vr = [], 260 | Dr = [], 261 | an = !1; 262 | function on() { 263 | if (t.preRun) 264 | for ( 265 | typeof t.preRun == "function" && (t.preRun = [t.preRun]); 266 | t.preRun.length; 267 | 268 | ) 269 | cn(t.preRun.shift()); 270 | yr(Lr); 271 | } 272 | function fn() { 273 | (an = !0), yr(Vr); 274 | } 275 | function sn() { 276 | if (t.postRun) 277 | for ( 278 | typeof t.postRun == "function" && (t.postRun = [t.postRun]); 279 | t.postRun.length; 280 | 281 | ) 282 | ln(t.postRun.shift()); 283 | yr(Dr); 284 | } 285 | function cn(r) { 286 | Lr.unshift(r); 287 | } 288 | function un(r) { 289 | Vr.unshift(r); 290 | } 291 | function ln(r) { 292 | Dr.unshift(r); 293 | } 294 | var G = 0, 295 | gr = null, 296 | ir = null; 297 | function vn(r) { 298 | G++, t.monitorRunDependencies && t.monitorRunDependencies(G); 299 | } 300 | function pn(r) { 301 | if ( 302 | (G--, 303 | t.monitorRunDependencies && t.monitorRunDependencies(G), 304 | G == 0 && (gr !== null && (clearInterval(gr), (gr = null)), ir)) 305 | ) { 306 | var n = ir; 307 | (ir = null), n(); 308 | } 309 | } 310 | (t.preloadedImages = {}), (t.preloadedAudios = {}); 311 | function ar(r) { 312 | t.onAbort && t.onAbort(r), 313 | (r += ""), 314 | P(r), 315 | (w = !0), 316 | (b = 1), 317 | (r = "abort(" + r + "). Build with -s ASSERTIONS=1 for more info."); 318 | var n = new WebAssembly.RuntimeError(r); 319 | throw (h(n), n); 320 | } 321 | var _n = "data:application/octet-stream;base64,"; 322 | function Hr(r) { 323 | return r.startsWith(_n); 324 | } 325 | 326 | // START CHANGED 327 | 328 | var R = 'https://unpkg.com/mp4-wasm@1.0.6/build/mp4.wasm'; 329 | /* 330 | t.locateFile 331 | ? ((R = "mp4.wasm"), Hr(R) || (R = z(R))) 332 | : (R = new URL("mp4.wasm", import.meta.url).toString()); 333 | */ 334 | 335 | // END CHANGED 336 | 337 | function Br(r) { 338 | try { 339 | if (r == R && X) return new Uint8Array(X); 340 | if (J) return J(r); 341 | throw "both async and sync fetching of the wasm failed"; 342 | } catch (n) { 343 | ar(n); 344 | } 345 | } 346 | function hn() { 347 | return !X && (W || k) && typeof fetch == "function" 348 | ? fetch(R, { credentials: "same-origin" }) 349 | .then(function (r) { 350 | if (!r.ok) 351 | throw "failed to load wasm binary file at '" + R + "'"; 352 | return r.arrayBuffer(); 353 | }) 354 | .catch(function () { 355 | return Br(R); 356 | }) 357 | : Promise.resolve().then(function () { 358 | return Br(R); 359 | }); 360 | } 361 | function gn() { 362 | var r = { a: ce }; 363 | function n(c, o) { 364 | var s = c.exports; 365 | (t.asm = s), 366 | (K = t.asm.x), 367 | Or(K.buffer), 368 | (tr = t.asm.B), 369 | un(t.asm.y), 370 | pn("wasm-instantiate"); 371 | } 372 | vn("wasm-instantiate"); 373 | function e(c) { 374 | n(c.instance); 375 | } 376 | function i(c) { 377 | return hn() 378 | .then(function (o) { 379 | var s = WebAssembly.instantiate(o, r); 380 | return s; 381 | }) 382 | .then(c, function (o) { 383 | P("failed to asynchronously prepare wasm: " + o), ar(o); 384 | }); 385 | } 386 | function a() { 387 | return !X && 388 | typeof WebAssembly.instantiateStreaming == "function" && 389 | !Hr(R) && 390 | typeof fetch == "function" 391 | ? fetch(R, { credentials: "same-origin" }).then(function (c) { 392 | var o = WebAssembly.instantiateStreaming(c, r); 393 | return o.then(e, function (s) { 394 | return ( 395 | P("wasm streaming compile failed: " + s), 396 | P("falling back to ArrayBuffer instantiation"), 397 | i(e) 398 | ); 399 | }); 400 | }) 401 | : i(e); 402 | } 403 | if (t.instantiateWasm) 404 | try { 405 | var f = t.instantiateWasm(r, n); 406 | return f; 407 | } catch (c) { 408 | return ( 409 | P("Module.instantiateWasm callback failed with error: " + c), !1 410 | ); 411 | } 412 | return a().catch(h), {}; 413 | } 414 | function yr(r) { 415 | for (; r.length > 0; ) { 416 | var n = r.shift(); 417 | if (typeof n == "function") { 418 | n(t); 419 | continue; 420 | } 421 | var e = n.func; 422 | typeof e == "number" 423 | ? n.arg === void 0 424 | ? tr.get(e)() 425 | : tr.get(e)(n.arg) 426 | : e(n.arg === void 0 ? null : n.arg); 427 | } 428 | } 429 | function yn(r, n, e, i) { 430 | ar( 431 | "Assertion failed: " + 432 | A(r) + 433 | ", at: " + 434 | [n ? A(n) : "unknown filename", e, i ? A(i) : "unknown function"] 435 | ); 436 | } 437 | function dn(r, n, e, i, a) {} 438 | function dr(r) { 439 | switch (r) { 440 | case 1: 441 | return 0; 442 | case 2: 443 | return 1; 444 | case 4: 445 | return 2; 446 | case 8: 447 | return 3; 448 | default: 449 | throw new TypeError("Unknown type size: " + r); 450 | } 451 | } 452 | function mn() { 453 | for (var r = new Array(256), n = 0; n < 256; ++n) 454 | r[n] = String.fromCharCode(n); 455 | jr = r; 456 | } 457 | var jr = void 0; 458 | function S(r) { 459 | for (var n = "", e = r; U[e]; ) n += jr[U[e++]]; 460 | return n; 461 | } 462 | var Q = {}, 463 | Y = {}, 464 | cr = {}, 465 | wn = 48, 466 | bn = 57; 467 | function Nr(r) { 468 | if (r === void 0) return "_unknown"; 469 | r = r.replace(/[^a-zA-Z0-9_]/g, "$"); 470 | var n = r.charCodeAt(0); 471 | return n >= wn && n <= bn ? "_" + r : r; 472 | } 473 | function qr(r, n) { 474 | return ( 475 | (r = Nr(r)), 476 | new Function( 477 | "body", 478 | "return function " + 479 | r + 480 | `() { 481 | "use strict"; return body.apply(this, arguments); 482 | }; 483 | ` 484 | )(n) 485 | ); 486 | } 487 | function mr(r, n) { 488 | var e = qr(n, function (i) { 489 | (this.name = n), (this.message = i); 490 | var a = new Error(i).stack; 491 | a !== void 0 && 492 | (this.stack = 493 | this.toString() + 494 | ` 495 | ` + 496 | a.replace(/^Error(:[^\n]*)?\n/, "")); 497 | }); 498 | return ( 499 | (e.prototype = Object.create(r.prototype)), 500 | (e.prototype.constructor = e), 501 | (e.prototype.toString = function () { 502 | return this.message === void 0 503 | ? this.name 504 | : this.name + ": " + this.message; 505 | }), 506 | e 507 | ); 508 | } 509 | var xr = void 0; 510 | function T(r) { 511 | throw new xr(r); 512 | } 513 | var zr = void 0; 514 | function Xr(r) { 515 | throw new zr(r); 516 | } 517 | function An(r, n, e) { 518 | r.forEach(function (o) { 519 | cr[o] = n; 520 | }); 521 | function i(o) { 522 | var s = e(o); 523 | s.length !== r.length && Xr("Mismatched type converter count"); 524 | for (var v = 0; v < r.length; ++v) H(r[v], s[v]); 525 | } 526 | var a = new Array(n.length), 527 | f = [], 528 | c = 0; 529 | n.forEach(function (o, s) { 530 | Y.hasOwnProperty(o) 531 | ? (a[s] = Y[o]) 532 | : (f.push(o), 533 | Q.hasOwnProperty(o) || (Q[o] = []), 534 | Q[o].push(function () { 535 | (a[s] = Y[o]), ++c, c === f.length && i(a); 536 | })); 537 | }), 538 | f.length === 0 && i(a); 539 | } 540 | function H(r, n, e) { 541 | if (((e = e || {}), !("argPackAdvance" in n))) 542 | throw new TypeError( 543 | "registerType registeredInstance requires argPackAdvance" 544 | ); 545 | var i = n.name; 546 | if ( 547 | (r || 548 | T('type "' + i + '" must have a positive integer typeid pointer'), 549 | Y.hasOwnProperty(r)) 550 | ) { 551 | if (e.ignoreDuplicateRegistrations) return; 552 | T("Cannot register type '" + i + "' twice"); 553 | } 554 | if (((Y[r] = n), delete cr[r], Q.hasOwnProperty(r))) { 555 | var a = Q[r]; 556 | delete Q[r], 557 | a.forEach(function (f) { 558 | f(); 559 | }); 560 | } 561 | } 562 | function En(r, n, e, i, a) { 563 | var f = dr(e); 564 | (n = S(n)), 565 | H(r, { 566 | name: n, 567 | fromWireType: function (c) { 568 | return !!c; 569 | }, 570 | toWireType: function (c, o) { 571 | return o ? i : a; 572 | }, 573 | argPackAdvance: 8, 574 | readValueFromPointer: function (c) { 575 | var o; 576 | if (e === 1) o = _r; 577 | else if (e === 2) o = Z; 578 | else if (e === 4) o = V; 579 | else throw new TypeError("Unknown boolean type size: " + n); 580 | return this.fromWireType(o[c >> f]); 581 | }, 582 | destructorFunction: null, 583 | }); 584 | } 585 | var wr = [], 586 | C = [ 587 | {}, 588 | { value: void 0 }, 589 | { value: null }, 590 | { value: !0 }, 591 | { value: !1 }, 592 | ]; 593 | function br(r) { 594 | r > 4 && --C[r].refcount == 0 && ((C[r] = void 0), wr.push(r)); 595 | } 596 | function Tn() { 597 | for (var r = 0, n = 5; n < C.length; ++n) C[n] !== void 0 && ++r; 598 | return r; 599 | } 600 | function Cn() { 601 | for (var r = 5; r < C.length; ++r) if (C[r] !== void 0) return C[r]; 602 | return null; 603 | } 604 | function Fn() { 605 | (t.count_emval_handles = Tn), (t.get_first_emval = Cn); 606 | } 607 | function M(r) { 608 | switch (r) { 609 | case void 0: 610 | return 1; 611 | case null: 612 | return 2; 613 | case !0: 614 | return 3; 615 | case !1: 616 | return 4; 617 | default: { 618 | var n = wr.length ? wr.pop() : C.length; 619 | return (C[n] = { refcount: 1, value: r }), n; 620 | } 621 | } 622 | } 623 | function Ar(r) { 624 | return this.fromWireType(D[r >> 2]); 625 | } 626 | function Pn(r, n) { 627 | (n = S(n)), 628 | H(r, { 629 | name: n, 630 | fromWireType: function (e) { 631 | var i = C[e].value; 632 | return br(e), i; 633 | }, 634 | toWireType: function (e, i) { 635 | return M(i); 636 | }, 637 | argPackAdvance: 8, 638 | readValueFromPointer: Ar, 639 | destructorFunction: null, 640 | }); 641 | } 642 | function Er(r) { 643 | if (r === null) return "null"; 644 | var n = typeof r; 645 | return n === "object" || n === "array" || n === "function" 646 | ? r.toString() 647 | : "" + r; 648 | } 649 | function Un(r, n) { 650 | switch (n) { 651 | case 2: 652 | return function (e) { 653 | return this.fromWireType(kr[e >> 2]); 654 | }; 655 | case 3: 656 | return function (e) { 657 | return this.fromWireType(Ir[e >> 3]); 658 | }; 659 | default: 660 | throw new TypeError("Unknown float type: " + r); 661 | } 662 | } 663 | function Rn(r, n, e) { 664 | var i = dr(e); 665 | (n = S(n)), 666 | H(r, { 667 | name: n, 668 | fromWireType: function (a) { 669 | return a; 670 | }, 671 | toWireType: function (a, f) { 672 | if (typeof f != "number" && typeof f != "boolean") 673 | throw new TypeError( 674 | 'Cannot convert "' + Er(f) + '" to ' + this.name 675 | ); 676 | return f; 677 | }, 678 | argPackAdvance: 8, 679 | readValueFromPointer: Un(n, i), 680 | destructorFunction: null, 681 | }); 682 | } 683 | function Sn(r, n) { 684 | if (!(r instanceof Function)) 685 | throw new TypeError( 686 | "new_ called with constructor type " + 687 | typeof r + 688 | " which is not a function" 689 | ); 690 | var e = qr(r.name || "unknownFunctionName", function () {}); 691 | e.prototype = r.prototype; 692 | var i = new e(), 693 | a = r.apply(i, n); 694 | return a instanceof Object ? a : i; 695 | } 696 | function Gr(r) { 697 | for (; r.length; ) { 698 | var n = r.pop(), 699 | e = r.pop(); 700 | e(n); 701 | } 702 | } 703 | function Wn(r, n, e, i, a) { 704 | var f = n.length; 705 | f < 2 && 706 | T( 707 | "argTypes array size mismatch! Must at least get return value and 'this' types!" 708 | ); 709 | for ( 710 | var c = n[1] !== null && e !== null, o = !1, s = 1; 711 | s < n.length; 712 | ++s 713 | ) 714 | if (n[s] !== null && n[s].destructorFunction === void 0) { 715 | o = !0; 716 | break; 717 | } 718 | for ( 719 | var v = n[0].name !== "void", g = "", d = "", s = 0; 720 | s < f - 2; 721 | ++s 722 | ) 723 | (g += (s !== 0 ? ", " : "") + "arg" + s), 724 | (d += (s !== 0 ? ", " : "") + "arg" + s + "Wired"); 725 | var F = 726 | "return function " + 727 | Nr(r) + 728 | "(" + 729 | g + 730 | `) { 731 | if (arguments.length !== ` + 732 | (f - 2) + 733 | `) { 734 | throwBindingError('function ` + 735 | r + 736 | " called with ' + arguments.length + ' arguments, expected " + 737 | (f - 2) + 738 | ` args!'); 739 | } 740 | `; 741 | o && 742 | (F += `var destructors = []; 743 | `); 744 | var $ = o ? "destructors" : "null", 745 | q = [ 746 | "throwBindingError", 747 | "invoker", 748 | "fn", 749 | "runDestructors", 750 | "retType", 751 | "classParam", 752 | ], 753 | fr = [T, i, a, Gr, n[0], n[1]]; 754 | c && 755 | (F += 756 | "var thisWired = classParam.toWireType(" + 757 | $ + 758 | `, this); 759 | `); 760 | for (var s = 0; s < f - 2; ++s) 761 | (F += 762 | "var arg" + 763 | s + 764 | "Wired = argType" + 765 | s + 766 | ".toWireType(" + 767 | $ + 768 | ", arg" + 769 | s + 770 | "); // " + 771 | n[s + 2].name + 772 | ` 773 | `), 774 | q.push("argType" + s), 775 | fr.push(n[s + 2]); 776 | if ( 777 | (c && (d = "thisWired" + (d.length > 0 ? ", " : "") + d), 778 | (F += 779 | (v ? "var rv = " : "") + 780 | "invoker(fn" + 781 | (d.length > 0 ? ", " : "") + 782 | d + 783 | `); 784 | `), 785 | o) 786 | ) 787 | F += `runDestructors(destructors); 788 | `; 789 | else 790 | for (var s = c ? 1 : 2; s < n.length; ++s) { 791 | var rr = s === 1 ? "thisWired" : "arg" + (s - 2) + "Wired"; 792 | n[s].destructorFunction !== null && 793 | ((F += 794 | rr + 795 | "_dtor(" + 796 | rr + 797 | "); // " + 798 | n[s].name + 799 | ` 800 | `), 801 | q.push(rr + "_dtor"), 802 | fr.push(n[s].destructorFunction)); 803 | } 804 | v && 805 | (F += `var ret = retType.fromWireType(rv); 806 | return ret; 807 | `), 808 | (F += `} 809 | `), 810 | q.push(F); 811 | var pe = Sn(Function, q).apply(null, fr); 812 | return pe; 813 | } 814 | function kn(r, n, e) { 815 | if (r[n].overloadTable === void 0) { 816 | var i = r[n]; 817 | (r[n] = function () { 818 | return ( 819 | r[n].overloadTable.hasOwnProperty(arguments.length) || 820 | T( 821 | "Function '" + 822 | e + 823 | "' called with an invalid number of arguments (" + 824 | arguments.length + 825 | ") - expects one of (" + 826 | r[n].overloadTable + 827 | ")!" 828 | ), 829 | r[n].overloadTable[arguments.length].apply(this, arguments) 830 | ); 831 | }), 832 | (r[n].overloadTable = []), 833 | (r[n].overloadTable[i.argCount] = i); 834 | } 835 | } 836 | function In(r, n, e) { 837 | t.hasOwnProperty(r) 838 | ? ((e === void 0 || 839 | (t[r].overloadTable !== void 0 && 840 | t[r].overloadTable[e] !== void 0)) && 841 | T("Cannot register public name '" + r + "' twice"), 842 | kn(t, r, r), 843 | t.hasOwnProperty(e) && 844 | T( 845 | "Cannot register multiple overloads of a function with the same number of arguments (" + 846 | e + 847 | ")!" 848 | ), 849 | (t[r].overloadTable[e] = n)) 850 | : ((t[r] = n), e !== void 0 && (t[r].numArguments = e)); 851 | } 852 | function On(r, n) { 853 | for (var e = [], i = 0; i < r; i++) e.push(V[(n >> 2) + i]); 854 | return e; 855 | } 856 | function Ln(r, n, e) { 857 | t.hasOwnProperty(r) || Xr("Replacing nonexistant public symbol"), 858 | t[r].overloadTable !== void 0 && e !== void 0 859 | ? (t[r].overloadTable[e] = n) 860 | : ((t[r] = n), (t[r].argCount = e)); 861 | } 862 | function Vn(r, n, e) { 863 | var i = t["dynCall_" + r]; 864 | return e && e.length ? i.apply(null, [n].concat(e)) : i.call(null, n); 865 | } 866 | function Dn(r, n, e) { 867 | return r.includes("j") ? Vn(r, n, e) : tr.get(n).apply(null, e); 868 | } 869 | function Hn(r, n) { 870 | var e = []; 871 | return function () { 872 | e.length = arguments.length; 873 | for (var i = 0; i < arguments.length; i++) e[i] = arguments[i]; 874 | return Dn(r, n, e); 875 | }; 876 | } 877 | function Bn(r, n) { 878 | r = S(r); 879 | function e() { 880 | return r.includes("j") ? Hn(r, n) : tr.get(n); 881 | } 882 | var i = e(); 883 | return ( 884 | typeof i != "function" && 885 | T("unknown function pointer with signature " + r + ": " + n), 886 | i 887 | ); 888 | } 889 | var Yr = void 0; 890 | function $r(r) { 891 | var n = Jr(r), 892 | e = S(n); 893 | return B(n), e; 894 | } 895 | function jn(r, n) { 896 | var e = [], 897 | i = {}; 898 | function a(f) { 899 | if (!i[f] && !Y[f]) { 900 | if (cr[f]) { 901 | cr[f].forEach(a); 902 | return; 903 | } 904 | e.push(f), (i[f] = !0); 905 | } 906 | } 907 | throw (n.forEach(a), new Yr(r + ": " + e.map($r).join([", "]))); 908 | } 909 | function Nn(r, n, e, i, a, f) { 910 | var c = On(n, e); 911 | (r = S(r)), 912 | (a = Bn(i, a)), 913 | In( 914 | r, 915 | function () { 916 | jn("Cannot call " + r + " due to unbound types", c); 917 | }, 918 | n - 1 919 | ), 920 | An([], c, function (o) { 921 | var s = [o[0], null].concat(o.slice(1)); 922 | return Ln(r, Wn(r, s, null, a, f), n - 1), []; 923 | }); 924 | } 925 | function qn(r, n, e) { 926 | switch (n) { 927 | case 0: 928 | return e 929 | ? function (a) { 930 | return _r[a]; 931 | } 932 | : function (a) { 933 | return U[a]; 934 | }; 935 | case 1: 936 | return e 937 | ? function (a) { 938 | return Z[a >> 1]; 939 | } 940 | : function (a) { 941 | return hr[a >> 1]; 942 | }; 943 | case 2: 944 | return e 945 | ? function (a) { 946 | return V[a >> 2]; 947 | } 948 | : function (a) { 949 | return D[a >> 2]; 950 | }; 951 | default: 952 | throw new TypeError("Unknown integer type: " + r); 953 | } 954 | } 955 | function xn(r, n, e, i, a) { 956 | (n = S(n)), a === -1 && (a = 4294967295); 957 | var f = dr(e), 958 | c = function (v) { 959 | return v; 960 | }; 961 | if (i === 0) { 962 | var o = 32 - 8 * e; 963 | c = function (v) { 964 | return (v << o) >>> o; 965 | }; 966 | } 967 | var s = n.includes("unsigned"); 968 | H(r, { 969 | name: n, 970 | fromWireType: c, 971 | toWireType: function (v, g) { 972 | if (typeof g != "number" && typeof g != "boolean") 973 | throw new TypeError( 974 | 'Cannot convert "' + Er(g) + '" to ' + this.name 975 | ); 976 | if (g < i || g > a) 977 | throw new TypeError( 978 | 'Passing a number "' + 979 | Er(g) + 980 | '" from JS side to C/C++ side to an argument of type "' + 981 | n + 982 | '", which is outside the valid range [' + 983 | i + 984 | ", " + 985 | a + 986 | "]!" 987 | ); 988 | return s ? g >>> 0 : g | 0; 989 | }, 990 | argPackAdvance: 8, 991 | readValueFromPointer: qn(n, f, i !== 0), 992 | destructorFunction: null, 993 | }); 994 | } 995 | function zn(r, n, e) { 996 | var i = [ 997 | Int8Array, 998 | Uint8Array, 999 | Int16Array, 1000 | Uint16Array, 1001 | Int32Array, 1002 | Uint32Array, 1003 | Float32Array, 1004 | Float64Array, 1005 | ], 1006 | a = i[n]; 1007 | function f(c) { 1008 | c = c >> 2; 1009 | var o = D, 1010 | s = o[c], 1011 | v = o[c + 1]; 1012 | return new a(pr, v, s); 1013 | } 1014 | (e = S(e)), 1015 | H( 1016 | r, 1017 | { 1018 | name: e, 1019 | fromWireType: f, 1020 | argPackAdvance: 8, 1021 | readValueFromPointer: f, 1022 | }, 1023 | { ignoreDuplicateRegistrations: !0 } 1024 | ); 1025 | } 1026 | function Xn(r, n) { 1027 | n = S(n); 1028 | var e = n === "std::string"; 1029 | H(r, { 1030 | name: n, 1031 | fromWireType: function (i) { 1032 | var a = D[i >> 2], 1033 | f; 1034 | if (e) 1035 | for (var c = i + 4, o = 0; o <= a; ++o) { 1036 | var s = i + 4 + o; 1037 | if (o == a || U[s] == 0) { 1038 | var v = s - c, 1039 | g = A(c, v); 1040 | f === void 0 1041 | ? (f = g) 1042 | : ((f += String.fromCharCode(0)), (f += g)), 1043 | (c = s + 1); 1044 | } 1045 | } 1046 | else { 1047 | for (var d = new Array(a), o = 0; o < a; ++o) 1048 | d[o] = String.fromCharCode(U[i + 4 + o]); 1049 | f = d.join(""); 1050 | } 1051 | return B(i), f; 1052 | }, 1053 | toWireType: function (i, a) { 1054 | a instanceof ArrayBuffer && (a = new Uint8Array(a)); 1055 | var f, 1056 | c = typeof a == "string"; 1057 | c || 1058 | a instanceof Uint8Array || 1059 | a instanceof Uint8ClampedArray || 1060 | a instanceof Int8Array || 1061 | T("Cannot pass non-string to std::string"), 1062 | e && c 1063 | ? (f = function () { 1064 | return vr(a); 1065 | }) 1066 | : (f = function () { 1067 | return a.length; 1068 | }); 1069 | var o = f(), 1070 | s = Cr(4 + o + 1); 1071 | if (((D[s >> 2] = o), e && c)) E(a, s + 4, o + 1); 1072 | else if (c) 1073 | for (var v = 0; v < o; ++v) { 1074 | var g = a.charCodeAt(v); 1075 | g > 255 && 1076 | (B(s), 1077 | T("String has UTF-16 code units that do not fit in 8 bits")), 1078 | (U[s + 4 + v] = g); 1079 | } 1080 | else for (var v = 0; v < o; ++v) U[s + 4 + v] = a[v]; 1081 | return i !== null && i.push(B, s), s; 1082 | }, 1083 | argPackAdvance: 8, 1084 | readValueFromPointer: Ar, 1085 | destructorFunction: function (i) { 1086 | B(i); 1087 | }, 1088 | }); 1089 | } 1090 | function Gn(r, n, e) { 1091 | e = S(e); 1092 | var i, a, f, c, o; 1093 | n === 2 1094 | ? ((i = Zr), 1095 | (a = Qr), 1096 | (c = Mr), 1097 | (f = function () { 1098 | return hr; 1099 | }), 1100 | (o = 1)) 1101 | : n === 4 && 1102 | ((i = rn), 1103 | (a = nn), 1104 | (c = en), 1105 | (f = function () { 1106 | return D; 1107 | }), 1108 | (o = 2)), 1109 | H(r, { 1110 | name: e, 1111 | fromWireType: function (s) { 1112 | for ( 1113 | var v = D[s >> 2], g = f(), d, F = s + 4, $ = 0; 1114 | $ <= v; 1115 | ++$ 1116 | ) { 1117 | var q = s + 4 + $ * n; 1118 | if ($ == v || g[q >> o] == 0) { 1119 | var fr = q - F, 1120 | rr = i(F, fr); 1121 | d === void 0 1122 | ? (d = rr) 1123 | : ((d += String.fromCharCode(0)), (d += rr)), 1124 | (F = q + n); 1125 | } 1126 | } 1127 | return B(s), d; 1128 | }, 1129 | toWireType: function (s, v) { 1130 | typeof v != "string" && 1131 | T("Cannot pass non-string to C++ string type " + e); 1132 | var g = c(v), 1133 | d = Cr(4 + g + n); 1134 | return ( 1135 | (D[d >> 2] = g >> o), 1136 | a(v, d + 4, g + n), 1137 | s !== null && s.push(B, d), 1138 | d 1139 | ); 1140 | }, 1141 | argPackAdvance: 8, 1142 | readValueFromPointer: Ar, 1143 | destructorFunction: function (s) { 1144 | B(s); 1145 | }, 1146 | }); 1147 | } 1148 | function Yn(r, n) { 1149 | (n = S(n)), 1150 | H(r, { 1151 | isVoid: !0, 1152 | name: n, 1153 | argPackAdvance: 0, 1154 | fromWireType: function () {}, 1155 | toWireType: function (e, i) {}, 1156 | }); 1157 | } 1158 | function or(r) { 1159 | return r || T("Cannot use deleted val. handle = " + r), C[r].value; 1160 | } 1161 | function Tr(r, n) { 1162 | var e = Y[r]; 1163 | return e === void 0 && T(n + " has unknown type " + $r(r)), e; 1164 | } 1165 | function $n(r, n, e) { 1166 | (r = or(r)), (n = Tr(n, "emval::as")); 1167 | var i = [], 1168 | a = M(i); 1169 | return (V[e >> 2] = a), n.toWireType(i, r); 1170 | } 1171 | function Jn(r, n) { 1172 | for (var e = new Array(r), i = 0; i < r; ++i) 1173 | e[i] = Tr(V[(n >> 2) + i], "parameter " + i); 1174 | return e; 1175 | } 1176 | function Kn(r, n, e, i) { 1177 | r = or(r); 1178 | for (var a = Jn(n, e), f = new Array(n), c = 0; c < n; ++c) { 1179 | var o = a[c]; 1180 | (f[c] = o.readValueFromPointer(i)), (i += o.argPackAdvance); 1181 | } 1182 | var s = r.apply(void 0, f); 1183 | return M(s); 1184 | } 1185 | function Zn(r, n) { 1186 | return (r = or(r)), (n = or(n)), M(r[n]); 1187 | } 1188 | function Qn(r) { 1189 | r > 4 && (C[r].refcount += 1); 1190 | } 1191 | function Mn(r) { 1192 | return (r = or(r)), typeof r == "number"; 1193 | } 1194 | var re = {}; 1195 | function ne(r) { 1196 | var n = re[r]; 1197 | return n === void 0 ? S(r) : n; 1198 | } 1199 | function ee(r) { 1200 | return M(ne(r)); 1201 | } 1202 | function te(r) { 1203 | var n = C[r].value; 1204 | Gr(n), br(r); 1205 | } 1206 | function ie(r, n) { 1207 | r = Tr(r, "_emval_take_value"); 1208 | var e = r.readValueFromPointer(n); 1209 | return M(e); 1210 | } 1211 | function ae() { 1212 | ar(); 1213 | } 1214 | function oe(r, n, e) { 1215 | U.copyWithin(r, n, n + e); 1216 | } 1217 | function fe(r) { 1218 | try { 1219 | return K.grow((r - pr.byteLength + 65535) >>> 16), Or(K.buffer), 1; 1220 | } catch (n) {} 1221 | } 1222 | function se(r) { 1223 | var n = U.length; 1224 | r = r >>> 0; 1225 | var e = 2147483648; 1226 | if (r > e) return !1; 1227 | for (var i = 1; i <= 4; i *= 2) { 1228 | var a = n * (1 + 0.2 / i); 1229 | a = Math.min(a, r + 100663296); 1230 | var f = Math.min(e, tn(Math.max(r, a), 65536)), 1231 | c = fe(f); 1232 | if (c) return !0; 1233 | } 1234 | return !1; 1235 | } 1236 | mn(), 1237 | (xr = t.BindingError = mr(Error, "BindingError")), 1238 | (zr = t.InternalError = mr(Error, "InternalError")), 1239 | Fn(), 1240 | (Yr = t.UnboundTypeError = mr(Error, "UnboundTypeError")); 1241 | var ce = { 1242 | a: yn, 1243 | q: dn, 1244 | u: En, 1245 | t: Pn, 1246 | m: Rn, 1247 | k: Nn, 1248 | d: xn, 1249 | c: zn, 1250 | n: Xn, 1251 | l: Gn, 1252 | v: Yn, 1253 | j: $n, 1254 | w: Kn, 1255 | b: br, 1256 | e: Zn, 1257 | g: Qn, 1258 | p: Mn, 1259 | f: ee, 1260 | i: te, 1261 | h: ie, 1262 | o: ae, 1263 | r: oe, 1264 | s: se, 1265 | }, 1266 | we = gn(), 1267 | ue = (t.___wasm_call_ctors = function () { 1268 | return (ue = t.___wasm_call_ctors = t.asm.y).apply(null, arguments); 1269 | }), 1270 | Cr = (t._malloc = function () { 1271 | return (Cr = t._malloc = t.asm.z).apply(null, arguments); 1272 | }), 1273 | B = (t._free = function () { 1274 | return (B = t._free = t.asm.A).apply(null, arguments); 1275 | }), 1276 | Jr = (t.___getTypeName = function () { 1277 | return (Jr = t.___getTypeName = t.asm.C).apply(null, arguments); 1278 | }), 1279 | le = (t.___embind_register_native_and_builtin_types = function () { 1280 | return (le = t.___embind_register_native_and_builtin_types = 1281 | t.asm.D).apply(null, arguments); 1282 | }), 1283 | ve = (t.dynCall_ijiii = function () { 1284 | return (ve = t.dynCall_ijiii = t.asm.E).apply(null, arguments); 1285 | }), 1286 | ur; 1287 | ir = function r() { 1288 | ur || Fr(), ur || (ir = r); 1289 | }; 1290 | function Fr(r) { 1291 | if (((r = r || p), G > 0 || (on(), G > 0))) return; 1292 | function n() { 1293 | ur || 1294 | ((ur = !0), 1295 | (t.calledRun = !0), 1296 | !w && 1297 | (fn(), 1298 | u(t), 1299 | t.onRuntimeInitialized && t.onRuntimeInitialized(), 1300 | sn())); 1301 | } 1302 | t.setStatus 1303 | ? (t.setStatus("Running..."), 1304 | setTimeout(function () { 1305 | setTimeout(function () { 1306 | t.setStatus(""); 1307 | }, 1), 1308 | n(); 1309 | }, 1)) 1310 | : n(); 1311 | } 1312 | if (((t.run = Fr), t.preInit)) 1313 | for ( 1314 | typeof t.preInit == "function" && (t.preInit = [t.preInit]); 1315 | t.preInit.length > 0; 1316 | 1317 | ) 1318 | t.preInit.pop()(); 1319 | return Fr(), t.ready; 1320 | }; 1321 | })(); 1322 | 1323 | /* post code */ 1324 | const START_CODE = new Uint8Array([0, 0, 0, 1]); 1325 | 1326 | function defaultError(error) { 1327 | console.error(error); 1328 | } 1329 | 1330 | Module.createFile = createFile; 1331 | export function createFile(initialCapacity = 256) { 1332 | let cursor = 0; 1333 | let usedBytes = 0; 1334 | let contents = new Uint8Array(initialCapacity); 1335 | return { 1336 | contents: function () { 1337 | return contents.slice(0, usedBytes); 1338 | }, 1339 | seek: function (offset) { 1340 | // offset in bytes 1341 | cursor = offset; 1342 | }, 1343 | write: function (data) { 1344 | const size = data.byteLength; 1345 | expand(cursor + size); 1346 | contents.set(data, cursor); 1347 | cursor += size; 1348 | usedBytes = Math.max(usedBytes, cursor); 1349 | return size; 1350 | }, 1351 | }; 1352 | 1353 | function expand(newCapacity) { 1354 | var prevCapacity = contents.length; 1355 | if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough. 1356 | // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity. 1357 | // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to 1358 | // avoid overshooting the allocation cap by a very large margin. 1359 | var CAPACITY_DOUBLING_MAX = 1024 * 1024; 1360 | newCapacity = Math.max( 1361 | newCapacity, 1362 | (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> 1363 | 0 1364 | ); 1365 | if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding. 1366 | const oldContents = contents; 1367 | contents = new Uint8Array(newCapacity); // Allocate new storage. 1368 | if (usedBytes > 0) contents.set(oldContents.subarray(0, usedBytes), 0); 1369 | } 1370 | } 1371 | 1372 | Module.isWebCodecsSupported = isWebCodecsSupported; 1373 | export function isWebCodecsSupported() { 1374 | return ( 1375 | typeof window !== "undefined" && typeof window.VideoEncoder === "function" 1376 | ); 1377 | } 1378 | 1379 | export function createWebCodecsEncoderWithModule(MP4, opts = {}) { 1380 | const { 1381 | width, 1382 | height, 1383 | groupOfPictures = 20, 1384 | fps = 30, 1385 | fragmentation = false, 1386 | sequential = false, 1387 | hevc = false, 1388 | format = "annexb", 1389 | // codec = "avc1.420034", // Baseline 4.2 1390 | codec = "avc1.4d0034", // Main 5.2 1391 | acceleration, 1392 | bitrate, 1393 | error = defaultError, 1394 | encoderOptions = {}, 1395 | flushFrequency = 10, 1396 | } = opts; 1397 | 1398 | if (!isWebCodecsSupported()) { 1399 | throw new Error( 1400 | "MP4 H264 encoding/decoding depends on WebCodecs API which is not supported in this environment" 1401 | ); 1402 | } 1403 | 1404 | if (typeof width !== "number" || typeof height !== "number") { 1405 | throw new Error("Must specify { width, height } options"); 1406 | } 1407 | 1408 | if (!isFinite(width) || width < 0 || !isFinite(height) || height < 0) { 1409 | throw new Error("{ width, height } options must be positive integers"); 1410 | } 1411 | 1412 | const file = createFile(); 1413 | const mux = MP4.create_muxer( 1414 | { 1415 | width, 1416 | height, 1417 | fps, 1418 | fragmentation, 1419 | sequential, 1420 | hevc, 1421 | }, 1422 | mux_write 1423 | ); 1424 | 1425 | const config = { 1426 | codec, 1427 | width: width, 1428 | height: height, 1429 | avc: { 1430 | format, 1431 | }, 1432 | hardwareAcceleration: acceleration, 1433 | // There is a bug on macOS if this is greater than 30 fps 1434 | // framerate: fps, 1435 | bitrate, 1436 | ...encoderOptions, 1437 | }; 1438 | 1439 | let frameIndex = 0; 1440 | 1441 | const encoder = new window.VideoEncoder({ 1442 | output(chunk, opts) { 1443 | writeAVC(chunk, opts); 1444 | }, 1445 | error, 1446 | }); 1447 | encoder.configure(config); 1448 | 1449 | return { 1450 | async end() { 1451 | await encoder.flush(); 1452 | encoder.close(); 1453 | MP4.finalize_muxer(mux); 1454 | return file.contents(); 1455 | }, 1456 | async addFrame(bitmap) { 1457 | const timestamp = (1 / fps) * frameIndex * 1000000; 1458 | const keyFrame = frameIndex % groupOfPictures === 0; 1459 | let frame = new VideoFrame(bitmap, { timestamp }); 1460 | encoder.encode(frame, { keyFrame }); 1461 | frame.close(); 1462 | if (flushFrequency != null && (frameIndex + 1) % flushFrequency === 0) { 1463 | await encoder.flush(); 1464 | } 1465 | frameIndex++; 1466 | }, 1467 | async flush() { 1468 | return encoder.flush(); 1469 | }, 1470 | }; 1471 | 1472 | function mux_write(data_ptr, size, offset) { 1473 | // seek to byte offset in file 1474 | file.seek(offset); 1475 | // get subarray of memory we are writing 1476 | const data = MP4.HEAPU8.subarray(data_ptr, data_ptr + size); 1477 | // write into virtual file 1478 | return file.write(data) !== data.byteLength; 1479 | } 1480 | 1481 | function write_nal(uint8) { 1482 | const p = MP4._malloc(uint8.byteLength); 1483 | MP4.HEAPU8.set(uint8, p); 1484 | MP4.mux_nal(mux, p, uint8.byteLength); 1485 | MP4._free(p); 1486 | } 1487 | 1488 | function writeAVC(chunk, opts) { 1489 | let avccConfig = null; 1490 | 1491 | let description; 1492 | if (opts) { 1493 | if (opts.description) { 1494 | description = opts.description; 1495 | } 1496 | if (opts.decoderConfig && opts.decoderConfig.description) { 1497 | description = opts.decoderConfig.description; 1498 | } 1499 | } 1500 | 1501 | if (description) { 1502 | try { 1503 | avccConfig = parseAVCC(description); 1504 | } catch (err) { 1505 | error(err); 1506 | return; 1507 | } 1508 | } 1509 | 1510 | const nal = []; 1511 | if (avccConfig) { 1512 | avccConfig.sps_list.forEach((sps) => { 1513 | nal.push(START_CODE); 1514 | nal.push(sps); 1515 | }); 1516 | avccConfig.pps_list.forEach((pps) => { 1517 | nal.push(START_CODE); 1518 | nal.push(pps); 1519 | }); 1520 | } 1521 | 1522 | if (format === "annexb") { 1523 | const uint8 = new Uint8Array(chunk.byteLength); 1524 | chunk.copyTo(uint8); 1525 | nal.push(uint8); 1526 | } else { 1527 | try { 1528 | const arrayBuf = new ArrayBuffer(chunk.byteLength); 1529 | chunk.copyTo(arrayBuf); 1530 | convertAVCToAnnexBInPlaceForLength4(arrayBuf).forEach((sub) => { 1531 | nal.push(START_CODE); 1532 | nal.push(sub); 1533 | }); 1534 | } catch (err) { 1535 | error(err); 1536 | return; 1537 | } 1538 | } 1539 | 1540 | write_nal(concatBuffers(nal)); 1541 | } 1542 | } 1543 | 1544 | function concatBuffers(arrays) { 1545 | // Calculate byteSize from all arrays 1546 | const size = arrays.reduce((a, b) => a + b.byteLength, 0); 1547 | // Allcolate a new buffer 1548 | const result = new Uint8Array(size); 1549 | let offset = 0; 1550 | for (let i = 0; i < arrays.length; i++) { 1551 | const arr = arrays[i]; 1552 | result.set(arr, offset); 1553 | offset += arr.byteLength; 1554 | } 1555 | return result; 1556 | } 1557 | 1558 | function convertAVCToAnnexBInPlaceForLength4(arrayBuf) { 1559 | const kLengthSize = 4; 1560 | let pos = 0; 1561 | const chunks = []; 1562 | const size = arrayBuf.byteLength; 1563 | const uint8 = new Uint8Array(arrayBuf); 1564 | while (pos + kLengthSize < size) { 1565 | // read uint 32, 4 byte NAL length 1566 | let nal_length = uint8[pos]; 1567 | nal_length = (nal_length << 8) + uint8[pos + 1]; 1568 | nal_length = (nal_length << 8) + uint8[pos + 2]; 1569 | nal_length = (nal_length << 8) + uint8[pos + 3]; 1570 | 1571 | chunks.push(new Uint8Array(arrayBuf, pos + kLengthSize, nal_length)); 1572 | if (nal_length == 0) throw new Error("Error: invalid nal_length 0"); 1573 | pos += kLengthSize + nal_length; 1574 | } 1575 | return chunks; 1576 | } 1577 | 1578 | function parseAVCC(avcc) { 1579 | const view = new DataView(avcc); 1580 | let off = 0; 1581 | const version = view.getUint8(off++); 1582 | const profile = view.getUint8(off++); 1583 | const compat = view.getUint8(off++); 1584 | const level = view.getUint8(off++); 1585 | const length_size = (view.getUint8(off++) & 0x3) + 1; 1586 | if (length_size !== 4) 1587 | throw new Error("Expected length_size to indicate 4 bytes"); 1588 | const numSPS = view.getUint8(off++) & 0x1f; 1589 | const sps_list = []; 1590 | for (let i = 0; i < numSPS; i++) { 1591 | const sps_len = view.getUint16(off, false); 1592 | off += 2; 1593 | const sps = new Uint8Array(view.buffer, off, sps_len); 1594 | sps_list.push(sps); 1595 | off += sps_len; 1596 | } 1597 | const numPPS = view.getUint8(off++); 1598 | const pps_list = []; 1599 | for (let i = 0; i < numPPS; i++) { 1600 | const pps_len = view.getUint16(off, false); 1601 | off += 2; 1602 | const pps = new Uint8Array(view.buffer, off, pps_len); 1603 | pps_list.push(pps); 1604 | off += pps_len; 1605 | } 1606 | return { 1607 | offset: off, 1608 | version, 1609 | profile, 1610 | compat, 1611 | level, 1612 | length_size, 1613 | pps_list, 1614 | sps_list, 1615 | numSPS, 1616 | }; 1617 | } 1618 | 1619 | export {Module as default}; 1620 | --------------------------------------------------------------------------------