Fix bitrate value used for video transcoding (#5183)

* Fix bitrate value used for video transcoding:

It should be 1000 times what it is now. The video size estimation was wrong since the retrieved duration value was in milliseconds, not seconds.

* Use `Duration` as the result type for `getDuration`
This commit is contained in:
Jorge Martin Espinosa
2025-08-18 23:12:11 +02:00
committed by GitHub
parent aac9642159
commit 5feb7a99a9
5 changed files with 15 additions and 8 deletions

View File

@@ -101,8 +101,9 @@ class DefaultMediaOptimizationSelectorPresenter @AssistedInject constructor(
val sizeEstimations = VideoCompressionPreset.entries
.map { preset ->
val bitRate = preset.compressorHelper().calculateOptimalBitrate(videoDimensions, 30)
val calculatedSize = (bitRate * duration / 8 * 1.1).roundToLong() // Adding 10% overhead for safety
val bitRateAsBytes = preset.compressorHelper().calculateOptimalBitrate(videoDimensions, 30) / 8f
val durationInSeconds = duration.inWholeSeconds.toFloat()
val calculatedSize = (bitRateAsBytes * durationInSeconds * 1.1f).roundToLong() // Adding 10% overhead for safety
VideoUploadEstimation(
preset = preset,
sizeInBytes = calculatedSize,

View File

@@ -18,10 +18,12 @@ import dagger.assisted.AssistedInject
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
interface VideoMetadataExtractor : AutoCloseable {
fun getSize(): Result<Size>
fun getDuration(): Result<Long>
fun getDuration(): Result<Duration>
interface Factory {
fun create(uri: Uri): VideoMetadataExtractor
}
@@ -57,9 +59,10 @@ class DefaultVideoMetadataExtractor @AssistedInject constructor(
}
}
override fun getDuration(): Result<Long> = runCatchingExceptions {
override fun getDuration(): Result<Duration> = runCatchingExceptions {
mediaMetadataRetriever.value.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong()
?.takeIf { it > 0L }
?.milliseconds
?: error("Could not retrieve video duration from metadata")
}

View File

@@ -34,6 +34,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.time.Duration.Companion.minutes
@RunWith(AndroidJUnit4::class)
class DefaultMediaOptimizationSelectorPresenterTest {
@@ -158,7 +159,7 @@ class DefaultMediaOptimizationSelectorPresenterTest {
mediaExtractorFactory = FakeVideoMetadataExtractorFactory(
FakeVideoMetadataExtractor(
sizeResult = Result.success(Size(10_000, 10_000)),
duration = Result.success(600L)
duration = Result.success(10.minutes)
)
),
)

View File

@@ -10,14 +10,16 @@ package io.element.android.features.messages.test.attachments.video
import android.net.Uri
import android.util.Size
import io.element.android.features.messages.impl.attachments.video.VideoMetadataExtractor
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
class FakeVideoMetadataExtractor(
private val sizeResult: Result<Size> = Result.success(Size(1, 1)),
private val duration: Result<Long> = Result.success(1L),
private val duration: Result<Duration> = Result.success(1.milliseconds),
) : VideoMetadataExtractor {
override fun getSize(): Result<Size> = sizeResult
override fun getDuration(): Result<Long> = duration
override fun getDuration(): Result<Duration> = duration
override fun close() = Unit
}

View File

@@ -38,7 +38,7 @@ class VideoCompressorHelper(
val pixelsPerFrame = outputSize.width * outputSize.height
// Apparently, 0.1 bits per pixel is a sweet spot for video compression
val bitsPerPixel = 0.1f
return (pixelsPerFrame * bitsPerPixel * frameRate).toLong() / 1000
return (pixelsPerFrame * bitsPerPixel * frameRate).toLong()
}
}