From eb9f300e601394d952b643b1fe6e80358d4d2e49 Mon Sep 17 00:00:00 2001 From: Thompson3142 <115718208+Thompson3142@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:32:06 +0200 Subject: [PATCH] Fix seekbar preview crashes (#11584) Fixed crashes from recycled bitmaps by creating real copies of bitmaps if necessary + some minor refactoring --- .../SeekbarPreviewThumbnailHolder.java | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHolder.java b/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHolder.java index 26065de15..2db6d39b2 100644 --- a/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHolder.java +++ b/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHolder.java @@ -132,17 +132,8 @@ public class SeekbarPreviewThumbnailHolder { // Get the bounds where the frame is found final int[] bounds = frameset.getFrameBoundsAt(currentPosMs); - generatedDataForUrl.put(currentPosMs, () -> { - // It can happen, that the original bitmap could not be downloaded - // In such a case - we don't want a NullPointer - simply return null - if (srcBitMap == null) { - return null; - } - - // Cut out the corresponding bitmap form the "srcBitMap" - return Bitmap.createBitmap(srcBitMap, bounds[1], bounds[2], - frameset.getFrameWidth(), frameset.getFrameHeight()); - }); + generatedDataForUrl.put(currentPosMs, + createBitmapSupplier(srcBitMap, bounds, frameset)); currentPosMs += frameset.getDurationPerFrame(); pos++; @@ -165,6 +156,33 @@ public class SeekbarPreviewThumbnailHolder { } } + private Supplier createBitmapSupplier(final Bitmap srcBitMap, + final int[] bounds, + final Frameset frameset) { + return () -> { + // It can happen, that the original bitmap could not be downloaded + // (or it was recycled though that should not happen) + // In such a case - we don't want a NullPointer/ + // "cannot use a recycled source in createBitmap" Exception -> simply return null + if (srcBitMap == null || srcBitMap.isRecycled()) { + return null; + } + + // Cut out the corresponding bitmap form the "srcBitMap" + final Bitmap cutOutBitmap = Bitmap.createBitmap(srcBitMap, bounds[1], bounds[2], + frameset.getFrameWidth(), frameset.getFrameHeight()); + + // If the cut out bitmap is identical to its source, + // we need to copy the bitmap to create a new instance. + // createBitmap allows itself to return the original object that is was created with + // this leads to recycled bitmaps being returned (if they are identical) + // Reference: https://stackoverflow.com/a/23683075 + first comment + // Fixes: https://github.com/TeamNewPipe/NewPipe/issues/11461 + return cutOutBitmap == srcBitMap + ? cutOutBitmap.copy(cutOutBitmap.getConfig(), true) : cutOutBitmap; + }; + } + @Nullable private Bitmap getBitMapFrom(final String url) { if (url == null) {