Skip to content

feat(video): add a preserveMetadata option to drop source metadata - #432

Merged
numandev1 merged 2 commits into
numandev1:mainfrom
simongt:feat/video-preserve-metadata
Nov 2, 2026
Merged

numandev1 merged 2 commits into
numandev1:mainfrom
simongt:feat/video-preserve-metadata

Conversation

@simongt

@simongt simongt commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Since #399, Video.compress copies the source video's metadata into the output on both platforms: Android writes the location as a udta/©xyz box, and iOS forwards every source metadata item to the writer. An app that uploads the compressed video has no way to leave the location out. We drop GPS from photos before they leave the device, and right now we carry a local patch to do the same for video.

This adds preserveMetadata?: boolean to the video options. It defaults to true, so the output is unchanged unless a caller opts out. With false:

  • Android skips the location lookup (MediaMetadataRetriever and LocationExtractor), so MP4Builder writes no ©xyz box.
  • iOS doesn't forward the source metadata items to the writer.

The option takes the same path as stripAudio: through VideoCompressorHelper on Android, and the compression helpers in VideoMain.swift on iOS. Options are already an AnyMap, so there's no spec change, and yarn nitrogen produced no diff. The README has a new entry under videoCompresssionType.

Closes #431

Changelog

[GENERAL] [ADDED] - Add a preserveMetadata option to Video.compress to leave the source metadata, such as the GPS location, out of the output

Test Plan

  • Ran local JS PR gate: yarn test:pr. 14 tests pass, including a new one for the option forwarding. Typecheck is clean, and lint has 0 errors (the 9 warnings are already on main).
  • If this changes compression/upload/download native behavior, ran the Harness tests on a simulator/device: yarn test:harness:android or yarn test:harness:ios. Not run: the harness spec has no Video.compress case, so it wouldn't exercise this. I ran it in an app instead, below.

I packed this branch (yarn prepack, then npm pack) into an Expo SDK 58 / React Native 0.88 app. Then I compressed two phone clips that carry a location, a Pixel .mp4 and an iPhone .MOV, with compressionMethod: 'manual', bitrate: 2_000_000 and maxSize: 1280: once with preserveMetadata: false and once with the option unset. I read each output's metadata with AVFoundation:

Device Option Pixel clip iPhone clip
Pixel 3 XL, Android 12 false no metadata, no ©xyz no metadata, no ©xyz
Pixel 3 XL, Android 12 unset ©xyz location ©xyz location
iPhone 17 Pro simulator, iOS 26.5 false no metadata no metadata
iPhone 17 Pro simulator, iOS 26.5 unset ©xyz location loci location and date

On Android the log also shows the lookup skipped: source location resolved: hasLocation=false source=not preserved. The video stays avc1 720×1280 at about 2 Mbps in every case.


Review follow-up: with preserveMetadata: false, the minimumFileSizeForCompress check no longer returns the source file untouched, on iOS (both modes) or on Android (auto mode, the only one with the check). yarn test:pr still passes. I re-ran it with the threshold set above the clip size, using a fresh Pixel clip that carries a location: false gave a new file with no metadata on the iOS 26.5 simulator (manual) and an Android emulator (auto), and with the option unset the original file came back as before.

Video.compress copies the source video's metadata into the output on
both platforms: Android writes the location as a udta/©xyz box, and
iOS forwards every source metadata item to the writer. An app that
uploads the compressed video has no way to leave the location out.

preserveMetadata defaults to true, so the output is unchanged unless
the caller opts out. With false, Android skips the location lookup
and writes no ©xyz box, and iOS forwards no source metadata. The
option takes the same path as stripAudio.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

On Android and iOS, videos at or below the compression-size threshold bypass preserveMetadata: false, returning originals with GPS metadata intact and risking location disclosure.

2 open issues
What changed in this PR

Adds preserveMetadata to Video.compress, allowing callers to opt out of copying source metadata such as GPS location while preserving existing behavior by default.

