Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import androidx.media3.common.Effect
import androidx.media3.common.util.UnstableApi
import androidx.media3.effect.BitmapOverlay
import androidx.media3.effect.OverlayEffect
import ch.waio.pro_video_editor.src.features.render.utils.getRotatedVideoDimensions
import java.io.File
import java.nio.ByteBuffer
import androidx.core.graphics.scale
import androidx.media3.effect.StaticOverlaySettings
import androidx.media3.effect.TimestampWrapper
import ch.waio.pro_video_editor.src.features.render.models.ImageLayer

/**
* Applies static image overlay on video.
Expand All @@ -38,7 +38,7 @@ import androidx.media3.effect.TimestampWrapper
fun applyImageLayer(
videoEffects: MutableList<Effect>,
inputFile: File,
imageLayers: List<ch.waio.pro_video_editor.src.features.render.models.ImageLayer>,
imageLayers: List<ImageLayer>,
rotationDegrees: Float,
cropWidth: Int?,
cropHeight: Int?,
Expand Down Expand Up @@ -90,7 +90,8 @@ fun applyTimedImageLayers(
// Scale to target size if provided
val sizedBitmap = if (layer.width != null && layer.height != null) {
val scaled = layerBitmap.scale(layer.width.toInt(), layer.height.toInt())
layerBitmap.recycle()
// scale() may return the same object when dimensions already match
if (scaled !== layerBitmap) layerBitmap.recycle()
scaled
} else {
layerBitmap
Expand All @@ -106,13 +107,8 @@ fun applyTimedImageLayers(

if (isStretched) {
// Stretch image to fill the entire video frame
val scaledOverlay = if (sizedBitmap.width != videoWidth || sizedBitmap.height != videoHeight) {
val scaled = sizedBitmap.scale(videoWidth, videoHeight)
sizedBitmap.recycle()
scaled
} else {
sizedBitmap
}
val scaledOverlay = sizedBitmap.scale(videoWidth, videoHeight)
if (scaledOverlay !== sizedBitmap) sizedBitmap.recycle()

val unpremultiplied = unpremultiplyAlpha(scaledOverlay)
if (unpremultiplied !== scaledOverlay) scaledOverlay.recycle()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
import java.io.File
import java.util.concurrent.atomic.AtomicInteger
import androidx.core.graphics.scale

/**
* Service for generating video thumbnail images.
Expand Down Expand Up @@ -140,13 +141,18 @@ class ThumbnailGenerator(private val context: Context) {
if (bitmap != null) {
val resized =
resizeBitmapKeepingAspect(bitmap, outputWidth, outputHeight, boxFit)
val bytes = compressBitmap(resized, outputFormat, jpegQuality)
thumbnails[index] = bytes
val duration = System.currentTimeMillis() - startTime
Log.d(
THUMBNAIL_TAG,
"βœ… [$index] Generated in $duration ms (${bytes.size} bytes)"
)
try {
val bytes = compressBitmap(resized, outputFormat, jpegQuality)
thumbnails[index] = bytes
val duration = System.currentTimeMillis() - startTime
Log.d(
THUMBNAIL_TAG,
"βœ… [$index] Generated in $duration ms (${bytes.size} bytes)"
)
} finally {
if (resized !== bitmap) bitmap.recycle()
resized.recycle()
}
} else {
Log.w(THUMBNAIL_TAG, "[$index] ❌ Null frame at ${timeUs / 1000} ms")
}
Expand Down Expand Up @@ -217,13 +223,18 @@ class ThumbnailGenerator(private val context: Context) {
if (bitmap != null) {
val resized =
resizeBitmapKeepingAspect(bitmap, outputWidth, outputHeight, boxFit)
val bytes = compressBitmap(resized, outputFormat, jpegQuality)
thumbnails[index] = bytes
val duration = System.currentTimeMillis() - startTime
Log.d(
THUMBNAIL_TAG,
"[$index] βœ… ${timeUs / 1000} ms in $duration ms (${bytes.size} bytes)"
)
try {
val bytes = compressBitmap(resized, outputFormat, jpegQuality)
thumbnails[index] = bytes
val duration = System.currentTimeMillis() - startTime
Log.d(
THUMBNAIL_TAG,
"[$index] βœ… ${timeUs / 1000} ms in $duration ms (${bytes.size} bytes)"
)
} finally {
if (resized !== bitmap) bitmap.recycle()
resized.recycle()
}
} else {
Log.w(THUMBNAIL_TAG, "[$index] ❌ Null frame at ${timeUs / 1000} ms")
}
Expand Down Expand Up @@ -328,7 +339,7 @@ class ThumbnailGenerator(private val context: Context) {
val resizedWidth = (originalWidth * scale).toInt()
val resizedHeight = (originalHeight * scale).toInt()

return Bitmap.createScaledBitmap(original, resizedWidth, resizedHeight, true)
return original.scale(resizedWidth, resizedHeight)
}

/**
Expand Down
Loading