android, desktop: catching decoding errors (#3314)

This commit is contained in:
Stanislav Dmitrenko
2023-11-04 17:21:29 +00:00
committed by GitHub
parent 10cbb13c26
commit eee233bd02
8 changed files with 100 additions and 61 deletions
@@ -200,7 +200,7 @@ actual class VideoPlayer actual constructor(
private fun setPreviewAndDuration() {
// It freezes main thread, doing it in IO thread
CoroutineScope(Dispatchers.IO).launch {
val previewAndDuration = VideoPlayerHolder.previewsAndDurations.getOrPut(uri) { getBitmapFromVideo(uri) }
val previewAndDuration = VideoPlayerHolder.previewsAndDurations.getOrPut(uri) { getBitmapFromVideo(uri, withAlertOnException = false) }
withContext(Dispatchers.Main) {
preview.value = previewAndDuration.preview ?: defaultPreview
duration.value = (previewAndDuration.duration ?: 0)
@@ -233,17 +233,13 @@ actual fun getFileSize(uri: URI): Long? {
actual fun getBitmapFromUri(uri: URI, withAlertOnException: Boolean): ImageBitmap? {
return if (Build.VERSION.SDK_INT >= 28) {
val source = ImageDecoder.createSource(androidAppContext.contentResolver, uri.toUri())
try {
val source = ImageDecoder.createSource(androidAppContext.contentResolver, uri.toUri())
ImageDecoder.decodeBitmap(source)
} catch (e: android.graphics.ImageDecoder.DecodeException) {
} catch (e: Exception) {
Log.e(TAG, "Unable to decode the image: ${e.stackTraceToString()}")
if (withAlertOnException) {
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.image_decoding_exception_title),
text = generalGetString(MR.strings.image_decoding_exception_desc)
)
}
if (withAlertOnException) showImageDecodingException()
null
}
} else {
@@ -253,17 +249,13 @@ actual fun getBitmapFromUri(uri: URI, withAlertOnException: Boolean): ImageBitma
actual fun getBitmapFromByteArray(data: ByteArray, withAlertOnException: Boolean): ImageBitmap? {
return if (Build.VERSION.SDK_INT >= 31) {
val source = ImageDecoder.createSource(data)
try {
val source = ImageDecoder.createSource(data)
ImageDecoder.decodeBitmap(source)
} catch (e: android.graphics.ImageDecoder.DecodeException) {
Log.e(TAG, "Unable to decode the image: ${e.stackTraceToString()}")
if (withAlertOnException) {
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.image_decoding_exception_title),
text = generalGetString(MR.strings.image_decoding_exception_desc)
)
}
if (withAlertOnException) showImageDecodingException()
null
}
} else {
@@ -273,17 +265,13 @@ actual fun getBitmapFromByteArray(data: ByteArray, withAlertOnException: Boolean
actual fun getDrawableFromUri(uri: URI, withAlertOnException: Boolean): Any? {
return if (Build.VERSION.SDK_INT >= 28) {
val source = ImageDecoder.createSource(androidAppContext.contentResolver, uri.toUri())
try {
val source = ImageDecoder.createSource(androidAppContext.contentResolver, uri.toUri())
ImageDecoder.decodeDrawable(source)
} catch (e: android.graphics.ImageDecoder.DecodeException) {
if (withAlertOnException) {
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.image_decoding_exception_title),
text = generalGetString(MR.strings.image_decoding_exception_desc)
)
}
} catch (e: Exception) {
Log.e(TAG, "Error while decoding drawable: ${e.stackTraceToString()}")
if (withAlertOnException) showImageDecodingException()
null
}
} else {
@@ -304,23 +292,29 @@ actual suspend fun saveTempImageUncompressed(image: ImageBitmap, asPng: Boolean)
ChatModel.filesToDelete.add(this)
}
} catch (e: Exception) {
Log.e(TAG, "Util.kt saveTempImageUncompressed error: ${e.message}")
Log.e(TAG, "Utils.android saveTempImageUncompressed error: ${e.message}")
null
}
}
actual suspend fun getBitmapFromVideo(uri: URI, timestamp: Long?, random: Boolean): VideoPlayerInterface.PreviewAndDuration {
val mmr = MediaMetadataRetriever()
mmr.setDataSource(androidAppContext, uri.toUri())
val durationMs = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong()
val image = when {
timestamp != null -> mmr.getFrameAtTime(timestamp * 1000, MediaMetadataRetriever.OPTION_CLOSEST)
random -> mmr.frameAtTime
else -> mmr.getFrameAtTime(0)
actual suspend fun getBitmapFromVideo(uri: URI, timestamp: Long?, random: Boolean, withAlertOnException: Boolean): VideoPlayerInterface.PreviewAndDuration =
try {
val mmr = MediaMetadataRetriever()
mmr.setDataSource(androidAppContext, uri.toUri())
val durationMs = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong()
val image = when {
timestamp != null -> mmr.getFrameAtTime(timestamp * 1000, MediaMetadataRetriever.OPTION_CLOSEST)
random -> mmr.frameAtTime
else -> mmr.getFrameAtTime(0)
}
mmr.release()
VideoPlayerInterface.PreviewAndDuration(image?.asImageBitmap(), durationMs, timestamp ?: 0)
} catch (e: Exception) {
Log.e(TAG, "Utils.android getBitmapFromVideo error: ${e.message}")
if (withAlertOnException) showVideoDecodingException()
VideoPlayerInterface.PreviewAndDuration(null, 0, 0)
}
mmr.release()
return VideoPlayerInterface.PreviewAndDuration(image?.asImageBitmap(), durationMs, timestamp ?: 0)
}
actual fun ByteArray.toBase64StringForPassphrase(): String = Base64.encodeToString(this, Base64.DEFAULT)