Skip to content

fix: enforce bitrate as a real maximum on Android and iOS/macOS#173

Merged
hm21 merged 8 commits into
stablefrom
fix/bitrate-limit
Jul 7, 2026
Merged

fix: enforce bitrate as a real maximum on Android and iOS/macOS#173
hm21 merged 8 commits into
stablefrom
fix/bitrate-limit

Conversation

@hm21

@hm21 hm21 commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Description

VideoQualityConfig.bitrate was documented as a quality setting but was silently ignored on a no-edit export: Android transmuxed the source untouched (an ~18 Mbit/s camera clip stayed ~18 Mbit/s despite an 8 Mbit/s request), and iOS/macOS mapped the value to the nearest AVAssetExportSession preset, which chooses its own bitrate (10–16 Mbit/s at 1080p). This makes bitrate a guaranteed maximum on all three platforms.

  • Android: before export, probe each source video's bitrate. If every track already fits cap × 1.2 (tolerance) and nothing else forces a re-encode, keep the lossless transmux fast path; otherwise force the Media3 video track through ResilientVideoEncoderFactory so the bitrate is actually applied. The decision is factored into a unit-tested BitrateCapPolicy and evaluated against the final (post pre-transcode/reverse/transition) clip paths.
  • iOS/macOS: replace the preset-based AVAssetExportSession render with an AVAssetReaderAVAssetWriter pipeline that sets AVVideoAverageBitRateKey (reusing the StopMotionGenerator pattern), preserving the video composition (filters/blur/layers/transitions), audio mix, global trim, frame-rate cap, progress and cancellation. A compliant no-edit source is remuxed losslessly via AVAssetExportPresetPassthrough.
  • bitrate == null: behavior unchanged. shouldOptimizeForNetworkUse (moov-at-front) works on both the fast and re-encode paths.

Note: an over-cap source that used to export losslessly is now re-encoded down to the cap.

Verification

  • ffprobe (macOS outputs): 12.5 Mbit/s HEVC + 8M cap → 6.8 Mbit/s H.264; 1.03 Mbit/s source + 8M cap → bit-identical video track (lossless copy); moov-at-front honored on both paths.
  • Integration tests: bitrate_cap_test.dart passes on macOS and a Galaxy S942B (Android 16); the full video_render_test.dart regression suite passes on both (macOS 78, Android 71 + 8 platform-skipped).
  • 8 new JUnit BitrateCapPolicy tests; iOS builds clean; flutter analyze + 251 Dart unit tests pass.
  • Manual ffprobe steps documented in example/docs/bitrate_cap_verification.md.

Related Issue: Closes #

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore

- Added `getVideoBitrate` method in `MediaInfoExtractor` to probe video bitrate.
- Updated integration tests to verify bitrate cap enforcement for compliant and over-cap sources.
- Introduced `BitrateCapPolicy` to determine when to force re-encoding based on requested bitrate cap.
- Created `BitrateCappedExporter` to handle video rendering with enforced bitrate limits.
- Enhanced documentation to clarify bitrate cap behavior and verification steps.
- Updated version to 2.4.0 to reflect new features and improvements.
@hm21 hm21 changed the title feat: Implement video bitrate cap enforcement across platforms fix: enforce bitrate as a real maximum on Android and iOS/macOS Jul 7, 2026
@hm21 hm21 merged commit d2343fc into stable Jul 7, 2026
1 check passed
@hm21 hm21 deleted the fix/bitrate-limit branch July 7, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant