Compare commits

..

No commits in common. "733644b535c3993195989ac74f6d352eed1f5925" and "878fa763c4faabf6fd7ba9fc05f4f81dab39ab8b" have entirely different histories.

6 changed files with 44 additions and 58 deletions

View file

@ -1,13 +1,14 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android { android {
compileSdkVersion 33 compileSdkVersion 29
defaultConfig { defaultConfig {
applicationId "io.lowrespalmtree.harvestdawn" applicationId "io.lowrespalmtree.harvestdawn"
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 33 targetSdkVersion 29
versionCode 4 versionCode 4
versionName "1.3" versionName "1.3"
} }
@ -25,20 +26,18 @@ android {
kotlinOptions { kotlinOptions {
jvmTarget = '1.8' jvmTarget = '1.8'
} }
buildFeatures { buildToolsVersion '29.0.2'
viewBinding true
}
} }
dependencies { dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.0" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.8.0' implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.4'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3' implementation 'androidx.navigation:navigation-ui-ktx:2.3.4'
implementation 'com.arthenica:ffmpeg-kit-full:5.1' implementation 'com.arthenica:mobile-ffmpeg-min-gpl:4.3.2'
} }

View file

@ -17,8 +17,7 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" android:theme="@style/AppTheme.NoActionBar">
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View file

