@osmo.inc/cli 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DEPLOY.md +87 -0
- package/README.md +243 -0
- package/RELEASE.md +164 -0
- package/SETUP.md +60 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/bin/osmo.mjs +12 -0
- package/dist/osmo.js +7817 -0
- package/node_modules/@esbuild/darwin-arm64/README.md +3 -0
- package/node_modules/@esbuild/darwin-arm64/bin/esbuild +0 -0
- package/node_modules/@esbuild/darwin-arm64/package.json +20 -0
- package/node_modules/esbuild/LICENSE.md +21 -0
- package/node_modules/esbuild/README.md +3 -0
- package/node_modules/esbuild/bin/esbuild +223 -0
- package/node_modules/esbuild/install.js +289 -0
- package/node_modules/esbuild/lib/main.d.ts +716 -0
- package/node_modules/esbuild/lib/main.js +2532 -0
- package/node_modules/esbuild/package.json +49 -0
- package/node_modules/fflate/LICENSE +21 -0
- package/node_modules/fflate/esm/index.mjs +2710 -0
- package/node_modules/fflate/package.json +128 -0
- package/node_modules/typescript/LICENSE.txt +55 -0
- package/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
- package/node_modules/typescript/lib/lib.d.ts +22 -0
- package/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
- package/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
- package/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
- package/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
- package/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
- package/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
- package/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
- package/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
- package/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
- package/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
- package/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
- package/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
- package/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
- package/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
- package/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
- package/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
- package/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
- package/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
- package/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
- package/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
- package/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
- package/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
- package/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
- package/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
- package/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
- package/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
- package/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
- package/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
- package/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
- package/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
- package/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
- package/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
- package/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
- package/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
- package/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
- package/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
- package/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
- package/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
- package/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
- package/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
- package/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
- package/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
- package/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
- package/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
- package/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
- package/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
- package/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
- package/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
- package/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
- package/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
- package/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
- package/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
- package/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
- package/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
- package/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
- package/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
- package/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
- package/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
- package/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
- package/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
- package/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
- package/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
- package/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
- package/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
- package/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
- package/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
- package/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
- package/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
- package/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
- package/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
- package/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
- package/node_modules/typescript/lib/lib.es6.d.ts +23 -0
- package/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
- package/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
- package/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
- package/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
- package/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
- package/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
- package/node_modules/typescript/lib/lib.esnext.float16.d.ts +445 -0
- package/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
- package/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
- package/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
- package/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
- package/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
- package/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
- package/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
- package/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
- package/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
- package/node_modules/typescript/lib/typescript.js +382 -0
- package/node_modules/typescript/package.json +57 -0
- package/package.json +54 -0
- package/release.json +136 -0
- package/runtime/apps/native/tools/compile.mjs +217 -0
- package/runtime/packages/scene/scripts/validate-strict.mjs +246 -0
- package/runtime/packages/scene/src/clip.d.mts +14 -0
- package/runtime/packages/scene/src/clip.mjs +15 -0
- package/runtime/packages/scene/src/color-value.d.mts +5 -0
- package/runtime/packages/scene/src/color-value.mjs +19 -0
- package/runtime/packages/scene/src/color.ts +1 -0
- package/runtime/packages/scene/src/effects.ts +213 -0
- package/runtime/packages/scene/src/elements.ts +491 -0
- package/runtime/packages/scene/src/evaluate.ts +919 -0
- package/runtime/packages/scene/src/index.ts +69 -0
- package/runtime/packages/scene/src/jsx-runtime.ts +73 -0
- package/runtime/packages/scene/src/knob-schema.ts +115 -0
- package/runtime/packages/scene/src/knobs.ts +118 -0
- package/runtime/packages/scene/src/mask.d.mts +6 -0
- package/runtime/packages/scene/src/mask.mjs +17 -0
- package/runtime/packages/scene/src/metadata.d.mts +23 -0
- package/runtime/packages/scene/src/metadata.mjs +44 -0
- package/runtime/packages/scene/src/motion-sampling.d.mts +2 -0
- package/runtime/packages/scene/src/motion-sampling.mjs +50 -0
- package/runtime/packages/scene/src/motion.ts +121 -0
- package/runtime/packages/scene/src/shader.ts +57 -0
- package/src/resource-examples/example-image/landscape.svg +7 -0
- package/src/resource-examples/example-image/resource.json +8 -0
- package/src/resource-examples/example-model/gem.glb +0 -0
- package/src/resource-examples/example-model/preview.svg +1 -0
- package/src/resource-examples/example-model/resource.json +7 -0
- package/src/resource-examples/example-scene/resource.json +1 -0
- package/src/resource-examples/example-scene/scene.tsx +8 -0
- package/src/resource-examples/example-shader/effect.wgsl +7 -0
- package/src/resource-examples/example-shader/preview.svg +1 -0
- package/src/resource-examples/example-shader/resource.json +27 -0
- package/src/resource-examples/example-shader/tint.wgsl +7 -0
- package/src/resource-examples/example-video/ambient.mp4 +0 -0
- package/src/resource-examples/example-video/resource.json +9 -0
- package/src/starter/scene.tsx +20 -0
- package/studio/index.html +2 -0
- package/studio/public/check-circle-filled.svg +3 -0
- package/studio/public/comment-cursor/active-outer.svg +3 -0
- package/studio/public/comment-cursor/default.svg +6 -0
- package/studio/public/osmo-studio-logo.svg +12 -0
- package/studio/public/pencil-simple.svg +5 -0
- package/studio/src/active-outer-TVYUEURE.svg +3 -0
- package/studio/src/app.css +4 -0
- package/studio/src/app.js +705 -0
- package/studio/src/default-6CTRH4V5.svg +6 -0
- package/studio/src/engine_bg.wasm +0 -0
- package/studio/src/inter-cyrillic-ext-wght-normal-IYF56FF6.woff2 +0 -0
- package/studio/src/inter-cyrillic-wght-normal-JEOLYBOO.woff2 +0 -0
- package/studio/src/inter-greek-ext-wght-normal-EOVOK2B5.woff2 +0 -0
- package/studio/src/inter-greek-wght-normal-IRE366VL.woff2 +0 -0
- package/studio/src/inter-latin-ext-wght-normal-HA22NDSG.woff2 +0 -0
- package/studio/src/inter-latin-wght-normal-NRMW37G5.woff2 +0 -0
- package/studio/src/inter-vietnamese-wght-normal-CE5GGD3W.woff2 +0 -0
- package/studio/src/osmo-studio-logo-D5R2V77B.svg +12 -0
- package/third-party/cargo/adler2@2.0.1/Cargo.toml +91 -0
- package/third-party/cargo/adler2@2.0.1/LICENSE-0BSD +12 -0
- package/third-party/cargo/adler2@2.0.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/adler2@2.0.1/LICENSE-MIT +23 -0
- package/third-party/cargo/allocator-api2@0.2.21/Cargo.toml +48 -0
- package/third-party/cargo/allocator-api2@0.2.21/LICENSE-APACHE +176 -0
- package/third-party/cargo/allocator-api2@0.2.21/LICENSE-MIT +23 -0
- package/third-party/cargo/arrayref@0.3.9/Cargo.toml +23 -0
- package/third-party/cargo/arrayref@0.3.9/LICENSE +26 -0
- package/third-party/cargo/arrayvec@0.7.8/Cargo.toml +112 -0
- package/third-party/cargo/arrayvec@0.7.8/LICENSE-APACHE +201 -0
- package/third-party/cargo/arrayvec@0.7.8/LICENSE-MIT +25 -0
- package/third-party/cargo/ascii@1.1.0/Cargo.toml +41 -0
- package/third-party/cargo/ascii@1.1.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/ascii@1.1.0/LICENSE-MIT +22 -0
- package/third-party/cargo/ash@0.38.0+1.3.281/Cargo.toml +66 -0
- package/third-party/cargo/ash@0.38.0+1.3.281/LICENSE-APACHE +67 -0
- package/third-party/cargo/ash@0.38.0+1.3.281/LICENSE-MIT +25 -0
- package/third-party/cargo/autocfg@1.5.1/Cargo.toml +75 -0
- package/third-party/cargo/autocfg@1.5.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/autocfg@1.5.1/LICENSE-MIT +25 -0
- package/third-party/cargo/base64@0.13.1/Cargo.toml +53 -0
- package/third-party/cargo/base64@0.13.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/base64@0.13.1/LICENSE-MIT +21 -0
- package/third-party/cargo/base64@0.22.1/Cargo.toml +85 -0
- package/third-party/cargo/base64@0.22.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/base64@0.22.1/LICENSE-MIT +21 -0
- package/third-party/cargo/bit-set@0.10.0/Cargo.toml +108 -0
- package/third-party/cargo/bit-set@0.10.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/bit-set@0.10.0/LICENSE-MIT +25 -0
- package/third-party/cargo/bit-vec@0.9.1/Cargo.toml +94 -0
- package/third-party/cargo/bit-vec@0.9.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/bit-vec@0.9.1/LICENSE-MIT +25 -0
- package/third-party/cargo/bitflags@2.13.0/Cargo.toml +120 -0
- package/third-party/cargo/bitflags@2.13.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/bitflags@2.13.0/LICENSE-MIT +25 -0
- package/third-party/cargo/block2@0.6.2/Cargo.toml +115 -0
- package/third-party/cargo/block2@0.6.2/MIT-terms.txt +22 -0
- package/third-party/cargo/block2@0.6.2/madsmtm-objc2-b4167b582b2f-LICENSE.md +34 -0
- package/third-party/cargo/bumpalo@3.20.3/Cargo.toml +99 -0
- package/third-party/cargo/bumpalo@3.20.3/LICENSE-APACHE +201 -0
- package/third-party/cargo/bumpalo@3.20.3/LICENSE-MIT +25 -0
- package/third-party/cargo/bytemuck@1.25.1/Cargo.toml +153 -0
- package/third-party/cargo/bytemuck@1.25.1/LICENSE-APACHE +61 -0
- package/third-party/cargo/bytemuck@1.25.1/LICENSE-MIT +9 -0
- package/third-party/cargo/bytemuck@1.25.1/LICENSE-ZLIB +11 -0
- package/third-party/cargo/bytemuck_derive@1.11.0/Cargo.toml +60 -0
- package/third-party/cargo/bytemuck_derive@1.11.0/LICENSE-APACHE +61 -0
- package/third-party/cargo/bytemuck_derive@1.11.0/LICENSE-MIT +9 -0
- package/third-party/cargo/bytemuck_derive@1.11.0/LICENSE-ZLIB +11 -0
- package/third-party/cargo/byteorder-lite@0.1.0/Cargo.toml +57 -0
- package/third-party/cargo/byteorder-lite@0.1.0/LICENSE-MIT +21 -0
- package/third-party/cargo/byteorder-lite@0.1.0/UNLICENSE +24 -0
- package/third-party/cargo/byteorder@1.5.0/COPYING +3 -0
- package/third-party/cargo/byteorder@1.5.0/Cargo.toml +54 -0
- package/third-party/cargo/byteorder@1.5.0/LICENSE-MIT +21 -0
- package/third-party/cargo/byteorder@1.5.0/UNLICENSE +24 -0
- package/third-party/cargo/cfg-if@1.0.4/Cargo.toml +47 -0
- package/third-party/cargo/cfg-if@1.0.4/LICENSE-APACHE +201 -0
- package/third-party/cargo/cfg-if@1.0.4/LICENSE-MIT +25 -0
- package/third-party/cargo/cfg_aliases@0.2.1/Cargo.toml +43 -0
- package/third-party/cargo/cfg_aliases@0.2.1/LICENSE +9 -0
- package/third-party/cargo/chunked_transfer@1.5.0/Cargo.toml +27 -0
- package/third-party/cargo/chunked_transfer@1.5.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/chunked_transfer@1.5.0/LICENSE-MIT +22 -0
- package/third-party/cargo/codespan-reporting@0.13.1/Cargo.toml +115 -0
- package/third-party/cargo/codespan-reporting@0.13.1/LICENSE +201 -0
- package/third-party/cargo/color_quant@1.1.0/Cargo.toml +20 -0
- package/third-party/cargo/color_quant@1.1.0/LICENSE +21 -0
- package/third-party/cargo/console_error_panic_hook@0.1.7/Cargo.toml +27 -0
- package/third-party/cargo/console_error_panic_hook@0.1.7/LICENSE-APACHE +201 -0
- package/third-party/cargo/console_error_panic_hook@0.1.7/LICENSE-MIT +25 -0
- package/third-party/cargo/core_maths@0.1.1/Cargo.toml +37 -0
- package/third-party/cargo/core_maths@0.1.1/LICENSE +21 -0
- package/third-party/cargo/cosmic-text@0.19.0/Cargo.toml +214 -0
- package/third-party/cargo/cosmic-text@0.19.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/cosmic-text@0.19.0/LICENSE-MIT +21 -0
- package/third-party/cargo/crc32fast@1.5.0/Cargo.toml +68 -0
- package/third-party/cargo/crc32fast@1.5.0/LICENSE-APACHE +202 -0
- package/third-party/cargo/crc32fast@1.5.0/LICENSE-MIT +21 -0
- package/third-party/cargo/data-url@0.3.2/Cargo.toml +63 -0
- package/third-party/cargo/data-url@0.3.2/LICENSE-APACHE +201 -0
- package/third-party/cargo/data-url@0.3.2/LICENSE-MIT +25 -0
- package/third-party/cargo/dispatch2@0.3.1/Cargo.toml +122 -0
- package/third-party/cargo/dispatch2@0.3.1/MIT-terms.txt +22 -0
- package/third-party/cargo/dispatch2@0.3.1/madsmtm-objc2-8852b424193c-LICENSE.md +34 -0
- package/third-party/cargo/dlib@0.5.3/Cargo.toml +43 -0
- package/third-party/cargo/dlib@0.5.3/LICENSE.txt +19 -0
- package/third-party/cargo/document-features@0.2.12/Cargo.toml +51 -0
- package/third-party/cargo/document-features@0.2.12/LICENSE-APACHE +73 -0
- package/third-party/cargo/document-features@0.2.12/LICENSE-MIT +19 -0
- package/third-party/cargo/equivalent@1.0.2/Cargo.toml +37 -0
- package/third-party/cargo/equivalent@1.0.2/LICENSE-APACHE +201 -0
- package/third-party/cargo/equivalent@1.0.2/LICENSE-MIT +25 -0
- package/third-party/cargo/errno@0.3.14/Cargo.toml +67 -0
- package/third-party/cargo/errno@0.3.14/LICENSE-APACHE +201 -0
- package/third-party/cargo/errno@0.3.14/LICENSE-MIT +25 -0
- package/third-party/cargo/etagere@0.3.0/Cargo.toml +57 -0
- package/third-party/cargo/etagere@0.3.0/LICENSE-APACHE +13 -0
- package/third-party/cargo/etagere@0.3.0/LICENSE-MIT +20 -0
- package/third-party/cargo/euclid@0.22.14/COPYRIGHT +5 -0
- package/third-party/cargo/euclid@0.22.14/Cargo.toml +66 -0
- package/third-party/cargo/euclid@0.22.14/LICENSE-APACHE +201 -0
- package/third-party/cargo/euclid@0.22.14/LICENSE-MIT +25 -0
- package/third-party/cargo/fastrand@2.5.0/Cargo.toml +89 -0
- package/third-party/cargo/fastrand@2.5.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/fastrand@2.5.0/LICENSE-MIT +23 -0
- package/third-party/cargo/fdeflate@0.3.7/Cargo.toml +55 -0
- package/third-party/cargo/fdeflate@0.3.7/LICENSE-APACHE +177 -0
- package/third-party/cargo/fdeflate@0.3.7/LICENSE-MIT +25 -0
- package/third-party/cargo/flate2@1.1.9/Cargo.toml +274 -0
- package/third-party/cargo/flate2@1.1.9/LICENSE-APACHE +201 -0
- package/third-party/cargo/flate2@1.1.9/LICENSE-MIT +25 -0
- package/third-party/cargo/float-cmp@0.9.0/Cargo.toml +39 -0
- package/third-party/cargo/float-cmp@0.9.0/LICENSE +19 -0
- package/third-party/cargo/float_next_after@1.0.0/Cargo.toml +43 -0
- package/third-party/cargo/float_next_after@1.0.0/LICENSE +23 -0
- package/third-party/cargo/foldhash@0.2.0/Cargo.toml +80 -0
- package/third-party/cargo/foldhash@0.2.0/LICENSE +19 -0
- package/third-party/cargo/font-types@0.11.3/Cargo.toml +55 -0
- package/third-party/cargo/font-types@0.11.3/LICENSE-APACHE +67 -0
- package/third-party/cargo/font-types@0.11.3/LICENSE-MIT +25 -0
- package/third-party/cargo/fontdb@0.23.0/Cargo.toml +83 -0
- package/third-party/cargo/fontdb@0.23.0/LICENSE +21 -0
- package/third-party/cargo/futures-core@0.3.32/Cargo.toml +66 -0
- package/third-party/cargo/futures-core@0.3.32/LICENSE-APACHE +202 -0
- package/third-party/cargo/futures-core@0.3.32/LICENSE-MIT +26 -0
- package/third-party/cargo/futures-task@0.3.32/Cargo.toml +58 -0
- package/third-party/cargo/futures-task@0.3.32/LICENSE-APACHE +202 -0
- package/third-party/cargo/futures-task@0.3.32/LICENSE-MIT +26 -0
- package/third-party/cargo/futures-util@0.3.32/Cargo.toml +181 -0
- package/third-party/cargo/futures-util@0.3.32/LICENSE-APACHE +202 -0
- package/third-party/cargo/futures-util@0.3.32/LICENSE-MIT +26 -0
- package/third-party/cargo/getrandom@0.4.3/Cargo.toml +165 -0
- package/third-party/cargo/getrandom@0.4.3/LICENSE-APACHE +201 -0
- package/third-party/cargo/getrandom@0.4.3/LICENSE-MIT +26 -0
- package/third-party/cargo/gif@0.14.2/Cargo.toml +84 -0
- package/third-party/cargo/gif@0.14.2/LICENSE-APACHE +201 -0
- package/third-party/cargo/gif@0.14.2/LICENSE-MIT +21 -0
- package/third-party/cargo/glam@0.33.2/Cargo.toml +354 -0
- package/third-party/cargo/glam@0.33.2/LICENSE-APACHE +201 -0
- package/third-party/cargo/glam@0.33.2/LICENSE-MIT +23 -0
- package/third-party/cargo/glow@0.17.0/Cargo.toml +122 -0
- package/third-party/cargo/glow@0.17.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/glow@0.17.0/LICENSE-MIT +23 -0
- package/third-party/cargo/glow@0.17.0/LICENSE-ZLIB +15 -0
- package/third-party/cargo/gltf-derive@1.4.1/Cargo.toml +34 -0
- package/third-party/cargo/gltf-derive@1.4.1/LICENSE-APACHE +202 -0
- package/third-party/cargo/gltf-derive@1.4.1/LICENSE-MIT +26 -0
- package/third-party/cargo/gltf-json@1.4.1/Cargo.toml +50 -0
- package/third-party/cargo/gltf-json@1.4.1/LICENSE-APACHE +202 -0
- package/third-party/cargo/gltf-json@1.4.1/LICENSE-MIT +26 -0
- package/third-party/cargo/gltf@1.4.1/Cargo.toml +122 -0
- package/third-party/cargo/gltf@1.4.1/LICENSE-APACHE +202 -0
- package/third-party/cargo/gltf@1.4.1/LICENSE-MIT +26 -0
- package/third-party/cargo/glyphon@0.12.0/Cargo.toml +35 -0
- package/third-party/cargo/glyphon@0.12.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/glyphon@0.12.0/LICENSE-MIT +23 -0
- package/third-party/cargo/glyphon@0.12.0/LICENSE-ZLIB +15 -0
- package/third-party/cargo/gpu-allocator@0.28.0/Cargo.toml +180 -0
- package/third-party/cargo/gpu-allocator@0.28.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/gpu-allocator@0.28.0/LICENSE-MIT +7 -0
- package/third-party/cargo/grid@1.0.1/Cargo.toml +77 -0
- package/third-party/cargo/grid@1.0.1/LICENSE +21 -0
- package/third-party/cargo/half@2.7.1/Cargo.toml +137 -0
- package/third-party/cargo/half@2.7.1/LICENSE-APACHE +176 -0
- package/third-party/cargo/half@2.7.1/LICENSE-MIT +19 -0
- package/third-party/cargo/harfrust@0.5.2/Cargo.toml +115 -0
- package/third-party/cargo/harfrust@0.5.2/harfbuzz-harfrust-efdae3142ab7-LICENSE +22 -0
- package/third-party/cargo/hashbrown@0.16.1/Cargo.toml +180 -0
- package/third-party/cargo/hashbrown@0.16.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/hashbrown@0.16.1/LICENSE-MIT +25 -0
- package/third-party/cargo/hashbrown@0.17.1/Cargo.toml +201 -0
- package/third-party/cargo/hashbrown@0.17.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/hashbrown@0.17.1/LICENSE-MIT +25 -0
- package/third-party/cargo/httpdate@1.0.3/Cargo.toml +35 -0
- package/third-party/cargo/httpdate@1.0.3/LICENSE-APACHE +201 -0
- package/third-party/cargo/httpdate@1.0.3/LICENSE-MIT +19 -0
- package/third-party/cargo/image-webp@0.2.4/Cargo.toml +63 -0
- package/third-party/cargo/image-webp@0.2.4/LICENSE-APACHE +177 -0
- package/third-party/cargo/image-webp@0.2.4/LICENSE-MIT +25 -0
- package/third-party/cargo/image@0.25.10/Cargo.toml +248 -0
- package/third-party/cargo/image@0.25.10/LICENSE-APACHE +177 -0
- package/third-party/cargo/image@0.25.10/LICENSE-MIT +25 -0
- package/third-party/cargo/imagesize@0.14.0/Cargo.toml +104 -0
- package/third-party/cargo/imagesize@0.14.0/LICENSE +21 -0
- package/third-party/cargo/indexmap@2.14.0/Cargo.toml +167 -0
- package/third-party/cargo/indexmap@2.14.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/indexmap@2.14.0/LICENSE-MIT +25 -0
- package/third-party/cargo/inflections@1.1.1/Cargo.toml +21 -0
- package/third-party/cargo/inflections@1.1.1/LICENSE +20 -0
- package/third-party/cargo/itoa@1.0.18/Cargo.toml +66 -0
- package/third-party/cargo/itoa@1.0.18/LICENSE-APACHE +176 -0
- package/third-party/cargo/itoa@1.0.18/LICENSE-MIT +23 -0
- package/third-party/cargo/js-sys@0.3.103/Cargo.toml +98 -0
- package/third-party/cargo/js-sys@0.3.103/LICENSE-APACHE +201 -0
- package/third-party/cargo/js-sys@0.3.103/LICENSE-MIT +25 -0
- package/third-party/cargo/khronos-egl@6.0.0/Cargo.toml +82 -0
- package/third-party/cargo/khronos-egl@6.0.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/khronos-egl@6.0.0/LICENSE-MIT +23 -0
- package/third-party/cargo/kurbo@0.13.1/Cargo.toml +230 -0
- package/third-party/cargo/kurbo@0.13.1/LICENSE-APACHE +202 -0
- package/third-party/cargo/kurbo@0.13.1/LICENSE-MIT +25 -0
- package/third-party/cargo/lazy_static@1.5.0/Cargo.toml +46 -0
- package/third-party/cargo/lazy_static@1.5.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/lazy_static@1.5.0/LICENSE-MIT +25 -0
- package/third-party/cargo/libc@0.2.186/Cargo.toml +229 -0
- package/third-party/cargo/libc@0.2.186/LICENSE-APACHE +176 -0
- package/third-party/cargo/libc@0.2.186/LICENSE-MIT +25 -0
- package/third-party/cargo/libloading@0.8.9/Cargo.toml +90 -0
- package/third-party/cargo/libloading@0.8.9/LICENSE +12 -0
- package/third-party/cargo/libm@0.2.16/Cargo.toml +61 -0
- package/third-party/cargo/libm@0.2.16/LICENSE.txt +258 -0
- package/third-party/cargo/linebender_resource_handle@0.1.1/Cargo.toml +107 -0
- package/third-party/cargo/linebender_resource_handle@0.1.1/LICENSE-APACHE +176 -0
- package/third-party/cargo/linebender_resource_handle@0.1.1/LICENSE-MIT +19 -0
- package/third-party/cargo/litrs@1.0.0/Cargo.toml +63 -0
- package/third-party/cargo/litrs@1.0.0/LICENSE-APACHE +176 -0
- package/third-party/cargo/litrs@1.0.0/LICENSE-MIT +25 -0
- package/third-party/cargo/lock_api@0.4.14/Cargo.toml +68 -0
- package/third-party/cargo/lock_api@0.4.14/LICENSE-APACHE +201 -0
- package/third-party/cargo/lock_api@0.4.14/LICENSE-MIT +25 -0
- package/third-party/cargo/log@0.4.33/Cargo.toml +152 -0
- package/third-party/cargo/log@0.4.33/LICENSE-APACHE +201 -0
- package/third-party/cargo/log@0.4.33/LICENSE-MIT +25 -0
- package/third-party/cargo/lru@0.16.4/Cargo.toml +47 -0
- package/third-party/cargo/lru@0.16.4/LICENSE +21 -0
- package/third-party/cargo/lyon_geom@1.0.19/Cargo.toml +69 -0
- package/third-party/cargo/lyon_geom@1.0.19/nical-lyon-56219c95c658-LICENSE-APACHE +13 -0
- package/third-party/cargo/lyon_geom@1.0.19/nical-lyon-56219c95c658-LICENSE-MIT +20 -0
- package/third-party/cargo/lyon_path@1.0.19/Cargo.toml +58 -0
- package/third-party/cargo/lyon_path@1.0.19/nical-lyon-56219c95c658-LICENSE-APACHE +13 -0
- package/third-party/cargo/lyon_path@1.0.19/nical-lyon-56219c95c658-LICENSE-MIT +20 -0
- package/third-party/cargo/lyon_tessellation@1.0.20/Cargo.toml +71 -0
- package/third-party/cargo/lyon_tessellation@1.0.20/nical-lyon-7fa75ea8eea3-LICENSE-APACHE +13 -0
- package/third-party/cargo/lyon_tessellation@1.0.20/nical-lyon-7fa75ea8eea3-LICENSE-MIT +20 -0
- package/third-party/cargo/memchr@2.8.3/COPYING +3 -0
- package/third-party/cargo/memchr@2.8.3/Cargo.toml +89 -0
- package/third-party/cargo/memchr@2.8.3/LICENSE-MIT +21 -0
- package/third-party/cargo/memchr@2.8.3/UNLICENSE +24 -0
- package/third-party/cargo/memmap2@0.9.11/Cargo.toml +59 -0
- package/third-party/cargo/memmap2@0.9.11/LICENSE-APACHE +201 -0
- package/third-party/cargo/memmap2@0.9.11/LICENSE-MIT +26 -0
- package/third-party/cargo/miniz_oxide@0.8.9/Cargo.toml +91 -0
- package/third-party/cargo/miniz_oxide@0.8.9/LICENSE +25 -0
- package/third-party/cargo/miniz_oxide@0.8.9/LICENSE-APACHE.md +177 -0
- package/third-party/cargo/miniz_oxide@0.8.9/LICENSE-MIT.md +24 -0
- package/third-party/cargo/miniz_oxide@0.8.9/LICENSE-ZLIB.md +14 -0
- package/third-party/cargo/moxcms@0.8.1/Cargo.toml +113 -0
- package/third-party/cargo/moxcms@0.8.1/LICENSE-APACHE.md +201 -0
- package/third-party/cargo/moxcms@0.8.1/LICENSE.md +26 -0
- package/third-party/cargo/naga-types@30.0.0/Cargo.toml +94 -0
- package/third-party/cargo/naga-types@30.0.0/LICENSE.APACHE +176 -0
- package/third-party/cargo/naga-types@30.0.0/LICENSE.MIT +21 -0
- package/third-party/cargo/naga@30.0.0/Cargo.toml +246 -0
- package/third-party/cargo/naga@30.0.0/LICENSE.APACHE +176 -0
- package/third-party/cargo/naga@30.0.0/LICENSE.MIT +21 -0
- package/third-party/cargo/num-traits@0.2.19/Cargo.toml +54 -0
- package/third-party/cargo/num-traits@0.2.19/LICENSE-APACHE +201 -0
- package/third-party/cargo/num-traits@0.2.19/LICENSE-MIT +25 -0
- package/third-party/cargo/objc2-core-foundation@0.3.2/Cargo.toml +221 -0
- package/third-party/cargo/objc2-core-foundation@0.3.2/MIT-terms.txt +22 -0
- package/third-party/cargo/objc2-core-foundation@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
- package/third-party/cargo/objc2-core-graphics@0.3.2/Cargo.toml +331 -0
- package/third-party/cargo/objc2-core-graphics@0.3.2/MIT-terms.txt +22 -0
- package/third-party/cargo/objc2-core-graphics@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
- package/third-party/cargo/objc2-encode@4.1.0/Cargo.toml +81 -0
- package/third-party/cargo/objc2-encode@4.1.0/MIT-terms.txt +22 -0
- package/third-party/cargo/objc2-encode@4.1.0/madsmtm-objc2-8d214f547736-LICENSE.md +34 -0
- package/third-party/cargo/objc2-foundation@0.3.2/Cargo.toml +529 -0
- package/third-party/cargo/objc2-foundation@0.3.2/MIT-terms.txt +22 -0
- package/third-party/cargo/objc2-foundation@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
- package/third-party/cargo/objc2-io-surface@0.3.2/Cargo.toml +139 -0
- package/third-party/cargo/objc2-io-surface@0.3.2/MIT-terms.txt +22 -0
- package/third-party/cargo/objc2-io-surface@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
- package/third-party/cargo/objc2-metal@0.3.2/Cargo.toml +601 -0
- package/third-party/cargo/objc2-metal@0.3.2/MIT-terms.txt +22 -0
- package/third-party/cargo/objc2-metal@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
- package/third-party/cargo/objc2-quartz-core@0.3.2/Cargo.toml +302 -0
- package/third-party/cargo/objc2-quartz-core@0.3.2/MIT-terms.txt +22 -0
- package/third-party/cargo/objc2-quartz-core@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
- package/third-party/cargo/objc2@0.6.4/Cargo.toml +232 -0
- package/third-party/cargo/objc2@0.6.4/MIT-terms.txt +22 -0
- package/third-party/cargo/objc2@0.6.4/madsmtm-objc2-8852b424193c-LICENSE.md +34 -0
- package/third-party/cargo/once_cell@1.21.4/Cargo.toml +119 -0
- package/third-party/cargo/once_cell@1.21.4/LICENSE-APACHE +201 -0
- package/third-party/cargo/once_cell@1.21.4/LICENSE-MIT +23 -0
- package/third-party/cargo/ordered-float@5.3.0/Cargo.toml +162 -0
- package/third-party/cargo/ordered-float@5.3.0/LICENSE-MIT +25 -0
- package/third-party/cargo/parking_lot@0.12.5/Cargo.toml +87 -0
- package/third-party/cargo/parking_lot@0.12.5/LICENSE-APACHE +201 -0
- package/third-party/cargo/parking_lot@0.12.5/LICENSE-MIT +25 -0
- package/third-party/cargo/parking_lot_core@0.9.12/Cargo.toml +72 -0
- package/third-party/cargo/parking_lot_core@0.9.12/LICENSE-APACHE +201 -0
- package/third-party/cargo/parking_lot_core@0.9.12/LICENSE-MIT +25 -0
- package/third-party/cargo/pico-args@0.5.0/Cargo.toml +32 -0
- package/third-party/cargo/pico-args@0.5.0/LICENSE +20 -0
- package/third-party/cargo/pin-project-lite@0.2.17/Cargo.toml +198 -0
- package/third-party/cargo/pin-project-lite@0.2.17/LICENSE-APACHE +177 -0
- package/third-party/cargo/pin-project-lite@0.2.17/LICENSE-MIT +23 -0
- package/third-party/cargo/pkg-config@0.3.33/Cargo.toml +43 -0
- package/third-party/cargo/pkg-config@0.3.33/LICENSE-APACHE +201 -0
- package/third-party/cargo/pkg-config@0.3.33/LICENSE-MIT +25 -0
- package/third-party/cargo/png@0.18.1/Cargo.toml +130 -0
- package/third-party/cargo/png@0.18.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/png@0.18.1/LICENSE-MIT +25 -0
- package/third-party/cargo/pollster@0.4.0/Cargo.toml +53 -0
- package/third-party/cargo/pollster@0.4.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/pollster@0.4.0/LICENSE-MIT +25 -0
- package/third-party/cargo/polycool@0.4.0/Cargo.toml +83 -0
- package/third-party/cargo/polycool@0.4.0/LICENSE-APACHE +202 -0
- package/third-party/cargo/polycool@0.4.0/LICENSE-MIT +25 -0
- package/third-party/cargo/pp-rs@0.2.1/Cargo.toml +23 -0
- package/third-party/cargo/pp-rs@0.2.1/LICENSE +29 -0
- package/third-party/cargo/presser@0.3.1/Cargo.toml +58 -0
- package/third-party/cargo/presser@0.3.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/presser@0.3.1/LICENSE-MIT +25 -0
- package/third-party/cargo/proc-macro2@1.0.106/Cargo.toml +105 -0
- package/third-party/cargo/proc-macro2@1.0.106/LICENSE-APACHE +176 -0
- package/third-party/cargo/proc-macro2@1.0.106/LICENSE-MIT +23 -0
- package/third-party/cargo/profiling@1.0.18/Cargo.toml +96 -0
- package/third-party/cargo/profiling@1.0.18/aclysma-profiling-8271551172eb-LICENSE-APACHE +201 -0
- package/third-party/cargo/profiling@1.0.18/aclysma-profiling-8271551172eb-LICENSE-MIT +21 -0
- package/third-party/cargo/pxfm@0.1.30/Cargo.toml +53 -0
- package/third-party/cargo/pxfm@0.1.30/LICENSE-APACHE.md +201 -0
- package/third-party/cargo/pxfm@0.1.30/LICENSE.md +26 -0
- package/third-party/cargo/quick-error@2.0.1/Cargo.toml +24 -0
- package/third-party/cargo/quick-error@2.0.1/LICENSE-APACHE +202 -0
- package/third-party/cargo/quick-error@2.0.1/LICENSE-MIT +19 -0
- package/third-party/cargo/quote@1.0.46/Cargo.toml +70 -0
- package/third-party/cargo/quote@1.0.46/LICENSE-APACHE +176 -0
- package/third-party/cargo/quote@1.0.46/LICENSE-MIT +23 -0
- package/third-party/cargo/rangemap@1.7.1/Cargo.toml +91 -0
- package/third-party/cargo/rangemap@1.7.1/LICENSE-APACHE +191 -0
- package/third-party/cargo/rangemap@1.7.1/LICENSE-MIT +7 -0
- package/third-party/cargo/raw-window-handle@0.6.2/Cargo.toml +56 -0
- package/third-party/cargo/raw-window-handle@0.6.2/LICENSE-APACHE.md +177 -0
- package/third-party/cargo/raw-window-handle@0.6.2/LICENSE-MIT.md +21 -0
- package/third-party/cargo/raw-window-handle@0.6.2/LICENSE-ZLIB.md +11 -0
- package/third-party/cargo/raw-window-metal@1.1.0/Cargo.toml +111 -0
- package/third-party/cargo/raw-window-metal@1.1.0/LICENSE-APACHE +202 -0
- package/third-party/cargo/raw-window-metal@1.1.0/LICENSE-MIT +17 -0
- package/third-party/cargo/read-fonts@0.37.0/Cargo.toml +95 -0
- package/third-party/cargo/read-fonts@0.37.0/LICENSE-APACHE +67 -0
- package/third-party/cargo/read-fonts@0.37.0/LICENSE-MIT +25 -0
- package/third-party/cargo/read-fonts@0.39.2/Cargo.toml +96 -0
- package/third-party/cargo/read-fonts@0.39.2/LICENSE-APACHE +67 -0
- package/third-party/cargo/read-fonts@0.39.2/LICENSE-MIT +25 -0
- package/third-party/cargo/renderdoc-sys@1.1.0/Cargo.toml +39 -0
- package/third-party/cargo/renderdoc-sys@1.1.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/renderdoc-sys@1.1.0/LICENSE-MIT +25 -0
- package/third-party/cargo/resvg@0.47.0/Cargo.toml +112 -0
- package/third-party/cargo/resvg@0.47.0/LICENSE-APACHE +176 -0
- package/third-party/cargo/resvg@0.47.0/LICENSE-MIT +25 -0
- package/third-party/cargo/rgb@0.8.53/Cargo.toml +110 -0
- package/third-party/cargo/rgb@0.8.53/LICENSE +21 -0
- package/third-party/cargo/roxmltree@0.21.1/Cargo.toml +75 -0
- package/third-party/cargo/roxmltree@0.21.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/roxmltree@0.21.1/LICENSE-MIT +21 -0
- package/third-party/cargo/rustc-hash@1.1.0/Cargo.toml +25 -0
- package/third-party/cargo/rustc-hash@1.1.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/rustc-hash@1.1.0/LICENSE-MIT +23 -0
- package/third-party/cargo/rustc-hash@2.1.3/Cargo.toml +50 -0
- package/third-party/cargo/rustc-hash@2.1.3/LICENSE-APACHE +176 -0
- package/third-party/cargo/rustc-hash@2.1.3/LICENSE-MIT +23 -0
- package/third-party/cargo/rustix@1.1.4/COPYRIGHT +29 -0
- package/third-party/cargo/rustix@1.1.4/Cargo.toml +292 -0
- package/third-party/cargo/rustix@1.1.4/LICENSE-APACHE +201 -0
- package/third-party/cargo/rustix@1.1.4/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
- package/third-party/cargo/rustix@1.1.4/LICENSE-MIT +23 -0
- package/third-party/cargo/rustversion@1.0.23/Cargo.toml +69 -0
- package/third-party/cargo/rustversion@1.0.23/LICENSE-APACHE +176 -0
- package/third-party/cargo/rustversion@1.0.23/LICENSE-MIT +23 -0
- package/third-party/cargo/rustybuzz@0.20.1/Cargo.toml +110 -0
- package/third-party/cargo/rustybuzz@0.20.1/LICENSE +22 -0
- package/third-party/cargo/scopeguard@1.2.0/Cargo.toml +43 -0
- package/third-party/cargo/scopeguard@1.2.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/scopeguard@1.2.0/LICENSE-MIT +25 -0
- package/third-party/cargo/self_cell@1.2.2/Cargo.toml +33 -0
- package/third-party/cargo/self_cell@1.2.2/LICENSE-APACHE +201 -0
- package/third-party/cargo/self_cell@1.2.2/LICENSE-GPLv2 +339 -0
- package/third-party/cargo/self_cell@1.3.0/Cargo.toml +33 -0
- package/third-party/cargo/self_cell@1.3.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/self_cell@1.3.0/LICENSE-GPLv2 +339 -0
- package/third-party/cargo/serde@1.0.228/Cargo.toml +84 -0
- package/third-party/cargo/serde@1.0.228/LICENSE-APACHE +176 -0
- package/third-party/cargo/serde@1.0.228/LICENSE-MIT +23 -0
- package/third-party/cargo/serde_core@1.0.228/Cargo.toml +87 -0
- package/third-party/cargo/serde_core@1.0.228/LICENSE-APACHE +176 -0
- package/third-party/cargo/serde_core@1.0.228/LICENSE-MIT +23 -0
- package/third-party/cargo/serde_derive@1.0.228/Cargo.toml +87 -0
- package/third-party/cargo/serde_derive@1.0.228/LICENSE-APACHE +176 -0
- package/third-party/cargo/serde_derive@1.0.228/LICENSE-MIT +23 -0
- package/third-party/cargo/serde_json@1.0.150/Cargo.toml +162 -0
- package/third-party/cargo/serde_json@1.0.150/LICENSE-APACHE +176 -0
- package/third-party/cargo/serde_json@1.0.150/LICENSE-MIT +23 -0
- package/third-party/cargo/simd-adler32@0.3.10/Cargo.toml +68 -0
- package/third-party/cargo/simd-adler32@0.3.10/LICENSE.md +21 -0
- package/third-party/cargo/simplecss@0.2.2/Cargo.toml +146 -0
- package/third-party/cargo/simplecss@0.2.2/LICENSE-APACHE +201 -0
- package/third-party/cargo/simplecss@0.2.2/LICENSE-MIT +21 -0
- package/third-party/cargo/siphasher@1.0.3/COPYING +7 -0
- package/third-party/cargo/siphasher@1.0.3/Cargo.toml +64 -0
- package/third-party/cargo/skrifa@0.40.0/Cargo.toml +86 -0
- package/third-party/cargo/skrifa@0.40.0/LICENSE-APACHE +67 -0
- package/third-party/cargo/skrifa@0.40.0/LICENSE-MIT +25 -0
- package/third-party/cargo/skrifa@0.42.1/Cargo.toml +86 -0
- package/third-party/cargo/skrifa@0.42.1/LICENSE-APACHE +67 -0
- package/third-party/cargo/skrifa@0.42.1/LICENSE-MIT +25 -0
- package/third-party/cargo/slab@0.4.12/Cargo.toml +67 -0
- package/third-party/cargo/slab@0.4.12/LICENSE +25 -0
- package/third-party/cargo/slotmap@1.1.1/Cargo.toml +83 -0
- package/third-party/cargo/slotmap@1.1.1/LICENSE +19 -0
- package/third-party/cargo/smallvec@1.15.2/Cargo.toml +103 -0
- package/third-party/cargo/smallvec@1.15.2/LICENSE-APACHE +201 -0
- package/third-party/cargo/smallvec@1.15.2/LICENSE-MIT +25 -0
- package/third-party/cargo/smol_str@0.3.6/Cargo.toml +155 -0
- package/third-party/cargo/smol_str@0.3.6/LICENSE-APACHE +201 -0
- package/third-party/cargo/smol_str@0.3.6/LICENSE-MIT +23 -0
- package/third-party/cargo/spirv@0.4.0+sdk-1.4.341.0/Cargo.toml +56 -0
- package/third-party/cargo/spirv@0.4.0+sdk-1.4.341.0/gfx-rs-rspirv-8afc3d0ac8e1-LICENSE +202 -0
- package/third-party/cargo/static_assertions@1.1.0/Cargo.toml +39 -0
- package/third-party/cargo/static_assertions@1.1.0/LICENSE-APACHE +202 -0
- package/third-party/cargo/static_assertions@1.1.0/LICENSE-MIT +21 -0
- package/third-party/cargo/strict-num@0.1.1/Cargo.toml +35 -0
- package/third-party/cargo/strict-num@0.1.1/LICENSE +19 -0
- package/third-party/cargo/svgtypes@0.16.1/Cargo.toml +57 -0
- package/third-party/cargo/svgtypes@0.16.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/svgtypes@0.16.1/LICENSE-MIT +20 -0
- package/third-party/cargo/swash@0.2.9/Cargo.toml +93 -0
- package/third-party/cargo/swash@0.2.9/LICENSE-APACHE +201 -0
- package/third-party/cargo/swash@0.2.9/LICENSE-MIT +25 -0
- package/third-party/cargo/syn@2.0.118/Cargo.toml +272 -0
- package/third-party/cargo/syn@2.0.118/LICENSE-APACHE +176 -0
- package/third-party/cargo/syn@2.0.118/LICENSE-MIT +23 -0
- package/third-party/cargo/sys-locale@0.3.2/Cargo.toml +73 -0
- package/third-party/cargo/sys-locale@0.3.2/LICENSE-APACHE +201 -0
- package/third-party/cargo/sys-locale@0.3.2/LICENSE-MIT +21 -0
- package/third-party/cargo/taffy@0.12.1/Cargo.toml +171 -0
- package/third-party/cargo/taffy@0.12.1/DioxusLabs-taffy-1c9e37a0a1cf-LICENSE.md +25 -0
- package/third-party/cargo/tempfile@3.27.0/Cargo.toml +105 -0
- package/third-party/cargo/tempfile@3.27.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/tempfile@3.27.0/LICENSE-MIT +25 -0
- package/third-party/cargo/termcolor@1.4.1/COPYING +3 -0
- package/third-party/cargo/termcolor@1.4.1/Cargo.toml +40 -0
- package/third-party/cargo/termcolor@1.4.1/LICENSE-MIT +21 -0
- package/third-party/cargo/termcolor@1.4.1/UNLICENSE +24 -0
- package/third-party/cargo/thiserror-impl@2.0.18/Cargo.toml +52 -0
- package/third-party/cargo/thiserror-impl@2.0.18/LICENSE-APACHE +176 -0
- package/third-party/cargo/thiserror-impl@2.0.18/LICENSE-MIT +23 -0
- package/third-party/cargo/thiserror@2.0.18/Cargo.toml +119 -0
- package/third-party/cargo/thiserror@2.0.18/LICENSE-APACHE +176 -0
- package/third-party/cargo/thiserror@2.0.18/LICENSE-MIT +23 -0
- package/third-party/cargo/tiny-skia-path@0.12.0/Cargo.toml +58 -0
- package/third-party/cargo/tiny-skia-path@0.12.0/LICENSE +30 -0
- package/third-party/cargo/tiny-skia@0.12.0/Cargo.toml +116 -0
- package/third-party/cargo/tiny-skia@0.12.0/LICENSE +30 -0
- package/third-party/cargo/tiny_http@0.12.0/Cargo.toml +82 -0
- package/third-party/cargo/tiny_http@0.12.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/tiny_http@0.12.0/LICENSE-MIT +25 -0
- package/third-party/cargo/tinyvec@1.12.0/Cargo.toml +184 -0
- package/third-party/cargo/tinyvec@1.12.0/LICENSE-APACHE.md +202 -0
- package/third-party/cargo/tinyvec@1.12.0/LICENSE-MIT.md +5 -0
- package/third-party/cargo/tinyvec@1.12.0/LICENSE-ZLIB.md +11 -0
- package/third-party/cargo/tinyvec_macros@0.1.1/Cargo.toml +19 -0
- package/third-party/cargo/tinyvec_macros@0.1.1/LICENSE-APACHE.md +202 -0
- package/third-party/cargo/tinyvec_macros@0.1.1/LICENSE-MIT.md +21 -0
- package/third-party/cargo/tinyvec_macros@0.1.1/LICENSE-ZLIB.md +20 -0
- package/third-party/cargo/ttf-parser@0.25.1/Cargo.toml +101 -0
- package/third-party/cargo/ttf-parser@0.25.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/ttf-parser@0.25.1/LICENSE-MIT +20 -0
- package/third-party/cargo/unicode-bidi-mirroring@0.4.0/Cargo.toml +22 -0
- package/third-party/cargo/unicode-bidi-mirroring@0.4.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/unicode-bidi-mirroring@0.4.0/LICENSE-MIT +21 -0
- package/third-party/cargo/unicode-bidi@0.3.18/COPYRIGHT +8 -0
- package/third-party/cargo/unicode-bidi@0.3.18/Cargo.toml +90 -0
- package/third-party/cargo/unicode-bidi@0.3.18/LICENSE-APACHE +201 -0
- package/third-party/cargo/unicode-bidi@0.3.18/LICENSE-MIT +25 -0
- package/third-party/cargo/unicode-ccc@0.4.0/Cargo.toml +22 -0
- package/third-party/cargo/unicode-ccc@0.4.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/unicode-ccc@0.4.0/LICENSE-MIT +21 -0
- package/third-party/cargo/unicode-ident@1.0.24/Cargo.toml +84 -0
- package/third-party/cargo/unicode-ident@1.0.24/LICENSE-APACHE +176 -0
- package/third-party/cargo/unicode-ident@1.0.24/LICENSE-MIT +23 -0
- package/third-party/cargo/unicode-ident@1.0.24/LICENSE-UNICODE +39 -0
- package/third-party/cargo/unicode-linebreak@0.1.5/Cargo.toml +32 -0
- package/third-party/cargo/unicode-linebreak@0.1.5/LICENSE +201 -0
- package/third-party/cargo/unicode-properties@0.1.4/COPYRIGHT +7 -0
- package/third-party/cargo/unicode-properties@0.1.4/Cargo.toml +65 -0
- package/third-party/cargo/unicode-properties@0.1.4/LICENSE-APACHE +201 -0
- package/third-party/cargo/unicode-properties@0.1.4/LICENSE-MIT +25 -0
- package/third-party/cargo/unicode-script@0.5.8/Cargo.toml +63 -0
- package/third-party/cargo/unicode-script@0.5.8/LICENSE-APACHE +201 -0
- package/third-party/cargo/unicode-script@0.5.8/LICENSE-MIT +27 -0
- package/third-party/cargo/unicode-segmentation@1.13.3/COPYRIGHT +7 -0
- package/third-party/cargo/unicode-segmentation@1.13.3/Cargo.toml +91 -0
- package/third-party/cargo/unicode-segmentation@1.13.3/LICENSE-APACHE +201 -0
- package/third-party/cargo/unicode-segmentation@1.13.3/LICENSE-MIT +25 -0
- package/third-party/cargo/unicode-vo@0.1.0/Cargo.toml +22 -0
- package/third-party/cargo/unicode-vo@0.1.0/LICENSE-APACHE +201 -0
- package/third-party/cargo/unicode-vo@0.1.0/LICENSE-MIT +21 -0
- package/third-party/cargo/unicode-width@0.2.2/COPYRIGHT +7 -0
- package/third-party/cargo/unicode-width@0.2.2/Cargo.toml +77 -0
- package/third-party/cargo/unicode-width@0.2.2/LICENSE-APACHE +201 -0
- package/third-party/cargo/unicode-width@0.2.2/LICENSE-MIT +25 -0
- package/third-party/cargo/unicode-xid@0.2.6/COPYRIGHT +7 -0
- package/third-party/cargo/unicode-xid@0.2.6/Cargo.toml +65 -0
- package/third-party/cargo/unicode-xid@0.2.6/LICENSE-APACHE +201 -0
- package/third-party/cargo/unicode-xid@0.2.6/LICENSE-MIT +25 -0
- package/third-party/cargo/urlencoding@2.1.3/Cargo.toml +41 -0
- package/third-party/cargo/urlencoding@2.1.3/LICENSE +20 -0
- package/third-party/cargo/usvg@0.47.0/Cargo.toml +138 -0
- package/third-party/cargo/usvg@0.47.0/LICENSE-APACHE +176 -0
- package/third-party/cargo/usvg@0.47.0/LICENSE-MIT +25 -0
- package/third-party/cargo/version_check@0.9.5/Cargo.toml +38 -0
- package/third-party/cargo/version_check@0.9.5/LICENSE-APACHE +201 -0
- package/third-party/cargo/version_check@0.9.5/LICENSE-MIT +19 -0
- package/third-party/cargo/wasm-bindgen-futures@0.4.76/Cargo.toml +88 -0
- package/third-party/cargo/wasm-bindgen-futures@0.4.76/LICENSE-APACHE +201 -0
- package/third-party/cargo/wasm-bindgen-futures@0.4.76/LICENSE-MIT +25 -0
- package/third-party/cargo/wasm-bindgen-macro-support@0.2.126/Cargo.toml +83 -0
- package/third-party/cargo/wasm-bindgen-macro-support@0.2.126/LICENSE-APACHE +201 -0
- package/third-party/cargo/wasm-bindgen-macro-support@0.2.126/LICENSE-MIT +25 -0
- package/third-party/cargo/wasm-bindgen-macro@0.2.126/Cargo.toml +73 -0
- package/third-party/cargo/wasm-bindgen-macro@0.2.126/LICENSE-APACHE +201 -0
- package/third-party/cargo/wasm-bindgen-macro@0.2.126/LICENSE-MIT +25 -0
- package/third-party/cargo/wasm-bindgen-shared@0.2.126/Cargo.toml +66 -0
- package/third-party/cargo/wasm-bindgen-shared@0.2.126/LICENSE-APACHE +201 -0
- package/third-party/cargo/wasm-bindgen-shared@0.2.126/LICENSE-MIT +25 -0
- package/third-party/cargo/wasm-bindgen@0.2.126/Cargo.toml +122 -0
- package/third-party/cargo/wasm-bindgen@0.2.126/LICENSE-APACHE +201 -0
- package/third-party/cargo/wasm-bindgen@0.2.126/LICENSE-MIT +25 -0
- package/third-party/cargo/wayland-sys@0.31.11/Cargo.toml +81 -0
- package/third-party/cargo/wayland-sys@0.31.11/LICENSE.txt +19 -0
- package/third-party/cargo/web-sys@0.3.103/Cargo.toml +2823 -0
- package/third-party/cargo/web-sys@0.3.103/LICENSE-APACHE +201 -0
- package/third-party/cargo/web-sys@0.3.103/LICENSE-MIT +25 -0
- package/third-party/cargo/weezl@0.1.12/Cargo.toml +120 -0
- package/third-party/cargo/weezl@0.1.12/LICENSE-APACHE +201 -0
- package/third-party/cargo/weezl@0.1.12/LICENSE-MIT +22 -0
- package/third-party/cargo/wgpu-core-deps-apple@30.0.0/Cargo.toml +53 -0
- package/third-party/cargo/wgpu-core-deps-apple@30.0.0/LICENSE.APACHE +176 -0
- package/third-party/cargo/wgpu-core-deps-apple@30.0.0/LICENSE.MIT +21 -0
- package/third-party/cargo/wgpu-core@30.0.0/Cargo.toml +237 -0
- package/third-party/cargo/wgpu-core@30.0.0/LICENSE.APACHE +176 -0
- package/third-party/cargo/wgpu-core@30.0.0/LICENSE.MIT +21 -0
- package/third-party/cargo/wgpu-hal@30.0.0/Cargo.toml +541 -0
- package/third-party/cargo/wgpu-hal@30.0.0/LICENSE.APACHE +176 -0
- package/third-party/cargo/wgpu-hal@30.0.0/LICENSE.MIT +21 -0
- package/third-party/cargo/wgpu-naga-bridge@30.0.0/Cargo.toml +46 -0
- package/third-party/cargo/wgpu-naga-bridge@30.0.0/LICENSE.APACHE +176 -0
- package/third-party/cargo/wgpu-naga-bridge@30.0.0/LICENSE.MIT +21 -0
- package/third-party/cargo/wgpu-types@30.0.0/Cargo.toml +161 -0
- package/third-party/cargo/wgpu-types@30.0.0/LICENSE.APACHE +176 -0
- package/third-party/cargo/wgpu-types@30.0.0/LICENSE.MIT +21 -0
- package/third-party/cargo/wgpu@30.0.0/Cargo.toml +278 -0
- package/third-party/cargo/wgpu@30.0.0/LICENSE.APACHE +176 -0
- package/third-party/cargo/wgpu@30.0.0/LICENSE.MIT +21 -0
- package/third-party/cargo/xmlwriter@0.1.0/Cargo.toml +23 -0
- package/third-party/cargo/xmlwriter@0.1.0/LICENSE +21 -0
- package/third-party/cargo/yazi@0.2.1/Cargo.toml +45 -0
- package/third-party/cargo/yazi@0.2.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/yazi@0.2.1/LICENSE-MIT +19 -0
- package/third-party/cargo/zeno@0.3.3/Cargo.toml +65 -0
- package/third-party/cargo/zeno@0.3.3/LICENSE-APACHE +201 -0
- package/third-party/cargo/zeno@0.3.3/LICENSE-MIT +25 -0
- package/third-party/cargo/zerocopy-derive@0.8.54/Cargo.toml +209 -0
- package/third-party/cargo/zerocopy-derive@0.8.54/LICENSE-APACHE +202 -0
- package/third-party/cargo/zerocopy-derive@0.8.54/LICENSE-BSD +24 -0
- package/third-party/cargo/zerocopy-derive@0.8.54/LICENSE-MIT +26 -0
- package/third-party/cargo/zerocopy@0.8.54/Cargo.toml +419 -0
- package/third-party/cargo/zerocopy@0.8.54/LICENSE-APACHE +202 -0
- package/third-party/cargo/zerocopy@0.8.54/LICENSE-BSD +24 -0
- package/third-party/cargo/zerocopy@0.8.54/LICENSE-MIT +26 -0
- package/third-party/cargo/zmij@1.0.23/Cargo.toml +90 -0
- package/third-party/cargo/zmij@1.0.23/LICENSE-MIT +23 -0
- package/third-party/cargo/zune-core@0.5.1/Cargo.toml +47 -0
- package/third-party/cargo/zune-core@0.5.1/LICENSE-APACHE +201 -0
- package/third-party/cargo/zune-core@0.5.1/LICENSE-MIT +21 -0
- package/third-party/cargo/zune-core@0.5.1/LICENSE-ZLIB +19 -0
- package/third-party/cargo/zune-jpeg@0.5.15/Cargo.toml +67 -0
- package/third-party/cargo/zune-jpeg@0.5.15/LICENSE-APACHE +201 -0
- package/third-party/cargo/zune-jpeg@0.5.15/LICENSE-MIT +21 -0
- package/third-party/cargo/zune-jpeg@0.5.15/LICENSE-ZLIB +19 -0
- package/third-party/inventory.json +3614 -0
- package/third-party/npm/@esbuild__darwin-arm64@0.27.4/esbuild-0.27.4-LICENSE.md +21 -0
- package/third-party/npm/@esbuild__darwin-arm64@0.27.4/go-LICENSE +27 -0
- package/third-party/npm/@esbuild__darwin-arm64@0.27.4/golang-x-sys-c0bba94af5f8-LICENSE +27 -0
- package/third-party/npm/@esbuild__darwin-arm64@0.27.4/package.json +20 -0
- package/third-party/npm/@floating-ui__core@1.7.5/LICENSE +20 -0
- package/third-party/npm/@floating-ui__core@1.7.5/package.json +63 -0
- package/third-party/npm/@floating-ui__dom@1.7.6/LICENSE +20 -0
- package/third-party/npm/@floating-ui__dom@1.7.6/package.json +71 -0
- package/third-party/npm/@floating-ui__react-dom@2.1.8/LICENSE +20 -0
- package/third-party/npm/@floating-ui__react-dom@2.1.8/package.json +76 -0
- package/third-party/npm/@floating-ui__utils@0.2.11/LICENSE +20 -0
- package/third-party/npm/@floating-ui__utils@0.2.11/package.json +70 -0
- package/third-party/npm/@radix-ui__primitive@1.1.7/LICENSE +21 -0
- package/third-party/npm/@radix-ui__primitive@1.1.7/package.json +79 -0
- package/third-party/npm/@radix-ui__react-arrow@1.1.15/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-arrow@1.1.15/package.json +68 -0
- package/third-party/npm/@radix-ui__react-collection@1.1.15/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-collection@1.1.15/package.json +71 -0
- package/third-party/npm/@radix-ui__react-compose-refs@1.1.5/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-compose-refs@1.1.5/package.json +60 -0
- package/third-party/npm/@radix-ui__react-context-menu@2.3.7/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-context-menu@2.3.7/package.json +73 -0
- package/third-party/npm/@radix-ui__react-context@1.2.2/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-context@1.2.2/package.json +60 -0
- package/third-party/npm/@radix-ui__react-direction@1.1.4/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-direction@1.1.4/package.json +60 -0
- package/third-party/npm/@radix-ui__react-dismissable-layer@1.1.19/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-dismissable-layer@1.1.19/package.json +74 -0
- package/third-party/npm/@radix-ui__react-focus-guards@1.1.6/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-focus-guards@1.1.6/package.json +60 -0
- package/third-party/npm/@radix-ui__react-focus-scope@1.1.16/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-focus-scope@1.1.16/package.json +71 -0
- package/third-party/npm/@radix-ui__react-id@1.1.4/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-id@1.1.4/package.json +63 -0
- package/third-party/npm/@radix-ui__react-menu@2.1.24/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-menu@2.1.24/package.json +86 -0
- package/third-party/npm/@radix-ui__react-popper@1.3.7/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-popper@1.3.7/package.json +78 -0
- package/third-party/npm/@radix-ui__react-portal@1.1.17/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-portal@1.1.17/package.json +69 -0
- package/third-party/npm/@radix-ui__react-presence@1.1.10/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-presence@1.1.10/package.json +68 -0
- package/third-party/npm/@radix-ui__react-primitive@2.1.10/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-primitive@2.1.10/package.json +68 -0
- package/third-party/npm/@radix-ui__react-roving-focus@1.1.19/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-roving-focus@1.1.19/package.json +78 -0
- package/third-party/npm/@radix-ui__react-slot@1.3.3/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-slot@1.3.3/package.json +63 -0
- package/third-party/npm/@radix-ui__react-use-callback-ref@1.1.4/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-use-callback-ref@1.1.4/package.json +60 -0
- package/third-party/npm/@radix-ui__react-use-controllable-state@1.2.6/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-use-controllable-state@1.2.6/package.json +65 -0
- package/third-party/npm/@radix-ui__react-use-effect-event@0.0.5/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-use-effect-event@0.0.5/package.json +65 -0
- package/third-party/npm/@radix-ui__react-use-is-hydrated@0.1.3/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-use-is-hydrated@0.1.3/package.json +61 -0
- package/third-party/npm/@radix-ui__react-use-layout-effect@1.1.4/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-use-layout-effect@1.1.4/package.json +60 -0
- package/third-party/npm/@radix-ui__react-use-size@1.1.4/LICENSE +21 -0
- package/third-party/npm/@radix-ui__react-use-size@1.1.4/package.json +63 -0
- package/third-party/npm/aria-hidden@1.2.6/LICENSE +21 -0
- package/third-party/npm/aria-hidden@1.2.6/package.json +71 -0
- package/third-party/npm/detect-node-es@1.1.0/LICENSE +21 -0
- package/third-party/npm/detect-node-es@1.1.0/package.json +29 -0
- package/third-party/npm/esbuild@0.27.4/LICENSE.md +21 -0
- package/third-party/npm/esbuild@0.27.4/package.json +49 -0
- package/third-party/npm/fflate@0.8.3/LICENSE +21 -0
- package/third-party/npm/fflate@0.8.3/package.json +128 -0
- package/third-party/npm/get-nonce@1.0.1/LICENSE +21 -0
- package/third-party/npm/get-nonce@1.0.1/package.json +68 -0
- package/third-party/npm/mediabunny@1.52.2/LICENSE +373 -0
- package/third-party/npm/mediabunny@1.52.2/package.json +136 -0
- package/third-party/npm/mediabunny@1.52.2/source/LICENSE +373 -0
- package/third-party/npm/mediabunny@1.52.2/source/package.json +136 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/adts/adts-demuxer.ts +400 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/adts/adts-muxer.ts +124 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/adts/adts-reader.ts +85 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/aes.ts +307 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/codec-data.ts +3178 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/codec.ts +1154 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/conversion.ts +2042 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/custom-coder.ts +212 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/decode.ts +263 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/demuxer.ts +43 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/encode.ts +1412 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/flac/flac-demuxer.ts +813 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/flac/flac-misc.ts +165 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/flac/flac-muxer.ts +350 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-demuxer.ts +995 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-misc.ts +81 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-muxer.ts +1529 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-segmented-input.ts +772 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/id3.ts +972 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/index.ts +319 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/input-format.ts +819 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/input-track.ts +1141 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/input.ts +571 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-boxes.ts +1911 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-demuxer.ts +3953 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-misc.ts +90 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-muxer.ts +1595 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-reader.ts +91 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/logging.ts +120 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/matroska/ebml.ts +770 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/matroska/matroska-demuxer.ts +2598 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/matroska/matroska-misc.ts +29 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/matroska/matroska-muxer.ts +1360 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/media-sink.ts +2589 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/media-source.ts +3041 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/metadata.ts +335 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/misc.ts +1336 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-demuxer.ts +469 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-muxer.ts +169 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-reader.ts +61 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-writer.ts +121 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/mpeg-ts/mpeg-ts-demuxer.ts +2519 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/mpeg-ts/mpeg-ts-misc.ts +32 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/mpeg-ts/mpeg-ts-muxer.ts +842 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/muxer.ts +80 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/node.ts +11 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-demuxer.ts +1087 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-misc.ts +116 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-muxer.ts +527 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-reader.ts +93 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/output-format.ts +1425 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/output.ts +940 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/packet.ts +287 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/pcm.ts +112 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/reader.ts +391 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/resample.ts +287 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/sample.ts +3231 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/segmented-input.ts +575 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/source.ts +2588 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/subtitles.ts +131 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/target.ts +871 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/tsconfig.json +16 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/wave/riff-writer.ts +36 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/wave/wave-demuxer.ts +583 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/wave/wave-muxer.ts +375 -0
- package/third-party/npm/mediabunny@1.52.2/source/src/writer.ts +128 -0
- package/third-party/npm/react-dom@19.3.0/LICENSE +21 -0
- package/third-party/npm/react-dom@19.3.0/package.json +117 -0
- package/third-party/npm/react-remove-scroll-bar@2.3.8/package.json +85 -0
- package/third-party/npm/react-remove-scroll-bar@2.3.8/react-remove-scroll-bar-LICENSE +21 -0
- package/third-party/npm/react-remove-scroll@2.7.2/LICENSE +21 -0
- package/third-party/npm/react-remove-scroll@2.7.2/package.json +98 -0
- package/third-party/npm/react-style-singleton@2.2.3/LICENSE +21 -0
- package/third-party/npm/react-style-singleton@2.2.3/package.json +90 -0
- package/third-party/npm/react@19.3.0/LICENSE +21 -0
- package/third-party/npm/react@19.3.0/package.json +51 -0
- package/third-party/npm/scheduler@0.28.0/LICENSE +21 -0
- package/third-party/npm/scheduler@0.28.0/package.json +27 -0
- package/third-party/npm/tslib@2.8.1/LICENSE.txt +12 -0
- package/third-party/npm/tslib@2.8.1/package.json +47 -0
- package/third-party/npm/typescript@5.9.3/LICENSE.txt +55 -0
- package/third-party/npm/typescript@5.9.3/ThirdPartyNoticeText.txt +193 -0
- package/third-party/npm/typescript@5.9.3/package.json +120 -0
- package/third-party/npm/use-callback-ref@1.3.3/LICENSE +21 -0
- package/third-party/npm/use-callback-ref@1.3.3/package.json +85 -0
- package/third-party/npm/use-sidecar@1.1.3/LICENSE +21 -0
- package/third-party/npm/use-sidecar@1.1.3/package.json +93 -0
- package/third-party/packages/render-engine/assets/OFL.txt +93 -0
- package/third-party/packages/studio/public/fonts/OFL.txt +93 -0
- package/third-party/packages/studio/vendor/osmo-icons/LICENSE +21 -0
- package/third-party/packages/studio/vendor/shadcn/LICENSE +21 -0
- package/third-party/repository-notices.md +41 -0
- package/third-party/rust-standard-library/COPYRIGHT-library.html +5556 -0
- package/third-party/rust-standard-library/licenses/Apache-2.0.txt +73 -0
- package/third-party/rust-standard-library/licenses/BSD-2-Clause.txt +9 -0
- package/third-party/rust-standard-library/licenses/CC-BY-SA-4.0.txt +427 -0
- package/third-party/rust-standard-library/licenses/GCC-exception-3.1.txt +30 -0
- package/third-party/rust-standard-library/licenses/GPL-2.0-only.txt +133 -0
- package/third-party/rust-standard-library/licenses/GPL-3.0-or-later.txt +202 -0
- package/third-party/rust-standard-library/licenses/ISC.txt +7 -0
- package/third-party/rust-standard-library/licenses/LLVM-exception.txt +15 -0
- package/third-party/rust-standard-library/licenses/MIT.txt +9 -0
- package/third-party/rust-standard-library/licenses/NCSA.txt +29 -0
- package/third-party/rust-standard-library/licenses/OFL-1.1.txt +43 -0
- package/third-party/rust-standard-library/licenses/Unicode-3.0.txt +39 -0
- package/third-party/rust-standard-library/version.txt +1 -0
- package/vendor/osmo-lite +0 -0
- package/vendor/osmo-scene-0.1.0.tgz +0 -0
- package/vendor/platform.json +1 -0
|
@@ -0,0 +1,3178 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026-present, Vanilagy and contributors
|
|
3
|
+
*
|
|
4
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { AVC_LEVEL_TABLE, VideoCodec, VP9_LEVEL_TABLE } from './codec';
|
|
10
|
+
import {
|
|
11
|
+
assert,
|
|
12
|
+
assertNever,
|
|
13
|
+
base64ToBytes,
|
|
14
|
+
bytesToBase64,
|
|
15
|
+
keyValueIterator,
|
|
16
|
+
getUint24,
|
|
17
|
+
last,
|
|
18
|
+
readExpGolomb,
|
|
19
|
+
readSignedExpGolomb,
|
|
20
|
+
Rational,
|
|
21
|
+
textDecoder,
|
|
22
|
+
textEncoder,
|
|
23
|
+
toDataView,
|
|
24
|
+
toUint8Array,
|
|
25
|
+
getChromiumVersion,
|
|
26
|
+
isChromium,
|
|
27
|
+
setUint24,
|
|
28
|
+
} from './misc';
|
|
29
|
+
import { Logging } from './logging';
|
|
30
|
+
import { PacketType } from './packet';
|
|
31
|
+
import { MetadataTags } from './metadata';
|
|
32
|
+
import { AC3_SAMPLE_RATES, EAC3_REDUCED_SAMPLE_RATES } from '../shared/ac3-misc';
|
|
33
|
+
import { Bitstream } from '../shared/bitstream';
|
|
34
|
+
|
|
35
|
+
// References for AVC/HEVC code:
|
|
36
|
+
// ISO 14496-15
|
|
37
|
+
// Rec. ITU-T H.264
|
|
38
|
+
// Rec. ITU-T H.265
|
|
39
|
+
// https://stackoverflow.com/questions/24884827
|
|
40
|
+
|
|
41
|
+
export enum AvcNalUnitType {
|
|
42
|
+
NON_IDR_SLICE = 1,
|
|
43
|
+
SLICE_DPA = 2,
|
|
44
|
+
SLICE_DPB = 3,
|
|
45
|
+
SLICE_DPC = 4,
|
|
46
|
+
IDR = 5,
|
|
47
|
+
SEI = 6,
|
|
48
|
+
SPS = 7,
|
|
49
|
+
PPS = 8,
|
|
50
|
+
AUD = 9,
|
|
51
|
+
SPS_EXT = 13,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export enum HevcNalUnitType {
|
|
55
|
+
RASL_N = 8,
|
|
56
|
+
RASL_R = 9,
|
|
57
|
+
BLA_W_LP = 16,
|
|
58
|
+
RSV_IRAP_VCL23 = 23,
|
|
59
|
+
VPS_NUT = 32,
|
|
60
|
+
SPS_NUT = 33,
|
|
61
|
+
PPS_NUT = 34,
|
|
62
|
+
AUD_NUT = 35,
|
|
63
|
+
PREFIX_SEI_NUT = 39,
|
|
64
|
+
SUFFIX_SEI_NUT = 40,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type NalUnitLocation = {
|
|
68
|
+
offset: number;
|
|
69
|
+
length: number;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const iterateNalUnitsInAnnexB = function* (packetData: Uint8Array): Generator<NalUnitLocation> {
|
|
73
|
+
let i = 0;
|
|
74
|
+
let nalStart = -1;
|
|
75
|
+
|
|
76
|
+
while (i < packetData.length - 2) {
|
|
77
|
+
const zeroIndex = packetData.indexOf(0, i);
|
|
78
|
+
if (zeroIndex === -1 || zeroIndex >= packetData.length - 2) {
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
i = zeroIndex;
|
|
82
|
+
|
|
83
|
+
let startCodeLength = 0;
|
|
84
|
+
|
|
85
|
+
// Check for 4-byte start code (0x00000001)
|
|
86
|
+
if (
|
|
87
|
+
i + 3 < packetData.length
|
|
88
|
+
&& packetData[i + 1] === 0
|
|
89
|
+
&& packetData[i + 2] === 0
|
|
90
|
+
&& packetData[i + 3] === 1
|
|
91
|
+
) {
|
|
92
|
+
startCodeLength = 4;
|
|
93
|
+
} else if (packetData[i + 1] === 0 && packetData[i + 2] === 1) {
|
|
94
|
+
// Check for 3-byte start code (0x000001)
|
|
95
|
+
startCodeLength = 3;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (startCodeLength === 0) {
|
|
99
|
+
i++;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// If we had a previous NAL unit, yield it
|
|
104
|
+
if (nalStart !== -1 && i > nalStart) {
|
|
105
|
+
yield {
|
|
106
|
+
offset: nalStart,
|
|
107
|
+
length: i - nalStart,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
nalStart = i + startCodeLength;
|
|
112
|
+
i = nalStart;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Yield the last NAL unit if there is one
|
|
116
|
+
if (nalStart !== -1 && nalStart < packetData.length) {
|
|
117
|
+
yield {
|
|
118
|
+
offset: nalStart,
|
|
119
|
+
length: packetData.length - nalStart,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const iterateNalUnitsInLengthPrefixed = function* (
|
|
125
|
+
packetData: Uint8Array,
|
|
126
|
+
lengthSize: 1 | 2 | 3 | 4,
|
|
127
|
+
): Generator<NalUnitLocation> {
|
|
128
|
+
let offset = 0;
|
|
129
|
+
const dataView = new DataView(packetData.buffer, packetData.byteOffset, packetData.byteLength);
|
|
130
|
+
|
|
131
|
+
while (offset + lengthSize <= packetData.length) {
|
|
132
|
+
let nalUnitLength: number;
|
|
133
|
+
if (lengthSize === 1) {
|
|
134
|
+
nalUnitLength = dataView.getUint8(offset);
|
|
135
|
+
} else if (lengthSize === 2) {
|
|
136
|
+
nalUnitLength = dataView.getUint16(offset, false);
|
|
137
|
+
} else if (lengthSize === 3) {
|
|
138
|
+
nalUnitLength = getUint24(dataView, offset, false);
|
|
139
|
+
} else {
|
|
140
|
+
assert(lengthSize === 4);
|
|
141
|
+
nalUnitLength = dataView.getUint32(offset, false);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
offset += lengthSize;
|
|
145
|
+
|
|
146
|
+
yield {
|
|
147
|
+
offset,
|
|
148
|
+
length: nalUnitLength,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
offset += nalUnitLength;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export const iterateAvcNalUnits = (packetData: Uint8Array, decoderConfig: VideoDecoderConfig) => {
|
|
156
|
+
if (decoderConfig.description) {
|
|
157
|
+
const bytes = toUint8Array(decoderConfig.description);
|
|
158
|
+
const lengthSizeMinusOne = bytes[4]! & 0b11;
|
|
159
|
+
const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
|
|
160
|
+
|
|
161
|
+
return iterateNalUnitsInLengthPrefixed(packetData, lengthSize);
|
|
162
|
+
} else {
|
|
163
|
+
return iterateNalUnitsInAnnexB(packetData);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export const extractNalUnitTypeForAvc = (byte: number) => {
|
|
168
|
+
return byte & 0x1F;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const removeEmulationPreventionBytes = (data: Uint8Array) => {
|
|
172
|
+
const result: number[] = [];
|
|
173
|
+
const len = data.length;
|
|
174
|
+
|
|
175
|
+
for (let i = 0; i < len; i++) {
|
|
176
|
+
// Look for the 0x000003 pattern
|
|
177
|
+
if (i + 2 < len && data[i] === 0x00 && data[i + 1] === 0x00 && data[i + 2] === 0x03) {
|
|
178
|
+
result.push(0x00, 0x00); // Push the first two bytes
|
|
179
|
+
i += 2; // Skip the 0x03 byte
|
|
180
|
+
} else {
|
|
181
|
+
result.push(data[i]!);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return new Uint8Array(result);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const ANNEX_B_START_CODE = new Uint8Array([0, 0, 0, 1]);
|
|
189
|
+
|
|
190
|
+
export const concatNalUnitsInAnnexB = (nalUnits: Uint8Array[]) => {
|
|
191
|
+
const totalLength = nalUnits.reduce((a, b) => a + ANNEX_B_START_CODE.byteLength + b.byteLength, 0);
|
|
192
|
+
const result = new Uint8Array(totalLength);
|
|
193
|
+
let offset = 0;
|
|
194
|
+
|
|
195
|
+
for (const nalUnit of nalUnits) {
|
|
196
|
+
result.set(ANNEX_B_START_CODE, offset);
|
|
197
|
+
offset += ANNEX_B_START_CODE.byteLength;
|
|
198
|
+
|
|
199
|
+
result.set(nalUnit, offset);
|
|
200
|
+
offset += nalUnit.byteLength;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return result;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
export const concatNalUnitsInLengthPrefixed = (nalUnits: Uint8Array[], lengthSize: 1 | 2 | 3 | 4) => {
|
|
207
|
+
const totalLength = nalUnits.reduce((a, b) => a + lengthSize + b.byteLength, 0);
|
|
208
|
+
const result = new Uint8Array(totalLength);
|
|
209
|
+
let offset = 0;
|
|
210
|
+
|
|
211
|
+
for (const nalUnit of nalUnits) {
|
|
212
|
+
const dataView = new DataView(result.buffer, result.byteOffset, result.byteLength);
|
|
213
|
+
|
|
214
|
+
switch (lengthSize) {
|
|
215
|
+
case 1:
|
|
216
|
+
dataView.setUint8(offset, nalUnit.byteLength);
|
|
217
|
+
break;
|
|
218
|
+
case 2:
|
|
219
|
+
dataView.setUint16(offset, nalUnit.byteLength, false);
|
|
220
|
+
break;
|
|
221
|
+
case 3:
|
|
222
|
+
setUint24(dataView, offset, nalUnit.byteLength, false);
|
|
223
|
+
break;
|
|
224
|
+
case 4:
|
|
225
|
+
dataView.setUint32(offset, nalUnit.byteLength, false);
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
offset += lengthSize;
|
|
230
|
+
|
|
231
|
+
result.set(nalUnit, offset);
|
|
232
|
+
offset += nalUnit.byteLength;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return result;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// Data specified in ISO 14496-15
|
|
239
|
+
export type AvcDecoderConfigurationRecord = {
|
|
240
|
+
configurationVersion: number;
|
|
241
|
+
avcProfileIndication: number;
|
|
242
|
+
profileCompatibility: number;
|
|
243
|
+
avcLevelIndication: number;
|
|
244
|
+
lengthSizeMinusOne: number;
|
|
245
|
+
sequenceParameterSets: Uint8Array[];
|
|
246
|
+
pictureParameterSets: Uint8Array[];
|
|
247
|
+
|
|
248
|
+
// Fields only for specific profiles:
|
|
249
|
+
chromaFormat: number | null;
|
|
250
|
+
bitDepthLumaMinus8: number | null;
|
|
251
|
+
bitDepthChromaMinus8: number | null;
|
|
252
|
+
sequenceParameterSetExt: Uint8Array[] | null;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
export const concatAvcNalUnits = (nalUnits: Uint8Array[], decoderConfig: VideoDecoderConfig) => {
|
|
256
|
+
if (decoderConfig.description) {
|
|
257
|
+
// Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config
|
|
258
|
+
|
|
259
|
+
const bytes = toUint8Array(decoderConfig.description);
|
|
260
|
+
const lengthSizeMinusOne = bytes[4]! & 0b11;
|
|
261
|
+
const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
|
|
262
|
+
|
|
263
|
+
return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize);
|
|
264
|
+
} else {
|
|
265
|
+
// Stream is in Annex B format
|
|
266
|
+
return concatNalUnitsInAnnexB(nalUnits);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/** Builds an AvcDecoderConfigurationRecord from an AVC packet in Annex B format. */
|
|
271
|
+
export const extractAvcDecoderConfigurationRecord = (packetData: Uint8Array): AvcDecoderConfigurationRecord | null => {
|
|
272
|
+
try {
|
|
273
|
+
const spsUnits: Uint8Array[] = [];
|
|
274
|
+
const ppsUnits: Uint8Array[] = [];
|
|
275
|
+
const spsExtUnits: Uint8Array[] = [];
|
|
276
|
+
|
|
277
|
+
for (const loc of iterateNalUnitsInAnnexB(packetData)) {
|
|
278
|
+
const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length);
|
|
279
|
+
const type = extractNalUnitTypeForAvc(nalUnit[0]!);
|
|
280
|
+
|
|
281
|
+
if (type === AvcNalUnitType.SPS) {
|
|
282
|
+
spsUnits.push(nalUnit);
|
|
283
|
+
} else if (type === AvcNalUnitType.PPS) {
|
|
284
|
+
ppsUnits.push(nalUnit);
|
|
285
|
+
} else if (type === AvcNalUnitType.SPS_EXT) {
|
|
286
|
+
spsExtUnits.push(nalUnit);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (spsUnits.length === 0) {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (ppsUnits.length === 0) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Let's get the first SPS for profile and level information
|
|
299
|
+
const spsData = spsUnits[0]!;
|
|
300
|
+
const spsInfo = parseAvcSps(spsData);
|
|
301
|
+
assert(spsInfo !== null);
|
|
302
|
+
|
|
303
|
+
const hasExtendedData = spsInfo.profileIdc === 100
|
|
304
|
+
|| spsInfo.profileIdc === 110
|
|
305
|
+
|| spsInfo.profileIdc === 122
|
|
306
|
+
|| spsInfo.profileIdc === 144;
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
configurationVersion: 1,
|
|
310
|
+
avcProfileIndication: spsInfo.profileIdc,
|
|
311
|
+
profileCompatibility: spsInfo.constraintFlags,
|
|
312
|
+
avcLevelIndication: spsInfo.levelIdc,
|
|
313
|
+
lengthSizeMinusOne: 3, // Typically 4 bytes for length field
|
|
314
|
+
sequenceParameterSets: spsUnits,
|
|
315
|
+
pictureParameterSets: ppsUnits,
|
|
316
|
+
chromaFormat: hasExtendedData ? spsInfo.chromaFormatIdc : null,
|
|
317
|
+
bitDepthLumaMinus8: hasExtendedData ? spsInfo.bitDepthLumaMinus8 : null,
|
|
318
|
+
bitDepthChromaMinus8: hasExtendedData ? spsInfo.bitDepthChromaMinus8 : null,
|
|
319
|
+
sequenceParameterSetExt: hasExtendedData ? spsExtUnits : null,
|
|
320
|
+
};
|
|
321
|
+
} catch (error) {
|
|
322
|
+
Logging._error('Error building AVC Decoder Configuration Record:', error);
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
/** Serializes an AvcDecoderConfigurationRecord into the format specified in Section 5.3.3.1 of ISO 14496-15. */
|
|
328
|
+
export const serializeAvcDecoderConfigurationRecord = (record: AvcDecoderConfigurationRecord) => {
|
|
329
|
+
const bytes: number[] = [];
|
|
330
|
+
|
|
331
|
+
// Write header
|
|
332
|
+
bytes.push(record.configurationVersion);
|
|
333
|
+
bytes.push(record.avcProfileIndication);
|
|
334
|
+
bytes.push(record.profileCompatibility);
|
|
335
|
+
bytes.push(record.avcLevelIndication);
|
|
336
|
+
bytes.push(0xFC | (record.lengthSizeMinusOne & 0x03)); // Reserved bits (6) + lengthSizeMinusOne (2)
|
|
337
|
+
|
|
338
|
+
// Reserved bits (3) + numOfSequenceParameterSets (5)
|
|
339
|
+
bytes.push(0xE0 | (record.sequenceParameterSets.length & 0x1F));
|
|
340
|
+
|
|
341
|
+
// Write SPS
|
|
342
|
+
for (const sps of record.sequenceParameterSets) {
|
|
343
|
+
const length = sps.byteLength;
|
|
344
|
+
bytes.push(length >> 8); // High byte
|
|
345
|
+
bytes.push(length & 0xFF); // Low byte
|
|
346
|
+
|
|
347
|
+
for (let i = 0; i < length; i++) {
|
|
348
|
+
bytes.push(sps[i]!);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
bytes.push(record.pictureParameterSets.length);
|
|
353
|
+
|
|
354
|
+
// Write PPS
|
|
355
|
+
for (const pps of record.pictureParameterSets) {
|
|
356
|
+
const length = pps.byteLength;
|
|
357
|
+
bytes.push(length >> 8); // High byte
|
|
358
|
+
bytes.push(length & 0xFF); // Low byte
|
|
359
|
+
|
|
360
|
+
for (let i = 0; i < length; i++) {
|
|
361
|
+
bytes.push(pps[i]!);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (
|
|
366
|
+
record.avcProfileIndication === 100
|
|
367
|
+
|| record.avcProfileIndication === 110
|
|
368
|
+
|| record.avcProfileIndication === 122
|
|
369
|
+
|| record.avcProfileIndication === 144
|
|
370
|
+
) {
|
|
371
|
+
assert(record.chromaFormat !== null);
|
|
372
|
+
assert(record.bitDepthLumaMinus8 !== null);
|
|
373
|
+
assert(record.bitDepthChromaMinus8 !== null);
|
|
374
|
+
assert(record.sequenceParameterSetExt !== null);
|
|
375
|
+
|
|
376
|
+
bytes.push(0xFC | (record.chromaFormat & 0x03)); // Reserved bits + chroma_format
|
|
377
|
+
bytes.push(0xF8 | (record.bitDepthLumaMinus8 & 0x07)); // Reserved bits + bit_depth_luma_minus8
|
|
378
|
+
bytes.push(0xF8 | (record.bitDepthChromaMinus8 & 0x07)); // Reserved bits + bit_depth_chroma_minus8
|
|
379
|
+
|
|
380
|
+
bytes.push(record.sequenceParameterSetExt.length);
|
|
381
|
+
|
|
382
|
+
// Write SPS Ext
|
|
383
|
+
for (const spsExt of record.sequenceParameterSetExt) {
|
|
384
|
+
const length = spsExt.byteLength;
|
|
385
|
+
bytes.push(length >> 8); // High byte
|
|
386
|
+
bytes.push(length & 0xFF); // Low byte
|
|
387
|
+
|
|
388
|
+
for (let i = 0; i < length; i++) {
|
|
389
|
+
bytes.push(spsExt[i]!);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return new Uint8Array(bytes);
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
/** Deserializes an AvcDecoderConfigurationRecord from the format specified in Section 5.3.3.1 of ISO 14496-15. */
|
|
398
|
+
export const deserializeAvcDecoderConfigurationRecord = (data: Uint8Array): AvcDecoderConfigurationRecord | null => {
|
|
399
|
+
try {
|
|
400
|
+
const view = toDataView(data);
|
|
401
|
+
let offset = 0;
|
|
402
|
+
|
|
403
|
+
// Read header
|
|
404
|
+
const configurationVersion = view.getUint8(offset++);
|
|
405
|
+
const avcProfileIndication = view.getUint8(offset++);
|
|
406
|
+
const profileCompatibility = view.getUint8(offset++);
|
|
407
|
+
const avcLevelIndication = view.getUint8(offset++);
|
|
408
|
+
const lengthSizeMinusOne = view.getUint8(offset++) & 0x03;
|
|
409
|
+
|
|
410
|
+
const numOfSequenceParameterSets = view.getUint8(offset++) & 0x1F;
|
|
411
|
+
|
|
412
|
+
// Read SPS
|
|
413
|
+
const sequenceParameterSets: Uint8Array[] = [];
|
|
414
|
+
for (let i = 0; i < numOfSequenceParameterSets; i++) {
|
|
415
|
+
const length = view.getUint16(offset, false);
|
|
416
|
+
offset += 2;
|
|
417
|
+
|
|
418
|
+
sequenceParameterSets.push(data.subarray(offset, offset + length));
|
|
419
|
+
offset += length;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const numOfPictureParameterSets = view.getUint8(offset++);
|
|
423
|
+
|
|
424
|
+
// Read PPS
|
|
425
|
+
const pictureParameterSets: Uint8Array[] = [];
|
|
426
|
+
for (let i = 0; i < numOfPictureParameterSets; i++) {
|
|
427
|
+
const length = view.getUint16(offset, false);
|
|
428
|
+
offset += 2;
|
|
429
|
+
|
|
430
|
+
pictureParameterSets.push(data.subarray(offset, offset + length));
|
|
431
|
+
offset += length;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const record: AvcDecoderConfigurationRecord = {
|
|
435
|
+
configurationVersion,
|
|
436
|
+
avcProfileIndication,
|
|
437
|
+
profileCompatibility,
|
|
438
|
+
avcLevelIndication,
|
|
439
|
+
lengthSizeMinusOne,
|
|
440
|
+
sequenceParameterSets,
|
|
441
|
+
pictureParameterSets,
|
|
442
|
+
chromaFormat: null,
|
|
443
|
+
bitDepthLumaMinus8: null,
|
|
444
|
+
bitDepthChromaMinus8: null,
|
|
445
|
+
sequenceParameterSetExt: null,
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// Check if there are extended profile fields
|
|
449
|
+
if (
|
|
450
|
+
(
|
|
451
|
+
avcProfileIndication === 100
|
|
452
|
+
|| avcProfileIndication === 110
|
|
453
|
+
|| avcProfileIndication === 122
|
|
454
|
+
|| avcProfileIndication === 144
|
|
455
|
+
)
|
|
456
|
+
&& offset + 4 <= data.length
|
|
457
|
+
) {
|
|
458
|
+
const chromaFormat = view.getUint8(offset++) & 0x03;
|
|
459
|
+
const bitDepthLumaMinus8 = view.getUint8(offset++) & 0x07;
|
|
460
|
+
const bitDepthChromaMinus8 = view.getUint8(offset++) & 0x07;
|
|
461
|
+
const numOfSequenceParameterSetExt = view.getUint8(offset++);
|
|
462
|
+
|
|
463
|
+
record.chromaFormat = chromaFormat;
|
|
464
|
+
record.bitDepthLumaMinus8 = bitDepthLumaMinus8;
|
|
465
|
+
record.bitDepthChromaMinus8 = bitDepthChromaMinus8;
|
|
466
|
+
|
|
467
|
+
// Read SPS Ext
|
|
468
|
+
const sequenceParameterSetExt: Uint8Array[] = [];
|
|
469
|
+
for (let i = 0; i < numOfSequenceParameterSetExt; i++) {
|
|
470
|
+
const length = view.getUint16(offset, false);
|
|
471
|
+
offset += 2;
|
|
472
|
+
|
|
473
|
+
sequenceParameterSetExt.push(data.subarray(offset, offset + length));
|
|
474
|
+
offset += length;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
record.sequenceParameterSetExt = sequenceParameterSetExt;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return record;
|
|
481
|
+
} catch (error) {
|
|
482
|
+
Logging._error('Error deserializing AVC Decoder Configuration Record:', error);
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
export type AvcSpsInfo = {
|
|
488
|
+
profileIdc: number;
|
|
489
|
+
constraintFlags: number;
|
|
490
|
+
levelIdc: number;
|
|
491
|
+
frameMbsOnlyFlag: number;
|
|
492
|
+
chromaFormatIdc: number;
|
|
493
|
+
bitDepthLumaMinus8: number;
|
|
494
|
+
bitDepthChromaMinus8: number;
|
|
495
|
+
codedWidth: number;
|
|
496
|
+
codedHeight: number;
|
|
497
|
+
displayWidth: number;
|
|
498
|
+
displayHeight: number;
|
|
499
|
+
pixelAspectRatio: Rational;
|
|
500
|
+
colourPrimaries: number;
|
|
501
|
+
transferCharacteristics: number;
|
|
502
|
+
matrixCoefficients: number;
|
|
503
|
+
fullRangeFlag: number;
|
|
504
|
+
numReorderFrames: number;
|
|
505
|
+
maxDecFrameBuffering: number;
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
const AVC_HEVC_ASPECT_RATIO_IDC_TABLE: Partial<Record<number, Rational>> = {
|
|
509
|
+
1: { num: 1, den: 1 },
|
|
510
|
+
2: { num: 12, den: 11 },
|
|
511
|
+
3: { num: 10, den: 11 },
|
|
512
|
+
4: { num: 16, den: 11 },
|
|
513
|
+
5: { num: 40, den: 33 },
|
|
514
|
+
6: { num: 24, den: 11 },
|
|
515
|
+
7: { num: 20, den: 11 },
|
|
516
|
+
8: { num: 32, den: 11 },
|
|
517
|
+
9: { num: 80, den: 33 },
|
|
518
|
+
10: { num: 18, den: 11 },
|
|
519
|
+
11: { num: 15, den: 11 },
|
|
520
|
+
12: { num: 64, den: 33 },
|
|
521
|
+
13: { num: 160, den: 99 },
|
|
522
|
+
14: { num: 4, den: 3 },
|
|
523
|
+
15: { num: 3, den: 2 },
|
|
524
|
+
16: { num: 2, den: 1 },
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
/** Parses an AVC SPS (Sequence Parameter Set) to extract basic information. */
|
|
528
|
+
export const parseAvcSps = (sps: Uint8Array): AvcSpsInfo | null => {
|
|
529
|
+
try {
|
|
530
|
+
const bitstream = new Bitstream(removeEmulationPreventionBytes(sps));
|
|
531
|
+
|
|
532
|
+
bitstream.skipBits(1); // forbidden_zero_bit
|
|
533
|
+
bitstream.skipBits(2); // nal_ref_idc
|
|
534
|
+
const nalUnitType = bitstream.readBits(5);
|
|
535
|
+
|
|
536
|
+
if (nalUnitType !== 7) { // SPS NAL unit type is 7
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const profileIdc = bitstream.readAlignedByte();
|
|
541
|
+
const constraintFlags = bitstream.readAlignedByte();
|
|
542
|
+
const levelIdc = bitstream.readAlignedByte();
|
|
543
|
+
|
|
544
|
+
readExpGolomb(bitstream); // seq_parameter_set_id
|
|
545
|
+
|
|
546
|
+
// "When chroma_format_idc is not present, it shall be inferred to be equal to 1 (4:2:0 chroma format)."
|
|
547
|
+
let chromaFormatIdc = 1;
|
|
548
|
+
// "When bit_depth_luma_minus8 is not present, it shall be inferred to be equal to 0.""
|
|
549
|
+
let bitDepthLumaMinus8 = 0;
|
|
550
|
+
// "When bit_depth_chroma_minus8 is not present, it shall be inferred to be equal to 0."
|
|
551
|
+
let bitDepthChromaMinus8 = 0;
|
|
552
|
+
// "When separate_colour_plane_flag is not present, it shall be inferred to be equal to 0."
|
|
553
|
+
let separateColourPlaneFlag = 0;
|
|
554
|
+
|
|
555
|
+
// Handle high profile chroma_format_idc
|
|
556
|
+
if (
|
|
557
|
+
profileIdc === 100
|
|
558
|
+
|| profileIdc === 110
|
|
559
|
+
|| profileIdc === 122
|
|
560
|
+
|| profileIdc === 244
|
|
561
|
+
|| profileIdc === 44
|
|
562
|
+
|| profileIdc === 83
|
|
563
|
+
|| profileIdc === 86
|
|
564
|
+
|| profileIdc === 118
|
|
565
|
+
|| profileIdc === 128
|
|
566
|
+
) {
|
|
567
|
+
chromaFormatIdc = readExpGolomb(bitstream);
|
|
568
|
+
if (chromaFormatIdc === 3) {
|
|
569
|
+
separateColourPlaneFlag = bitstream.readBits(1);
|
|
570
|
+
}
|
|
571
|
+
bitDepthLumaMinus8 = readExpGolomb(bitstream);
|
|
572
|
+
bitDepthChromaMinus8 = readExpGolomb(bitstream);
|
|
573
|
+
bitstream.skipBits(1); // qpprime_y_zero_transform_bypass_flag
|
|
574
|
+
const seqScalingMatrixPresentFlag = bitstream.readBits(1);
|
|
575
|
+
if (seqScalingMatrixPresentFlag) {
|
|
576
|
+
for (let i = 0; i < (chromaFormatIdc !== 3 ? 8 : 12); i++) {
|
|
577
|
+
const seqScalingListPresentFlag = bitstream.readBits(1);
|
|
578
|
+
if (seqScalingListPresentFlag) {
|
|
579
|
+
const sizeOfScalingList = i < 6 ? 16 : 64;
|
|
580
|
+
let lastScale = 8;
|
|
581
|
+
let nextScale = 8;
|
|
582
|
+
for (let j = 0; j < sizeOfScalingList; j++) {
|
|
583
|
+
if (nextScale !== 0) {
|
|
584
|
+
const deltaScale = readSignedExpGolomb(bitstream);
|
|
585
|
+
nextScale = (lastScale + deltaScale + 256) % 256;
|
|
586
|
+
}
|
|
587
|
+
lastScale = nextScale === 0 ? lastScale : nextScale;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
readExpGolomb(bitstream); // log2_max_frame_num_minus4
|
|
595
|
+
|
|
596
|
+
const picOrderCntType = readExpGolomb(bitstream);
|
|
597
|
+
if (picOrderCntType === 0) {
|
|
598
|
+
readExpGolomb(bitstream); // log2_max_pic_order_cnt_lsb_minus4
|
|
599
|
+
} else if (picOrderCntType === 1) {
|
|
600
|
+
bitstream.skipBits(1); // delta_pic_order_always_zero_flag
|
|
601
|
+
readSignedExpGolomb(bitstream); // offset_for_non_ref_pic
|
|
602
|
+
readSignedExpGolomb(bitstream); // offset_for_top_to_bottom_field
|
|
603
|
+
const numRefFramesInPicOrderCntCycle = readExpGolomb(bitstream);
|
|
604
|
+
for (let i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
|
605
|
+
readSignedExpGolomb(bitstream); // offset_for_ref_frame[i]
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
readExpGolomb(bitstream); // max_num_ref_frames
|
|
610
|
+
bitstream.skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
|
611
|
+
|
|
612
|
+
const picWidthInMbsMinus1 = readExpGolomb(bitstream);
|
|
613
|
+
const picHeightInMapUnitsMinus1 = readExpGolomb(bitstream);
|
|
614
|
+
const codedWidth = 16 * (picWidthInMbsMinus1 + 1);
|
|
615
|
+
const codedHeight = 16 * (picHeightInMapUnitsMinus1 + 1);
|
|
616
|
+
let displayWidth = codedWidth;
|
|
617
|
+
let displayHeight = codedHeight;
|
|
618
|
+
|
|
619
|
+
const frameMbsOnlyFlag = bitstream.readBits(1);
|
|
620
|
+
if (!frameMbsOnlyFlag) {
|
|
621
|
+
bitstream.skipBits(1); // mb_adaptive_frame_field_flag
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
bitstream.skipBits(1); // direct_8x8_inference_flag
|
|
625
|
+
const frameCroppingFlag = bitstream.readBits(1);
|
|
626
|
+
|
|
627
|
+
if (frameCroppingFlag) {
|
|
628
|
+
const frameCropLeftOffset = readExpGolomb(bitstream);
|
|
629
|
+
const frameCropRightOffset = readExpGolomb(bitstream);
|
|
630
|
+
const frameCropTopOffset = readExpGolomb(bitstream);
|
|
631
|
+
const frameCropBottomOffset = readExpGolomb(bitstream);
|
|
632
|
+
|
|
633
|
+
let cropUnitX: number;
|
|
634
|
+
let cropUnitY: number;
|
|
635
|
+
|
|
636
|
+
const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0;
|
|
637
|
+
if (chromaArrayType === 0) {
|
|
638
|
+
// "If ChromaArrayType is equal to 0, CropUnitX and CropUnitY are derived as:"
|
|
639
|
+
cropUnitX = 1;
|
|
640
|
+
cropUnitY = 2 - frameMbsOnlyFlag;
|
|
641
|
+
} else {
|
|
642
|
+
// "Otherwise (ChromaArrayType is equal to 1, 2, or 3), CropUnitX and CropUnitY are derived as:"
|
|
643
|
+
const subWidthC = chromaFormatIdc === 3 ? 1 : 2;
|
|
644
|
+
const subHeightC = chromaFormatIdc === 1 ? 2 : 1;
|
|
645
|
+
|
|
646
|
+
cropUnitX = subWidthC;
|
|
647
|
+
cropUnitY = subHeightC * (2 - frameMbsOnlyFlag);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
displayWidth -= (cropUnitX * (frameCropLeftOffset + frameCropRightOffset));
|
|
651
|
+
displayHeight -= (cropUnitY * (frameCropTopOffset + frameCropBottomOffset));
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// 2 = unspecified
|
|
655
|
+
let colourPrimaries = 2;
|
|
656
|
+
let transferCharacteristics = 2;
|
|
657
|
+
let matrixCoefficients = 2;
|
|
658
|
+
let fullRangeFlag = 0;
|
|
659
|
+
let pixelAspectRatio: Rational = { num: 1, den: 1 };
|
|
660
|
+
|
|
661
|
+
let numReorderFrames: number | null = null;
|
|
662
|
+
let maxDecFrameBuffering: number | null = null;
|
|
663
|
+
|
|
664
|
+
const vuiParametersPresentFlag = bitstream.readBits(1);
|
|
665
|
+
if (vuiParametersPresentFlag) {
|
|
666
|
+
const aspectRatioInfoPresentFlag = bitstream.readBits(1);
|
|
667
|
+
if (aspectRatioInfoPresentFlag) {
|
|
668
|
+
const aspectRatioIdc = bitstream.readBits(8);
|
|
669
|
+
|
|
670
|
+
if (aspectRatioIdc === 255) { // Extended_SAR
|
|
671
|
+
pixelAspectRatio = {
|
|
672
|
+
num: bitstream.readBits(16),
|
|
673
|
+
den: bitstream.readBits(16),
|
|
674
|
+
};
|
|
675
|
+
} else {
|
|
676
|
+
const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspectRatioIdc];
|
|
677
|
+
if (aspectRatio) {
|
|
678
|
+
pixelAspectRatio = aspectRatio;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const overscanInfoPresentFlag = bitstream.readBits(1);
|
|
684
|
+
if (overscanInfoPresentFlag) {
|
|
685
|
+
bitstream.skipBits(1); // overscan_appropriate_flag
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const videoSignalTypePresentFlag = bitstream.readBits(1);
|
|
689
|
+
if (videoSignalTypePresentFlag) {
|
|
690
|
+
bitstream.skipBits(3); // video_format
|
|
691
|
+
fullRangeFlag = bitstream.readBits(1);
|
|
692
|
+
const colourDescriptionPresentFlag = bitstream.readBits(1);
|
|
693
|
+
if (colourDescriptionPresentFlag) {
|
|
694
|
+
colourPrimaries = bitstream.readBits(8);
|
|
695
|
+
transferCharacteristics = bitstream.readBits(8);
|
|
696
|
+
matrixCoefficients = bitstream.readBits(8);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const chromaLocInfoPresentFlag = bitstream.readBits(1);
|
|
701
|
+
if (chromaLocInfoPresentFlag) {
|
|
702
|
+
readExpGolomb(bitstream); // chroma_sample_loc_type_top_field
|
|
703
|
+
readExpGolomb(bitstream); // chroma_sample_loc_type_bottom_field
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const timingInfoPresentFlag = bitstream.readBits(1);
|
|
707
|
+
if (timingInfoPresentFlag) {
|
|
708
|
+
bitstream.skipBits(32); // num_units_in_tick
|
|
709
|
+
bitstream.skipBits(32); // time_scale
|
|
710
|
+
bitstream.skipBits(1); // fixed_frame_rate_flag
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
const nalHrdParametersPresentFlag = bitstream.readBits(1);
|
|
714
|
+
if (nalHrdParametersPresentFlag) {
|
|
715
|
+
skipAvcHrdParameters(bitstream);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
const vclHrdParametersPresentFlag = bitstream.readBits(1);
|
|
719
|
+
if (vclHrdParametersPresentFlag) {
|
|
720
|
+
skipAvcHrdParameters(bitstream);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) {
|
|
724
|
+
bitstream.skipBits(1); // low_delay_hrd_flag
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
bitstream.skipBits(1); // pic_struct_present_flag
|
|
728
|
+
|
|
729
|
+
const bitstreamRestrictionFlag = bitstream.readBits(1);
|
|
730
|
+
if (bitstreamRestrictionFlag) {
|
|
731
|
+
bitstream.skipBits(1); // motion_vectors_over_pic_boundaries_flag
|
|
732
|
+
readExpGolomb(bitstream); // max_bytes_per_pic_denom
|
|
733
|
+
readExpGolomb(bitstream); // max_bits_per_mb_denom
|
|
734
|
+
readExpGolomb(bitstream); // log2_max_mv_length_horizontal
|
|
735
|
+
readExpGolomb(bitstream); // log2_max_mv_length_vertical
|
|
736
|
+
numReorderFrames = readExpGolomb(bitstream);
|
|
737
|
+
maxDecFrameBuffering = readExpGolomb(bitstream);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (numReorderFrames === null) {
|
|
742
|
+
assert(maxDecFrameBuffering === null);
|
|
743
|
+
const constraintSet3Flag = constraintFlags & 0b00010000;
|
|
744
|
+
|
|
745
|
+
if (
|
|
746
|
+
(profileIdc === 44 || profileIdc === 86 || profileIdc === 100
|
|
747
|
+
|| profileIdc === 110 || profileIdc === 122 || profileIdc === 244
|
|
748
|
+
) && constraintSet3Flag
|
|
749
|
+
) {
|
|
750
|
+
// "If profile_idc is equal to 44, 86, 100, 110, 122, or 244 and constraint_set3_flag is equal to 1, the
|
|
751
|
+
// value of num_reorder_frames shall be inferred to be equal to 0."
|
|
752
|
+
numReorderFrames = 0;
|
|
753
|
+
maxDecFrameBuffering = 0;
|
|
754
|
+
} else {
|
|
755
|
+
const picWidthInMbs = picWidthInMbsMinus1 + 1;
|
|
756
|
+
const picHeightInMapUnits = picHeightInMapUnitsMinus1 + 1;
|
|
757
|
+
const frameHeightInMbs = (2 - frameMbsOnlyFlag) * picHeightInMapUnits;
|
|
758
|
+
|
|
759
|
+
const levelInfo = AVC_LEVEL_TABLE.find(
|
|
760
|
+
x => x.level >= levelIdc,
|
|
761
|
+
) ?? last(AVC_LEVEL_TABLE)!;
|
|
762
|
+
|
|
763
|
+
// "MaxDpbFrames is equal to
|
|
764
|
+
// Min( MaxDpbMbs / ( picWidthInMbs * frameHeightInMbs ), 16 ) and MaxDpbMbs is given in Table A-1."
|
|
765
|
+
const maxDpbFrames = Math.min(
|
|
766
|
+
Math.floor(levelInfo.maxDpbMbs / (picWidthInMbs * frameHeightInMbs)),
|
|
767
|
+
16,
|
|
768
|
+
);
|
|
769
|
+
|
|
770
|
+
// "Otherwise, [...] the value of num_reorder_frames shall be inferred to be equal to MaxDpbFrames."
|
|
771
|
+
numReorderFrames = maxDpbFrames;
|
|
772
|
+
maxDecFrameBuffering = maxDpbFrames;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
assert(maxDecFrameBuffering !== null);
|
|
777
|
+
|
|
778
|
+
return {
|
|
779
|
+
profileIdc,
|
|
780
|
+
constraintFlags,
|
|
781
|
+
levelIdc,
|
|
782
|
+
frameMbsOnlyFlag,
|
|
783
|
+
chromaFormatIdc,
|
|
784
|
+
bitDepthLumaMinus8,
|
|
785
|
+
bitDepthChromaMinus8,
|
|
786
|
+
codedWidth,
|
|
787
|
+
codedHeight,
|
|
788
|
+
displayWidth,
|
|
789
|
+
displayHeight,
|
|
790
|
+
pixelAspectRatio,
|
|
791
|
+
colourPrimaries,
|
|
792
|
+
matrixCoefficients,
|
|
793
|
+
transferCharacteristics,
|
|
794
|
+
fullRangeFlag,
|
|
795
|
+
numReorderFrames,
|
|
796
|
+
maxDecFrameBuffering,
|
|
797
|
+
};
|
|
798
|
+
} catch (error) {
|
|
799
|
+
Logging._error('Error parsing AVC SPS:', error);
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
|
|
804
|
+
const skipAvcHrdParameters = (bitstream: Bitstream) => {
|
|
805
|
+
const cpb_cnt_minus1 = readExpGolomb(bitstream);
|
|
806
|
+
bitstream.skipBits(4); // bit_rate_scale
|
|
807
|
+
bitstream.skipBits(4); // cpb_size_scale
|
|
808
|
+
|
|
809
|
+
for (let i = 0; i <= cpb_cnt_minus1; i++) {
|
|
810
|
+
readExpGolomb(bitstream); // bit_rate_value_minus1[i]
|
|
811
|
+
readExpGolomb(bitstream); // cpb_size_value_minus1[i]
|
|
812
|
+
bitstream.skipBits(1); // cbr_flag[i]
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
bitstream.skipBits(5); // initial_cpb_removal_delay_length_minus1
|
|
816
|
+
bitstream.skipBits(5); // cpb_removal_delay_length_minus1
|
|
817
|
+
bitstream.skipBits(5); // dpb_output_delay_length_minus1
|
|
818
|
+
bitstream.skipBits(5); // time_offset_length
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
// Data specified in ISO 14496-15
|
|
822
|
+
export type HevcDecoderConfigurationRecord = {
|
|
823
|
+
configurationVersion: number;
|
|
824
|
+
generalProfileSpace: number;
|
|
825
|
+
generalTierFlag: number;
|
|
826
|
+
generalProfileIdc: number;
|
|
827
|
+
generalProfileCompatibilityFlags: number;
|
|
828
|
+
generalConstraintIndicatorFlags: Uint8Array; // 6 bytes long
|
|
829
|
+
generalLevelIdc: number;
|
|
830
|
+
minSpatialSegmentationIdc: number;
|
|
831
|
+
parallelismType: number;
|
|
832
|
+
chromaFormatIdc: number;
|
|
833
|
+
bitDepthLumaMinus8: number;
|
|
834
|
+
bitDepthChromaMinus8: number;
|
|
835
|
+
avgFrameRate: number;
|
|
836
|
+
constantFrameRate: number;
|
|
837
|
+
numTemporalLayers: number;
|
|
838
|
+
temporalIdNested: number;
|
|
839
|
+
lengthSizeMinusOne: number;
|
|
840
|
+
arrays: {
|
|
841
|
+
arrayCompleteness: number;
|
|
842
|
+
nalUnitType: number;
|
|
843
|
+
nalUnits: Uint8Array[];
|
|
844
|
+
}[];
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
export type HevcSpsInfo = {
|
|
848
|
+
displayWidth: number;
|
|
849
|
+
displayHeight: number;
|
|
850
|
+
pixelAspectRatio: Rational;
|
|
851
|
+
colourPrimaries: number;
|
|
852
|
+
transferCharacteristics: number;
|
|
853
|
+
matrixCoefficients: number;
|
|
854
|
+
fullRangeFlag: number;
|
|
855
|
+
maxDecFrameBuffering: number;
|
|
856
|
+
spsMaxSubLayersMinus1: number;
|
|
857
|
+
spsTemporalIdNestingFlag: number;
|
|
858
|
+
generalProfileSpace: number;
|
|
859
|
+
generalTierFlag: number;
|
|
860
|
+
generalProfileIdc: number;
|
|
861
|
+
generalProfileCompatibilityFlags: number;
|
|
862
|
+
generalConstraintIndicatorFlags: Uint8Array;
|
|
863
|
+
generalLevelIdc: number;
|
|
864
|
+
chromaFormatIdc: number;
|
|
865
|
+
bitDepthLumaMinus8: number;
|
|
866
|
+
bitDepthChromaMinus8: number;
|
|
867
|
+
minSpatialSegmentationIdc: number;
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
export const concatHevcNalUnits = (nalUnits: Uint8Array[], decoderConfig: VideoDecoderConfig) => {
|
|
871
|
+
if (decoderConfig.description) {
|
|
872
|
+
// Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config
|
|
873
|
+
|
|
874
|
+
const bytes = toUint8Array(decoderConfig.description);
|
|
875
|
+
const lengthSizeMinusOne = bytes[21]! & 0b11;
|
|
876
|
+
const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
|
|
877
|
+
|
|
878
|
+
return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize);
|
|
879
|
+
} else {
|
|
880
|
+
// Stream is in Annex B format
|
|
881
|
+
return concatNalUnitsInAnnexB(nalUnits);
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
export const iterateHevcNalUnits = (packetData: Uint8Array, decoderConfig: VideoDecoderConfig) => {
|
|
886
|
+
if (decoderConfig.description) {
|
|
887
|
+
const bytes = toUint8Array(decoderConfig.description);
|
|
888
|
+
const lengthSizeMinusOne = bytes[21]! & 0b11;
|
|
889
|
+
const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
|
|
890
|
+
|
|
891
|
+
return iterateNalUnitsInLengthPrefixed(packetData, lengthSize);
|
|
892
|
+
} else {
|
|
893
|
+
return iterateNalUnitsInAnnexB(packetData);
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
export const extractNalUnitTypeForHevc = (byte: number) => {
|
|
898
|
+
return (byte >> 1) & 0x3F;
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
/** Parses an HEVC SPS (Sequence Parameter Set) to extract video information. */
|
|
902
|
+
export const parseHevcSps = (sps: Uint8Array): HevcSpsInfo | null => {
|
|
903
|
+
try {
|
|
904
|
+
const bitstream = new Bitstream(removeEmulationPreventionBytes(sps));
|
|
905
|
+
|
|
906
|
+
bitstream.skipBits(16); // NAL header
|
|
907
|
+
|
|
908
|
+
bitstream.readBits(4); // sps_video_parameter_set_id
|
|
909
|
+
const spsMaxSubLayersMinus1 = bitstream.readBits(3);
|
|
910
|
+
const spsTemporalIdNestingFlag = bitstream.readBits(1);
|
|
911
|
+
|
|
912
|
+
const {
|
|
913
|
+
general_profile_space,
|
|
914
|
+
general_tier_flag,
|
|
915
|
+
general_profile_idc,
|
|
916
|
+
general_profile_compatibility_flags,
|
|
917
|
+
general_constraint_indicator_flags,
|
|
918
|
+
general_level_idc,
|
|
919
|
+
} = parseProfileTierLevel(bitstream, spsMaxSubLayersMinus1);
|
|
920
|
+
|
|
921
|
+
readExpGolomb(bitstream); // sps_seq_parameter_set_id
|
|
922
|
+
|
|
923
|
+
const chromaFormatIdc = readExpGolomb(bitstream);
|
|
924
|
+
let separateColourPlaneFlag = 0;
|
|
925
|
+
if (chromaFormatIdc === 3) {
|
|
926
|
+
separateColourPlaneFlag = bitstream.readBits(1);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
const picWidthInLumaSamples = readExpGolomb(bitstream);
|
|
930
|
+
const picHeightInLumaSamples = readExpGolomb(bitstream);
|
|
931
|
+
|
|
932
|
+
let displayWidth = picWidthInLumaSamples;
|
|
933
|
+
let displayHeight = picHeightInLumaSamples;
|
|
934
|
+
|
|
935
|
+
if (bitstream.readBits(1)) { // conformance_window_flag
|
|
936
|
+
const confWinLeftOffset = readExpGolomb(bitstream);
|
|
937
|
+
const confWinRightOffset = readExpGolomb(bitstream);
|
|
938
|
+
const confWinTopOffset = readExpGolomb(bitstream);
|
|
939
|
+
const confWinBottomOffset = readExpGolomb(bitstream);
|
|
940
|
+
|
|
941
|
+
// SubWidthC and SubHeightC depend on chroma_format_idc and separate_colour_plane_flag
|
|
942
|
+
let subWidthC = 1;
|
|
943
|
+
let subHeightC = 1;
|
|
944
|
+
const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0;
|
|
945
|
+
if (chromaArrayType === 1) {
|
|
946
|
+
subWidthC = 2;
|
|
947
|
+
subHeightC = 2;
|
|
948
|
+
} else if (chromaArrayType === 2) {
|
|
949
|
+
subWidthC = 2;
|
|
950
|
+
subHeightC = 1;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
displayWidth -= (confWinLeftOffset + confWinRightOffset) * subWidthC;
|
|
954
|
+
displayHeight -= (confWinTopOffset + confWinBottomOffset) * subHeightC;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
const bitDepthLumaMinus8 = readExpGolomb(bitstream);
|
|
958
|
+
const bitDepthChromaMinus8 = readExpGolomb(bitstream);
|
|
959
|
+
readExpGolomb(bitstream); // log2_max_pic_order_cnt_lsb_minus4
|
|
960
|
+
|
|
961
|
+
const spsSubLayerOrderingInfoPresentFlag = bitstream.readBits(1);
|
|
962
|
+
const startI = spsSubLayerOrderingInfoPresentFlag ? 0 : spsMaxSubLayersMinus1;
|
|
963
|
+
let spsMaxNumReorderPics = 0;
|
|
964
|
+
for (let i = startI; i <= spsMaxSubLayersMinus1; i++) {
|
|
965
|
+
readExpGolomb(bitstream); // sps_max_dec_pic_buffering_minus1[i]
|
|
966
|
+
spsMaxNumReorderPics = readExpGolomb(bitstream); // sps_max_num_reorder_pics[i]
|
|
967
|
+
readExpGolomb(bitstream); // sps_max_latency_increase_plus1[i]
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
readExpGolomb(bitstream); // log2_min_luma_coding_block_size_minus3
|
|
971
|
+
readExpGolomb(bitstream); // log2_diff_max_min_luma_coding_block_size
|
|
972
|
+
readExpGolomb(bitstream); // log2_min_luma_transform_block_size_minus2
|
|
973
|
+
readExpGolomb(bitstream); // log2_diff_max_min_luma_transform_block_size
|
|
974
|
+
readExpGolomb(bitstream); // max_transform_hierarchy_depth_inter
|
|
975
|
+
readExpGolomb(bitstream); // max_transform_hierarchy_depth_intra
|
|
976
|
+
|
|
977
|
+
if (bitstream.readBits(1)) { // scaling_list_enabled_flag
|
|
978
|
+
if (bitstream.readBits(1)) {
|
|
979
|
+
skipScalingListData(bitstream);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
bitstream.skipBits(1); // amp_enabled_flag
|
|
984
|
+
bitstream.skipBits(1); // sample_adaptive_offset_enabled_flag
|
|
985
|
+
|
|
986
|
+
if (bitstream.readBits(1)) { // pcm_enabled_flag
|
|
987
|
+
bitstream.skipBits(4); // pcm_sample_bit_depth_luma_minus1
|
|
988
|
+
bitstream.skipBits(4); // pcm_sample_bit_depth_chroma_minus1
|
|
989
|
+
readExpGolomb(bitstream); // log2_min_pcm_luma_coding_block_size_minus3
|
|
990
|
+
readExpGolomb(bitstream); // log2_diff_max_min_pcm_luma_coding_block_size
|
|
991
|
+
bitstream.skipBits(1); // pcm_loop_filter_disabled_flag
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const numShortTermRefPicSets = readExpGolomb(bitstream);
|
|
995
|
+
skipAllStRefPicSets(bitstream, numShortTermRefPicSets);
|
|
996
|
+
|
|
997
|
+
if (bitstream.readBits(1)) { // long_term_ref_pics_present_flag
|
|
998
|
+
const numLongTermRefPicsSps = readExpGolomb(bitstream);
|
|
999
|
+
for (let i = 0; i < numLongTermRefPicsSps; i++) {
|
|
1000
|
+
readExpGolomb(bitstream); // lt_ref_pic_poc_lsb_sps[i]
|
|
1001
|
+
bitstream.skipBits(1); // used_by_curr_pic_lt_sps_flag[i]
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
bitstream.skipBits(1); // sps_temporal_mvp_enabled_flag
|
|
1006
|
+
bitstream.skipBits(1); // strong_intra_smoothing_enabled_flag
|
|
1007
|
+
|
|
1008
|
+
let colourPrimaries = 2;
|
|
1009
|
+
let transferCharacteristics = 2;
|
|
1010
|
+
let matrixCoefficients = 2;
|
|
1011
|
+
let fullRangeFlag = 0;
|
|
1012
|
+
let minSpatialSegmentationIdc = 0;
|
|
1013
|
+
let pixelAspectRatio: Rational = { num: 1, den: 1 };
|
|
1014
|
+
|
|
1015
|
+
if (bitstream.readBits(1)) { // vui_parameters_present_flag
|
|
1016
|
+
const vui = parseHevcVui(bitstream, spsMaxSubLayersMinus1);
|
|
1017
|
+
pixelAspectRatio = vui.pixelAspectRatio;
|
|
1018
|
+
colourPrimaries = vui.colourPrimaries;
|
|
1019
|
+
transferCharacteristics = vui.transferCharacteristics;
|
|
1020
|
+
matrixCoefficients = vui.matrixCoefficients;
|
|
1021
|
+
fullRangeFlag = vui.fullRangeFlag;
|
|
1022
|
+
minSpatialSegmentationIdc = vui.minSpatialSegmentationIdc;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
return {
|
|
1026
|
+
displayWidth,
|
|
1027
|
+
displayHeight,
|
|
1028
|
+
pixelAspectRatio,
|
|
1029
|
+
colourPrimaries,
|
|
1030
|
+
transferCharacteristics,
|
|
1031
|
+
matrixCoefficients,
|
|
1032
|
+
fullRangeFlag,
|
|
1033
|
+
maxDecFrameBuffering: spsMaxNumReorderPics + 1,
|
|
1034
|
+
spsMaxSubLayersMinus1,
|
|
1035
|
+
spsTemporalIdNestingFlag,
|
|
1036
|
+
generalProfileSpace: general_profile_space,
|
|
1037
|
+
generalTierFlag: general_tier_flag,
|
|
1038
|
+
generalProfileIdc: general_profile_idc,
|
|
1039
|
+
generalProfileCompatibilityFlags: general_profile_compatibility_flags,
|
|
1040
|
+
generalConstraintIndicatorFlags: general_constraint_indicator_flags,
|
|
1041
|
+
generalLevelIdc: general_level_idc,
|
|
1042
|
+
chromaFormatIdc,
|
|
1043
|
+
bitDepthLumaMinus8,
|
|
1044
|
+
bitDepthChromaMinus8,
|
|
1045
|
+
minSpatialSegmentationIdc,
|
|
1046
|
+
};
|
|
1047
|
+
} catch (error) {
|
|
1048
|
+
Logging._error('Error parsing HEVC SPS:', error);
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
/** Builds a HevcDecoderConfigurationRecord from an HEVC packet in Annex B format. */
|
|
1054
|
+
export const extractHevcDecoderConfigurationRecord = (packetData: Uint8Array) => {
|
|
1055
|
+
try {
|
|
1056
|
+
const vpsUnits: Uint8Array[] = [];
|
|
1057
|
+
const spsUnits: Uint8Array[] = [];
|
|
1058
|
+
const ppsUnits: Uint8Array[] = [];
|
|
1059
|
+
const seiUnits: Uint8Array[] = [];
|
|
1060
|
+
|
|
1061
|
+
for (const loc of iterateNalUnitsInAnnexB(packetData)) {
|
|
1062
|
+
const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length);
|
|
1063
|
+
const type = extractNalUnitTypeForHevc(nalUnit[0]!);
|
|
1064
|
+
|
|
1065
|
+
if (type === HevcNalUnitType.VPS_NUT) {
|
|
1066
|
+
vpsUnits.push(nalUnit);
|
|
1067
|
+
} else if (type === HevcNalUnitType.SPS_NUT) {
|
|
1068
|
+
spsUnits.push(nalUnit);
|
|
1069
|
+
} else if (type === HevcNalUnitType.PPS_NUT) {
|
|
1070
|
+
ppsUnits.push(nalUnit);
|
|
1071
|
+
} else if (type === HevcNalUnitType.PREFIX_SEI_NUT || type === HevcNalUnitType.SUFFIX_SEI_NUT) {
|
|
1072
|
+
seiUnits.push(nalUnit);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
if (spsUnits.length === 0 || ppsUnits.length === 0) return null;
|
|
1077
|
+
|
|
1078
|
+
const spsInfo = parseHevcSps(spsUnits[0]!);
|
|
1079
|
+
if (!spsInfo) return null;
|
|
1080
|
+
|
|
1081
|
+
// Parse PPS for parallelismType
|
|
1082
|
+
let parallelismType = 0;
|
|
1083
|
+
if (ppsUnits.length > 0) {
|
|
1084
|
+
const pps = ppsUnits[0]!;
|
|
1085
|
+
const ppsBitstream = new Bitstream(removeEmulationPreventionBytes(pps));
|
|
1086
|
+
|
|
1087
|
+
ppsBitstream.skipBits(16); // NAL header
|
|
1088
|
+
readExpGolomb(ppsBitstream); // pps_pic_parameter_set_id
|
|
1089
|
+
readExpGolomb(ppsBitstream); // pps_seq_parameter_set_id
|
|
1090
|
+
ppsBitstream.skipBits(1); // dependent_slice_segments_enabled_flag
|
|
1091
|
+
ppsBitstream.skipBits(1); // output_flag_present_flag
|
|
1092
|
+
ppsBitstream.skipBits(3); // num_extra_slice_header_bits
|
|
1093
|
+
ppsBitstream.skipBits(1); // sign_data_hiding_enabled_flag
|
|
1094
|
+
ppsBitstream.skipBits(1); // cabac_init_present_flag
|
|
1095
|
+
readExpGolomb(ppsBitstream); // num_ref_idx_l0_default_active_minus1
|
|
1096
|
+
readExpGolomb(ppsBitstream); // num_ref_idx_l1_default_active_minus1
|
|
1097
|
+
readSignedExpGolomb(ppsBitstream); // init_qp_minus26
|
|
1098
|
+
ppsBitstream.skipBits(1); // constrained_intra_pred_flag
|
|
1099
|
+
ppsBitstream.skipBits(1); // transform_skip_enabled_flag
|
|
1100
|
+
if (ppsBitstream.readBits(1)) { // cu_qp_delta_enabled_flag
|
|
1101
|
+
readExpGolomb(ppsBitstream); // diff_cu_qp_delta_depth
|
|
1102
|
+
}
|
|
1103
|
+
readSignedExpGolomb(ppsBitstream); // pps_cb_qp_offset
|
|
1104
|
+
readSignedExpGolomb(ppsBitstream); // pps_cr_qp_offset
|
|
1105
|
+
ppsBitstream.skipBits(1); // pps_slice_chroma_qp_offsets_present_flag
|
|
1106
|
+
ppsBitstream.skipBits(1); // weighted_pred_flag
|
|
1107
|
+
ppsBitstream.skipBits(1); // weighted_bipred_flag
|
|
1108
|
+
ppsBitstream.skipBits(1); // transquant_bypass_enabled_flag
|
|
1109
|
+
const tiles_enabled_flag = ppsBitstream.readBits(1);
|
|
1110
|
+
const entropy_coding_sync_enabled_flag = ppsBitstream.readBits(1);
|
|
1111
|
+
|
|
1112
|
+
if (!tiles_enabled_flag && !entropy_coding_sync_enabled_flag) parallelismType = 0;
|
|
1113
|
+
else if (tiles_enabled_flag && !entropy_coding_sync_enabled_flag) parallelismType = 2;
|
|
1114
|
+
else if (!tiles_enabled_flag && entropy_coding_sync_enabled_flag) parallelismType = 3;
|
|
1115
|
+
else parallelismType = 0;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
const arrays = [
|
|
1119
|
+
...(vpsUnits.length
|
|
1120
|
+
? [
|
|
1121
|
+
{
|
|
1122
|
+
arrayCompleteness: 1,
|
|
1123
|
+
nalUnitType: HevcNalUnitType.VPS_NUT,
|
|
1124
|
+
nalUnits: vpsUnits,
|
|
1125
|
+
},
|
|
1126
|
+
]
|
|
1127
|
+
: []),
|
|
1128
|
+
...(spsUnits.length
|
|
1129
|
+
? [
|
|
1130
|
+
{
|
|
1131
|
+
arrayCompleteness: 1,
|
|
1132
|
+
nalUnitType: HevcNalUnitType.SPS_NUT,
|
|
1133
|
+
nalUnits: spsUnits,
|
|
1134
|
+
},
|
|
1135
|
+
]
|
|
1136
|
+
: []),
|
|
1137
|
+
...(ppsUnits.length
|
|
1138
|
+
? [
|
|
1139
|
+
{
|
|
1140
|
+
arrayCompleteness: 1,
|
|
1141
|
+
nalUnitType: HevcNalUnitType.PPS_NUT,
|
|
1142
|
+
nalUnits: ppsUnits,
|
|
1143
|
+
},
|
|
1144
|
+
]
|
|
1145
|
+
: []),
|
|
1146
|
+
...(seiUnits.length
|
|
1147
|
+
? [
|
|
1148
|
+
{
|
|
1149
|
+
arrayCompleteness: 1,
|
|
1150
|
+
nalUnitType: extractNalUnitTypeForHevc(seiUnits[0]![0]!),
|
|
1151
|
+
nalUnits: seiUnits,
|
|
1152
|
+
},
|
|
1153
|
+
]
|
|
1154
|
+
: []),
|
|
1155
|
+
];
|
|
1156
|
+
|
|
1157
|
+
const record: HevcDecoderConfigurationRecord = {
|
|
1158
|
+
configurationVersion: 1,
|
|
1159
|
+
generalProfileSpace: spsInfo.generalProfileSpace,
|
|
1160
|
+
generalTierFlag: spsInfo.generalTierFlag,
|
|
1161
|
+
generalProfileIdc: spsInfo.generalProfileIdc,
|
|
1162
|
+
generalProfileCompatibilityFlags: spsInfo.generalProfileCompatibilityFlags,
|
|
1163
|
+
generalConstraintIndicatorFlags: spsInfo.generalConstraintIndicatorFlags,
|
|
1164
|
+
generalLevelIdc: spsInfo.generalLevelIdc,
|
|
1165
|
+
minSpatialSegmentationIdc: spsInfo.minSpatialSegmentationIdc,
|
|
1166
|
+
parallelismType,
|
|
1167
|
+
chromaFormatIdc: spsInfo.chromaFormatIdc,
|
|
1168
|
+
bitDepthLumaMinus8: spsInfo.bitDepthLumaMinus8,
|
|
1169
|
+
bitDepthChromaMinus8: spsInfo.bitDepthChromaMinus8,
|
|
1170
|
+
avgFrameRate: 0,
|
|
1171
|
+
constantFrameRate: 0,
|
|
1172
|
+
numTemporalLayers: spsInfo.spsMaxSubLayersMinus1 + 1,
|
|
1173
|
+
temporalIdNested: spsInfo.spsTemporalIdNestingFlag,
|
|
1174
|
+
lengthSizeMinusOne: 3,
|
|
1175
|
+
arrays,
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
return record;
|
|
1179
|
+
} catch (error) {
|
|
1180
|
+
Logging._error('Error building HEVC Decoder Configuration Record:', error);
|
|
1181
|
+
return null;
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
const parseProfileTierLevel = (
|
|
1186
|
+
bitstream: Bitstream,
|
|
1187
|
+
maxNumSubLayersMinus1: number,
|
|
1188
|
+
) => {
|
|
1189
|
+
const general_profile_space = bitstream.readBits(2);
|
|
1190
|
+
const general_tier_flag = bitstream.readBits(1);
|
|
1191
|
+
const general_profile_idc = bitstream.readBits(5);
|
|
1192
|
+
|
|
1193
|
+
let general_profile_compatibility_flags = 0;
|
|
1194
|
+
for (let i = 0; i < 32; i++) {
|
|
1195
|
+
general_profile_compatibility_flags = (general_profile_compatibility_flags << 1) | bitstream.readBits(1);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
const general_constraint_indicator_flags = new Uint8Array(6);
|
|
1199
|
+
for (let i = 0; i < 6; i++) {
|
|
1200
|
+
general_constraint_indicator_flags[i] = bitstream.readBits(8);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
const general_level_idc = bitstream.readBits(8);
|
|
1204
|
+
|
|
1205
|
+
const sub_layer_profile_present_flag: number[] = [];
|
|
1206
|
+
const sub_layer_level_present_flag: number[] = [];
|
|
1207
|
+
for (let i = 0; i < maxNumSubLayersMinus1; i++) {
|
|
1208
|
+
sub_layer_profile_present_flag.push(bitstream.readBits(1));
|
|
1209
|
+
sub_layer_level_present_flag.push(bitstream.readBits(1));
|
|
1210
|
+
}
|
|
1211
|
+
if (maxNumSubLayersMinus1 > 0) {
|
|
1212
|
+
for (let i = maxNumSubLayersMinus1; i < 8; i++) {
|
|
1213
|
+
bitstream.skipBits(2); // reserved_zero_2bits
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
for (let i = 0; i < maxNumSubLayersMinus1; i++) {
|
|
1217
|
+
if (sub_layer_profile_present_flag[i]) bitstream.skipBits(88);
|
|
1218
|
+
if (sub_layer_level_present_flag[i]) bitstream.skipBits(8);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
return {
|
|
1222
|
+
general_profile_space,
|
|
1223
|
+
general_tier_flag,
|
|
1224
|
+
general_profile_idc,
|
|
1225
|
+
general_profile_compatibility_flags,
|
|
1226
|
+
general_constraint_indicator_flags,
|
|
1227
|
+
general_level_idc,
|
|
1228
|
+
};
|
|
1229
|
+
};
|
|
1230
|
+
|
|
1231
|
+
const skipScalingListData = (bitstream: Bitstream) => {
|
|
1232
|
+
for (let sizeId = 0; sizeId < 4; sizeId++) {
|
|
1233
|
+
for (let matrixId = 0; matrixId < (sizeId === 3 ? 2 : 6); matrixId++) {
|
|
1234
|
+
const scaling_list_pred_mode_flag = bitstream.readBits(1);
|
|
1235
|
+
if (!scaling_list_pred_mode_flag) {
|
|
1236
|
+
readExpGolomb(bitstream); // scaling_list_pred_matrix_id_delta
|
|
1237
|
+
} else {
|
|
1238
|
+
const coefNum = Math.min(64, 1 << (4 + (sizeId << 1)));
|
|
1239
|
+
if (sizeId > 1) {
|
|
1240
|
+
readSignedExpGolomb(bitstream); // scaling_list_dc_coef_minus8
|
|
1241
|
+
}
|
|
1242
|
+
for (let i = 0; i < coefNum; i++) {
|
|
1243
|
+
readSignedExpGolomb(bitstream); // scaling_list_delta_coef
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
const skipAllStRefPicSets = (bitstream: Bitstream, num_short_term_ref_pic_sets: number) => {
|
|
1251
|
+
const NumDeltaPocs: number[] = [];
|
|
1252
|
+
for (let stRpsIdx = 0; stRpsIdx < num_short_term_ref_pic_sets; stRpsIdx++) {
|
|
1253
|
+
NumDeltaPocs[stRpsIdx] = skipStRefPicSet(bitstream, stRpsIdx, num_short_term_ref_pic_sets, NumDeltaPocs);
|
|
1254
|
+
}
|
|
1255
|
+
};
|
|
1256
|
+
|
|
1257
|
+
const skipStRefPicSet = (
|
|
1258
|
+
bitstream: Bitstream,
|
|
1259
|
+
stRpsIdx: number,
|
|
1260
|
+
num_short_term_ref_pic_sets: number,
|
|
1261
|
+
NumDeltaPocs: number[],
|
|
1262
|
+
) => {
|
|
1263
|
+
let NumDeltaPocsThis = 0;
|
|
1264
|
+
let inter_ref_pic_set_prediction_flag = 0;
|
|
1265
|
+
let RefRpsIdx = 0;
|
|
1266
|
+
|
|
1267
|
+
if (stRpsIdx !== 0) {
|
|
1268
|
+
inter_ref_pic_set_prediction_flag = bitstream.readBits(1);
|
|
1269
|
+
}
|
|
1270
|
+
if (inter_ref_pic_set_prediction_flag) {
|
|
1271
|
+
if (stRpsIdx === num_short_term_ref_pic_sets) {
|
|
1272
|
+
const delta_idx_minus1 = readExpGolomb(bitstream);
|
|
1273
|
+
RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1);
|
|
1274
|
+
} else {
|
|
1275
|
+
RefRpsIdx = stRpsIdx - 1;
|
|
1276
|
+
}
|
|
1277
|
+
bitstream.readBits(1); // delta_rps_sign
|
|
1278
|
+
readExpGolomb(bitstream); // abs_delta_rps_minus1
|
|
1279
|
+
|
|
1280
|
+
// The number of iterations is NumDeltaPocs[RefRpsIdx] + 1
|
|
1281
|
+
const numDelta = NumDeltaPocs[RefRpsIdx] ?? 0;
|
|
1282
|
+
for (let j = 0; j <= numDelta; j++) {
|
|
1283
|
+
const used_by_curr_pic_flag = bitstream.readBits(1);
|
|
1284
|
+
if (!used_by_curr_pic_flag) {
|
|
1285
|
+
bitstream.readBits(1); // use_delta_flag
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
NumDeltaPocsThis = NumDeltaPocs[RefRpsIdx]!;
|
|
1289
|
+
} else {
|
|
1290
|
+
const num_negative_pics = readExpGolomb(bitstream);
|
|
1291
|
+
const num_positive_pics = readExpGolomb(bitstream);
|
|
1292
|
+
|
|
1293
|
+
for (let i = 0; i < num_negative_pics; i++) {
|
|
1294
|
+
readExpGolomb(bitstream); // delta_poc_s0_minus1[i]
|
|
1295
|
+
bitstream.readBits(1); // used_by_curr_pic_s0_flag[i]
|
|
1296
|
+
}
|
|
1297
|
+
for (let i = 0; i < num_positive_pics; i++) {
|
|
1298
|
+
readExpGolomb(bitstream); // delta_poc_s1_minus1[i]
|
|
1299
|
+
bitstream.readBits(1); // used_by_curr_pic_s1_flag[i]
|
|
1300
|
+
}
|
|
1301
|
+
NumDeltaPocsThis = num_negative_pics + num_positive_pics;
|
|
1302
|
+
}
|
|
1303
|
+
return NumDeltaPocsThis;
|
|
1304
|
+
};
|
|
1305
|
+
|
|
1306
|
+
const parseHevcVui = (bitstream: Bitstream, sps_max_sub_layers_minus1: number) => {
|
|
1307
|
+
// Defaults: 2 = unspecified
|
|
1308
|
+
let colourPrimaries = 2;
|
|
1309
|
+
let transferCharacteristics = 2;
|
|
1310
|
+
let matrixCoefficients = 2;
|
|
1311
|
+
let fullRangeFlag = 0;
|
|
1312
|
+
let minSpatialSegmentationIdc = 0;
|
|
1313
|
+
let pixelAspectRatio: Rational = { num: 1, den: 1 };
|
|
1314
|
+
|
|
1315
|
+
if (bitstream.readBits(1)) { // aspect_ratio_info_present_flag
|
|
1316
|
+
const aspect_ratio_idc = bitstream.readBits(8);
|
|
1317
|
+
if (aspect_ratio_idc === 255) {
|
|
1318
|
+
pixelAspectRatio = {
|
|
1319
|
+
num: bitstream.readBits(16),
|
|
1320
|
+
den: bitstream.readBits(16),
|
|
1321
|
+
};
|
|
1322
|
+
} else {
|
|
1323
|
+
const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspect_ratio_idc];
|
|
1324
|
+
if (aspectRatio) {
|
|
1325
|
+
pixelAspectRatio = aspectRatio;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
if (bitstream.readBits(1)) { // overscan_info_present_flag
|
|
1330
|
+
bitstream.readBits(1); // overscan_appropriate_flag
|
|
1331
|
+
}
|
|
1332
|
+
if (bitstream.readBits(1)) { // video_signal_type_present_flag
|
|
1333
|
+
bitstream.readBits(3); // video_format
|
|
1334
|
+
fullRangeFlag = bitstream.readBits(1);
|
|
1335
|
+
if (bitstream.readBits(1)) { // colour_description_present_flag
|
|
1336
|
+
colourPrimaries = bitstream.readBits(8);
|
|
1337
|
+
transferCharacteristics = bitstream.readBits(8);
|
|
1338
|
+
matrixCoefficients = bitstream.readBits(8);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
if (bitstream.readBits(1)) { // chroma_loc_info_present_flag
|
|
1342
|
+
readExpGolomb(bitstream); // chroma_sample_loc_type_top_field
|
|
1343
|
+
readExpGolomb(bitstream); // chroma_sample_loc_type_bottom_field
|
|
1344
|
+
}
|
|
1345
|
+
bitstream.readBits(1); // neutral_chroma_indication_flag
|
|
1346
|
+
bitstream.readBits(1); // field_seq_flag
|
|
1347
|
+
bitstream.readBits(1); // frame_field_info_present_flag
|
|
1348
|
+
if (bitstream.readBits(1)) { // default_display_window_flag
|
|
1349
|
+
readExpGolomb(bitstream); // def_disp_win_left_offset
|
|
1350
|
+
readExpGolomb(bitstream); // def_disp_win_right_offset
|
|
1351
|
+
readExpGolomb(bitstream); // def_disp_win_top_offset
|
|
1352
|
+
readExpGolomb(bitstream); // def_disp_win_bottom_offset
|
|
1353
|
+
}
|
|
1354
|
+
if (bitstream.readBits(1)) { // vui_timing_info_present_flag
|
|
1355
|
+
bitstream.readBits(32); // vui_num_units_in_tick
|
|
1356
|
+
bitstream.readBits(32); // vui_time_scale
|
|
1357
|
+
if (bitstream.readBits(1)) { // vui_poc_proportional_to_timing_flag
|
|
1358
|
+
readExpGolomb(bitstream); // vui_num_ticks_poc_diff_one_minus1
|
|
1359
|
+
}
|
|
1360
|
+
if (bitstream.readBits(1)) {
|
|
1361
|
+
skipHevcHrdParameters(bitstream, true, sps_max_sub_layers_minus1);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
if (bitstream.readBits(1)) { // bitstream_restriction_flag
|
|
1365
|
+
bitstream.readBits(1); // tiles_fixed_structure_flag
|
|
1366
|
+
bitstream.readBits(1); // motion_vectors_over_pic_boundaries_flag
|
|
1367
|
+
bitstream.readBits(1); // restricted_ref_pic_lists_flag
|
|
1368
|
+
minSpatialSegmentationIdc = readExpGolomb(bitstream);
|
|
1369
|
+
readExpGolomb(bitstream); // max_bytes_per_pic_denom
|
|
1370
|
+
readExpGolomb(bitstream); // max_bits_per_min_cu_denom
|
|
1371
|
+
readExpGolomb(bitstream); // log2_max_mv_length_horizontal
|
|
1372
|
+
readExpGolomb(bitstream); // log2_max_mv_length_vertical
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
return {
|
|
1376
|
+
pixelAspectRatio,
|
|
1377
|
+
colourPrimaries,
|
|
1378
|
+
transferCharacteristics,
|
|
1379
|
+
matrixCoefficients,
|
|
1380
|
+
fullRangeFlag,
|
|
1381
|
+
minSpatialSegmentationIdc,
|
|
1382
|
+
};
|
|
1383
|
+
};
|
|
1384
|
+
|
|
1385
|
+
const skipHevcHrdParameters = (
|
|
1386
|
+
bitstream: Bitstream,
|
|
1387
|
+
commonInfPresentFlag: boolean,
|
|
1388
|
+
maxNumSubLayersMinus1: number,
|
|
1389
|
+
) => {
|
|
1390
|
+
let nal_hrd_parameters_present_flag = false;
|
|
1391
|
+
let vcl_hrd_parameters_present_flag = false;
|
|
1392
|
+
let sub_pic_hrd_params_present_flag = false;
|
|
1393
|
+
|
|
1394
|
+
if (commonInfPresentFlag) {
|
|
1395
|
+
nal_hrd_parameters_present_flag = bitstream.readBits(1) === 1;
|
|
1396
|
+
vcl_hrd_parameters_present_flag = bitstream.readBits(1) === 1;
|
|
1397
|
+
if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
|
|
1398
|
+
sub_pic_hrd_params_present_flag = bitstream.readBits(1) === 1;
|
|
1399
|
+
if (sub_pic_hrd_params_present_flag) {
|
|
1400
|
+
bitstream.readBits(8); // tick_divisor_minus2
|
|
1401
|
+
bitstream.readBits(5); // du_cpb_removal_delay_increment_length_minus1
|
|
1402
|
+
bitstream.readBits(1); // sub_pic_cpb_params_in_pic_timing_sei_flag
|
|
1403
|
+
bitstream.readBits(5); // dpb_output_delay_du_length_minus1
|
|
1404
|
+
}
|
|
1405
|
+
bitstream.readBits(4); // bit_rate_scale
|
|
1406
|
+
bitstream.readBits(4); // cpb_size_scale
|
|
1407
|
+
if (sub_pic_hrd_params_present_flag) {
|
|
1408
|
+
bitstream.readBits(4); // cpb_size_du_scale
|
|
1409
|
+
}
|
|
1410
|
+
bitstream.readBits(5); // initial_cpb_removal_delay_length_minus1
|
|
1411
|
+
bitstream.readBits(5); // au_cpb_removal_delay_length_minus1
|
|
1412
|
+
bitstream.readBits(5); // dpb_output_delay_length_minus1
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
for (let i = 0; i <= maxNumSubLayersMinus1; i++) {
|
|
1417
|
+
const fixed_pic_rate_general_flag = bitstream.readBits(1) === 1;
|
|
1418
|
+
let fixed_pic_rate_within_cvs_flag = true; // Default assumption if general is true
|
|
1419
|
+
if (!fixed_pic_rate_general_flag) {
|
|
1420
|
+
fixed_pic_rate_within_cvs_flag = bitstream.readBits(1) === 1;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
let low_delay_hrd_flag = false; // Default assumption
|
|
1424
|
+
if (fixed_pic_rate_within_cvs_flag) {
|
|
1425
|
+
readExpGolomb(bitstream); // elemental_duration_in_tc_minus1[i]
|
|
1426
|
+
} else {
|
|
1427
|
+
low_delay_hrd_flag = bitstream.readBits(1) === 1;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
let CpbCnt = 1; // Default if low_delay is true
|
|
1431
|
+
if (!low_delay_hrd_flag) {
|
|
1432
|
+
const cpb_cnt_minus1 = readExpGolomb(bitstream); // cpb_cnt_minus1[i]
|
|
1433
|
+
CpbCnt = cpb_cnt_minus1 + 1;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
if (nal_hrd_parameters_present_flag) {
|
|
1437
|
+
skipSubLayerHrdParameters(bitstream, CpbCnt, sub_pic_hrd_params_present_flag);
|
|
1438
|
+
}
|
|
1439
|
+
if (vcl_hrd_parameters_present_flag) {
|
|
1440
|
+
skipSubLayerHrdParameters(bitstream, CpbCnt, sub_pic_hrd_params_present_flag);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
|
|
1445
|
+
const skipSubLayerHrdParameters = (
|
|
1446
|
+
bitstream: Bitstream,
|
|
1447
|
+
CpbCnt: number,
|
|
1448
|
+
sub_pic_hrd_params_present_flag: boolean,
|
|
1449
|
+
) => {
|
|
1450
|
+
for (let i = 0; i < CpbCnt; i++) {
|
|
1451
|
+
readExpGolomb(bitstream); // bit_rate_value_minus1[i]
|
|
1452
|
+
readExpGolomb(bitstream); // cpb_size_value_minus1[i]
|
|
1453
|
+
if (sub_pic_hrd_params_present_flag) {
|
|
1454
|
+
readExpGolomb(bitstream); // cpb_size_du_value_minus1[i]
|
|
1455
|
+
readExpGolomb(bitstream); // bit_rate_du_value_minus1[i]
|
|
1456
|
+
}
|
|
1457
|
+
bitstream.readBits(1); // cbr_flag[i]
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
/** Serializes an HevcDecoderConfigurationRecord into the format specified in Section 8.3.3.1 of ISO 14496-15. */
|
|
1462
|
+
export const serializeHevcDecoderConfigurationRecord = (record: HevcDecoderConfigurationRecord) => {
|
|
1463
|
+
const bytes: number[] = [];
|
|
1464
|
+
|
|
1465
|
+
bytes.push(record.configurationVersion);
|
|
1466
|
+
|
|
1467
|
+
bytes.push(
|
|
1468
|
+
((record.generalProfileSpace & 0x3) << 6)
|
|
1469
|
+
| ((record.generalTierFlag & 0x1) << 5)
|
|
1470
|
+
| (record.generalProfileIdc & 0x1F),
|
|
1471
|
+
);
|
|
1472
|
+
|
|
1473
|
+
bytes.push((record.generalProfileCompatibilityFlags >>> 24) & 0xFF);
|
|
1474
|
+
bytes.push((record.generalProfileCompatibilityFlags >>> 16) & 0xFF);
|
|
1475
|
+
bytes.push((record.generalProfileCompatibilityFlags >>> 8) & 0xFF);
|
|
1476
|
+
bytes.push(record.generalProfileCompatibilityFlags & 0xFF);
|
|
1477
|
+
|
|
1478
|
+
bytes.push(...record.generalConstraintIndicatorFlags);
|
|
1479
|
+
|
|
1480
|
+
bytes.push(record.generalLevelIdc & 0xFF);
|
|
1481
|
+
|
|
1482
|
+
bytes.push(0xF0 | ((record.minSpatialSegmentationIdc >> 8) & 0x0F)); // Reserved + high nibble
|
|
1483
|
+
bytes.push(record.minSpatialSegmentationIdc & 0xFF); // Low byte
|
|
1484
|
+
|
|
1485
|
+
bytes.push(0xFC | (record.parallelismType & 0x03));
|
|
1486
|
+
|
|
1487
|
+
bytes.push(0xFC | (record.chromaFormatIdc & 0x03));
|
|
1488
|
+
|
|
1489
|
+
bytes.push(0xF8 | (record.bitDepthLumaMinus8 & 0x07));
|
|
1490
|
+
|
|
1491
|
+
bytes.push(0xF8 | (record.bitDepthChromaMinus8 & 0x07));
|
|
1492
|
+
|
|
1493
|
+
bytes.push((record.avgFrameRate >> 8) & 0xFF); // High byte
|
|
1494
|
+
bytes.push(record.avgFrameRate & 0xFF); // Low byte
|
|
1495
|
+
|
|
1496
|
+
bytes.push(
|
|
1497
|
+
((record.constantFrameRate & 0x03) << 6)
|
|
1498
|
+
| ((record.numTemporalLayers & 0x07) << 3)
|
|
1499
|
+
| ((record.temporalIdNested & 0x01) << 2)
|
|
1500
|
+
| (record.lengthSizeMinusOne & 0x03),
|
|
1501
|
+
);
|
|
1502
|
+
|
|
1503
|
+
bytes.push(record.arrays.length & 0xFF);
|
|
1504
|
+
|
|
1505
|
+
for (const arr of record.arrays) {
|
|
1506
|
+
bytes.push(
|
|
1507
|
+
((arr.arrayCompleteness & 0x01) << 7)
|
|
1508
|
+
| (0 << 6)
|
|
1509
|
+
| (arr.nalUnitType & 0x3F),
|
|
1510
|
+
);
|
|
1511
|
+
|
|
1512
|
+
bytes.push((arr.nalUnits.length >> 8) & 0xFF); // High byte
|
|
1513
|
+
bytes.push(arr.nalUnits.length & 0xFF); // Low byte
|
|
1514
|
+
|
|
1515
|
+
for (const nal of arr.nalUnits) {
|
|
1516
|
+
bytes.push((nal.length >> 8) & 0xFF); // High byte
|
|
1517
|
+
bytes.push(nal.length & 0xFF); // Low byte
|
|
1518
|
+
|
|
1519
|
+
for (let i = 0; i < nal.length; i++) {
|
|
1520
|
+
bytes.push(nal[i]!);
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
return new Uint8Array(bytes);
|
|
1526
|
+
};
|
|
1527
|
+
|
|
1528
|
+
/** Deserializes an HevcDecoderConfigurationRecord from the format specified in Section 8.3.3.1 of ISO 14496-15. */
|
|
1529
|
+
export const deserializeHevcDecoderConfigurationRecord = (data: Uint8Array): HevcDecoderConfigurationRecord | null => {
|
|
1530
|
+
try {
|
|
1531
|
+
const view = toDataView(data);
|
|
1532
|
+
let offset = 0;
|
|
1533
|
+
|
|
1534
|
+
const configurationVersion = view.getUint8(offset++);
|
|
1535
|
+
|
|
1536
|
+
const byte1 = view.getUint8(offset++);
|
|
1537
|
+
const generalProfileSpace = (byte1 >> 6) & 0x3;
|
|
1538
|
+
const generalTierFlag = (byte1 >> 5) & 0x1;
|
|
1539
|
+
const generalProfileIdc = byte1 & 0x1F;
|
|
1540
|
+
|
|
1541
|
+
const generalProfileCompatibilityFlags = view.getUint32(offset, false);
|
|
1542
|
+
offset += 4;
|
|
1543
|
+
|
|
1544
|
+
const generalConstraintIndicatorFlags = data.subarray(offset, offset + 6);
|
|
1545
|
+
offset += 6;
|
|
1546
|
+
|
|
1547
|
+
const generalLevelIdc = view.getUint8(offset++);
|
|
1548
|
+
|
|
1549
|
+
const minSpatialSegmentationIdc = ((view.getUint8(offset++) & 0x0F) << 8) | view.getUint8(offset++);
|
|
1550
|
+
|
|
1551
|
+
const parallelismType = view.getUint8(offset++) & 0x03;
|
|
1552
|
+
|
|
1553
|
+
const chromaFormatIdc = view.getUint8(offset++) & 0x03;
|
|
1554
|
+
|
|
1555
|
+
const bitDepthLumaMinus8 = view.getUint8(offset++) & 0x07;
|
|
1556
|
+
|
|
1557
|
+
const bitDepthChromaMinus8 = view.getUint8(offset++) & 0x07;
|
|
1558
|
+
|
|
1559
|
+
const avgFrameRate = view.getUint16(offset, false);
|
|
1560
|
+
offset += 2;
|
|
1561
|
+
|
|
1562
|
+
const byte21 = view.getUint8(offset++);
|
|
1563
|
+
const constantFrameRate = (byte21 >> 6) & 0x03;
|
|
1564
|
+
const numTemporalLayers = (byte21 >> 3) & 0x07;
|
|
1565
|
+
const temporalIdNested = (byte21 >> 2) & 0x01;
|
|
1566
|
+
const lengthSizeMinusOne = byte21 & 0x03;
|
|
1567
|
+
|
|
1568
|
+
const numOfArrays = view.getUint8(offset++);
|
|
1569
|
+
|
|
1570
|
+
const arrays: HevcDecoderConfigurationRecord['arrays'] = [];
|
|
1571
|
+
for (let i = 0; i < numOfArrays; i++) {
|
|
1572
|
+
const arrByte = view.getUint8(offset++);
|
|
1573
|
+
const arrayCompleteness = (arrByte >> 7) & 0x01;
|
|
1574
|
+
const nalUnitType = arrByte & 0x3F;
|
|
1575
|
+
|
|
1576
|
+
const numNalus = view.getUint16(offset, false);
|
|
1577
|
+
offset += 2;
|
|
1578
|
+
|
|
1579
|
+
const nalUnits: Uint8Array[] = [];
|
|
1580
|
+
for (let j = 0; j < numNalus; j++) {
|
|
1581
|
+
const nalUnitLength = view.getUint16(offset, false);
|
|
1582
|
+
offset += 2;
|
|
1583
|
+
|
|
1584
|
+
nalUnits.push(data.subarray(offset, offset + nalUnitLength));
|
|
1585
|
+
offset += nalUnitLength;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
arrays.push({
|
|
1589
|
+
arrayCompleteness,
|
|
1590
|
+
nalUnitType,
|
|
1591
|
+
nalUnits,
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
return {
|
|
1596
|
+
configurationVersion,
|
|
1597
|
+
generalProfileSpace,
|
|
1598
|
+
generalTierFlag,
|
|
1599
|
+
generalProfileIdc,
|
|
1600
|
+
generalProfileCompatibilityFlags,
|
|
1601
|
+
generalConstraintIndicatorFlags,
|
|
1602
|
+
generalLevelIdc,
|
|
1603
|
+
minSpatialSegmentationIdc,
|
|
1604
|
+
parallelismType,
|
|
1605
|
+
chromaFormatIdc,
|
|
1606
|
+
bitDepthLumaMinus8,
|
|
1607
|
+
bitDepthChromaMinus8,
|
|
1608
|
+
avgFrameRate,
|
|
1609
|
+
constantFrameRate,
|
|
1610
|
+
numTemporalLayers,
|
|
1611
|
+
temporalIdNested,
|
|
1612
|
+
lengthSizeMinusOne,
|
|
1613
|
+
arrays,
|
|
1614
|
+
};
|
|
1615
|
+
} catch (error) {
|
|
1616
|
+
Logging._error('Error deserializing HEVC Decoder Configuration Record:', error);
|
|
1617
|
+
return null;
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
|
|
1621
|
+
enum HevcNaluOrderState {
|
|
1622
|
+
audAllowed,
|
|
1623
|
+
beforeFirstVcl,
|
|
1624
|
+
afterFirstVcl,
|
|
1625
|
+
eoBitstreamAllowed,
|
|
1626
|
+
noMoreDataAllowed,
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
// This function sanitzes the contents of an HEVC packet such that
|
|
1630
|
+
// https://source.chromium.org/chromium/chromium/src/+/main:media/formats/mp4/hevc.cc's validation logic does not trip
|
|
1631
|
+
// up on its contents. The validation is often too strict and rejects packets that Chromium could decode just fine.
|
|
1632
|
+
// Chromium code retrieved on 2026-04-29.
|
|
1633
|
+
// See https://issues.chromium.org/issues/507611247.
|
|
1634
|
+
export const sanitizeHevcPacketForChromium = (
|
|
1635
|
+
packetData: Uint8Array,
|
|
1636
|
+
decoderConfig: VideoDecoderConfig,
|
|
1637
|
+
): Uint8Array | null => {
|
|
1638
|
+
const removedNalUnits = new Set<number>();
|
|
1639
|
+
let orderState: HevcNaluOrderState = HevcNaluOrderState.audAllowed;
|
|
1640
|
+
|
|
1641
|
+
for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {
|
|
1642
|
+
if (orderState === HevcNaluOrderState.noMoreDataAllowed) {
|
|
1643
|
+
removedNalUnits.add(loc.offset);
|
|
1644
|
+
continue;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
const type = extractNalUnitTypeForHevc(packetData[loc.offset]!);
|
|
1648
|
+
|
|
1649
|
+
if (orderState === HevcNaluOrderState.eoBitstreamAllowed && type !== 37 /* EOB_NUT */) {
|
|
1650
|
+
removedNalUnits.add(loc.offset);
|
|
1651
|
+
continue;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
let remove = false;
|
|
1655
|
+
|
|
1656
|
+
if (type === 35) { // AUD_NUT
|
|
1657
|
+
if (orderState > HevcNaluOrderState.audAllowed) {
|
|
1658
|
+
remove = true;
|
|
1659
|
+
} else {
|
|
1660
|
+
orderState = HevcNaluOrderState.beforeFirstVcl;
|
|
1661
|
+
}
|
|
1662
|
+
} else if (type <= 31) { // VCL (0-31)
|
|
1663
|
+
if (orderState > HevcNaluOrderState.afterFirstVcl) {
|
|
1664
|
+
remove = true;
|
|
1665
|
+
} else {
|
|
1666
|
+
orderState = HevcNaluOrderState.afterFirstVcl;
|
|
1667
|
+
}
|
|
1668
|
+
} else if (type === 36) { // EOS_NUT
|
|
1669
|
+
if (orderState !== HevcNaluOrderState.afterFirstVcl) {
|
|
1670
|
+
remove = true;
|
|
1671
|
+
} else {
|
|
1672
|
+
orderState = HevcNaluOrderState.eoBitstreamAllowed;
|
|
1673
|
+
}
|
|
1674
|
+
} else if (type === 37) { // EOB_NUT
|
|
1675
|
+
if (orderState < HevcNaluOrderState.afterFirstVcl) {
|
|
1676
|
+
remove = true;
|
|
1677
|
+
} else {
|
|
1678
|
+
orderState = HevcNaluOrderState.noMoreDataAllowed;
|
|
1679
|
+
}
|
|
1680
|
+
} else if (
|
|
1681
|
+
type === 32 || type === 33 || type === 34 || type === 39
|
|
1682
|
+
|| (type >= 41 && type <= 44) || (type >= 48 && type <= 55)
|
|
1683
|
+
) { // VPS, SPS, PPS, PREFIX_SEI, RSV_NVCL41..44, UNSPEC48..55
|
|
1684
|
+
if (orderState > HevcNaluOrderState.beforeFirstVcl) {
|
|
1685
|
+
remove = true;
|
|
1686
|
+
} else {
|
|
1687
|
+
orderState = HevcNaluOrderState.beforeFirstVcl;
|
|
1688
|
+
}
|
|
1689
|
+
} else if (
|
|
1690
|
+
type === 38 || type === 40
|
|
1691
|
+
|| (type >= 45 && type <= 47) || (type >= 56 && type <= 63)
|
|
1692
|
+
) { // FD, SUFFIX_SEI, RSV_NVCL45..47, UNSPEC56..63
|
|
1693
|
+
if (orderState < HevcNaluOrderState.afterFirstVcl) {
|
|
1694
|
+
remove = true;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
if (remove) {
|
|
1699
|
+
removedNalUnits.add(loc.offset);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
// If nothing violated the rules, return null to signal that
|
|
1704
|
+
if (removedNalUnits.size === 0) {
|
|
1705
|
+
return null;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
const filteredNalUnits: Uint8Array[] = [];
|
|
1709
|
+
for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {
|
|
1710
|
+
if (!removedNalUnits.has(loc.offset)) {
|
|
1711
|
+
filteredNalUnits.push(packetData.subarray(loc.offset, loc.offset + loc.length));
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
return concatHevcNalUnits(filteredNalUnits, decoderConfig);
|
|
1716
|
+
};
|
|
1717
|
+
|
|
1718
|
+
export type Vp9CodecInfo = {
|
|
1719
|
+
profile: number;
|
|
1720
|
+
level: number;
|
|
1721
|
+
bitDepth: number;
|
|
1722
|
+
chromaSubsampling: number;
|
|
1723
|
+
videoFullRangeFlag: number;
|
|
1724
|
+
colourPrimaries: number;
|
|
1725
|
+
transferCharacteristics: number;
|
|
1726
|
+
matrixCoefficients: number;
|
|
1727
|
+
};
|
|
1728
|
+
|
|
1729
|
+
export const extractVp9CodecInfoFromPacket = (
|
|
1730
|
+
packet: Uint8Array,
|
|
1731
|
+
): Vp9CodecInfo | null => {
|
|
1732
|
+
// eslint-disable-next-line @stylistic/max-len
|
|
1733
|
+
// https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.7-20170222-draft.pdf
|
|
1734
|
+
// http://downloads.webmproject.org/docs/vp9/vp9-bitstream_superframe-and-uncompressed-header_v1.0.pdf
|
|
1735
|
+
|
|
1736
|
+
const bitstream = new Bitstream(packet);
|
|
1737
|
+
|
|
1738
|
+
// Frame marker (0b10)
|
|
1739
|
+
const frameMarker = bitstream.readBits(2);
|
|
1740
|
+
if (frameMarker !== 2) {
|
|
1741
|
+
return null;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
// Profile
|
|
1745
|
+
const profileLowBit = bitstream.readBits(1);
|
|
1746
|
+
const profileHighBit = bitstream.readBits(1);
|
|
1747
|
+
const profile = (profileHighBit << 1) + profileLowBit;
|
|
1748
|
+
|
|
1749
|
+
// Skip reserved bit for profile 3
|
|
1750
|
+
if (profile === 3) {
|
|
1751
|
+
bitstream.skipBits(1);
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// show_existing_frame
|
|
1755
|
+
const showExistingFrame = bitstream.readBits(1);
|
|
1756
|
+
|
|
1757
|
+
if (showExistingFrame === 1) {
|
|
1758
|
+
return null;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
// frame_type (0 = key frame)
|
|
1762
|
+
const frameType = bitstream.readBits(1);
|
|
1763
|
+
|
|
1764
|
+
if (frameType !== 0) {
|
|
1765
|
+
return null;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
// Skip show_frame and error_resilient_mode
|
|
1769
|
+
bitstream.skipBits(2);
|
|
1770
|
+
|
|
1771
|
+
// Sync code (0x498342)
|
|
1772
|
+
const syncCode = bitstream.readBits(24);
|
|
1773
|
+
if (syncCode !== 0x498342) {
|
|
1774
|
+
return null;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
// Color config
|
|
1778
|
+
let bitDepth = 8;
|
|
1779
|
+
if (profile >= 2) {
|
|
1780
|
+
const tenOrTwelveBit = bitstream.readBits(1);
|
|
1781
|
+
bitDepth = tenOrTwelveBit ? 12 : 10;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
// Color space
|
|
1785
|
+
const colorSpace = bitstream.readBits(3);
|
|
1786
|
+
|
|
1787
|
+
let chromaSubsampling = 0;
|
|
1788
|
+
let videoFullRangeFlag = 0;
|
|
1789
|
+
|
|
1790
|
+
if (colorSpace !== 7) { // 7 is CS_RGB
|
|
1791
|
+
const colorRange = bitstream.readBits(1);
|
|
1792
|
+
videoFullRangeFlag = colorRange;
|
|
1793
|
+
|
|
1794
|
+
if (profile === 1 || profile === 3) {
|
|
1795
|
+
const subsamplingX = bitstream.readBits(1);
|
|
1796
|
+
const subsamplingY = bitstream.readBits(1);
|
|
1797
|
+
|
|
1798
|
+
// 0 = 4:2:0 vertical
|
|
1799
|
+
// 1 = 4:2:0 colocated
|
|
1800
|
+
// 2 = 4:2:2
|
|
1801
|
+
// 3 = 4:4:4
|
|
1802
|
+
chromaSubsampling = !subsamplingX && !subsamplingY
|
|
1803
|
+
? 3 // 0,0 = 4:4:4
|
|
1804
|
+
: subsamplingX && !subsamplingY
|
|
1805
|
+
? 2 // 1,0 = 4:2:2
|
|
1806
|
+
: 1; // 1,1 = 4:2:0 colocated (default)
|
|
1807
|
+
|
|
1808
|
+
// Skip reserved bit
|
|
1809
|
+
bitstream.skipBits(1);
|
|
1810
|
+
} else {
|
|
1811
|
+
// For profile 0 and 2, always 4:2:0
|
|
1812
|
+
chromaSubsampling = 1; // Using colocated as default
|
|
1813
|
+
}
|
|
1814
|
+
} else {
|
|
1815
|
+
// RGB is always 4:4:4
|
|
1816
|
+
chromaSubsampling = 3;
|
|
1817
|
+
videoFullRangeFlag = 1;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// Parse frame size
|
|
1821
|
+
const widthMinusOne = bitstream.readBits(16);
|
|
1822
|
+
const heightMinusOne = bitstream.readBits(16);
|
|
1823
|
+
|
|
1824
|
+
const width = widthMinusOne + 1;
|
|
1825
|
+
const height = heightMinusOne + 1;
|
|
1826
|
+
|
|
1827
|
+
// Calculate level based on dimensions
|
|
1828
|
+
const pictureSize = width * height;
|
|
1829
|
+
let level = last(VP9_LEVEL_TABLE)!.level; // Default to highest level
|
|
1830
|
+
for (const entry of VP9_LEVEL_TABLE) {
|
|
1831
|
+
if (pictureSize <= entry.maxPictureSize) {
|
|
1832
|
+
level = entry.level;
|
|
1833
|
+
break;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
// Map color_space to standard values
|
|
1838
|
+
const matrixCoefficients = colorSpace === 7
|
|
1839
|
+
? 0
|
|
1840
|
+
: colorSpace === 2
|
|
1841
|
+
? 1
|
|
1842
|
+
: colorSpace === 1
|
|
1843
|
+
? 6
|
|
1844
|
+
: 2;
|
|
1845
|
+
|
|
1846
|
+
const colourPrimaries = colorSpace === 2
|
|
1847
|
+
? 1
|
|
1848
|
+
: colorSpace === 1
|
|
1849
|
+
? 6
|
|
1850
|
+
: 2;
|
|
1851
|
+
|
|
1852
|
+
const transferCharacteristics = colorSpace === 2
|
|
1853
|
+
? 1
|
|
1854
|
+
: colorSpace === 1
|
|
1855
|
+
? 6
|
|
1856
|
+
: 2;
|
|
1857
|
+
|
|
1858
|
+
return {
|
|
1859
|
+
profile,
|
|
1860
|
+
level,
|
|
1861
|
+
bitDepth,
|
|
1862
|
+
chromaSubsampling,
|
|
1863
|
+
videoFullRangeFlag,
|
|
1864
|
+
colourPrimaries,
|
|
1865
|
+
transferCharacteristics,
|
|
1866
|
+
matrixCoefficients,
|
|
1867
|
+
};
|
|
1868
|
+
};
|
|
1869
|
+
|
|
1870
|
+
export type Av1CodecInfo = {
|
|
1871
|
+
profile: number;
|
|
1872
|
+
level: number;
|
|
1873
|
+
tier: number;
|
|
1874
|
+
bitDepth: number;
|
|
1875
|
+
monochrome: number;
|
|
1876
|
+
chromaSubsamplingX: number;
|
|
1877
|
+
chromaSubsamplingY: number;
|
|
1878
|
+
chromaSamplePosition: number;
|
|
1879
|
+
};
|
|
1880
|
+
|
|
1881
|
+
/** Iterates over all OBUs in an AV1 packet bitstream. */
|
|
1882
|
+
export const iterateAv1PacketObus = function* (packet: Uint8Array) {
|
|
1883
|
+
// https://aomediacodec.github.io/av1-spec/av1-spec.pdf
|
|
1884
|
+
|
|
1885
|
+
const bitstream = new Bitstream(packet);
|
|
1886
|
+
|
|
1887
|
+
const readLeb128 = (): number | null => {
|
|
1888
|
+
let value = 0;
|
|
1889
|
+
|
|
1890
|
+
for (let i = 0; i < 8; i++) {
|
|
1891
|
+
const byte = bitstream.readAlignedByte();
|
|
1892
|
+
|
|
1893
|
+
value |= ((byte & 0x7f) << (i * 7));
|
|
1894
|
+
|
|
1895
|
+
if (!(byte & 0x80)) {
|
|
1896
|
+
break;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
// Spec requirement
|
|
1900
|
+
if (i === 7 && (byte & 0x80)) {
|
|
1901
|
+
return null;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
// Spec requirement
|
|
1906
|
+
if (value >= 2 ** 32 - 1) {
|
|
1907
|
+
return null;
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
return value;
|
|
1911
|
+
};
|
|
1912
|
+
|
|
1913
|
+
while (bitstream.getBitsLeft() >= 8) {
|
|
1914
|
+
// Parse OBU header
|
|
1915
|
+
bitstream.skipBits(1);
|
|
1916
|
+
const obuType = bitstream.readBits(4);
|
|
1917
|
+
const obuExtension = bitstream.readBits(1);
|
|
1918
|
+
const obuHasSizeField = bitstream.readBits(1);
|
|
1919
|
+
bitstream.skipBits(1);
|
|
1920
|
+
|
|
1921
|
+
// Skip extension header if present
|
|
1922
|
+
if (obuExtension) {
|
|
1923
|
+
bitstream.skipBits(8);
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
// Read OBU size if present
|
|
1927
|
+
let obuSize: number;
|
|
1928
|
+
if (obuHasSizeField) {
|
|
1929
|
+
const obuSizeValue = readLeb128();
|
|
1930
|
+
if (obuSizeValue === null) return; // It was invalid
|
|
1931
|
+
obuSize = obuSizeValue;
|
|
1932
|
+
} else {
|
|
1933
|
+
// Calculate remaining bits and convert to bytes, rounding down
|
|
1934
|
+
obuSize = Math.floor(bitstream.getBitsLeft() / 8);
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
assert(bitstream.pos % 8 === 0);
|
|
1938
|
+
|
|
1939
|
+
yield {
|
|
1940
|
+
type: obuType,
|
|
1941
|
+
data: packet.subarray(bitstream.pos / 8, bitstream.pos / 8 + obuSize),
|
|
1942
|
+
};
|
|
1943
|
+
|
|
1944
|
+
// Move to next OBU
|
|
1945
|
+
bitstream.skipBits(obuSize * 8);
|
|
1946
|
+
}
|
|
1947
|
+
};
|
|
1948
|
+
|
|
1949
|
+
/**
|
|
1950
|
+
* When AV1 codec information is not provided by the container, we can still try to extract the information by digging
|
|
1951
|
+
* into the AV1 bitstream.
|
|
1952
|
+
*/
|
|
1953
|
+
export const extractAv1CodecInfoFromPacket = (
|
|
1954
|
+
packet: Uint8Array,
|
|
1955
|
+
): Av1CodecInfo | null => {
|
|
1956
|
+
// https://aomediacodec.github.io/av1-spec/av1-spec.pdf
|
|
1957
|
+
|
|
1958
|
+
for (const { type, data } of iterateAv1PacketObus(packet)) {
|
|
1959
|
+
if (type !== 1) {
|
|
1960
|
+
continue; // 1 == OBU_SEQUENCE_HEADER
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
const bitstream = new Bitstream(data);
|
|
1964
|
+
|
|
1965
|
+
// Read sequence header fields
|
|
1966
|
+
const seqProfile = bitstream.readBits(3);
|
|
1967
|
+
|
|
1968
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1969
|
+
const stillPicture = bitstream.readBits(1);
|
|
1970
|
+
|
|
1971
|
+
const reducedStillPictureHeader = bitstream.readBits(1);
|
|
1972
|
+
|
|
1973
|
+
let seqLevel = 0;
|
|
1974
|
+
let seqTier = 0;
|
|
1975
|
+
let bufferDelayLengthMinus1 = 0;
|
|
1976
|
+
|
|
1977
|
+
if (reducedStillPictureHeader) {
|
|
1978
|
+
seqLevel = bitstream.readBits(5);
|
|
1979
|
+
} else {
|
|
1980
|
+
// Parse timing_info_present_flag
|
|
1981
|
+
const timingInfoPresentFlag = bitstream.readBits(1);
|
|
1982
|
+
|
|
1983
|
+
if (timingInfoPresentFlag) {
|
|
1984
|
+
// Skip timing info (num_units_in_display_tick, time_scale, equal_picture_interval)
|
|
1985
|
+
bitstream.skipBits(32); // num_units_in_display_tick
|
|
1986
|
+
bitstream.skipBits(32); // time_scale
|
|
1987
|
+
const equalPictureInterval = bitstream.readBits(1);
|
|
1988
|
+
|
|
1989
|
+
if (equalPictureInterval) {
|
|
1990
|
+
// Skip num_ticks_per_picture_minus_1 (uvlc)
|
|
1991
|
+
// Since this is variable length, we'd need to implement uvlc reading
|
|
1992
|
+
// For now, we'll return null as this is rare
|
|
1993
|
+
return null;
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
// Parse decoder_model_info_present_flag
|
|
1998
|
+
const decoderModelInfoPresentFlag = bitstream.readBits(1);
|
|
1999
|
+
|
|
2000
|
+
if (decoderModelInfoPresentFlag) {
|
|
2001
|
+
// Store buffer_delay_length_minus_1 instead of just skipping
|
|
2002
|
+
bufferDelayLengthMinus1 = bitstream.readBits(5);
|
|
2003
|
+
bitstream.skipBits(32); // num_units_in_decoding_tick
|
|
2004
|
+
bitstream.skipBits(5); // buffer_removal_time_length_minus_1
|
|
2005
|
+
bitstream.skipBits(5); // frame_presentation_time_length_minus_1
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
// Parse operating_points_cnt_minus_1
|
|
2009
|
+
const operatingPointsCntMinus1 = bitstream.readBits(5);
|
|
2010
|
+
|
|
2011
|
+
// For each operating point
|
|
2012
|
+
for (let i = 0; i <= operatingPointsCntMinus1; i++) {
|
|
2013
|
+
// operating_point_idc[i]
|
|
2014
|
+
bitstream.skipBits(12);
|
|
2015
|
+
|
|
2016
|
+
// seq_level_idx[i]
|
|
2017
|
+
const seqLevelIdx = bitstream.readBits(5);
|
|
2018
|
+
|
|
2019
|
+
if (i === 0) {
|
|
2020
|
+
seqLevel = seqLevelIdx;
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
if (seqLevelIdx > 7) {
|
|
2024
|
+
// seq_tier[i]
|
|
2025
|
+
const seqTierTemp = bitstream.readBits(1);
|
|
2026
|
+
if (i === 0) {
|
|
2027
|
+
seqTier = seqTierTemp;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
if (decoderModelInfoPresentFlag) {
|
|
2032
|
+
// decoder_model_present_for_this_op[i]
|
|
2033
|
+
const decoderModelPresentForThisOp = bitstream.readBits(1);
|
|
2034
|
+
|
|
2035
|
+
if (decoderModelPresentForThisOp) {
|
|
2036
|
+
const n = bufferDelayLengthMinus1 + 1;
|
|
2037
|
+
bitstream.skipBits(n); // decoder_buffer_delay[op]
|
|
2038
|
+
bitstream.skipBits(n); // encoder_buffer_delay[op]
|
|
2039
|
+
bitstream.skipBits(1); // low_delay_mode_flag[op]
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
// initial_display_delay_present_flag
|
|
2044
|
+
const initialDisplayDelayPresentFlag = bitstream.readBits(1);
|
|
2045
|
+
|
|
2046
|
+
if (initialDisplayDelayPresentFlag) {
|
|
2047
|
+
// initial_display_delay_minus_1[i]
|
|
2048
|
+
bitstream.skipBits(4);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
// Frame size
|
|
2054
|
+
const frameWidthBitsMinus1 = bitstream.readBits(4);
|
|
2055
|
+
const frameHeightBitsMinus1 = bitstream.readBits(4);
|
|
2056
|
+
const n1 = frameWidthBitsMinus1 + 1;
|
|
2057
|
+
bitstream.skipBits(n1); // max_frame_width_minus_1
|
|
2058
|
+
const n2 = frameHeightBitsMinus1 + 1;
|
|
2059
|
+
bitstream.skipBits(n2); // max_frame_height_minus_1
|
|
2060
|
+
|
|
2061
|
+
// Frame IDs
|
|
2062
|
+
let frameIdNumbersPresentFlag = 0;
|
|
2063
|
+
if (reducedStillPictureHeader) {
|
|
2064
|
+
frameIdNumbersPresentFlag = 0;
|
|
2065
|
+
} else {
|
|
2066
|
+
frameIdNumbersPresentFlag = bitstream.readBits(1);
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
if (frameIdNumbersPresentFlag) {
|
|
2070
|
+
bitstream.skipBits(4); // delta_frame_id_length_minus_2
|
|
2071
|
+
bitstream.skipBits(3); // additional_frame_id_length_minus_1
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
bitstream.skipBits(1); // use_128x128_superblock
|
|
2075
|
+
bitstream.skipBits(1); // enable_filter_intra
|
|
2076
|
+
bitstream.skipBits(1); // enable_intra_edge_filter
|
|
2077
|
+
|
|
2078
|
+
if (!reducedStillPictureHeader) {
|
|
2079
|
+
bitstream.skipBits(1); // enable_interintra_compound
|
|
2080
|
+
bitstream.skipBits(1); // enable_masked_compound
|
|
2081
|
+
bitstream.skipBits(1); // enable_warped_motion
|
|
2082
|
+
bitstream.skipBits(1); // enable_dual_filter
|
|
2083
|
+
const enableOrderHint = bitstream.readBits(1);
|
|
2084
|
+
|
|
2085
|
+
if (enableOrderHint) {
|
|
2086
|
+
bitstream.skipBits(1); // enable_jnt_comp
|
|
2087
|
+
bitstream.skipBits(1); // enable_ref_frame_mvs
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
const seqChooseScreenContentTools = bitstream.readBits(1);
|
|
2091
|
+
let seqForceScreenContentTools = 0;
|
|
2092
|
+
|
|
2093
|
+
if (seqChooseScreenContentTools) {
|
|
2094
|
+
seqForceScreenContentTools = 2; // SELECT_SCREEN_CONTENT_TOOLS
|
|
2095
|
+
} else {
|
|
2096
|
+
seqForceScreenContentTools = bitstream.readBits(1);
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
if (seqForceScreenContentTools > 0) {
|
|
2100
|
+
const seqChooseIntegerMv = bitstream.readBits(1);
|
|
2101
|
+
if (!seqChooseIntegerMv) {
|
|
2102
|
+
bitstream.skipBits(1); // seq_force_integer_mv
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
if (enableOrderHint) {
|
|
2107
|
+
bitstream.skipBits(3); // order_hint_bits_minus_1
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
bitstream.skipBits(1); // enable_superres
|
|
2112
|
+
bitstream.skipBits(1); // enable_cdef
|
|
2113
|
+
bitstream.skipBits(1); // enable_restoration
|
|
2114
|
+
|
|
2115
|
+
// color_config()
|
|
2116
|
+
const highBitdepth = bitstream.readBits(1);
|
|
2117
|
+
|
|
2118
|
+
let bitDepth = 8;
|
|
2119
|
+
if (seqProfile === 2 && highBitdepth) {
|
|
2120
|
+
const twelveBit = bitstream.readBits(1);
|
|
2121
|
+
bitDepth = twelveBit ? 12 : 10;
|
|
2122
|
+
} else if (seqProfile <= 2) {
|
|
2123
|
+
bitDepth = highBitdepth ? 10 : 8;
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
let monochrome = 0;
|
|
2127
|
+
if (seqProfile !== 1) {
|
|
2128
|
+
monochrome = bitstream.readBits(1);
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
let chromaSubsamplingX = 1;
|
|
2132
|
+
let chromaSubsamplingY = 1;
|
|
2133
|
+
let chromaSamplePosition = 0;
|
|
2134
|
+
|
|
2135
|
+
if (!monochrome) {
|
|
2136
|
+
if (seqProfile === 0) {
|
|
2137
|
+
chromaSubsamplingX = 1;
|
|
2138
|
+
chromaSubsamplingY = 1;
|
|
2139
|
+
} else if (seqProfile === 1) {
|
|
2140
|
+
chromaSubsamplingX = 0;
|
|
2141
|
+
chromaSubsamplingY = 0;
|
|
2142
|
+
} else {
|
|
2143
|
+
if (bitDepth === 12) {
|
|
2144
|
+
chromaSubsamplingX = bitstream.readBits(1);
|
|
2145
|
+
if (chromaSubsamplingX) {
|
|
2146
|
+
chromaSubsamplingY = bitstream.readBits(1);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
if (chromaSubsamplingX && chromaSubsamplingY) {
|
|
2152
|
+
chromaSamplePosition = bitstream.readBits(2);
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
return {
|
|
2157
|
+
profile: seqProfile,
|
|
2158
|
+
level: seqLevel,
|
|
2159
|
+
tier: seqTier,
|
|
2160
|
+
bitDepth,
|
|
2161
|
+
monochrome,
|
|
2162
|
+
chromaSubsamplingX,
|
|
2163
|
+
chromaSubsamplingY,
|
|
2164
|
+
chromaSamplePosition,
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
return null;
|
|
2169
|
+
};
|
|
2170
|
+
|
|
2171
|
+
export const parseOpusIdentificationHeader = (bytes: Uint8Array) => {
|
|
2172
|
+
const view = toDataView(bytes);
|
|
2173
|
+
|
|
2174
|
+
const outputChannelCount = view.getUint8(9);
|
|
2175
|
+
const preSkip = view.getUint16(10, true);
|
|
2176
|
+
const inputSampleRate = view.getUint32(12, true);
|
|
2177
|
+
const outputGain = view.getInt16(16, true);
|
|
2178
|
+
const channelMappingFamily = view.getUint8(18);
|
|
2179
|
+
|
|
2180
|
+
let channelMappingTable: Uint8Array | null = null;
|
|
2181
|
+
if (channelMappingFamily) {
|
|
2182
|
+
channelMappingTable = bytes.subarray(19, 19 + 2 + outputChannelCount);
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
return {
|
|
2186
|
+
outputChannelCount,
|
|
2187
|
+
preSkip,
|
|
2188
|
+
inputSampleRate,
|
|
2189
|
+
outputGain,
|
|
2190
|
+
channelMappingFamily,
|
|
2191
|
+
channelMappingTable,
|
|
2192
|
+
};
|
|
2193
|
+
};
|
|
2194
|
+
|
|
2195
|
+
// From https://datatracker.ietf.org/doc/html/rfc6716, in 48 kHz samples
|
|
2196
|
+
const OPUS_FRAME_DURATION_TABLE = [
|
|
2197
|
+
480, 960, 1920, 2880,
|
|
2198
|
+
480, 960, 1920, 2880,
|
|
2199
|
+
480, 960, 1920, 2880,
|
|
2200
|
+
480, 960,
|
|
2201
|
+
480, 960,
|
|
2202
|
+
120, 240, 480, 960,
|
|
2203
|
+
120, 240, 480, 960,
|
|
2204
|
+
120, 240, 480, 960,
|
|
2205
|
+
120, 240, 480, 960,
|
|
2206
|
+
];
|
|
2207
|
+
|
|
2208
|
+
export const parseOpusTocByte = (packet: Uint8Array) => {
|
|
2209
|
+
const config = packet[0]! >> 3;
|
|
2210
|
+
const code = packet[0]! & 0b11;
|
|
2211
|
+
|
|
2212
|
+
// A packet may pack more than one frame, in which case its duration is the frame duration times the number of
|
|
2213
|
+
// frames it carries. See https://datatracker.ietf.org/doc/html/rfc6716, section 3.2.
|
|
2214
|
+
let frameCount: number;
|
|
2215
|
+
if (code === 0) {
|
|
2216
|
+
frameCount = 1;
|
|
2217
|
+
} else if (code === 1 || code === 2) {
|
|
2218
|
+
frameCount = 2;
|
|
2219
|
+
} else {
|
|
2220
|
+
// Code 3: the frame count sits in the six low bits of the frame count byte
|
|
2221
|
+
frameCount = packet[1]! & 0b111111;
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
return {
|
|
2225
|
+
durationInSamples: OPUS_FRAME_DURATION_TABLE[config]! * frameCount,
|
|
2226
|
+
};
|
|
2227
|
+
};
|
|
2228
|
+
|
|
2229
|
+
// Based on vorbis_parser.c from FFmpeg.
|
|
2230
|
+
export const parseModesFromVorbisSetupPacket = (setupHeader: Uint8Array) => {
|
|
2231
|
+
// Verify that this is a Setup header.
|
|
2232
|
+
if (setupHeader.length < 7) {
|
|
2233
|
+
throw new Error('Setup header is too short.');
|
|
2234
|
+
}
|
|
2235
|
+
if (setupHeader[0] !== 5) {
|
|
2236
|
+
throw new Error('Wrong packet type in Setup header.');
|
|
2237
|
+
}
|
|
2238
|
+
const signature = String.fromCharCode(...setupHeader.slice(1, 7));
|
|
2239
|
+
if (signature !== 'vorbis') {
|
|
2240
|
+
throw new Error('Invalid packet signature in Setup header.');
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
// Reverse the entire buffer.
|
|
2244
|
+
const bufSize = setupHeader.length;
|
|
2245
|
+
const revBuffer = new Uint8Array(bufSize);
|
|
2246
|
+
for (let i = 0; i < bufSize; i++) {
|
|
2247
|
+
revBuffer[i] = setupHeader[bufSize - 1 - i]!;
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
// Initialize a Bitstream on the reversed buffer.
|
|
2251
|
+
const bitstream = new Bitstream(revBuffer);
|
|
2252
|
+
|
|
2253
|
+
// --- Find the framing bit.
|
|
2254
|
+
// In FFmpeg code, we scan until get_bits1() returns 1.
|
|
2255
|
+
let gotFramingBit = 0;
|
|
2256
|
+
while (bitstream.getBitsLeft() > 97) {
|
|
2257
|
+
if (bitstream.readBits(1) === 1) {
|
|
2258
|
+
gotFramingBit = bitstream.pos;
|
|
2259
|
+
break;
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
if (gotFramingBit === 0) {
|
|
2263
|
+
throw new Error('Invalid Setup header: framing bit not found.');
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
// --- Search backwards for a valid mode header.
|
|
2267
|
+
// We try to “guess” the number of modes by reading a fixed pattern.
|
|
2268
|
+
let modeCount = 0;
|
|
2269
|
+
let gotModeHeader = false;
|
|
2270
|
+
let lastModeCount = 0;
|
|
2271
|
+
while (bitstream.getBitsLeft() >= 97) {
|
|
2272
|
+
const tempPos = bitstream.pos;
|
|
2273
|
+
const a = bitstream.readBits(8);
|
|
2274
|
+
const b = bitstream.readBits(16);
|
|
2275
|
+
const c = bitstream.readBits(16);
|
|
2276
|
+
// If a > 63 or b or c nonzero, assume we’ve gone too far.
|
|
2277
|
+
if (a > 63 || b !== 0 || c !== 0) {
|
|
2278
|
+
bitstream.pos = tempPos;
|
|
2279
|
+
break;
|
|
2280
|
+
}
|
|
2281
|
+
bitstream.skipBits(1);
|
|
2282
|
+
modeCount++;
|
|
2283
|
+
if (modeCount > 64) {
|
|
2284
|
+
break;
|
|
2285
|
+
}
|
|
2286
|
+
const bsClone = bitstream.clone();
|
|
2287
|
+
const candidate = bsClone.readBits(6) + 1;
|
|
2288
|
+
if (candidate === modeCount) {
|
|
2289
|
+
gotModeHeader = true;
|
|
2290
|
+
lastModeCount = modeCount;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
if (!gotModeHeader) {
|
|
2294
|
+
throw new Error('Invalid Setup header: mode header not found.');
|
|
2295
|
+
}
|
|
2296
|
+
if (lastModeCount > 63) {
|
|
2297
|
+
throw new Error(`Unsupported mode count: ${lastModeCount}.`);
|
|
2298
|
+
}
|
|
2299
|
+
const finalModeCount = lastModeCount;
|
|
2300
|
+
|
|
2301
|
+
// --- Reinitialize the bitstream.
|
|
2302
|
+
bitstream.pos = 0;
|
|
2303
|
+
// Skip the bits up to the found framing bit.
|
|
2304
|
+
bitstream.skipBits(gotFramingBit);
|
|
2305
|
+
|
|
2306
|
+
// --- Now read, for each mode (in reverse order), 40 bits then one bit.
|
|
2307
|
+
// That one bit is the mode blockflag.
|
|
2308
|
+
const modeBlockflags = Array(finalModeCount).fill(0) as number[];
|
|
2309
|
+
for (let i = finalModeCount - 1; i >= 0; i--) {
|
|
2310
|
+
bitstream.skipBits(40);
|
|
2311
|
+
modeBlockflags[i] = bitstream.readBits(1);
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
return { modeBlockflags };
|
|
2315
|
+
};
|
|
2316
|
+
|
|
2317
|
+
/** Determines a packet's type (key or delta) by digging into the packet bitstream. */
|
|
2318
|
+
export const determineVideoPacketType = (
|
|
2319
|
+
codec: VideoCodec,
|
|
2320
|
+
decoderConfig: VideoDecoderConfig,
|
|
2321
|
+
packetData: Uint8Array,
|
|
2322
|
+
): PacketType | null => {
|
|
2323
|
+
switch (codec) {
|
|
2324
|
+
case 'avc': {
|
|
2325
|
+
for (const loc of iterateAvcNalUnits(packetData, decoderConfig)) {
|
|
2326
|
+
const nalTypeByte = packetData[loc.offset]!;
|
|
2327
|
+
const type = extractNalUnitTypeForAvc(nalTypeByte);
|
|
2328
|
+
|
|
2329
|
+
if (type >= AvcNalUnitType.NON_IDR_SLICE && type <= AvcNalUnitType.SLICE_DPC) {
|
|
2330
|
+
return 'delta';
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
if (type === AvcNalUnitType.IDR) {
|
|
2334
|
+
return 'key';
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
// In addition to IDR, Recovery Point SEI also counts as a valid H.264 keyframe by current consensus.
|
|
2338
|
+
// See https://github.com/w3c/webcodecs/issues/650 for the relevant discussion. WebKit and Firefox have
|
|
2339
|
+
// always supported them, but Chromium hasn't, therefore the (admittedly dirty) version check.
|
|
2340
|
+
if (type === AvcNalUnitType.SEI && (!isChromium() || getChromiumVersion()! >= 144)) {
|
|
2341
|
+
const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length);
|
|
2342
|
+
const bytes = removeEmulationPreventionBytes(nalUnit);
|
|
2343
|
+
let pos = 1; // Skip NALU header
|
|
2344
|
+
|
|
2345
|
+
// sei_rbsp()
|
|
2346
|
+
do {
|
|
2347
|
+
// sei_message()
|
|
2348
|
+
let payloadType = 0;
|
|
2349
|
+
while (true) {
|
|
2350
|
+
const nextByte = bytes[pos++];
|
|
2351
|
+
if (nextByte === undefined) break;
|
|
2352
|
+
payloadType += nextByte;
|
|
2353
|
+
|
|
2354
|
+
if (nextByte < 255) {
|
|
2355
|
+
break;
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
let payloadSize = 0;
|
|
2360
|
+
while (true) {
|
|
2361
|
+
const nextByte = bytes[pos++];
|
|
2362
|
+
if (nextByte === undefined) break;
|
|
2363
|
+
payloadSize += nextByte;
|
|
2364
|
+
|
|
2365
|
+
if (nextByte < 255) {
|
|
2366
|
+
break;
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// sei_payload()
|
|
2371
|
+
const PAYLOAD_TYPE_RECOVERY_POINT = 6;
|
|
2372
|
+
if (payloadType === PAYLOAD_TYPE_RECOVERY_POINT) {
|
|
2373
|
+
const bitstream = new Bitstream(bytes);
|
|
2374
|
+
bitstream.pos = 8 * pos;
|
|
2375
|
+
|
|
2376
|
+
const recoveryFrameCount = readExpGolomb(bitstream);
|
|
2377
|
+
const exactMatchFlag = bitstream.readBits(1);
|
|
2378
|
+
|
|
2379
|
+
if (recoveryFrameCount === 0 && exactMatchFlag === 1) {
|
|
2380
|
+
// https://github.com/w3c/webcodecs/pull/910
|
|
2381
|
+
// "recovery_frame_cnt == 0 and exact_match_flag=1 in the SEI recovery payload"
|
|
2382
|
+
return 'key';
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
pos += payloadSize;
|
|
2387
|
+
} while (pos < bytes.length - 1);
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
return 'delta';
|
|
2392
|
+
};
|
|
2393
|
+
|
|
2394
|
+
case 'hevc': {
|
|
2395
|
+
for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {
|
|
2396
|
+
const type = extractNalUnitTypeForHevc(packetData[loc.offset]!);
|
|
2397
|
+
if (type < HevcNalUnitType.BLA_W_LP) {
|
|
2398
|
+
return 'delta';
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
if (type <= HevcNalUnitType.RSV_IRAP_VCL23) {
|
|
2402
|
+
return 'key';
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
return 'delta';
|
|
2407
|
+
};
|
|
2408
|
+
|
|
2409
|
+
case 'vp8': {
|
|
2410
|
+
// VP8, once again, by far the easiest to deal with.
|
|
2411
|
+
const frameType = packetData[0]! & 0b1;
|
|
2412
|
+
return frameType === 0 ? 'key' : 'delta';
|
|
2413
|
+
};
|
|
2414
|
+
|
|
2415
|
+
case 'vp9': {
|
|
2416
|
+
const bitstream = new Bitstream(packetData);
|
|
2417
|
+
|
|
2418
|
+
if (bitstream.readBits(2) !== 2) {
|
|
2419
|
+
return null;
|
|
2420
|
+
};
|
|
2421
|
+
|
|
2422
|
+
const profileLowBit = bitstream.readBits(1);
|
|
2423
|
+
const profileHighBit = bitstream.readBits(1);
|
|
2424
|
+
const profile = (profileHighBit << 1) + profileLowBit;
|
|
2425
|
+
|
|
2426
|
+
// Skip reserved bit for profile 3
|
|
2427
|
+
if (profile === 3) {
|
|
2428
|
+
bitstream.skipBits(1);
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
const showExistingFrame = bitstream.readBits(1);
|
|
2432
|
+
if (showExistingFrame) {
|
|
2433
|
+
return null;
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
const frameType = bitstream.readBits(1);
|
|
2437
|
+
return frameType === 0 ? 'key' : 'delta';
|
|
2438
|
+
};
|
|
2439
|
+
|
|
2440
|
+
case 'av1': {
|
|
2441
|
+
let reducedStillPictureHeader = false;
|
|
2442
|
+
|
|
2443
|
+
for (const { type, data } of iterateAv1PacketObus(packetData)) {
|
|
2444
|
+
if (type === 1) { // OBU_SEQUENCE_HEADER
|
|
2445
|
+
const bitstream = new Bitstream(data);
|
|
2446
|
+
|
|
2447
|
+
bitstream.skipBits(4);
|
|
2448
|
+
reducedStillPictureHeader = !!bitstream.readBits(1);
|
|
2449
|
+
} else if (
|
|
2450
|
+
type === 3 // OBU_FRAME_HEADER
|
|
2451
|
+
|| type === 6 // OBU_FRAME
|
|
2452
|
+
|| type === 7 // OBU_REDUNDANT_FRAME_HEADER
|
|
2453
|
+
) {
|
|
2454
|
+
if (reducedStillPictureHeader) {
|
|
2455
|
+
return 'key';
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
const bitstream = new Bitstream(data);
|
|
2459
|
+
const showExistingFrame = bitstream.readBits(1);
|
|
2460
|
+
if (showExistingFrame) {
|
|
2461
|
+
return null;
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
const frameType = bitstream.readBits(2);
|
|
2465
|
+
return frameType === 0 ? 'key' : 'delta';
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
return null;
|
|
2470
|
+
};
|
|
2471
|
+
|
|
2472
|
+
case 'prores': {
|
|
2473
|
+
return 'key';
|
|
2474
|
+
};
|
|
2475
|
+
|
|
2476
|
+
default: {
|
|
2477
|
+
assertNever(codec);
|
|
2478
|
+
assert(false);
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
|
|
2483
|
+
export enum FlacBlockType {
|
|
2484
|
+
STREAMINFO = 0,
|
|
2485
|
+
VORBIS_COMMENT = 4,
|
|
2486
|
+
PICTURE = 6,
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
export const readVorbisComments = (bytes: Uint8Array, metadataTags: MetadataTags) => {
|
|
2490
|
+
// https://datatracker.ietf.org/doc/html/rfc7845#section-5.2
|
|
2491
|
+
|
|
2492
|
+
const commentView = toDataView(bytes);
|
|
2493
|
+
let commentPos = 0;
|
|
2494
|
+
|
|
2495
|
+
const vendorStringLength = commentView.getUint32(commentPos, true);
|
|
2496
|
+
commentPos += 4;
|
|
2497
|
+
|
|
2498
|
+
const vendorString = textDecoder.decode(
|
|
2499
|
+
bytes.subarray(commentPos, commentPos + vendorStringLength),
|
|
2500
|
+
);
|
|
2501
|
+
commentPos += vendorStringLength;
|
|
2502
|
+
|
|
2503
|
+
if (vendorStringLength > 0) {
|
|
2504
|
+
// Expose the vendor string in the raw metadata
|
|
2505
|
+
metadataTags.raw ??= {};
|
|
2506
|
+
metadataTags.raw['vendor'] ??= vendorString;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
const listLength = commentView.getUint32(commentPos, true);
|
|
2510
|
+
commentPos += 4;
|
|
2511
|
+
|
|
2512
|
+
// Loop over all metadata tags
|
|
2513
|
+
for (let i = 0; i < listLength; i++) {
|
|
2514
|
+
const stringLength = commentView.getUint32(commentPos, true);
|
|
2515
|
+
commentPos += 4;
|
|
2516
|
+
|
|
2517
|
+
const string = textDecoder.decode(
|
|
2518
|
+
bytes.subarray(commentPos, commentPos + stringLength),
|
|
2519
|
+
);
|
|
2520
|
+
commentPos += stringLength;
|
|
2521
|
+
|
|
2522
|
+
const separatorIndex = string.indexOf('=');
|
|
2523
|
+
if (separatorIndex === -1) {
|
|
2524
|
+
continue;
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
const key = string.slice(0, separatorIndex).toUpperCase();
|
|
2528
|
+
const value = string.slice(separatorIndex + 1);
|
|
2529
|
+
|
|
2530
|
+
metadataTags.raw ??= {};
|
|
2531
|
+
metadataTags.raw[key] ??= value;
|
|
2532
|
+
|
|
2533
|
+
switch (key) {
|
|
2534
|
+
case 'TITLE': {
|
|
2535
|
+
metadataTags.title ??= value;
|
|
2536
|
+
}; break;
|
|
2537
|
+
|
|
2538
|
+
case 'DESCRIPTION': {
|
|
2539
|
+
metadataTags.description ??= value;
|
|
2540
|
+
}; break;
|
|
2541
|
+
|
|
2542
|
+
case 'ARTIST': {
|
|
2543
|
+
metadataTags.artist ??= value;
|
|
2544
|
+
}; break;
|
|
2545
|
+
|
|
2546
|
+
case 'ALBUM': {
|
|
2547
|
+
metadataTags.album ??= value;
|
|
2548
|
+
}; break;
|
|
2549
|
+
|
|
2550
|
+
case 'ALBUMARTIST': {
|
|
2551
|
+
metadataTags.albumArtist ??= value;
|
|
2552
|
+
}; break;
|
|
2553
|
+
|
|
2554
|
+
case 'COMMENT': {
|
|
2555
|
+
metadataTags.comment ??= value;
|
|
2556
|
+
}; break;
|
|
2557
|
+
|
|
2558
|
+
case 'LYRICS': {
|
|
2559
|
+
metadataTags.lyrics ??= value;
|
|
2560
|
+
}; break;
|
|
2561
|
+
|
|
2562
|
+
case 'TRACKNUMBER': {
|
|
2563
|
+
const parts = value.split('/');
|
|
2564
|
+
const trackNum = Number.parseInt(parts[0]!, 10);
|
|
2565
|
+
const tracksTotal = parts[1] && Number.parseInt(parts[1], 10);
|
|
2566
|
+
|
|
2567
|
+
if (Number.isInteger(trackNum) && trackNum > 0) {
|
|
2568
|
+
metadataTags.trackNumber ??= trackNum;
|
|
2569
|
+
}
|
|
2570
|
+
if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) {
|
|
2571
|
+
metadataTags.tracksTotal ??= tracksTotal;
|
|
2572
|
+
}
|
|
2573
|
+
}; break;
|
|
2574
|
+
|
|
2575
|
+
case 'TRACKTOTAL': {
|
|
2576
|
+
const tracksTotal = Number.parseInt(value, 10);
|
|
2577
|
+
if (Number.isInteger(tracksTotal) && tracksTotal > 0) {
|
|
2578
|
+
metadataTags.tracksTotal ??= tracksTotal;
|
|
2579
|
+
}
|
|
2580
|
+
}; break;
|
|
2581
|
+
|
|
2582
|
+
case 'DISCNUMBER': {
|
|
2583
|
+
const parts = value.split('/');
|
|
2584
|
+
const discNum = Number.parseInt(parts[0]!, 10);
|
|
2585
|
+
const discsTotal = parts[1] && Number.parseInt(parts[1], 10);
|
|
2586
|
+
|
|
2587
|
+
if (Number.isInteger(discNum) && discNum > 0) {
|
|
2588
|
+
metadataTags.discNumber ??= discNum;
|
|
2589
|
+
}
|
|
2590
|
+
if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) {
|
|
2591
|
+
metadataTags.discsTotal ??= discsTotal;
|
|
2592
|
+
}
|
|
2593
|
+
}; break;
|
|
2594
|
+
|
|
2595
|
+
case 'DISCTOTAL': {
|
|
2596
|
+
const discsTotal = Number.parseInt(value, 10);
|
|
2597
|
+
if (Number.isInteger(discsTotal) && discsTotal > 0) {
|
|
2598
|
+
metadataTags.discsTotal ??= discsTotal;
|
|
2599
|
+
}
|
|
2600
|
+
}; break;
|
|
2601
|
+
|
|
2602
|
+
case 'DATE': {
|
|
2603
|
+
const date = new Date(value);
|
|
2604
|
+
if (!Number.isNaN(date.getTime())) {
|
|
2605
|
+
metadataTags.date ??= date;
|
|
2606
|
+
}
|
|
2607
|
+
}; break;
|
|
2608
|
+
|
|
2609
|
+
case 'GENRE': {
|
|
2610
|
+
metadataTags.genre ??= value;
|
|
2611
|
+
}; break;
|
|
2612
|
+
|
|
2613
|
+
case 'METADATA_BLOCK_PICTURE': {
|
|
2614
|
+
// https://datatracker.ietf.org/doc/rfc9639/ Section 8.8
|
|
2615
|
+
const decoded = base64ToBytes(value);
|
|
2616
|
+
|
|
2617
|
+
const view = toDataView(decoded);
|
|
2618
|
+
const pictureType = view.getUint32(0, false);
|
|
2619
|
+
const mediaTypeLength = view.getUint32(4, false);
|
|
2620
|
+
const mediaType = String.fromCharCode(...decoded.subarray(8, 8 + mediaTypeLength)); // ASCII
|
|
2621
|
+
const descriptionLength = view.getUint32(8 + mediaTypeLength, false);
|
|
2622
|
+
const description = textDecoder.decode(decoded.subarray(
|
|
2623
|
+
12 + mediaTypeLength,
|
|
2624
|
+
12 + mediaTypeLength + descriptionLength,
|
|
2625
|
+
));
|
|
2626
|
+
const dataLength = view.getUint32(mediaTypeLength + descriptionLength + 28);
|
|
2627
|
+
const data = decoded.subarray(
|
|
2628
|
+
mediaTypeLength + descriptionLength + 32,
|
|
2629
|
+
mediaTypeLength + descriptionLength + 32 + dataLength,
|
|
2630
|
+
);
|
|
2631
|
+
|
|
2632
|
+
metadataTags.images ??= [];
|
|
2633
|
+
metadataTags.images.push({
|
|
2634
|
+
data,
|
|
2635
|
+
mimeType: mediaType,
|
|
2636
|
+
kind: pictureType === 3 ? 'coverFront' : pictureType === 4 ? 'coverBack' : 'unknown',
|
|
2637
|
+
name: undefined,
|
|
2638
|
+
description: description || undefined,
|
|
2639
|
+
});
|
|
2640
|
+
}; break;
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
};
|
|
2644
|
+
|
|
2645
|
+
export const createVorbisComments = (headerBytes: Uint8Array, tags: MetadataTags, writeImages: boolean) => {
|
|
2646
|
+
// https://datatracker.ietf.org/doc/html/rfc7845#section-5.2
|
|
2647
|
+
|
|
2648
|
+
const commentHeaderParts: Uint8Array[] = [
|
|
2649
|
+
headerBytes,
|
|
2650
|
+
];
|
|
2651
|
+
|
|
2652
|
+
const vendorString = 'Mediabunny';
|
|
2653
|
+
const encodedVendorString = textEncoder.encode(vendorString);
|
|
2654
|
+
|
|
2655
|
+
let currentBuffer = new Uint8Array(4 + encodedVendorString.length);
|
|
2656
|
+
let currentView = new DataView(currentBuffer.buffer);
|
|
2657
|
+
currentView.setUint32(0, encodedVendorString.length, true);
|
|
2658
|
+
currentBuffer.set(encodedVendorString, 4);
|
|
2659
|
+
|
|
2660
|
+
commentHeaderParts.push(currentBuffer);
|
|
2661
|
+
|
|
2662
|
+
const writtenTags = new Set<string>();
|
|
2663
|
+
const addCommentTag = (key: string, value: string) => {
|
|
2664
|
+
const joined = `${key}=${value}`;
|
|
2665
|
+
const encoded = textEncoder.encode(joined);
|
|
2666
|
+
|
|
2667
|
+
currentBuffer = new Uint8Array(4 + encoded.length);
|
|
2668
|
+
currentView = new DataView(currentBuffer.buffer);
|
|
2669
|
+
|
|
2670
|
+
currentView.setUint32(0, encoded.length, true);
|
|
2671
|
+
currentBuffer.set(encoded, 4);
|
|
2672
|
+
|
|
2673
|
+
commentHeaderParts.push(currentBuffer);
|
|
2674
|
+
writtenTags.add(key);
|
|
2675
|
+
};
|
|
2676
|
+
|
|
2677
|
+
for (const { key, value } of keyValueIterator(tags)) {
|
|
2678
|
+
switch (key) {
|
|
2679
|
+
case 'title': {
|
|
2680
|
+
addCommentTag('TITLE', value);
|
|
2681
|
+
}; break;
|
|
2682
|
+
|
|
2683
|
+
case 'description': {
|
|
2684
|
+
addCommentTag('DESCRIPTION', value);
|
|
2685
|
+
}; break;
|
|
2686
|
+
|
|
2687
|
+
case 'artist': {
|
|
2688
|
+
addCommentTag('ARTIST', value);
|
|
2689
|
+
}; break;
|
|
2690
|
+
|
|
2691
|
+
case 'album': {
|
|
2692
|
+
addCommentTag('ALBUM', value);
|
|
2693
|
+
}; break;
|
|
2694
|
+
|
|
2695
|
+
case 'albumArtist': {
|
|
2696
|
+
addCommentTag('ALBUMARTIST', value);
|
|
2697
|
+
}; break;
|
|
2698
|
+
|
|
2699
|
+
case 'genre': {
|
|
2700
|
+
addCommentTag('GENRE', value);
|
|
2701
|
+
}; break;
|
|
2702
|
+
|
|
2703
|
+
case 'date': {
|
|
2704
|
+
const rawVersion = tags.raw?.['DATE'] ?? tags.raw?.['date'];
|
|
2705
|
+
if (rawVersion && typeof rawVersion === 'string') {
|
|
2706
|
+
addCommentTag('DATE', rawVersion);
|
|
2707
|
+
} else {
|
|
2708
|
+
addCommentTag('DATE', value.toISOString().slice(0, 10));
|
|
2709
|
+
}
|
|
2710
|
+
}; break;
|
|
2711
|
+
|
|
2712
|
+
case 'comment': {
|
|
2713
|
+
addCommentTag('COMMENT', value);
|
|
2714
|
+
}; break;
|
|
2715
|
+
|
|
2716
|
+
case 'lyrics': {
|
|
2717
|
+
addCommentTag('LYRICS', value);
|
|
2718
|
+
}; break;
|
|
2719
|
+
|
|
2720
|
+
case 'trackNumber': {
|
|
2721
|
+
addCommentTag('TRACKNUMBER', value.toString());
|
|
2722
|
+
}; break;
|
|
2723
|
+
|
|
2724
|
+
case 'tracksTotal': {
|
|
2725
|
+
addCommentTag('TRACKTOTAL', value.toString());
|
|
2726
|
+
}; break;
|
|
2727
|
+
|
|
2728
|
+
case 'discNumber': {
|
|
2729
|
+
addCommentTag('DISCNUMBER', value.toString());
|
|
2730
|
+
}; break;
|
|
2731
|
+
|
|
2732
|
+
case 'discsTotal': {
|
|
2733
|
+
addCommentTag('DISCTOTAL', value.toString());
|
|
2734
|
+
}; break;
|
|
2735
|
+
|
|
2736
|
+
case 'images': {
|
|
2737
|
+
// For example, in .flac, we put the pictures in a different section,
|
|
2738
|
+
// not in the Vorbis comment header.
|
|
2739
|
+
if (!writeImages) {
|
|
2740
|
+
break;
|
|
2741
|
+
}
|
|
2742
|
+
for (const image of value) {
|
|
2743
|
+
// https://datatracker.ietf.org/doc/rfc9639/ Section 8.8
|
|
2744
|
+
const pictureType = image.kind === 'coverFront' ? 3 : image.kind === 'coverBack' ? 4 : 0;
|
|
2745
|
+
const encodedMediaType = new Uint8Array(image.mimeType.length);
|
|
2746
|
+
|
|
2747
|
+
for (let i = 0; i < image.mimeType.length; i++) {
|
|
2748
|
+
encodedMediaType[i] = image.mimeType.charCodeAt(i);
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
const encodedDescription = textEncoder.encode(image.description ?? '');
|
|
2752
|
+
|
|
2753
|
+
const buffer = new Uint8Array(
|
|
2754
|
+
4 // Picture type
|
|
2755
|
+
+ 4 // MIME type length
|
|
2756
|
+
+ encodedMediaType.length // MIME type
|
|
2757
|
+
+ 4 // Description length
|
|
2758
|
+
+ encodedDescription.length // Description
|
|
2759
|
+
+ 16 // Width, height, color depth, number of colors
|
|
2760
|
+
+ 4 // Picture data length
|
|
2761
|
+
+ image.data.length, // Picture data
|
|
2762
|
+
);
|
|
2763
|
+
const view = toDataView(buffer);
|
|
2764
|
+
|
|
2765
|
+
view.setUint32(0, pictureType, false);
|
|
2766
|
+
view.setUint32(4, encodedMediaType.length, false);
|
|
2767
|
+
buffer.set(encodedMediaType, 8);
|
|
2768
|
+
view.setUint32(8 + encodedMediaType.length, encodedDescription.length, false);
|
|
2769
|
+
buffer.set(encodedDescription, 12 + encodedMediaType.length);
|
|
2770
|
+
// Skip a bunch of fields (width, height, color depth, number of colors)
|
|
2771
|
+
view.setUint32(
|
|
2772
|
+
28 + encodedMediaType.length + encodedDescription.length, image.data.length, false,
|
|
2773
|
+
);
|
|
2774
|
+
buffer.set(
|
|
2775
|
+
image.data,
|
|
2776
|
+
32 + encodedMediaType.length + encodedDescription.length,
|
|
2777
|
+
);
|
|
2778
|
+
|
|
2779
|
+
const encoded = bytesToBase64(buffer);
|
|
2780
|
+
addCommentTag('METADATA_BLOCK_PICTURE', encoded);
|
|
2781
|
+
}
|
|
2782
|
+
}; break;
|
|
2783
|
+
|
|
2784
|
+
case 'raw': {
|
|
2785
|
+
// Handled later
|
|
2786
|
+
}; break;
|
|
2787
|
+
|
|
2788
|
+
default: assertNever(key);
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
if (tags.raw) {
|
|
2793
|
+
for (const key in tags.raw) {
|
|
2794
|
+
const value = tags.raw[key] ?? tags.raw[key.toLowerCase()];
|
|
2795
|
+
if (key === 'vendor' || value == null || writtenTags.has(key)) {
|
|
2796
|
+
continue;
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2799
|
+
if (typeof value === 'string') {
|
|
2800
|
+
addCommentTag(key, value);
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
const listLengthBuffer = new Uint8Array(4);
|
|
2806
|
+
toDataView(listLengthBuffer).setUint32(0, writtenTags.size, true);
|
|
2807
|
+
commentHeaderParts.splice(2, 0, listLengthBuffer); // Insert after the header and vendor section
|
|
2808
|
+
|
|
2809
|
+
// Merge all comment header parts into a single buffer
|
|
2810
|
+
const commentHeaderLength = commentHeaderParts.reduce((a, b) => a + b.length, 0);
|
|
2811
|
+
const commentHeader = new Uint8Array(commentHeaderLength);
|
|
2812
|
+
|
|
2813
|
+
let pos = 0;
|
|
2814
|
+
for (const part of commentHeaderParts) {
|
|
2815
|
+
commentHeader.set(part, pos);
|
|
2816
|
+
pos += part.length;
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
return commentHeader;
|
|
2820
|
+
};
|
|
2821
|
+
|
|
2822
|
+
// ============================================================================
|
|
2823
|
+
// AC-3 / E-AC-3 Parsing
|
|
2824
|
+
// Reference: ETSI TS 102 366 V1.4.1
|
|
2825
|
+
// ============================================================================
|
|
2826
|
+
|
|
2827
|
+
/**
|
|
2828
|
+
* Channel counts indexed by acmod (Table 4.3).
|
|
2829
|
+
* Does NOT include LFE - add lfeon to get total channel count.
|
|
2830
|
+
*/
|
|
2831
|
+
export const AC3_ACMOD_CHANNEL_COUNTS = [2, 1, 2, 3, 3, 4, 4, 5];
|
|
2832
|
+
|
|
2833
|
+
export interface Ac3FrameInfo {
|
|
2834
|
+
/** Sample rate code */
|
|
2835
|
+
fscod: number;
|
|
2836
|
+
/** Bitstream ID */
|
|
2837
|
+
bsid: number;
|
|
2838
|
+
/** Bitstream mode */
|
|
2839
|
+
bsmod: number;
|
|
2840
|
+
/** Audio coding mode */
|
|
2841
|
+
acmod: number;
|
|
2842
|
+
/** LFE channel on */
|
|
2843
|
+
lfeon: number;
|
|
2844
|
+
/** Bit rate code (0-18, maps to bitrate via Table F.4.1) */
|
|
2845
|
+
bitRateCode: number;
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
/**
|
|
2849
|
+
* Parse an AC-3 syncframe to extract BSI (Bit Stream Information) fields.
|
|
2850
|
+
* Section 4.3
|
|
2851
|
+
*/
|
|
2852
|
+
export const parseAc3SyncFrame = (data: Uint8Array): Ac3FrameInfo | null => {
|
|
2853
|
+
if (data.length < 7) {
|
|
2854
|
+
return null;
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
// Check sync word (0x0B77)
|
|
2858
|
+
if (data[0] !== 0x0B || data[1] !== 0x77) {
|
|
2859
|
+
return null;
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2862
|
+
const bitstream = new Bitstream(data);
|
|
2863
|
+
bitstream.skipBits(16); // sync word
|
|
2864
|
+
bitstream.skipBits(16); // crc1
|
|
2865
|
+
|
|
2866
|
+
const fscod = bitstream.readBits(2);
|
|
2867
|
+
if (fscod === 3) {
|
|
2868
|
+
return null; // Reserved, invalid
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
const frmsizecod = bitstream.readBits(6);
|
|
2872
|
+
const bsid = bitstream.readBits(5);
|
|
2873
|
+
|
|
2874
|
+
// Verify this is AC-3
|
|
2875
|
+
if (bsid > 8) {
|
|
2876
|
+
return null;
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
const bsmod = bitstream.readBits(3);
|
|
2880
|
+
const acmod = bitstream.readBits(3);
|
|
2881
|
+
|
|
2882
|
+
// Skip cmixlev (center downmix level) if three front channels are in use (L, C, R).
|
|
2883
|
+
if ((acmod & 0x1) !== 0 && acmod !== 0x1) {
|
|
2884
|
+
bitstream.skipBits(2);
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2887
|
+
// Skip surmixlev (surround downmix level) if surround channels are in use.
|
|
2888
|
+
if ((acmod & 0x4) !== 0) {
|
|
2889
|
+
bitstream.skipBits(2);
|
|
2890
|
+
}
|
|
2891
|
+
|
|
2892
|
+
// Skip dsurmod if stereo (acmod === 2)
|
|
2893
|
+
if (acmod === 0x2) {
|
|
2894
|
+
bitstream.skipBits(2);
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
const lfeon = bitstream.readBits(1);
|
|
2898
|
+
const bitRateCode = Math.floor(frmsizecod / 2);
|
|
2899
|
+
|
|
2900
|
+
return { fscod, bsid, bsmod, acmod, lfeon, bitRateCode };
|
|
2901
|
+
};
|
|
2902
|
+
|
|
2903
|
+
/**
|
|
2904
|
+
* AC-3 frame sizes in bytes, indexed by [3 * frmsizecod + fscod].
|
|
2905
|
+
* fscod: 0=48kHz, 1=44.1kHz, 2=32kHz
|
|
2906
|
+
* Values are 16-bit words * 2 (to convert to bytes).
|
|
2907
|
+
* Table 4.13
|
|
2908
|
+
*/
|
|
2909
|
+
export const AC3_FRAME_SIZES = [
|
|
2910
|
+
// frmsizecod, [48kHz, 44.1kHz, 32kHz] in bytes
|
|
2911
|
+
64 * 2, 69 * 2, 96 * 2,
|
|
2912
|
+
64 * 2, 70 * 2, 96 * 2,
|
|
2913
|
+
80 * 2, 87 * 2, 120 * 2,
|
|
2914
|
+
80 * 2, 88 * 2, 120 * 2,
|
|
2915
|
+
96 * 2, 104 * 2, 144 * 2,
|
|
2916
|
+
96 * 2, 105 * 2, 144 * 2,
|
|
2917
|
+
112 * 2, 121 * 2, 168 * 2,
|
|
2918
|
+
112 * 2, 122 * 2, 168 * 2,
|
|
2919
|
+
128 * 2, 139 * 2, 192 * 2,
|
|
2920
|
+
128 * 2, 140 * 2, 192 * 2,
|
|
2921
|
+
160 * 2, 174 * 2, 240 * 2,
|
|
2922
|
+
160 * 2, 175 * 2, 240 * 2,
|
|
2923
|
+
192 * 2, 208 * 2, 288 * 2,
|
|
2924
|
+
192 * 2, 209 * 2, 288 * 2,
|
|
2925
|
+
224 * 2, 243 * 2, 336 * 2,
|
|
2926
|
+
224 * 2, 244 * 2, 336 * 2,
|
|
2927
|
+
256 * 2, 278 * 2, 384 * 2,
|
|
2928
|
+
256 * 2, 279 * 2, 384 * 2,
|
|
2929
|
+
320 * 2, 348 * 2, 480 * 2,
|
|
2930
|
+
320 * 2, 349 * 2, 480 * 2,
|
|
2931
|
+
384 * 2, 417 * 2, 576 * 2,
|
|
2932
|
+
384 * 2, 418 * 2, 576 * 2,
|
|
2933
|
+
448 * 2, 487 * 2, 672 * 2,
|
|
2934
|
+
448 * 2, 488 * 2, 672 * 2,
|
|
2935
|
+
512 * 2, 557 * 2, 768 * 2,
|
|
2936
|
+
512 * 2, 558 * 2, 768 * 2,
|
|
2937
|
+
640 * 2, 696 * 2, 960 * 2,
|
|
2938
|
+
640 * 2, 697 * 2, 960 * 2,
|
|
2939
|
+
768 * 2, 835 * 2, 1152 * 2,
|
|
2940
|
+
768 * 2, 836 * 2, 1152 * 2,
|
|
2941
|
+
896 * 2, 975 * 2, 1344 * 2,
|
|
2942
|
+
896 * 2, 976 * 2, 1344 * 2,
|
|
2943
|
+
1024 * 2, 1114 * 2, 1536 * 2,
|
|
2944
|
+
1024 * 2, 1115 * 2, 1536 * 2,
|
|
2945
|
+
1152 * 2, 1253 * 2, 1728 * 2,
|
|
2946
|
+
1152 * 2, 1254 * 2, 1728 * 2,
|
|
2947
|
+
1280 * 2, 1393 * 2, 1920 * 2,
|
|
2948
|
+
1280 * 2, 1394 * 2, 1920 * 2,
|
|
2949
|
+
];
|
|
2950
|
+
|
|
2951
|
+
/** Number of samples per AC-3 syncframe (always 1536) */
|
|
2952
|
+
export const AC3_SAMPLES_PER_FRAME = 1536;
|
|
2953
|
+
|
|
2954
|
+
/**
|
|
2955
|
+
* AC-3 registration_descriptor for MPEG-TS.
|
|
2956
|
+
* Section A.2.3
|
|
2957
|
+
*/
|
|
2958
|
+
export const AC3_REGISTRATION_DESCRIPTOR = new Uint8Array([0x05, 0x04, 0x41, 0x43, 0x2d, 0x33]);
|
|
2959
|
+
|
|
2960
|
+
/** E-AC-3 registration_descriptor for MPEG-TS/ */
|
|
2961
|
+
export const EAC3_REGISTRATION_DESCRIPTOR = new Uint8Array([0x05, 0x04, 0x45, 0x41, 0x43, 0x33]);
|
|
2962
|
+
|
|
2963
|
+
/** Number of audio blocks per syncframe, indexed by numblkscod */
|
|
2964
|
+
export const EAC3_NUMBLKS_TABLE = [1, 2, 3, 6];
|
|
2965
|
+
|
|
2966
|
+
/**
|
|
2967
|
+
* E-AC-3 independent substream info.
|
|
2968
|
+
* Each independent substream represents a separate audio program.
|
|
2969
|
+
*/
|
|
2970
|
+
export interface Eac3SubstreamInfo {
|
|
2971
|
+
/** Sample rate code */
|
|
2972
|
+
fscod: number;
|
|
2973
|
+
/** Sample rate code 2 (ATSC A/52:2018) */
|
|
2974
|
+
fscod2: number | null;
|
|
2975
|
+
/** Bitstream ID */
|
|
2976
|
+
bsid: number;
|
|
2977
|
+
/** Bitstream mode */
|
|
2978
|
+
bsmod: number;
|
|
2979
|
+
/** Audio coding mode */
|
|
2980
|
+
acmod: number;
|
|
2981
|
+
/** LFE channel on */
|
|
2982
|
+
lfeon: number;
|
|
2983
|
+
/** Number of dependent substreams */
|
|
2984
|
+
numDepSub: number;
|
|
2985
|
+
/** Channel locations for dependent substreams */
|
|
2986
|
+
chanLoc: number;
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
/**
|
|
2990
|
+
* E-AC-3 decoder configuration (dec3 box contents).
|
|
2991
|
+
*/
|
|
2992
|
+
export interface Eac3FrameInfo {
|
|
2993
|
+
/** Data rate in kbps */
|
|
2994
|
+
dataRate: number;
|
|
2995
|
+
/** Independent substreams */
|
|
2996
|
+
substreams: Eac3SubstreamInfo[];
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
/**
|
|
3000
|
+
* Parse an E-AC-3 syncframe to extract BSI fields.
|
|
3001
|
+
* Section E.1.2
|
|
3002
|
+
*/
|
|
3003
|
+
export const parseEac3SyncFrame = (data: Uint8Array): Eac3FrameInfo | null => {
|
|
3004
|
+
if (data.length < 6) {
|
|
3005
|
+
return null;
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
// Check sync word (0x0B77)
|
|
3009
|
+
if (data[0] !== 0x0B || data[1] !== 0x77) {
|
|
3010
|
+
return null;
|
|
3011
|
+
}
|
|
3012
|
+
|
|
3013
|
+
const bitstream = new Bitstream(data);
|
|
3014
|
+
bitstream.skipBits(16); // sync word
|
|
3015
|
+
|
|
3016
|
+
const strmtyp = bitstream.readBits(2);
|
|
3017
|
+
bitstream.skipBits(3); // substreamid
|
|
3018
|
+
|
|
3019
|
+
// Only parse independent substreams (strmtyp 0 or 2)
|
|
3020
|
+
if (strmtyp !== 0 && strmtyp !== 2) {
|
|
3021
|
+
return null;
|
|
3022
|
+
}
|
|
3023
|
+
|
|
3024
|
+
const frmsiz = bitstream.readBits(11);
|
|
3025
|
+
const fscod = bitstream.readBits(2);
|
|
3026
|
+
|
|
3027
|
+
let fscod2 = 0;
|
|
3028
|
+
let numblkscod: number;
|
|
3029
|
+
|
|
3030
|
+
if (fscod === 3) {
|
|
3031
|
+
// fscod2 enables reduced sample rates (24/22.05/16 kHz) per ATSC A/52:2018
|
|
3032
|
+
fscod2 = bitstream.readBits(2);
|
|
3033
|
+
numblkscod = 3; // Implicitly 6 blocks when fscod=3
|
|
3034
|
+
} else {
|
|
3035
|
+
numblkscod = bitstream.readBits(2);
|
|
3036
|
+
}
|
|
3037
|
+
|
|
3038
|
+
const acmod = bitstream.readBits(3);
|
|
3039
|
+
const lfeon = bitstream.readBits(1);
|
|
3040
|
+
const bsid = bitstream.readBits(5);
|
|
3041
|
+
|
|
3042
|
+
// Verify this is E-AC-3
|
|
3043
|
+
if (bsid < 11 || bsid > 16) {
|
|
3044
|
+
return null;
|
|
3045
|
+
}
|
|
3046
|
+
|
|
3047
|
+
// Calculate data rate: ((frmsiz + 1) * fs) / (numblks * 16)
|
|
3048
|
+
const numblks = EAC3_NUMBLKS_TABLE[numblkscod]!;
|
|
3049
|
+
let fs: number;
|
|
3050
|
+
if (fscod < 3) {
|
|
3051
|
+
fs = AC3_SAMPLE_RATES[fscod]! / 1000;
|
|
3052
|
+
} else {
|
|
3053
|
+
fs = EAC3_REDUCED_SAMPLE_RATES[fscod2]! / 1000;
|
|
3054
|
+
}
|
|
3055
|
+
const dataRate = Math.round(((frmsiz + 1) * fs) / (numblks * 16));
|
|
3056
|
+
|
|
3057
|
+
// These fields require parsing beyond the first frame.
|
|
3058
|
+
// Defaults are correct for almost all content.
|
|
3059
|
+
const bsmod = 0;
|
|
3060
|
+
const numDepSub = 0;
|
|
3061
|
+
const chanLoc = 0;
|
|
3062
|
+
|
|
3063
|
+
const substream: Eac3SubstreamInfo = {
|
|
3064
|
+
fscod,
|
|
3065
|
+
fscod2,
|
|
3066
|
+
bsid,
|
|
3067
|
+
bsmod,
|
|
3068
|
+
acmod,
|
|
3069
|
+
lfeon,
|
|
3070
|
+
numDepSub,
|
|
3071
|
+
chanLoc,
|
|
3072
|
+
};
|
|
3073
|
+
|
|
3074
|
+
return {
|
|
3075
|
+
dataRate,
|
|
3076
|
+
substreams: [substream],
|
|
3077
|
+
};
|
|
3078
|
+
};
|
|
3079
|
+
|
|
3080
|
+
/**
|
|
3081
|
+
* Parse a dec3 box to extract E-AC-3 parameters.
|
|
3082
|
+
* Section F.6
|
|
3083
|
+
*/
|
|
3084
|
+
export const parseEac3Config = (data: Uint8Array): Eac3FrameInfo | null => {
|
|
3085
|
+
if (data.length < 2) {
|
|
3086
|
+
return null;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
const bitstream = new Bitstream(data);
|
|
3090
|
+
|
|
3091
|
+
const dataRate = bitstream.readBits(13);
|
|
3092
|
+
const numIndSub = bitstream.readBits(3);
|
|
3093
|
+
|
|
3094
|
+
const substreams: Eac3SubstreamInfo[] = [];
|
|
3095
|
+
|
|
3096
|
+
for (let i = 0; i <= numIndSub; i++) {
|
|
3097
|
+
// Check we have enough data for this substream
|
|
3098
|
+
// Each substream needs at least 24 bits (3 bytes) without dependent subs
|
|
3099
|
+
if (Math.ceil(bitstream.pos / 8) + 3 > data.length) {
|
|
3100
|
+
break;
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
const fscod = bitstream.readBits(2);
|
|
3104
|
+
const bsid = bitstream.readBits(5);
|
|
3105
|
+
bitstream.skipBits(1); // reserved
|
|
3106
|
+
bitstream.skipBits(1); // asvc
|
|
3107
|
+
const bsmod = bitstream.readBits(3);
|
|
3108
|
+
const acmod = bitstream.readBits(3);
|
|
3109
|
+
const lfeon = bitstream.readBits(1);
|
|
3110
|
+
bitstream.skipBits(3); // reserved
|
|
3111
|
+
const numDepSub = bitstream.readBits(4);
|
|
3112
|
+
|
|
3113
|
+
let chanLoc = 0;
|
|
3114
|
+
|
|
3115
|
+
if (numDepSub > 0) {
|
|
3116
|
+
chanLoc = bitstream.readBits(9);
|
|
3117
|
+
} else {
|
|
3118
|
+
bitstream.skipBits(1); // reserved
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
substreams.push({
|
|
3122
|
+
fscod,
|
|
3123
|
+
fscod2: null,
|
|
3124
|
+
bsid,
|
|
3125
|
+
bsmod,
|
|
3126
|
+
acmod,
|
|
3127
|
+
lfeon,
|
|
3128
|
+
numDepSub,
|
|
3129
|
+
chanLoc,
|
|
3130
|
+
});
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
if (substreams.length === 0) {
|
|
3134
|
+
return null;
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
return { dataRate, substreams };
|
|
3138
|
+
};
|
|
3139
|
+
|
|
3140
|
+
/**
|
|
3141
|
+
* Get sample rate from E-AC-3 config.
|
|
3142
|
+
* See ATSC A/52:2018 for handling fscod2.
|
|
3143
|
+
*/
|
|
3144
|
+
export const getEac3SampleRate = (config: Eac3FrameInfo): number | null => {
|
|
3145
|
+
const sub = config.substreams[0];
|
|
3146
|
+
assert(sub);
|
|
3147
|
+
|
|
3148
|
+
if (sub.fscod < 3) {
|
|
3149
|
+
return AC3_SAMPLE_RATES[sub.fscod]!;
|
|
3150
|
+
} else if (sub.fscod2 !== null && sub.fscod2 < 3) {
|
|
3151
|
+
return EAC3_REDUCED_SAMPLE_RATES[sub.fscod2]!;
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
return null;
|
|
3155
|
+
};
|
|
3156
|
+
|
|
3157
|
+
/**
|
|
3158
|
+
* Get channel count from E-AC-3 config (first independent substream only).
|
|
3159
|
+
*/
|
|
3160
|
+
export const getEac3ChannelCount = (config: Eac3FrameInfo): number => {
|
|
3161
|
+
const sub = config.substreams[0];
|
|
3162
|
+
assert(sub);
|
|
3163
|
+
|
|
3164
|
+
let channels = AC3_ACMOD_CHANNEL_COUNTS[sub.acmod]! + sub.lfeon;
|
|
3165
|
+
|
|
3166
|
+
// Add channels from dependent substreams
|
|
3167
|
+
if (sub.numDepSub > 0) {
|
|
3168
|
+
const CHAN_LOC_COUNTS = [2, 2, 1, 1, 2, 2, 2, 1, 1];
|
|
3169
|
+
|
|
3170
|
+
for (let bit = 0; bit < 9; bit++) {
|
|
3171
|
+
if (sub.chanLoc & (1 << (8 - bit))) {
|
|
3172
|
+
channels += CHAN_LOC_COUNTS[bit]!;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
|
|
3177
|
+
return channels;
|
|
3178
|
+
};
|