munim-ffmpeg 0.3.1 → 0.4.1

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/README.md CHANGED
@@ -137,14 +137,14 @@ Codec availability is determined by the native FFmpeg builds described in [Bundl
137
137
 
138
138
  ## Where this is verified
139
139
 
140
- Every release runs the example's 24-check device suite. For 0.3.x:
140
+ Every release runs the example's 25-check device suite. For 0.4.x:
141
141
 
142
142
  | Target | Result |
143
143
  | --- | --- |
144
- | iPad Air (M3), iOS 26 | 24/24 |
145
- | iOS Simulator, arm64 | 24/24 |
146
- | Galaxy A14 5G, arm64-v8a | 24/24 |
147
- | Android emulator, arm64 | 13/24 — see below |
144
+ | iPad Air (M3), iOS 26 | 25/25 |
145
+ | iOS Simulator, arm64 | 25/25 |
146
+ | Galaxy A14 5G, arm64-v8a | 25/25 |
147
+ | Android emulator, arm64 | Software encoding passes; hardware encoding does not — see below |
148
148
  | Android `armeabi-v7a`, `x86_64` | Built and statically checked, not executed |
149
149
 
150
150
  `x86_64` cannot be run on an Apple Silicon machine: the Android emulator refuses non-native system images, and no x86_64 hardware was available. Both remaining ABIs were verified to be correct ELF binaries with the right architecture, the expected JNI exports, only system libraries unresolved, and the same FFmpeg 9.0.1 and codec set as arm64.
@@ -153,13 +153,16 @@ Every release runs the example's 24-check device suite. For 0.3.x:
153
153
 
154
154
  An Android emulator has no working MediaCodec **encoder**. `h264_mediacodec` and `hevc_mediacodec` report success and produce a file containing no frames, so anything downstream of an encode fails. Everything else — audio encoding, filters, FFprobe, muxing, cancellation, protocols — works normally there.
155
155
 
156
- This is an emulator limitation, not a package one, but it is worth knowing before debugging: **test video encoding on a physical device**. If you need encoding to work in an emulator, encode to a software codec the build does provide:
156
+ This is an emulator limitation, not a package one, but it is worth knowing before debugging: **test video encoding on a physical device**.
157
+
158
+ `pickEncoder` cannot detect it, because MediaCodec *is* present in an emulator — it just does not work. When you need encoding to succeed regardless of environment, ask for the software encoder by name:
157
159
 
158
160
  ```typescript
159
- const encoder = await pickEncoder(['h264_videotoolbox', 'h264_mediacodec', 'mpeg4'])
161
+ // Deterministic anywhere: emulators, CI, older devices.
162
+ await execute(['-y', '-i', input, '-c:v', 'libopenh264', '-pix_fmt', 'yuv420p', output])
160
163
  ```
161
164
 
162
- `mpeg4` and `libvpx-vp9` are software encoders and work everywhere. There is deliberately no software H.264 encoder: `libx264` is GPL, and bundling it would make every app using this package GPL too.
165
+ `libopenh264`, `mpeg4` and `libvpx-vp9` are all software encoders and work everywhere.
163
166
 
164
167
  ## Bundled FFmpeg builds
165
168
 
@@ -173,7 +176,7 @@ Both platforms run **FFmpeg 9.0.1**, built from [ffmpeg.org](https://www.ffmpeg.
173
176
  | TLS | SecureTransport | mbedTLS |
174
177
  | Minimum | iOS 15.1 | API 24, 16 KB pages |
175
178
 
176
- Linked libraries, identical on both: **LAME** (MP3), **Opus**, **libvpx** (VP8/VP9), **dav1d** (AV1 decoding), plus everything FFmpeg builds natively.
179
+ Linked libraries, identical on both: **LAME** (MP3), **Opus**, **libvpx** (VP8/VP9), **dav1d** (AV1 decoding), **openh264** (software H.264), plus everything FFmpeg builds natively.
177
180
 
178
181
  FFmpeg's own `ffmpeg` and `ffprobe` tools are compiled to run inside your app process, so the argument arrays you pass are handled by the real command-line code paths rather than a reimplementation.
179
182
 
@@ -181,20 +184,26 @@ FFmpeg's own `ffmpeg` and `ffprobe` tools are compiled to run inside your app pr
181
184
 
182
185
  Verified by running the example's device suite: iOS reports 186 encoders, Android 184. Everything FFmpeg builds natively (`aac`, `alac`, `flac`, `mpeg4`, `mjpeg`, `png`, `gif`, `pcm_*`, …) is on both, as are `libmp3lame`, `libopus`, `libvpx`, and `libvpx-vp9`.
183
186
 
184
- H.264 and HEVC come from the platform's hardware encoder, which is faster and smaller than bundling x264and keeps the package LGPL:
187
+ H.264 and HEVC come from the platform's hardware encoder, which is faster and uses less power than a software encoder. `libopenh264` is there as a software H.264 fallback for anywhere hardware encoding is unavailable an emulator, for instance:
185
188
 
186
189
  | Encoder | iOS | Android |
187
190
  | --- | --- | --- |
188
191
  | `h264_videotoolbox`, `hevc_videotoolbox`, `prores_videotoolbox` | ✅ | ❌ |
189
192
  | `h264_mediacodec`, `hevc_mediacodec`, `vp8_mediacodec`, `vp9_mediacodec` | ❌ | ✅ |
190
193
  | `aac_at`, `alac_at` (AudioToolbox) | ✅ | ❌ |
194
+ | `libopenh264` (H.264, software) | ✅ | ✅ |
191
195
 
192
196
  Resolve the name at runtime instead of branching on `Platform.OS`:
193
197
 
194
198
  ```typescript
195
199
  import { execute, pickEncoder } from 'munim-ffmpeg'
196
200
 
197
- const h264 = await pickEncoder(['h264_videotoolbox', 'h264_mediacodec'])
201
+ // Hardware first, software as the fallback.
202
+ const h264 = await pickEncoder([
203
+ 'h264_videotoolbox',
204
+ 'h264_mediacodec',
205
+ 'libopenh264',
206
+ ])
198
207
  if (!h264) throw new Error('No H.264 encoder in this build')
199
208
 
200
209
  await execute(['-y', '-i', inputPath, '-c:v', h264, outputPath])
@@ -622,7 +631,9 @@ if (result.success) {
622
631
 
623
632
  The JavaScript, TypeScript, Swift, Kotlin, C core, and generated Nitro bridge in this repository are Apache-2.0.
624
633
 
625
- The bundled FFmpeg 9.0.1 is **LGPLv3**, on both platforms. It is configured without `--enable-gpl`, so no x264, x265, xvid, or vid.stab: H.264 and HEVC encoding come from VideoToolbox and MediaCodec instead. The external libraries it does link are LAME (LGPL), Opus (BSD), libvpx (BSD), dav1d (BSD), and mbedTLS (Apache-2.0) on Android.
634
+ The bundled FFmpeg 9.0.1 is **LGPLv3**, on both platforms. It is configured without `--enable-gpl`, so no x264, x265, xvid, or vid.stab. The external libraries it links are LAME (LGPL), Opus (BSD), libvpx (BSD), dav1d (BSD), openh264 (BSD 2-clause), and mbedTLS (Apache-2.0) on Android.
635
+
636
+ > **A note on H.264 patents.** Hardware encoders are covered by the licences device manufacturers already pay for. Software H.264 encoding through `libopenh264` is not: Cisco's royalty coverage applies to *their* prebuilt binary, and this package builds openh264 from source. If you ship software H.264 encoding at scale, check where you stand with AVC licensing. Hardware encoders avoid the question entirely, which is why `pickEncoder` should list them first.
626
637
 
627
638
  In practice that means your application does **not** inherit GPL obligations. LGPL still applies: the FFmpeg libraries are linked and their license and notices must be conveyed with your app, and users must be able to relink against a modified FFmpeg. The exact configuration used is recorded in [`scripts/ffmpeg/build-ios.sh`](./scripts/ffmpeg/build-ios.sh) and [`build-android.sh`](./scripts/ffmpeg/build-android.sh), and the binaries can be reproduced from them.
628
639
 
@@ -681,7 +692,7 @@ Nitrogen output under `nitrogen/generated` is committed. Change the `.nitro.ts`
681
692
 
682
693
  ### Example app
683
694
 
684
- `example/` is an Expo app that runs a 24-check device suite: H.264 and HEVC encoding, VP9/Opus in WebM, MP3, AAC, scaling and multi-step filter graphs, muxing, demuxing, trimming, concatenation, thumbnails, audio resampling, awkward file paths, concurrent sessions, single and global cancellation, protocol support, and both failure paths. Fixtures are generated in JavaScript, so the suite needs no network or bundled media. Results are rendered on screen, written to `munim-ffmpeg-suite.json` in the app's document directory, and logged as `MUNIM_FFMPEG_SUITE_RESULT`.
695
+ `example/` is an Expo app that runs a 25-check device suite: H.264 and HEVC encoding, VP9/Opus in WebM, MP3, AAC, scaling and multi-step filter graphs, software H.264 via openh264, muxing, demuxing, trimming, concatenation, thumbnails, audio resampling, awkward file paths, concurrent sessions, single and global cancellation, protocol support, and both failure paths. Fixtures are generated in JavaScript, so the suite needs no network or bundled media. Results are rendered on screen, written to `munim-ffmpeg-suite.json` in the app's document directory, and logged as `MUNIM_FFMPEG_SUITE_RESULT`.
685
696
 
686
697
  ```bash
687
698
  npm run example:ios
@@ -23,9 +23,11 @@ apply plugin: 'org.jetbrains.kotlin.android'
23
23
  apply from: '../nitrogen/generated/android/NitroMunimFfmpeg+autolinking.gradle'
24
24
  apply from: "./fix-prefab.gradle"
25
25
 
26
- if (isNewArchitectureEnabled()) {
27
- apply plugin: "com.facebook.react"
28
- }
26
+ // Deliberately not applying the "com.facebook.react" plugin: Nitro generates
27
+ // its own bindings, and the React plugin also emits React Native's own
28
+ // TurboModule specs into this library. Those then collide with the app's copies
29
+ // and every consumer's release build fails with "Type
30
+ // com.facebook.fbreact.specs.* is defined multiple times".
29
31
 
30
32
  def getExtOrDefault(name) {
31
33
  return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["NitroMunimFfmpeg_" + name]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "munim-ffmpeg",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "Fast FFmpeg and FFprobe for Expo and React Native, powered by Nitro Modules",
5
5
  "main": "lib/index",
6
6
  "module": "lib/index",
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "archive": "munim-ffmpeg-binaries.tar.gz",
3
- "sha256": "5d3a286633c584ffb2ef9dec091695f5ba8f8db88187058df7143ef258e15beb",
3
+ "sha256": "e78e41e80741ec747d148e00749e2f689b96b1b7efa51dc7d6f65d4fc0ab7463",
4
4
  "ffmpeg": "9.0.1"
5
5
  }