Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions FEATURE_MATRIX.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Feature Matrix

Last updated: 2026-04-04
Last updated: 2026-04-13

This file tracks the public plugin contract and the current platform support level for each capability.

Expand All @@ -12,19 +12,20 @@ This file tracks the public plugin contract and the current platform support lev
| `getPluginVersion()` | Resolves `{ version: string }` on iOS, Android, and web | Web returns `"web"` as a platform marker. |
| `reencodeVideo(options)` | Resolves when the job is accepted by iOS and returns `{ jobId, status: "queued" }` when available | Android and web reject with `UNIMPLEMENTED`. |
| `convertImage(options)` | Resolves `{ outputPath, format }` on iOS and Android | Web rejects with `UNIMPLEMENTED`. |
| `convertAudio(options)` | Resolves `{ outputPath, format }` on iOS for `m4a` output | Android and web reject with `UNIMPLEMENTED`. |
| `progress` listener | Emits `{ jobId, progress, state, message?, outputPath? }` | `fileId` is kept as a compatibility alias for `jobId`. |

## Failure contract

Use these codes as the shared error vocabulary for JS consumers:

| Code | Meaning | Current producers |
| ------------------------ | ------------------------------------------------------------ | ----------------------------------------------- |
| `UNIMPLEMENTED` | The API is not implemented on the current platform | Android/web `reencodeVideo`, web `convertImage` |
| `UNAVAILABLE` | The API exists but cannot be used in the current environment | Reserved for future capabilities |
| `INVALID_ARGUMENT` | Caller input failed local validation | iOS `reencodeVideo` validation |
| `PLUGIN_NOT_INITIALIZED` | Native core could not be initialized | iOS native wrapper |
| `TRANSCODE_FAILED` | The media pipeline failed after acceptance or during setup | iOS native wrapper and Rust bridge |
| Code | Meaning | Current producers |
| ------------------------ | ------------------------------------------------------------ | --------------------------------------------------------------------------- |
| `UNIMPLEMENTED` | The API is not implemented on the current platform | Android/web `reencodeVideo`, Android/web `convertAudio`, web `convertImage` |
| `UNAVAILABLE` | The API exists but cannot be used in the current environment | Reserved for future capabilities |
| `INVALID_ARGUMENT` | Caller input failed local validation | iOS media wrapper validation |
| `PLUGIN_NOT_INITIALIZED` | Native core could not be initialized | iOS native wrapper |
| `TRANSCODE_FAILED` | The media pipeline failed after acceptance or during setup | iOS native wrappers and Rust bridge |

## Platform support

Expand All @@ -35,6 +36,7 @@ Use these codes as the shared error vocabulary for JS consumers:
| `reencodeVideo` acceptance contract | ✅ | ❌ `UNIMPLEMENTED` | ❌ `UNIMPLEMENTED` | Covered for iOS helpers and web/Android unsupported behavior |
| `reencodeVideo` media execution | ⚠️ Experimental | ❌ | ❌ | Wrapper contract covered; media regression fixtures still pending |
| `convertImage` | ✅ `jpeg`/`png` | ✅ `webp`/`jpeg`/`png` | ❌ `UNIMPLEMENTED` | Covered by iOS native tests, Android unit tests, and Maestro flows |
| `convertAudio` | ✅ `m4a` | ❌ `UNIMPLEMENTED` | ❌ `UNIMPLEMENTED` | Covered by iOS native tests plus web and Android unsupported tests |
| `progress` listener contract | ✅ | ❌ | ❌ | Covered by iOS helper tests |
| `probeMedia` | ❌ Planned | ❌ Planned | ❌ Planned | Not started |
| `generateThumbnail` | ❌ Planned | ❌ Planned | ❌ Planned | Not started |
Expand All @@ -46,6 +48,7 @@ Use these codes as the shared error vocabulary for JS consumers:

