Skip to content

Commit 2679ed1

Browse files
committed
feat(gui): load or create thumbnail videos on project loading
If the temp files still exist, they are assumed to be correct and are loaded. Otherwise, the thumbnail videos are recreated before entering the DiffScreen. Signed-off-by: Anton Kriese <[email protected]>
1 parent 7231926 commit 2679ed1

File tree

3 files changed

+41
-16
lines changed

3 files changed

+41
-16
lines changed
Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,46 @@
11
package logic
22

3+
import androidx.compose.runtime.MutableState
4+
import models.AppState
35
import org.bytedeco.javacv.FFmpegFrameRecorder
46
import wrappers.IterableFrameGrabber
57
import wrappers.Resettable2DFrameConverter
68
import java.awt.image.BufferedImage
79
import java.io.File
810

9-
fun createThumbnailVideo(
11+
/**
12+
* Creates a scaled video from the input video as a temp file.
13+
*
14+
* @param inputPath [String] containing the path to the input video.
15+
* @param scale [Float] containing the scaling factor, must be greater than 0f.
16+
* @return [String] containing the path to the scaled video.
17+
*/
18+
fun createScaledVideo(
1019
inputPath: String,
11-
downScaling: Float = 0.5f,
20+
scale: Float = 0.5f,
1221
): String {
13-
assert(downScaling > 0.0f && downScaling <= 1.0f) { "Downscaling factor must be between 0 and 1" }
22+
assert(scale > 0.0f) { "Scaling factor must be positive!" }
1423
val outputPath = kotlin.io.path.createTempFile(prefix = "gui_thumbnail_video", suffix = ".mkv").toString()
1524

1625
val grabber = IterableFrameGrabber(File(inputPath))
1726

1827
val inWidth = grabber.imageWidth
1928
val inHeight = grabber.imageHeight
2029

21-
val outWidth = (inWidth * downScaling).toInt()
22-
val outHeight = (inHeight * downScaling).toInt()
30+
val outWidth = (inWidth * scale).toInt()
31+
val outHeight = (inHeight * scale).toInt()
2332

2433
val recorder = FFmpegFrameRecorder(outputPath, outWidth, outHeight)
25-
2634
val converter = Resettable2DFrameConverter()
2735

36+
// copy some metadata over
2837
recorder.frameRate = grabber.frameRate
2938
recorder.videoCodec = grabber.videoCodec
3039

3140
recorder.start()
3241

3342
for (image in grabber) {
34-
// do something with the frame
43+
// scale down the image and record it
3544
val scaledImage = BufferedImage(outWidth, outHeight, BufferedImage.TYPE_3BYTE_BGR)
3645
scaledImage.createGraphics().drawImage(image.getScaledInstance(outWidth, outHeight, 0), 0, 0, null)
3746
recorder.record(converter.convert(scaledImage))
@@ -42,3 +51,16 @@ fun createThumbnailVideo(
4251

4352
return outputPath
4453
}
54+
55+
/**
56+
* Creates the thumbnail videos for the reference and current videos and updates their paths in the global state.
57+
*
58+
* @param state [MutableState]<[AppState]> containing the global state.
59+
*/
60+
fun createThumbnailVideos(state: MutableState<AppState>) {
61+
// create the thumbnail videos
62+
val tempReference = createScaledVideo(state.value.videoReferencePath!!, 0.25f)
63+
val tempCurrent = createScaledVideo(state.value.videoCurrentPath!!, 0.25f)
64+
65+
state.value = state.value.copy(thumbnailVideoPathReference = tempReference, thumbnailVideoPathCurrent = tempCurrent)
66+
}

GUI/src/main/kotlin/ui/components/general/ProjectManager.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import androidx.compose.ui.text.font.FontWeight
1010
import androidx.compose.ui.unit.DpOffset
1111
import androidx.compose.ui.unit.dp
1212
import com.fasterxml.jackson.module.kotlin.readValue
13+
import logic.createThumbnailVideos
1314
import logic.getVideoMetadata
1415
import models.AppState
1516
import models.JsonMapper
1617
import org.bytedeco.javacv.FFmpegFrameGrabber
1718
import org.bytedeco.javacv.FFmpegFrameRecorder
1819
import org.bytedeco.javacv.Frame
20+
import java.io.File
1921

2022
/**
2123
* Dropdown menu to open and save projects
@@ -131,6 +133,15 @@ fun handleOpenProject(
131133
state.value.outputPath = path
132134
// reset unsaved changes
133135
state.value.hasUnsavedChanges = false
136+
137+
// if the temp thumbnail videos exist, use them. Otherwise, create them again which might take a few seconds
138+
if (!(
139+
state.value.thumbnailVideoPathReference?.let { File(it).exists() } == true &&
140+
state.value.thumbnailVideoPathCurrent?.let { File(it).exists() } == true
141+
)
142+
) {
143+
createThumbnailVideos(state)
144+
}
134145
} else {
135146
errorText.value = "The selected file does not contain a valid project."
136147
}

GUI/src/main/kotlin/ui/components/selectVideoScreen/ComputeDifferencesButton.kt

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import androidx.compose.ui.Modifier
1313
import androidx.compose.ui.text.style.TextAlign
1414
import androidx.compose.ui.unit.dp
1515
import kotlinx.coroutines.*
16-
import logic.createThumbnailVideo
16+
import logic.createThumbnailVideos
1717
import logic.differenceGeneratorWrapper.DifferenceGeneratorWrapper
1818
import logic.getVideoMetadata
1919
import models.AppState
@@ -117,14 +117,6 @@ suspend fun runComputation(
117117
state.value = state.value.copy(screen = Screen.DiffScreen, hasUnsavedChanges = true)
118118
}
119119

120-
fun createThumbnailVideos(state: MutableState<AppState>) {
121-
// create the thumbnail videos
122-
val tempReference = createThumbnailVideo(state.value.videoReferencePath!!, 0.25f)
123-
val tempCurrent = createThumbnailVideo(state.value.videoCurrentPath!!, 0.25f)
124-
125-
state.value = state.value.copy(thumbnailVideoPathReference = tempReference, thumbnailVideoPathCurrent = tempCurrent)
126-
}
127-
128120
private fun calculateVideoDifferences(
129121
state: MutableState<AppState>,
130122
errorDialogText: MutableState<String?>,

0 commit comments

Comments
 (0)