{"_id":"@bsky.app/video-compressor","name":"@bsky.app/video-compressor","dist-tags":{"latest":"0.2.0"},"versions":{"0.2.0":{"name":"@bsky.app/video-compressor","version":"0.2.0","license":"MIT","description":"Hardware-accelerated video compression for React Native and Expo. iOS + Android use VideoToolbox / MediaCodec; web uses WebCodecs via mediabunny.","repository":{"type":"git","url":"git+https://github.com/bluesky-social/toolbox.git"},"author":{"name":"Bluesky Social PBC","email":"hello@blueskyweb.xyz"},"homepage":"https://github.com/bluesky-social/toolbox/tree/main/packages/video-compressor","main":"build/index.js","types":"build/index.d.ts","scripts":{"build":"expo-module clean && EXPO_NONINTERACTIVE=1 expo-module build","clean":"expo-module clean","lint":"expo-module lint","typecheck":"tsc --noEmit","expo-module":"expo-module"},"keywords":["react-native","expo","video","compression","h264","hevc","webcodecs","mediabunny","ios","android","web"],"dependencies":{"mediabunny":"^1.25.3"},"devDependencies":{"@types/react":"catalog:","expo":"catalog:","expo-module-scripts":"catalog:","expo-modules-core":"catalog:","react":"catalog:","react-native":"catalog:"},"peerDependencies":{"expo":"*","react":"*","react-native":"*"},"gitHead":"4f31a009b00526bb9964b0f1b1555b31f8d72d9c","_id":"@bsky.app/video-compressor@0.2.0","bugs":{"url":"https://github.com/bluesky-social/toolbox/issues"},"_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-hQPT/zxy3MoODuN7QM5Q0jA5anrrwKfka4o9BTz821sAaiRWW8E4vdw4xsbuhfUXRNOSXknQbDHch2Toh178Xw==","shasum":"3107874ee6d8bb8c49c88feea61fa5f2f27206bb","tarball":"https://registry.npmjs.org/@bsky.app/video-compressor/-/video-compressor-0.2.0.tgz","fileCount":172,"unpackedSize":928644,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGQjD/aV4BMvM+3TOTkFnYnPPOV7tZccNQFw94rORHP6AiAoBAiXoSVdasThXjCEkxUi0/eZD9zm2LtITyiTT7NHrA=="}]},"_npmUser":{"name":"vineyardbovines","email":"spencerfpope@gmail.com"},"directories":{},"maintainers":[{"name":"ds-boyce","email":"ds@blueskyweb.xyz"},{"name":"vineyardbovines","email":"spencerfpope@gmail.com"},{"name":"estrattonbailey","email":"npm@esb.lol"},{"name":"mozzius","email":"mozzius@protonmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/video-compressor_0.2.0_1784816611850_0.6398314050760154"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-23T14:23:31.692Z","0.2.0":"2026-07-23T14:23:31.983Z","modified":"2026-07-23T14:23:32.218Z"},"maintainers":[{"name":"ds-boyce","email":"ds@blueskyweb.xyz"},{"name":"vineyardbovines","email":"spencerfpope@gmail.com"},{"name":"estrattonbailey","email":"npm@esb.lol"},{"name":"mozzius","email":"mozzius@protonmail.com"}],"description":"Hardware-accelerated video compression for React Native and Expo. iOS + Android use VideoToolbox / MediaCodec; web uses WebCodecs via mediabunny.","homepage":"https://github.com/bluesky-social/toolbox/tree/main/packages/video-compressor","keywords":["react-native","expo","video","compression","h264","hevc","webcodecs","mediabunny","ios","android","web"],"repository":{"type":"git","url":"git+https://github.com/bluesky-social/toolbox.git"},"author":{"name":"Bluesky Social PBC","email":"hello@blueskyweb.xyz"},"bugs":{"url":"https://github.com/bluesky-social/toolbox/issues"},"license":"MIT","readme":"# @bsky.app/video-compressor\n\nVideo compression for React Native and Expo across iOS, Android, and web.\niOS uses `AVAssetReader`/`AVAssetWriter` + VideoToolbox. Android uses\nMediaCodec + MediaMuxer. Web uses WebCodecs through\n[mediabunny](https://github.com/Vanilagy/mediabunny).\n\n## Installation\n\n```\nnpm install @bsky.app/video-compressor\n```\n\n## Usage\n\n```ts\nimport {compress, probe} from '@bsky.app/video-compressor'\n\nconst meta = await probe(uri)\n\nconst controller = new AbortController()\nconst result = await compress(\n  uri,\n  {\n    targetBitrate: 3_000_000, // 0 = let the encoder pick\n    maxSize: 1920, // long-edge cap in px\n    codec: 'auto', // 'auto' | 'h264' | 'hevc'\n    frameRateCap: 30,\n  },\n  {\n    onProgress: p => console.log(p), // 0..1\n    signal: controller.signal,\n  },\n)\n```\n\n`probe(uri)` returns a `VideoMetadata` object — width, height, duration,\nbitrate, codec, frame rate, rotation, etc. `compress` returns the output\n`uri`, file `size`, `mimeType`, dimensions, duration, and the codec actually\nused.\n\nCancellation is wired through `AbortSignal`. Calling `abort()` mid-run cancels\nthe underlying native session and rejects the promise with an `AbortError`.\n\n## Platform behavior\n\n| Platform | Backend                                                                                                                    |\n| -------- | -------------------------------------------------------------------------------------------------------------------------- |\n| iOS      | AVAssetReader/Writer + VideoToolbox                                                                                        |\n| Android  | MediaCodec + MediaMuxer (GL color-space convert)                                                                           |\n| Web      | WebCodecs via mediabunny. Falls back avc → hevc → vp9 → vp8 by browser support; container switches MP4 ↔ WebM accordingly. |\n\n`compress()` can also return the input unchanged. Set `passthroughGif: false`\nto force-encode GIFs (default skips them), or set\n`passthroughBelowBytes: 25_000_000` to skip files under a size threshold. On\nweb, missing WebCodecs is also a passthrough. The result's `passthroughReason`\ntells you which path it took.\n\n## Input format support\n\nCovered by the fixture corpus in `example/assets/fixtures` (see\n`example/scripts/generate-fixtures.sh`). Both example apps have a \"Run all\nfixtures\" button that runs the full corpus through `compress` and shows\n✅/❌ per fixture, so support claims can be re-verified after any change.\n\n| Input                          | iOS                | Android            | Web                  |\n| ------------------------------ | ------------------ | ------------------ | -------------------- |\n| H.264 MP4 (incl. 4K, portrait) | ✅                 | ✅                 | ✅                   |\n| HEVC MOV                       | ✅                 | ✅                 | ✅ ¹                 |\n| HEVC HDR (HLG) MOV             | ✅ tone-mapped SDR | ✅ tone-mapped SDR | ✅ ¹ tone-mapped SDR |\n| VP9 WebM                       | ❌                 | ✅                 | ✅                   |\n| H.264 AVI                      | ❌                 | ❌                 | ❌                   |\n\n¹ Needs browser HEVC decode support (Safari; Chrome with hardware decode).\n\n## Example app\n\nA small Expo app demonstrating the module — and benchmarking it against\n[`react-native-compressor`](https://github.com/Shobbak/react-native-compressor)\n— lives in `example/`. See `example/README.md` for run instructions and the\noptional `bench/compare.sh` ffprobe-based comparison script. A Vite app\nexercising the web backend lives in `web-example/`.\n","readmeFilename":"README.md","_rev":"1-76adc98921b6731f5073e2ae2efd6839"}