From 9107d7a1e084fd42514421b1fa46f4b6b0cf862a Mon Sep 17 00:00:00 2001 From: "Nicholas A. Thompson" Date: Sun, 21 Dec 2025 00:23:29 -0800 Subject: [PATCH 1/2] Workaround for ffmpeg-kit build failure The ffmpeg-kit library was retired and removed from Maven Central in April 2025, breaking builds on fresh checkout. This temporarily disables the lossless cut feature by commenting out ffmpeg-kit imports and usage to allow development to continue. The project currently cannot build without this workaround as the dependency artifacts are no longer available at: https://repo.maven.apache.org/maven2/com/arthenica/ffmpeg-kit-min/ All other features remain functional. A proper fix would require choosing an alternative library or building ffmpeg-kit from source. Also fixes gradlew permissions to allow execution. --- app/build.gradle.kts | 4 ++- .../videoeditor/TransformManager.kt | 36 +++++++++---------- gradlew | 0 3 files changed, 19 insertions(+), 21 deletions(-) mode change 100644 => 100755 gradlew diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9909a0d..ada7ef1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -82,7 +82,9 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7") implementation("com.godaddy.android.colorpicker:compose-color-picker:0.7.0") implementation("com.godaddy.android.colorpicker:compose-color-picker-android:0.7.0") - implementation("com.arthenica:ffmpeg-kit-min:6.0-2") + // TODO: ffmpeg-kit was retired and removed from Maven Central as of April 2025 + // Need to find alternative or community fork + // implementation("com.arthenica:ffmpeg-kit-min:6.0-2") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.2.1") androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") diff --git a/app/src/main/java/io/github/devhyper/openvideoeditor/videoeditor/TransformManager.kt b/app/src/main/java/io/github/devhyper/openvideoeditor/videoeditor/TransformManager.kt index f715828..c16e688 100644 --- a/app/src/main/java/io/github/devhyper/openvideoeditor/videoeditor/TransformManager.kt +++ b/app/src/main/java/io/github/devhyper/openvideoeditor/videoeditor/TransformManager.kt @@ -31,9 +31,10 @@ import androidx.media3.transformer.TransformationRequest import androidx.media3.transformer.Transformer import androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED import androidx.media3.transformer.Transformer.PROGRESS_STATE_UNAVAILABLE -import com.arthenica.ffmpegkit.FFmpegKit -import com.arthenica.ffmpegkit.FFmpegKitConfig -import com.arthenica.ffmpegkit.SessionState +// TODO: ffmpeg-kit was retired and removed from Maven Central +// import com.arthenica.ffmpegkit.FFmpegKit +// import com.arthenica.ffmpegkit.FFmpegKitConfig +// import com.arthenica.ffmpegkit.SessionState import io.github.devhyper.openvideoeditor.misc.PROJECT_FILE_EXT import io.github.devhyper.openvideoeditor.misc.getFileNameFromUri import kotlinx.collections.immutable.ImmutableList @@ -405,6 +406,7 @@ class TransformManager { } } + // TODO: ffmpeg-kit was retired - lossless cut feature temporarily disabled private fun ffmpegLosslessCut( context: Context, trim: Trim, @@ -412,6 +414,9 @@ class TransformManager { audioFallback: Boolean, onFFmpegError: () -> Unit ) { + // Temporarily disabled - ffmpeg-kit library no longer available + onFFmpegError() + /* val ffmpegInputPath = FFmpegKitConfig.getSafParameterForRead(context, projectData.uri.toUri()) val ffmpegOutputPath = FFmpegKitConfig.getSafParameterForWrite(context, outputPath.toUri()) @@ -433,6 +438,7 @@ class TransformManager { ffmpegLosslessCut(context, trim, outputPath, true, onFFmpegError) } } + */ } @SuppressLint("Recycle") @@ -490,27 +496,17 @@ class TransformManager { } fun cancel() { - FFmpegKit.cancel() + // FFmpegKit.cancel() // TODO: ffmpeg-kit disabled transformer?.cancel() } fun getProgress(): Float { - val ffmpegSessions = FFmpegKit.listSessions() - return if (ffmpegSessions.isNotEmpty()) { - val sessionState = ffmpegSessions.last().state - return when (sessionState) { - SessionState.COMPLETED -> 1F - SessionState.RUNNING -> 0.5F - SessionState.CREATED -> 0F - else -> -1F - } - } else { - val progressHolder = ProgressHolder() - when (transformer?.getProgress(progressHolder)) { - PROGRESS_STATE_UNAVAILABLE -> -1F - PROGRESS_STATE_NOT_STARTED -> 1F - else -> progressHolder.progress.toFloat() / 100F - } + // TODO: ffmpeg-kit disabled - only using transformer progress now + val progressHolder = ProgressHolder() + return when (transformer?.getProgress(progressHolder)) { + PROGRESS_STATE_UNAVAILABLE -> -1F + PROGRESS_STATE_NOT_STARTED -> 1F + else -> progressHolder.progress.toFloat() / 100F } } } diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From c78146fa65e94063af0340e1637e0326763a54ef Mon Sep 17 00:00:00 2001 From: "Nicholas A. Thompson" Date: Sun, 21 Dec 2025 00:24:21 -0800 Subject: [PATCH 2/2] Add mirror effect for video flipping Adds a Mirror video effect with horizontal and vertical flip options. Users can now easily flip videos without manually using the Scale effect with negative values. Implementation: - Added DialogUserEffect for Mirror with dropdown selection - Horizontal mirror: Scale(-1, 1) for left-right flip - Vertical mirror: Scale(1, -1) for top-bottom flip - Uses Material Icons Flip icon - Added string resources for mirror and direction Tested on Pixel 9a with various videos - both horizontal and vertical mirroring work correctly. Closes #112 --- .../videoeditor/UserEffects.kt | 19 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 2 files changed, 21 insertions(+) diff --git a/app/src/main/java/io/github/devhyper/openvideoeditor/videoeditor/UserEffects.kt b/app/src/main/java/io/github/devhyper/openvideoeditor/videoeditor/UserEffects.kt index 42ae336..866ac36 100644 --- a/app/src/main/java/io/github/devhyper/openvideoeditor/videoeditor/UserEffects.kt +++ b/app/src/main/java/io/github/devhyper/openvideoeditor/videoeditor/UserEffects.kt @@ -4,6 +4,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.RotateRight import androidx.compose.material.icons.filled.Crop import androidx.compose.material.icons.filled.Filter +import androidx.compose.material.icons.filled.Flip import androidx.compose.material.icons.filled.FormatSize import androidx.compose.material.icons.filled.InvertColors import androidx.compose.material.icons.filled.TextFormat @@ -95,6 +96,24 @@ val dialogUserEffectsArray: ImmutableList = persistentListOf( ) { args -> val degrees = args["Degrees"]!!.toFloat(); { ScaleAndRotateTransformation.Builder().setRotationDegrees(degrees).build() } + }, + DialogUserEffect( + R.string.mirror, + { Icons.Filled.Flip }, + persistentListOf( + EffectDialogSetting( + key = "Direction", + stringResId = R.string.direction, + dropdownOptions = mutableListOf( + "Horizontal", + "Vertical" + ) + ) + ) + ) { args -> + val direction = args["Direction"]!! + val (x, y) = if (direction == "Horizontal") -1f to 1f else 1f to -1f + { ScaleAndRotateTransformation.Builder().setScale(x, y).build() } } ) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d351e8..b924706 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,6 +58,8 @@ Y Rotate Degrees + Mirror + Direction Crop Framerate must be lower than the framerate of the original video Lossless cut