- iOS is still the reference platform for media work.
- `convertImage()` does not depend on the Rust FFmpeg core and remains available even when `reencodeVideo()` is unavailable in SwiftPM builds.
- `convertAudio()` currently relies on `AVAssetExportSession` on iOS and is limited to `m4a` output.
- Android currently implements image conversion without the broader FFmpeg job pipeline.
- `getCapabilities()` is the machine-readable source of truth for app-side feature gating.
- Android and web should reject unsupported media APIs explicitly instead of failing implicitly.
Expand Down
88 changes: 55 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,26 +53,28 @@ bunx cap sync
| `getPluginVersion` | ✅ | ✅ | ✅ | Returns a `{ version }` payload on every platform; use `getCapabilities().platform` for platform detection. |
| `reencodeVideo` | ⚠️ Experimental | ❌ | ❌ | iOS accepts a queued job and reports lifecycle via `progress`; Android and web reject with `UNIMPLEMENTED`. |
| `convertImage` | ✅ | ✅ | ❌ | iOS converts still images to `jpeg` or `png`; Android converts to `webp`, `jpeg`, or `png`; web rejects. |
| `convertAudio` | ✅ | ❌ | ❌ | iOS converts audio to `m4a`; Android and web reject with `UNIMPLEMENTED`. |

## Platform status

| Platform | Status | Notes |
| -------- | ----------------------------- | ---------------------------------------------------------------------------------------- |
| iOS | Early implementation | Current reference platform for media work. |
| Android | Partial native implementation | `convertImage` is native; the broader FFmpeg media engine still needs to be implemented. |
| Web | Stub only | Media operations are intentionally unsupported right now. |
| Platform | Status | Notes |
| -------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------- |
| iOS | Early implementation | Current reference platform for media work. |
| Android | Partial native implementation | `convertImage` is native; the broader FFmpeg media engine and `convertAudio` still need to be implemented. |
| Web | Stub only | Media operations are intentionally unsupported right now. |

## API

<docgen-index>

