@stefanmartin/expo-video-watermark 0.3.3 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,6 +19,8 @@ import androidx.media3.effect.StaticOverlaySettings
19
19
  import androidx.media3.effect.TextureOverlay
20
20
  import androidx.media3.transformer.Composition
21
21
  import androidx.media3.transformer.EditedMediaItem
22
+ import androidx.media3.transformer.EditedMediaItemSequence
23
+ import androidx.media3.common.C
22
24
  import androidx.media3.transformer.Effects
23
25
  import androidx.media3.transformer.ExportException
24
26
  import androidx.media3.transformer.ExportResult
@@ -228,6 +230,9 @@ class ExpoVideoWatermarkModule : Module() {
228
230
  val frameRate = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CAPTURE_FRAMERATE)?.toFloatOrNull() ?: 0f
229
231
  val colorStandard = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COLOR_STANDARD) ?: "unknown"
230
232
  val colorTransfer = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COLOR_TRANSFER) ?: "unknown"
233
+ val colorTransferInt = colorTransfer.toIntOrNull()
234
+ // Check for HDR color transfer characteristics. 6 = PQ (ST2084), 7 = HLG. See MediaFormat constants.
235
+ val isHdr = colorTransferInt == 6 || colorTransferInt == 7
231
236
  retriever.release()
232
237
 
233
238
  // Build comprehensive video info string for debugging
@@ -237,7 +242,7 @@ class ExpoVideoWatermarkModule : Module() {
237
242
  append("duration=${duration}ms, ")
238
243
  append("frameRate=$frameRate, ")
239
244
  append("colorStandard=$colorStandard, ")
240
- append("colorTransfer=$colorTransfer")
245
+ append("colorTransfer=$colorTransfer (isHdr=$isHdr)")
241
246
  }
242
247
  Log.d(TAG, "[Step 6] Video metadata: $videoInfo")
243
248
 
@@ -310,7 +315,8 @@ class ExpoVideoWatermarkModule : Module() {
310
315
  // Step 11: Create overlay effect with proper typing
311
316
  val overlayEffect = try {
312
317
  OverlayEffect(ImmutableList.of<TextureOverlay>(bitmapOverlay))
313
- } catch (e: Exception) {
318
+ }
319
+ catch (e: Exception) {
314
320
  scaledWatermark.recycle()
315
321
  promise.reject("STEP11_OVERLAY_EFFECT_ERROR", "[Step 11] Failed to create overlay effect: ${e.message}", e)
316
322
  return
@@ -325,7 +331,7 @@ class ExpoVideoWatermarkModule : Module() {
325
331
  // Step 13: Create media item from video
326
332
  val mediaItem = MediaItem.fromUri("file://$cleanVideoPath")
327
333
 
328
- // Step 14: Create edited media item with effects
334
+ // Step 14: Create edited media item (HDR mode is set on Composition, not EditedMediaItem in 1.9.1+)
329
335
  val editedMediaItem = try {
330
336
  EditedMediaItem.Builder(mediaItem)
331
337
  .setEffects(effects)
@@ -336,18 +342,28 @@ class ExpoVideoWatermarkModule : Module() {
336
342
  return
337
343
  }
338
344
 
339
- // Step 14b: Create composition with HDR to SDR tone mapping
340
- // Use MediaCodec-based tone mapping (avoids OpenGL frame processing issues on some devices)
345
+ // Step 14b: Create composition with EditedMediaItemSequence (required in Media3 1.9.1+)
341
346
  val composition = try {
342
- Composition.Builder(listOf(editedMediaItem))
343
- .setHdrMode(Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC)
347
+ // Wrap EditedMediaItem in a sequence (must specify track types in 1.9.1+)
348
+ val sequence = EditedMediaItemSequence.Builder(setOf(C.TRACK_TYPE_VIDEO, C.TRACK_TYPE_AUDIO))
349
+ .addItem(editedMediaItem)
344
350
  .build()
351
+
352
+ // Build composition with HDR mode if needed
353
+ val compositionBuilder = Composition.Builder(sequence)
354
+ if (isHdr) {
355
+ Log.d(TAG, "[Step 14b] HDR video detected. Applying tone-mapping to composition.")
356
+ compositionBuilder.setHdrMode(Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC)
357
+ } else {
358
+ Log.d(TAG, "[Step 14b] SDR video detected. No tone-mapping needed.")
359
+ }
360
+ compositionBuilder.build()
345
361
  } catch (e: Exception) {
346
362
  scaledWatermark.recycle()
347
363
  promise.reject("STEP14B_COMPOSITION_ERROR", "[Step 14b] Failed to create composition: ${e.message}", e)
348
364
  return
349
365
  }
350
- Log.d(TAG, "[Step 14b] Created composition with HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC")
366
+ Log.d(TAG, "[Step 14b] Composition created successfully.")
351
367
 
352
368
  // Handler for main thread callbacks
353
369
  val mainHandler = Handler(Looper.getMainLooper())
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stefanmartin/expo-video-watermark",
3
- "version": "0.3.3",
3
+ "version": "0.4.1",
4
4
  "description": "Creating video watermarks on locally stored videos",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",