diff --git a/android/build.gradle b/android/build.gradle index 48443cca5..94fd8f477 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'com.android.library' def DEFAULT_COMPILE_SDK_VERSION = 30 def DEFAULT_BUILD_TOOLS_VERSION = "29.0.3" def DEFAULT_TARGET_SDK_VERSION = 30 -def DEFAULT_MIN_SDK_VERSION = 16 +def DEFAULT_MIN_SDK_VERSION = 21 android { compileSdkVersion rootProject.hasProperty('compileSdkVersion') ? rootProject.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION @@ -23,4 +23,8 @@ dependencies { implementation 'com.facebook.react:react-native:+' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'com.github.yalantis:ucrop:2.2.6-native' + + implementation 'androidx.media3:media3-transformer:1.4.1' + implementation 'androidx.media3:media3-effect:1.4.1' + implementation 'androidx.media3:media3-common:1.4.1' } diff --git a/android/src/main/java/com/reactnative/ivpusic/imagepicker/Compression.java b/android/src/main/java/com/reactnative/ivpusic/imagepicker/Compression.java index 5ea266c56..b226533f9 100644 --- a/android/src/main/java/com/reactnative/ivpusic/imagepicker/Compression.java +++ b/android/src/main/java/com/reactnative/ivpusic/imagepicker/Compression.java @@ -9,6 +9,16 @@ import android.util.Log; import android.util.Pair; +import androidx.annotation.OptIn; +import androidx.media3.common.MediaItem; +import androidx.media3.common.MimeTypes; +import androidx.media3.common.util.UnstableApi; +import androidx.media3.transformer.Composition; +import androidx.media3.transformer.EditedMediaItem; +import androidx.media3.transformer.ExportException; +import androidx.media3.transformer.ExportResult; +import androidx.media3.transformer.Transformer; + import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReadableMap; @@ -153,9 +163,36 @@ private Pair calculateTargetDimensions(int currentWidth, int c return Pair.create(width, height); } - synchronized void compressVideo(final Activity activity, final ReadableMap options, final String originalVideo, final String compressedVideo, final Promise promise) { - // todo: video compression + @OptIn(markerClass = UnstableApi.class) + synchronized void compressVideo( + final Activity activity, final ReadableMap options, final String originalVideo, final String compressedVideo, final Promise promise) { // failed attempt 1: ffmpeg => slow and licensing issues - promise.resolve(originalVideo); + // promise.resolve(originalVideo); + + Transformer.Listener transformerListener = + new Transformer.Listener() { + @Override + public void onCompleted(Composition composition, ExportResult result) { + promise.resolve(compressedVideo); + } + + @Override + public void onError(Composition composition, ExportResult result, + ExportException exception) { + promise.reject("unable to convert input to h264"); + } + }; + + MediaItem inputMediaItem = MediaItem.fromUri(originalVideo); + EditedMediaItem editedMediaItem = + new EditedMediaItem.Builder(inputMediaItem).setFrameRate(15).build(); + Transformer transformer = + new Transformer.Builder(activity) + .setVideoMimeType(MimeTypes.VIDEO_H264) + .setAudioMimeType(MimeTypes.AUDIO_AAC) + .addListener(transformerListener) + .build(); + transformer.start(editedMediaItem, compressedVideo); + } }