* [`getCapabilities()`](#getcapabilities)
* [`reencodeVideo(...)`](#reencodevideo)
* [`convertImage(...)`](#convertimage)
* [`addListener('progress', ...)`](#addlistenerprogress-)
* [`getPluginVersion()`](#getpluginversion)
* [Interfaces](#interfaces)
* [Type Aliases](#type-aliases)
- [`getCapabilities()`](#getcapabilities)
- [`reencodeVideo(...)`](#reencodevideo)
- [`convertImage(...)`](#convertimage)
- [`convertAudio(...)`](#convertaudio)
- [`addListener('progress', ...)`](#addlistenerprogress-)
- [`getPluginVersion()`](#getpluginversion)
- [Interfaces](#interfaces)
- [Type Aliases](#type-aliases)

</docgen-index>

Expand All @@ -89,8 +91,7 @@ Return the machine-readable capability matrix for the current platform.

**Returns:** <code>Promise&lt;<a href="#ffmpegcapabilitiesresult">FFmpegCapabilitiesResult</a>&gt;</code>

--------------------

---

### reencodeVideo(...)

Expand All @@ -111,8 +112,7 @@ Android and web currently reject with `UNIMPLEMENTED`.

**Returns:** <code>Promise&lt;<a href="#ffmpegacceptedjob">FFmpegAcceptedJob</a>&gt;</code>

--------------------

---

### convertImage(...)

Expand All @@ -132,8 +132,26 @@ Web currently rejects with `UNIMPLEMENTED`.

**Returns:** <code>Promise&lt;<a href="#convertimageresult">ConvertImageResult</a>&gt;</code>

--------------------
---

### convertAudio(...)

```typescript
convertAudio(options: ConvertAudioOptions) => Promise<ConvertAudioResult>
```

Convert audio into another container or codec.

iOS currently supports `m4a`.
Android and web currently reject with `UNIMPLEMENTED`.

| Param | Type |
| ------------- | ------------------------------------------------------------------- |
| **`options`** | <code><a href="#convertaudiooptions">ConvertAudioOptions</a></code> |

**Returns:** <code>Promise&lt;<a href="#convertaudioresult">ConvertAudioResult</a>&gt;</code>

---

### addListener('progress', ...)

Expand All @@ -150,8 +168,7 @@ Listen for media job progress.

**Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>

--------------------

---

### getPluginVersion()

Expand All @@ -163,20 +180,17 @@ Get the plugin package version reported by the current platform implementation.

**Returns:** <code>Promise&lt;<a href="#pluginversionresult">PluginVersionResult</a>&gt;</code>

--------------------

---

### Interfaces


#### FFmpegCapabilitiesResult

| Prop | Type |
| -------------- | --------------------------------------------------------------------------------- |
| **`platform`** | <code>string</code> |
| **`features`** | <code><a href="#ffmpegcapabilitiesfeatures">FFmpegCapabilitiesFeatures</a></code> |


#### FFmpegCapabilitiesFeatures

| Prop | Type |
Expand All @@ -185,30 +199,28 @@ Get the plugin package version reported by the current platform implementation.
| **`getCapabilities`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |
| **`reencodeVideo`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |
| **`convertImage`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |
| **`convertAudio`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |
| **`progressEvents`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |
| **`probeMedia`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |
| **`generateThumbnail`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |
| **`extractAudio`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |
| **`remux`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |
| **`trim`** | <code><a href="#ffmpegcapability">FFmpegCapability</a></code> |


#### FFmpegCapability

| Prop | Type |
| ------------ | ------------------------------------------------------------------------- |
| **`status`** | <code><a href="#ffmpegcapabilitystatus">FFmpegCapabilityStatus</a></code> |
| **`reason`** | <code>string</code> |


#### FFmpegAcceptedJob

| Prop | Type |
| ------------ | --------------------- |
| **`jobId`** | <code>string</code> |
| **`status`** | <code>'queued'</code> |


#### ReencodeVideoOptions

| Prop | Type |
Expand All @@ -219,15 +231,13 @@ Get the plugin package version reported by the current platform implementation.
| **`height`** | <code>number</code> |
| **`bitrate`** | <code>number</code> |


#### ConvertImageResult

| Prop | Type |
| ---------------- | --------------------------------------------------------------- |
| **`outputPath`** | <code>string</code> |
| **`format`** | <code><a href="#imageoutputformat">ImageOutputFormat</a></code> |


#### ConvertImageOptions

| Prop | Type | Description |
Expand All @@ -237,14 +247,27 @@ Get the plugin package version reported by the current platform implementation.
| **`format`** | <code><a href="#imageoutputformat">ImageOutputFormat</a></code> | |
| **`quality`** | <code>number</code> | Compression quality in the inclusive range `0.0..1.0`. Native platforms reject values outside that range. |

#### ConvertAudioResult

| Prop | Type |
| ---------------- | --------------------------------------------------------------- |
| **`outputPath`** | <code>string</code> |
| **`format`** | <code><a href="#audiooutputformat">AudioOutputFormat</a></code> |

#### ConvertAudioOptions

| Prop | Type |
| ---------------- | --------------------------------------------------------------- |
| **`inputPath`** | <code>string</code> |
| **`outputPath`** | <code>string</code> |
| **`format`** | <code><a href="#audiooutputformat">AudioOutputFormat</a></code> |

#### PluginListenerHandle

| Prop | Type |
| ------------ | ----------------------------------------- |
| **`remove`** | <code>() =&gt; Promise&lt;void&gt;</code> |


#### FFmpegProgressEvent

| Prop | Type | Description |
Expand All @@ -256,26 +279,25 @@ Get the plugin package version reported by the current platform implementation.
| **`outputPath`** | <code>string</code> | |
| **`fileId`** | <code>string</code> | Legacy alias kept for compatibility while callers migrate to `jobId`. |


#### PluginVersionResult

| Prop | Type |
| ------------- | ------------------- |
| **`version`** | <code>string</code> |


### Type Aliases


#### FFmpegCapabilityStatus

<code>'available' | 'experimental' | 'unimplemented' | 'unavailable'</code>


#### ImageOutputFormat

<code>'webp' | 'jpeg' | 'png'</code>

#### AudioOutputFormat

<code>'m4a'</code>

#### FFmpegProgressState

Expand Down
Loading
Loading