Compare commits
No commits in common. "733644b535c3993195989ac74f6d352eed1f5925" and "878fa763c4faabf6fd7ba9fc05f4f81dab39ab8b" have entirely different histories.
733644b535
...
878fa763c4
|
@ -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'
|
||||||
}
|
}
|
|
@ -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" />
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,5 +18,4 @@ android.useAndroidX=true
|
||||||
# Automatically convert third-party libraries to use AndroidX
|
# Automatically convert third-party libraries to use AndroidX
|
||||||
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
|
|
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -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
|
||||||
|
|
Reference in a new issue