@ -21,15 +21,15 @@ import android.widget.VideoView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.net.toUri import androidx.core.net.toUri
import com.arthenica.ffmpegkit.FFmpegKit import com.arthenica.mobileffmpeg.Config.RETURN_CODE_CANCEL
import com.arthenica.ffmpegkit.FFprobeKit import com.arthenica.mobileffmpeg.Config.RETURN_CODE_SUCCESS
import com.arthenica.ffmpegkit.ReturnCode import com.arthenica.mobileffmpeg.FFmpeg
import com.arthenica.mobileffmpeg.FFprobe
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileOutputStream import java.io.FileOutputStream
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import kotlin.math.roundToLong
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val spinner: ProgressBar? get() = findViewById(R.id.progressBar) private val spinner: ProgressBar? get() = findViewById(R.id.progressBar)
@ -171,26 +171,25 @@ class MainActivity : AppCompatActivity() {
currentVideoPath = null currentVideoPath = null
currentVideoUri = null currentVideoUri = null
val mediaInfo = FFprobe.getMediaInformation(inputVideoPath)
// Detect vertical/horizontal resolution, because at the moment we downscale everything to // Detect vertical/horizontal resolution, because at the moment we downscale everything to
// fit Telegram's media preview requirements. If FFprobe fails to returns data, we consider // fit Telegram's media preview requirements. If FFprobe fails to returns data, we consider
// by default the video to be vertical. // by default the video to be vertical.
val session = FFprobeKit.getMediaInformation(inputVideoPath) val isVertical = mediaInfo?.let {
var isVertical = true it.streams.getOrNull(0)?.let { streamInformation ->
var duration: Double = 0.0
if (ReturnCode.isSuccess(session.returnCode)) {
session.mediaInformation.streams.getOrNull(0)?.let { streamInformation ->
if (streamInformation.height != null && streamInformation.width != null) if (streamInformation.height != null && streamInformation.width != null)
isVertical = streamInformation.height > streamInformation.width streamInformation.height > streamInformation.width
else
true
} }
duration = session.mediaInformation.duration.toDouble() } ?: true
} val duration = mediaInfo?.duration?.toLong() ?: 0L
// Save the soundtrack as well cause we can't pass a resource to FFMPEG. // Save the soundtrack as well cause we can't pass a resource to FFMPEG.
// Should be done only once, then it's kept in app internal storage. // Should be done only once, then it's kept in app internal storage.
val themeId = getThemeId() val themeId = getThemeId()
val soundFile = File(filesDir, "$themeId.m4a") val soundFile = File(filesDir, "$themeId.m4a")
if (!soundFile.exists()) { if (!soundFile.exists()) {
Log.i(TAG, "Prepare sound file with a filesystem path.")
resources.openRawResource(getThemeRawResource(themeId)).use { resource -> resources.openRawResource(getThemeRawResource(themeId)).use { resource ->
FileOutputStream(soundFile).use { fos -> FileOutputStream(soundFile).use { fos ->
fos.buffered().write(resource.buffered().readBytes()) fos.buffered().write(resource.buffered().readBytes())
@ -225,7 +224,7 @@ class MainActivity : AppCompatActivity() {
private class MixTask( private class MixTask(
private val activity: WeakReference<MainActivity>, private val activity: WeakReference<MainActivity>,
private val duration: Double, private val duration: Long,
private val videoIsVertical: Boolean private val videoIsVertical: Boolean
): AsyncTask<String, Void, Boolean>() { ): AsyncTask<String, Void, Boolean>() {
private lateinit var videoPath: String private lateinit var videoPath: String
@ -239,41 +238,30 @@ class MainActivity : AppCompatActivity() {
videoPath = params[0]!! videoPath = params[0]!!
val audioPath = params[1]!! val audioPath = params[1]!!
outputPath = params[2]!! outputPath = params[2]!!
//val width = if (videoIsVertical) 480 else 640 val width = if (videoIsVertical) 480 else 640
val durationOpt = if (duration > 0) { val durationOpt = if (duration > 0) "-t ${duration}ms" else ""
"-t ${(duration * 1000).roundToLong()}ms"
} else {
""
}
val command = ( val command = (
"-i $videoPath -i $audioPath" "-i $videoPath -i $audioPath"
+ " -filter_complex amix=duration=longest" + " -filter_complex amix=duration=longest"
+ " -preset ultrafast" + " -preset ultrafast"
+ " -c:v mpeg4" // -crf 26 -vf scale=$width:trunc(ow/a/2)*2 -pix_fmt yuv420p + " -c:v libx264 -crf 26 -vf scale=$width:trunc(ow/a/2)*2 -pix_fmt yuv420p"
+ " $durationOpt -y $outputPath" + " $durationOpt -y $outputPath"
) )
Log.d(TAG, "Calling FFmpeg with command: $command") Log.d(TAG, "Calling FFmpeg with command: $command")
val rc = FFmpegKit.execute(command).returnCode return when (val rc = FFmpeg.execute(command)) {
if (ReturnCode.isSuccess(rc)) { RETURN_CODE_SUCCESS -> true.also { Log.i(TAG, "Mix succeeded.") }
Log.i(TAG, "Mix succeeded.") RETURN_CODE_CANCEL -> false.also { Log.i(TAG, "Mix cancelled.") }
return true else -> false .also { Log.e(TAG, "Mix failed! rc = $rc") }
} }
if (ReturnCode.isCancel(rc))
Log.i(TAG, "Mix cancelled.")
else
Log.e(TAG, "Mix failed! rc = $rc")
return false
} }
override fun onPostExecute(result: Boolean?) { override fun onPostExecute(result: Boolean?) {
File(videoPath).delete() File(videoPath).delete()
activity.get()?.let { activity.get()?.let {
if (result == true) { if (result == true)
it.handleFfmpegOutput(outputPath) it.handleFfmpegOutput(outputPath)
} else { else
it.toast("Crasse de brin !!!")
it.setLoading(false) it.setLoading(false)
}
} }
} }
} }

View file

@ -1,12 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = "1.3.72"
repositories { repositories {
google() google()
mavenCentral() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.4.2' classpath 'com.android.tools.build:gradle:4.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
@ -16,7 +17,7 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
google() google()
mavenCentral() jcenter()
} }
} }

View file

@ -19,4 +19,3 @@ android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official
org.gradle.unsafe.configuration-cache=true

View file

@ -1,6 +1,6 @@
#Mon Apr 03 13:32:21 CEST 2023 #Wed Mar 17 16:33:26 CET 2021
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip