@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
|
-
}
|
|
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
|
|
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
|
|
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
|
-
|
|
343
|
-
|
|
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]
|
|
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())
|