Changes:

  • Exposes and documents the option in the JavaScript API.
  • Threads it through Android and iOS compression paths to control metadata copying.
  • Adds a JavaScript test for option forwarding.

Native behavior was not runtime-verified during this review.

File Description
src/​Video/​index.tsx Defines and forwards the metadata opt-out.
README.md Documents the option and default behavior.
ios/​Video/​VideoMain.swift Conditionally forwards source metadata to the exporter.
android/​src/​main/​java/​com/​reactnativecompressor/​Video/​VideoCompressorHelper.kt Parses and forwards the option for manual compression.
android/​src/​main/​java/​com/​reactnativecompressor/​Video/​VideoCompressor/​VideoCompressorClass.kt Passes the option through the compression pipeline.
android/​src/​main/​java/​com/​reactnativecompressor/​Video/​VideoCompressor/​compressor/​Compressor.kt Skips source location extraction when opted out.
android/​src/​main/​java/​com/​reactnativecompressor/​Video/​AutoVideoCompression.kt Forwards the option for automatic compression.
android/​src/​main/​java/​com/​reactnativecompressor/​Utils/​Utils.kt Threads the option into the native compressor.
__tests__/​compressor.test.ts Tests forwarding of explicit metadata preferences.

Review effort: Balanced

Comment thread ios/Video/VideoMain.swift Resolved
A video at or under minimumFileSizeForCompress skipped compression and
came back as the source file, with its location still in it. That
happened on iOS in both modes and on Android in auto mode, so
preserveMetadata: false did not hold when a caller set a threshold.

With preserveMetadata false, the size check no longer short-circuits,
and the export runs without the source metadata. The option is new and
defaults to true, so no existing caller changes.
@simongt

simongt commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

🟡 Changes recommended

On Android and iOS, videos at or below the compression-size threshold bypass preserveMetadata: false, returning originals with GPS metadata intact and risking location disclosure.

2 open issues

What changed in this PR
Adds preserveMetadata to Video.compress, allowing callers to opt out of copying source metadata such as GPS location while preserving existing behavior by default.

Changes:

  • Exposes and documents the option in the JavaScript API.
  • Threads it through Android and iOS compression paths to control metadata copying.
  • Adds a JavaScript test for option forwarding.

Native behavior was not runtime-verified during this review.

File Description
src/​Video/​index.tsx Defines and forwards the metadata opt-out.
README.md Documents the option and default behavior.
ios/​Video/​VideoMain.swift Conditionally forwards source metadata to the exporter.
android/​src/​main/​java/​com/​reactnativecompressor/​Video/​VideoCompressorHelper.kt Parses and forwards the option for manual compression.
android/​src/​main/​java/​com/​reactnativecompressor/​Video/​VideoCompressor/​VideoCompressorClass.kt Passes the option through the compression pipeline.
android/​src/​main/​java/​com/​reactnativecompressor/​Video/​VideoCompressor/​compressor/​Compressor.kt Skips source location extraction when opted out.
android/​src/​main/​java/​com/​reactnativecompressor/​Video/​AutoVideoCompression.kt Forwards the option for automatic compression.
android/​src/​main/​java/​com/​reactnativecompressor/​Utils/​Utils.kt Threads the option into the native compressor.
__tests__/​compressor.test.ts Tests forwarding of explicit metadata preferences.
Review effort: Balanced

Review follow-up: with preserveMetadata: false, the minimumFileSizeForCompress check no longer returns the source file untouched, on iOS (both modes) or on Android (auto mode, the only one with the check). yarn test:pr still passes. I re-ran it with the threshold set above the clip size, using a fresh Pixel clip that carries a location: false gave a new file with no metadata on the iOS 26.5 simulator (manual) and an Android emulator (auto), and with the option unset the original file came back as before.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues were identified, although native behavior was not independently runtime-verified.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@numandev1
numandev1 merged commit 344bdd0 into numandev1:main Nov 2, 2026
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.

Option to leave source metadata out of Video.compress output

3 participants