Skip to content

Commit

Permalink
Merge pull request #873 from UstadMobile/dev-compress
Browse files Browse the repository at this point in the history
Dev compress
  • Loading branch information
mikedawson committed Apr 17, 2024
2 parents da1c9e1 + 6bcbb5d commit 66e8a1d
Show file tree
Hide file tree
Showing 169 changed files with 28,823 additions and 809 deletions.
24 changes: 21 additions & 3 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,33 @@ using apt-get on Ubuntu or MSI/EXE for Windows).

On Ubuntu:
```
apt-get install openjdk-18-jdk ffmpeg
apt-get install openjdk-18-jdk mediainfo sox libsox-fmt-mp3
```
Note: if you have other Java versions, make sure you run the server jar using JDK17+. You can use ``sudo update-alternatives --config java``
to set the default java version to run.

If using Ubuntu 23.10+, you can use the HandBrakeCLI from the Ubuntu package manager (1.6.1):
```
apt-get install handbrake-cli
```

Previous versions (including 22.04 LTS) package HandBrake 1.5 (which is not supported due to lack of
AV1 support). You can install the latest HandBrake CLI using flatpak as per [HandBrake website](https://handbrake.fr/downloads2.php):
```
apt-get install flatpak
flatpak install /path/where/downloaded/HandBrakeCLI-1.7.3-x86_64.flatpak
```

On Windows:
* Download and install Java (JDK17+) if not already installed from the Java site [https://www.oracle.com/java/technologies/downloads/#jdk17-windows](https://www.oracle.com/java/technologies/downloads/#jdk17-windows)
* FFMPEG is required. If you don't already have it in your path, the server can download it for you
when you run it for the first time.
* Use Winget to download and install MediaInfo and HandBrakeCLI:
```
winget install -e --id MediaArea.MediaInfo
winget install -e --id HandBrake.HandBrake.CLI
```
* Download and install from the [Sox website](https://sourceforge.net/projects/sox/files/sox/14.4.2/)
(the Winget package does not work because it does not get added to the path).


### 3. Unzip ustad-server.zip and start server

Expand Down
65 changes: 55 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,47 @@ entire project.
* __Step 1: Download and install Android Studio__: If you don't already have the latest version, download
from [https://developer.android.com/studio](https://developer.android.com/studio).

* __Step 2: Make sure that java is on your system path__: If you already have OpenJDK17, you can
use that, otherwise you need to download from the Java website or install using your system package
manager.

Supported JDK Version: JDK17 (only). JDK21 not supported yet due to Proguard issues on app-desktop.
* __Step 2: Install dependencies__

Development requirements are:
* JDK17 (only): JDK21 not supported yet due to Proguard issues on app-desktop.
* MediaInfo: MediaInfo is used by the server and desktop version to validate media files and extract
metadata
* VLC (3.0.0)+ : VLC is used on the desktop version (via VLC4J) to play videos.
* HandBrakeCLI (1.6.0+): HandBrake (Command Line Interface) is used by the server and desktop version
to compress videos.
* SOX (14+) : Sox is used to transcode audio files

Linux:

Install OpenJDK17, ffmpeg, and mediainfo using the system package manager e.g.
If you already have JDK 17 installed, you can use it.

OpenJDK17, mediainfo, and vlc, can be installed using the system package manager e.g.

```
sudo apt-get install openjdk-17-jdk mediainfo vlc sox libsox-fmt-mp3
```

If using Ubuntu 23.10+, you can use the HandBrakeCLI from the Ubuntu package manager (1.6.1):
```
apt-get install handbrake-cli
```

Previous versions (including 22.04 LTS) has HandBrake 1.5 (which is not supported due to lack of
AV1 support). You can install the latest HandBrake CLI using flatpak as per [HandBrake website](https://handbrake.fr/downloads2.php):
```
apt-get install flatpak
flatpak install /path/where/downloaded/HandBrakeCLI-1.7.3-x86_64.flatpak
```

Ghostscript (optional): The ghostscript (gs) command can be used to compress PDFs.
```
sudo apt-get install openjdk-17-jdk ffmpeg mediainfo
apt-get install ghostscript
```

Windows:

__JDK__
Download and install Java (JDK17) if not already installed from the Java site
[https://www.oracle.com/java/technologies/downloads/#jdk17-windows](https://www.oracle.com/java/technologies/downloads/#jdk17-windows)

Expand All @@ -96,8 +121,28 @@ Now find the PATH variable. Append ```;%JAVA_HOME%\bin``` to the value and save

Further details: see the [Java website](https://www.java.com/en/download/help/path.html).

If you don't have ffmpeg installed, the server can download it for you when you run it for the first
time.
__VLC__
Download and install from [https://www.videolan.org/](https://www.videolan.org/). Make sure to choose
a 64bit version (using a non-64bit version will fail). VLC is used by the Desktop version to play
videos via VLCJ.

__MediaInfo__
Download and install such that the MediaInfo command is in the PATH. This can be done using winget:

```
winget install -e --id MediaArea.MediaInfo
```

__HandBrakeCLI__
Download and install such that the HandBrakeCLI command is in the PATH. This can be done using winget:

```
winget install -e --id HandBrake.HandBrake.CLI
```

__Sox__
Download and install from the [Sox website](https://sourceforge.net/projects/sox/files/sox/14.4.2/) (the Winget package does not work because it does not get
added to the path).

* __Step 3: Import the project in Android Studio__: Select File, New, Project from Version Control. Enter
https://github.com/UstadMobile/UstadMobile.git and wait for the project to import. Switch to the
Expand Down Expand Up @@ -157,7 +202,7 @@ Code is contained (mostly) in the following modules:
* [core](core/) : Contains view models, ui state, core business logic.
* [sharedse](sharedse/): Contains some shared implementations for operating systems with a disk (JVM/Android)
* [lib-database](lib-database/): contains the database: DAOs (e.g. SQL queries), and entity classes.
* [lib-ui-compose](lib-ui-compose/): contains Compose multiplatform UI code used by app-android and app-desktop
* [lib-ui-compose](lib-ui-compose/): contains Compose multiplatform UI code used by app-android and app-desktop.
* [lib-util](lib-util/): Small utility functions
* [test-end-to-end](test-end-to-end/) End-to-end tests that run the app and server.
* [testserver-controller](testserver-controller/) An HTTP server that can control starting and
Expand Down
18 changes: 7 additions & 11 deletions app-android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.plugin.serialization'
id 'org.jetbrains.kotlin.android'
id 'org.jetbrains.kotlin.kapt'
id 'kotlin-parcelize'
alias(libs.plugins.jetbrains.compose)
alias(libs.plugins.license)
Expand All @@ -18,7 +17,6 @@ if(keyStoreFile == null) {

def keyStorePropertiesExists = rootProject.file(keyStoreFile).exists()
def keystoreProperties = new Properties()
def baseAppId = "com.toughra.ustadmobile"

if (keyStorePropertiesExists) {
keystoreProperties.load(new FileInputStream(rootProject.file(keyStoreFile)))
Expand All @@ -36,17 +34,9 @@ configurations.all {
resolutionStrategy.force 'org.objenesis:objenesis:2.6'
}

kapt {
javacOptions {
// Increase the max count of errors from annotation processors.
// Default is 100.
option("-Xmaxerrs", 500)
}
}

android {
buildFeatures {
dataBinding true
dataBinding false
}

//APK splitting would interfere with sideloading the app between different targets and the size
Expand Down Expand Up @@ -332,6 +322,12 @@ dependencies {

implementation libs.androidx.browser
implementation libs.androidx.core.splashscreen


androidTestImplementation libs.androidx.test.runner
androidTestImplementation libs.junit
androidTestImplementation libs.androidx.test.core
androidTestUtil libs.androidx.test.orchestrator
}

licenseReport {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.ustadmobile.core.domain.compress.audio

import android.content.Context
import android.media.MediaCodecList
import androidx.core.net.toUri
import androidx.test.core.app.ApplicationProvider
import com.ustadmobile.core.uri.UriHelperAndroid
import com.ustadmobile.door.DoorUri
import com.ustadmobile.door.ext.toFile
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder

class CompressAudioUseCaseAndroidTest {


@JvmField
@Rule
var tempFolder = TemporaryFolder()

@Test
fun initTest() {
val context = ApplicationProvider.getApplicationContext<Context>()

val codecList = MediaCodecList(MediaCodecList.ALL_CODECS)
val audioEncoders = codecList.codecInfos.filter { codecInfo ->
codecInfo.isEncoder && codecInfo.supportedTypes.any { it.startsWith("audio") }
}
println(audioEncoders.flatMap { it.supportedTypes.toList() }.joinToString())

val compressAudioUseCase = CompressAudioUseCaseAndroid(
appContext = context,
uriHelper = UriHelperAndroid(context)
)
val audioFile = tempFolder.newFile()
this::class.java.getResourceAsStream("/river.mp3")!!.use { inStream ->
audioFile.outputStream().use {
inStream.copyTo(it)
it.flush()
}
}

val result = runBlocking {
compressAudioUseCase(
fromUri = audioFile.toUri().toString(),
)
}

Assert.assertNotNull(result)

val resultFile = DoorUri.parse(result!!.uri).toFile()
assertTrue(resultFile.exists())
assertTrue(resultFile.length() > 0)
println("result for is ${resultFile.length()}")
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,25 @@ package com.ustadmobile.core.domain.compress.image

import android.content.Context
import android.net.Uri
import android.os.Build
import androidx.core.net.toFile
import androidx.core.net.toUri
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.core.app.ApplicationProvider
import com.ustadmobile.core.domain.compress.CompressParams
import org.junit.Assert.assertTrue
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config

@RunWith(RobolectricTestRunner::class)
@Config(sdk = intArrayOf(Build.VERSION_CODES.TIRAMISU))
class CompressUseCaseAndroidTest {
class CompressImageUseCaseAndroidTest {

@JvmField
@Rule
val tempFolder = TemporaryFolder()

@Test
fun givenInputImage_whenInvoked_thenWillCompress(){
val context = getApplicationContext<Context>()
val context = ApplicationProvider.getApplicationContext<Context>()
val tmpFile = tempFolder.newFile()
val outFile = tempFolder.newFile()
javaClass.getResourceAsStream("/image/testfile1.png")!!.use { assetIn ->
Expand All @@ -42,14 +36,15 @@ class CompressUseCaseAndroidTest {
fromUri = tmpFile.toUri().toString(),
toUri = outFile.toUri().toString(),
params = CompressParams(
maxWidth = 300,
maxHeight = 300,
maxWidth = 800,
maxHeight = 800,
)
)
val resultUri = Uri.parse(result.uri)
val resultUri = Uri.parse(result!!.uri)
val resultFile = resultUri.toFile()
assertTrue(resultUri.toFile().exists())
assertTrue(resultFile.length() > 0)
Assert.assertTrue(resultUri.toFile().exists())
Assert.assertTrue(resultFile.length() > 0)
Assert.assertTrue(resultFile.length() < tmpFile.length())
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.ustadmobile.core.domain.compress.video

import android.content.Context
import android.net.Uri
import androidx.core.net.toFile
import androidx.core.net.toUri
import androidx.test.core.app.ApplicationProvider
import com.ustadmobile.core.domain.compress.CompressParams
import com.ustadmobile.core.domain.compress.CompressionLevel
import com.ustadmobile.core.uri.UriHelperAndroid
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.io.File
import java.io.FileOutputStream

class CompressVideoUseCaseAndroidTest {

@JvmField
@Rule
var tempFolder = TemporaryFolder()

lateinit var videoFile: File

lateinit var useCase: CompressVideoUseCaseAndroid

@Before
fun setup() {
val context = ApplicationProvider.getApplicationContext<Context>()
val uriHelper = UriHelperAndroid(context)
useCase = CompressVideoUseCaseAndroid(context, uriHelper)

videoFile = tempFolder.newFile("bus.mp4")
this::class.java.getResourceAsStream("/bus.mp4")!!.use { assetIn ->
FileOutputStream(videoFile).use { fileOut ->
assetIn.copyTo(fileOut)
fileOut.flush()
}
}
}

private fun compressAndAssert(compressionLevel: CompressionLevel) {
runBlocking {
val result = useCase(
fromUri = videoFile.toUri().toString(),
params = CompressParams(
compressionLevel = compressionLevel
)
)

val outFile = Uri.parse(result!!.uri).toFile()
Assert.assertTrue(outFile.length() > 0)
}
}

@Test
fun givenValidVideo_whenCompressLow_thenWillCompress() {
compressAndAssert(CompressionLevel.LOW)
}

@Test
fun givenValidVideo_whenCompressMedium_thenWillCompress() {
compressAndAssert(CompressionLevel.MEDIUM)
}

@Test
fun givenValidVideo_whenCompressHigh_thenWillCompress() {
compressAndAssert(CompressionLevel.HIGH)
}


}
Binary file added app-android/src/androidTest/resources/bunny.mp4
Binary file not shown.
Binary file added app-android/src/androidTest/resources/bus.mp4
Binary file not shown.
Binary file added app-android/src/androidTest/resources/river.mp3
Binary file not shown.

0 comments on commit 66e8a1d

Please sign in to comment.