video_compress_kit_android 0.0.3
video_compress_kit_android: ^0.0.3 copied to clipboard
Android implementation of the video_compress_kit plugin using MediaCodec.
video_compress_kit_android #
The Android implementation of video_compress_kit.
Usage #
You should not depend on this package directly. Add the app-facing package instead:
dependencies:
video_compress_kit: ^0.0.1
The Android implementation is automatically endorsed and registered.
How It Works #
Video Compression Pipeline #
Uses Android's built-in MediaCodec hardware video encoder with
MediaExtractor for demuxing and MediaMuxer for muxing. No bundled native
libraries — the entire implementation rides on top of OS APIs, adding
~0 MB to your APK size.
Input MP4
→ MediaExtractor (demux video + audio tracks)
→ MediaCodec decoder (hardware H.264 decode)
→ Surface transfer
→ MediaCodec encoder (hardware H.264 encode)
├─ H.264 Profile: Baseline / Main / High (API 23+)
├─ Bitrate mode: VBR / CBR / CQ (API 21+)
├─ CQ quality: KEY_QUALITY (0–100)
└─ Color standard: BT.601 / BT.709 (API 24+)
→ MediaMuxer + audio passthrough
→ Mp4FastStart (if faststart=true): relocate moov atom
→ Output MP4
Image Compression Pipeline #
Uses Android's built-in BitmapFactory for decoding and Bitmap.compress()
for re-encoding. No third-party image libraries.
Input image (JPEG / PNG / WebP / etc.)
→ BitmapFactory.decodeFile (with inSampleSize for memory efficiency)
→ Scale to maxWidth / maxHeight (proportional)
→ Bitmap.compress(format, quality, outputStream)
├─ JPEG: CompressFormat.JPEG
├─ PNG: CompressFormat.PNG
└─ WebP: CompressFormat.WEBP / WEBP_LOSSY (API 30+)
→ ExifInterface: copy EXIF tags (if keepExif = true)
→ Output file
Per-Session Architecture #
Each compressVideo() call creates a VideoCompressor instance stored in a
ConcurrentHashMap<String, VideoCompressor> keyed by sessionId. This enables:
- Concurrent compressions — multiple videos processed in parallel
- Per-session progress — each compressor reports progress tagged with its session ID
- Per-session cancellation — cancel a specific session without affecting others
- Cancel all — iterate the map and cancel every active session
┌──────────────────────────────────┐
│ VideoCompressKitAndroidPlugin │
│ │
│ compressors: ConcurrentHashMap │
│ ┌────────────┬────────────┐ │
│ │ "job-1" │ "job-2" │ │
│ │ Compressor │ Compressor │ │
│ └────────────┴────────────┘ │
│ │
│ cancelCompression("job-1") │
│ → compressors["job-1"].cancel()│
│ │
│ cancelCompression(null) │
│ → cancel ALL │
└──────────────────────────────────┘
Video Feature Support Matrix #
| Feature | Support | Notes |
|---|---|---|
| H.264 encoding | ✅ | Hardware-accelerated via MediaCodec |
| Resolution scaling | ✅ | Aspect-ratio preserved |
| Custom bitrate | ✅ | Overrides preset default |
| Custom frame rate | ✅ | |
| Audio passthrough | ✅ | Copies audio track without re-encoding |
| H.264 Baseline profile | ✅ | KEY_PROFILE, API 23+ |
| H.264 Main profile | ✅ | KEY_PROFILE, API 23+ |
| H.264 High profile | ✅ | KEY_PROFILE, API 23+ |
| VBR bitrate mode | ✅ | BITRATE_MODE_VBR (default) |
| CBR bitrate mode | ✅ | BITRATE_MODE_CBR |
| CQ bitrate mode | ✅* | BITRATE_MODE_CQ + KEY_QUALITY (API 21+). Falls back to VBR if hardware doesn't support CQ |
| BT.601 color standard | ✅ | KEY_COLOR_STANDARD (API 24+) |
| BT.709 color standard | ✅ | KEY_COLOR_STANDARD (API 24+) |
| Faststart (moov atom) | ✅ | Custom Mp4FastStart post-processor — pure Kotlin, zero dependencies. Patches stco/co64 offsets and rewrites as ftyp + moov + mdat. ~1–2 s I/O overhead. Non-fatal on failure. |
| Per-session progress | ✅ | Event channel with {sessionId, progress} |
| Per-session cancel | ✅ | ConcurrentHashMap keyed by sessionId |
| Delete original file | ✅ |
CQ fallback: Not all Android hardware encoders support
BITRATE_MODE_CQ. The implementation wraps CQ configuration in a try/catch — if the encoder rejects CQ mode, it automatically falls back to VBR with the preset bitrate.
Image Feature Support Matrix #
| Feature | Support | Notes |
|---|---|---|
| JPEG output | ✅ | Bitmap.CompressFormat.JPEG |
| PNG output | ✅ | Bitmap.CompressFormat.PNG (lossless, quality ignored) |
| WebP output | ✅ | WEBP_LOSSY on API 30+, WEBP on older |
| Quality control | ✅ | 1–100 for JPEG/WebP |
| Resize (maxWidth / maxHeight) | ✅ | Proportional scaling with inSampleSize for memory efficiency |
| EXIF metadata copy | ✅ | ExifInterface — copies orientation, GPS, camera, and date tags |
Requirements #
| Requirement | Value |
|---|---|
| Min SDK | 24 (Android 7.0) |
| Compile SDK | 36 |
| Kotlin | 2.x |
| Java | 17 |
| Dependencies | kotlinx-coroutines-android:1.7.3 |
Native APIs Used #
| API | Purpose | Min API |
|---|---|---|
MediaExtractor |
Demux input video/audio tracks | 16 |
MediaCodec |
Hardware H.264 decode/encode | 16 |
MediaMuxer |
Mux encoded video + audio into MP4 | 18 |
MediaFormat |
Configure encoder (profile, bitrate mode, CQ, color) | 16+ |
BitmapFactory |
Decode images with inSampleSize |
1 |
Bitmap.compress |
Re-encode images to JPEG/PNG/WebP | 1 |
ExifInterface |
Read/write EXIF metadata | 24 |
MediaMetadataRetriever |
Get video metadata, extract frames | 10 |
Mp4FastStart (custom) |
Post-process MP4 to relocate moov atom before mdat | N/A (pure Kotlin) |
License #
MIT — see LICENSE.