Skip to content

Android / OPPO Motion Photo to Apple Live Photo - #16

Merged
21Z121Z1 merged 76 commits into
mainfrom
feature/android-motion-photo-live-photo
Aug 11, 2026
Merged

Android / OPPO Motion Photo to Apple Live Photo#16
21Z121Z1 merged 76 commits into
mainfrom
feature/android-motion-photo-live-photo

Conversation

@21Z121Z1

@21Z121Z1 21Z121Z1 commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Scope

Implements Android Motion Photo / OPPO Live Photo → Apple Live Photo resource pairs (.heic still + .mov paired video) without changing the existing ProXDR / ISO HDR / OPPO-compatible / Portrait / Photographic Styles conversion core.

The supplied real-fixture gate is now green on GitHub's macos-26-arm64 runner, and the ordinary XDRemux CI + policy checks are also green on the current head.

Real sample coverage

The supplied archives contain 14 files:

  • OPPO ColorOS 15: 3 JPEG Live Photos
  • OPPO ColorOS 16: 2 JPEG Live Photos, both dual-BMFF-stream inputs
  • Samsung: 2 JPEG Motion Photos + 4 HEIC Motion Photos (two duplicate pairs)
  • Xiaomi: 1 JPEG Motion Photo
  • vivo: 2 JPEG Motion Photos

Every file in the first archive contains Ultra HDR gain-map metadata. The two vivo samples are standard SDR Motion Photos.

The real samples exposed and now lock down several format details:

  • Samsung JPEG Motion Photos can contain an earlier BMFF-looking vendor region inside the static resource; semantic Container:Directory ranges select the real MotionPhoto payload.
  • Samsung HEIC Motion Photo V1 stores video in top-level mpvd; the declared MotionPhoto length may also cover trailing Samsung sefd, so only mpvd payload becomes the Apple MOV.
  • Xiaomi uses a positive-length Ultra HDR GainMap resource before the trailing MotionPhoto video.
  • ColorOS 16 uses two concatenated BMFF streams; Stream 1 is selected for the Apple paired video.
  • OPPO/Samsung/Xiaomi/vivo samples cover HEVC variants and AAC layouts; compressed media payloads are verified byte-for-byte across MP4 → MOV remux.

Exact fixture SHA-256 values, byte ranges, presentation timestamps, stream counts and expected gain-map state are locked in UploadedMotionPhotoFixtureGateTests.

Architecture

XDRemuxCore/MotionPhoto

  • normalized MotionPhotoAsset / item / checked byte-range model
  • Android Motion Photo V1 parser (Camera/GCamera, Container/GContainer)
  • legacy MicroVideo V1b compatibility
  • JPEG + HEIC/HEIF Motion Photo inputs
  • HEIF top-level mpvd parser with Samsung trailing-sefd handling
  • strict directory/range/EOF validation and bounded BMFF scanning
  • positive-length Ultra HDR GainMap resources remain inside the still resource passed to ImageIO
  • bounded FileHandle payload extraction
  • DTD/entity rejection, checked integer arithmetic and parser limits
  • OPPO LPEX parser + ColorOS 15/16 vendor extension
  • ColorOS 16 dual-stream topology correction and Stream 1 selection

XDRemuxAppleFeatures/LivePhoto

  • ImageIO HEIC still writer with kCGImageDestinationPreserveGainMap = true
  • stale Android Motion Photo XMP excluded while EXIF/TIFF/etc. metadata is preserved
  • Apple MakerNote key 17 shared identifier
  • compressed video/audio passthrough into MOV; no silent H.264 fallback
  • canonical QuickTime content identifier + exactly one still-image-time timed metadata sample
  • OPPO Live Photo transform/reference-dimension metadata
  • source timeline resolver using actual sample PTS
  • still-image-time validation at the actual MOV metadata timebase precision
  • pair validator checks identifier, still time, audio, gain-map state, geometry/orientation, transform metadata and PhotoKit loadability
  • compressed passthrough validator hashes encoded sample storage ranges before/after remux
  • transactional HEIC+MOV commit with rollback

CLI / batch

  • xdremux convert --input <motion.jpg> auto-routes without a new command/flag
  • JPEG source remains untouched and produces sibling .heic + .mov
  • HEIC Motion Photo source remains untouched and defaults to .live.heic + .live.mov
  • explicit output requires .heic/.heif
  • default batch discovers JPEG Motion Photos and classifies HEIF Motion Photos before the existing ProXDR HEIC path
  • pair-aware collision/skip/resume checkpointing
  • generated Apple Live Photo stills cannot fall back into the legacy ProXDR *.heic scan

Validation

Current head: 571d0a886f67a88ba68aa0984cb29ba265c1a03e

All three pull-request checks are green:

  • XDRemux Policy — success
  • XDRemux CI — success
  • Motion Photo Real Fixture Gate — success

The strict real-fixture gate ran on macOS 26.5.2 / build 25F84 / arm64 and successfully:

  1. downloaded the private fixture archive from XDREMUX_FIXTURE_ARCHIVE_URL;
  2. verified all 14 supplied filenames;
  3. verified exact fixture identities and parser characterization;
  4. converted every supplied Samsung / Xiaomi / OPPO / vivo sample to HEIC+MOV;
  5. verified source files remained unchanged;
  6. verified expected gain-map state and removal of stale Android Motion Photo XMP;
  7. verified compressed video/audio passthrough;
  8. verified HEIC/MOV identifier and still-image-time metadata;
  9. required PHLivePhoto.request to construct a real Apple PHLivePhoto for every generated pair.

UploadedMotionPhotoFixtureGateTests completed in 173.748 seconds with 0 failures.

The first strict run exposed a real QuickTime metadata timebase quantization case (~1.27 ms). The validator was corrected to compare the resolved source timestamp at the stored MOV metadata timescale rather than using an arbitrary 1 ms threshold; the real-fixture gate then passed in full. A synthetic regression test now covers this behavior.

The Motion Photo fixture archive is intentionally isolated from the pre-existing ProXDR/Apple-feature regression fixture bundle; ordinary CI now uses XDREMUX_REGRESSION_FIXTURE_ARCHIVE_URL for that older optional bundle, while XDREMUX_FIXTURE_ARCHIVE_URL is reserved for the dedicated Motion Photo gate.

Deliberately deferred

  • AVIF Motion Photo input support
  • ColorOS 16 blur-fill/content re-render path; current scope preserves the source still/HDR data and compressed motion/audio and uses alignment metadata rather than modifying image/video content

@21Z121Z1 21Z121Z1 changed the title WIP: Android Motion Photo to Apple Live Photo Android / OPPO Motion Photo to Apple Live Photo Aug 11, 2026
@21Z121Z1
21Z121Z1 marked this pull request as ready for review August 11, 2026 18:15
Copilot AI lite review requested due to automatic review settings August 11, 2026 18:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@21Z121Z1
21Z121Z1 merged commit ea09860 into main Aug 11, 2026
3 checks passed
@21Z121Z1
21Z121Z1 deleted the feature/android-motion-photo-live-photo branch August 11, 2026 18:15
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.

2 participants