From 929ee04814c9bde0303eef838f87ceab5cb5c838 Mon Sep 17 00:00:00 2001 From: Alan Evans Date: Mon, 5 Aug 2019 10:48:18 -0400 Subject: [PATCH] Handle missing video duration. On EncodingException, or no duration metadata found, when video < 100MB, continue with send. --- .../securesms/jobs/MediaResizer.java | 14 +++++++- .../securesms/video/InMemoryTranscoder.java | 32 ++++++++++++++----- .../securesms/video/VideoSizeException.java | 8 +++++ .../securesms/video/VideoSourceException.java | 12 +++++++ 4 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/video/VideoSizeException.java create mode 100644 src/org/thoughtcrime/securesms/video/VideoSourceException.java diff --git a/src/org/thoughtcrime/securesms/jobs/MediaResizer.java b/src/org/thoughtcrime/securesms/jobs/MediaResizer.java index a9310ef330..7824df71eb 100644 --- a/src/org/thoughtcrime/securesms/jobs/MediaResizer.java +++ b/src/org/thoughtcrime/securesms/jobs/MediaResizer.java @@ -11,6 +11,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.database.AttachmentDatabase; +import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.mms.MediaStream; @@ -22,6 +23,8 @@ import org.thoughtcrime.securesms.util.BitmapDecodingException; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.video.InMemoryTranscoder; +import org.thoughtcrime.securesms.video.VideoSourceException; +import org.thoughtcrime.securesms.video.VideoSizeException; import org.thoughtcrime.securesms.video.videoconverter.EncodingException; import java.io.ByteArrayInputStream; @@ -31,6 +34,8 @@ import java.util.List; final class MediaResizer { + private static final String TAG = Log.tag(MediaResizer.class); + @NonNull private final Context context; @NonNull private final MediaConstraints constraints; @@ -114,7 +119,14 @@ final class MediaResizer { } } } - } catch (IOException | MmsException | EncodingException e) { + } catch (VideoSourceException | EncodingException e) { + if (attachment.getSize() > constraints.getVideoMaxSize(context)) { + throw new UndeliverableMessageException("Duration not found, attachment too large to skip transcode", e); + } else { + Log.w(TAG, "Duration not found, video small enough to skip transcode", e); + return attachment; + } + } catch (IOException | MmsException | VideoSizeException e) { throw new UndeliverableMessageException("Failed to transcode", e); } } diff --git a/src/org/thoughtcrime/securesms/video/InMemoryTranscoder.java b/src/org/thoughtcrime/securesms/video/InMemoryTranscoder.java index 5eb42444b6..63656c61d2 100644 --- a/src/org/thoughtcrime/securesms/video/InMemoryTranscoder.java +++ b/src/org/thoughtcrime/securesms/video/InMemoryTranscoder.java @@ -12,7 +12,6 @@ import com.google.android.exoplayer2.util.MimeTypes; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.MediaStream; -import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.thoughtcrime.securesms.util.MemoryFileDescriptor; import org.thoughtcrime.securesms.video.videoconverter.EncodingException; import org.thoughtcrime.securesms.video.videoconverter.MediaConverter; @@ -53,12 +52,17 @@ public final class InMemoryTranscoder implements Closeable { /** * @param upperSizeLimit A upper size to transcode to. The actual output size can be up to 10% smaller. */ - public InMemoryTranscoder(@NonNull Context context, @NonNull MediaDataSource dataSource, long upperSizeLimit) throws IOException { + public InMemoryTranscoder(@NonNull Context context, @NonNull MediaDataSource dataSource, long upperSizeLimit) throws IOException, VideoSourceException { this.context = context; this.dataSource = dataSource; final MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); - mediaMetadataRetriever.setDataSource(dataSource); + try { + mediaMetadataRetriever.setDataSource(dataSource); + } catch (RuntimeException e) { + Log.w(TAG, "Unable to read datasource", e); + throw new VideoSourceException("Unable to read datasource", e); + } long upperSizeLimitWithMargin = (long) (upperSizeLimit / 1.1); @@ -80,7 +84,7 @@ public final class InMemoryTranscoder implements Closeable { : OUTPUT_FORMAT; } - public @NonNull MediaStream transcode(@NonNull Progress progress) throws IOException, UndeliverableMessageException, EncodingException { + public @NonNull MediaStream transcode(@NonNull Progress progress) throws IOException, EncodingException, VideoSizeException { if (memoryFile != null) throw new AssertionError("Not expecting to reuse transcoder"); float durationSec = duration / 1000f; @@ -107,7 +111,7 @@ public final class InMemoryTranscoder implements Closeable { numberFormat.format(inputBitRate))); if (fileSizeEstimate > upperSizeLimit) { - throw new UndeliverableMessageException("Size constraints could not be met!"); + throw new VideoSizeException("Size constraints could not be met!"); } memoryFile = MemoryFileDescriptor.newMemoryFileDescriptor(context, @@ -153,7 +157,7 @@ public final class InMemoryTranscoder implements Closeable { numberFormat.format(bitRate(outSize, duration)))); if (outSize > upperSizeLimit) { - throw new UndeliverableMessageException("Size constraints could not be met!"); + throw new VideoSizeException("Size constraints could not be met!"); } memoryFile.seek(0); @@ -185,8 +189,20 @@ public final class InMemoryTranscoder implements Closeable { return Math.max(MINIMUM_TARGET_VIDEO_BITRATE, Math.min(MAXIMUM_TARGET_VIDEO_BITRATE, (int) bitRateToFixTarget)); } - private static long getDuration(MediaMetadataRetriever mediaMetadataRetriever) { - return Long.parseLong(mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)); + private static long getDuration(MediaMetadataRetriever mediaMetadataRetriever) throws VideoSourceException { + String durationString = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + if (durationString == null) { + throw new VideoSourceException("Cannot determine duration of video, null meta data"); + } + try { + long duration = Long.parseLong(durationString); + if (duration <= 0) { + throw new VideoSourceException("Cannot determine duration of video, meta data: " + durationString); + } + return duration; + } catch (NumberFormatException e) { + throw new VideoSourceException("Cannot determine duration of video, meta data: " + durationString, e); + } } private static boolean containsLocation(MediaMetadataRetriever mediaMetadataRetriever) { diff --git a/src/org/thoughtcrime/securesms/video/VideoSizeException.java b/src/org/thoughtcrime/securesms/video/VideoSizeException.java new file mode 100644 index 0000000000..2f08008f92 --- /dev/null +++ b/src/org/thoughtcrime/securesms/video/VideoSizeException.java @@ -0,0 +1,8 @@ +package org.thoughtcrime.securesms.video; + +public final class VideoSizeException extends Exception { + + VideoSizeException(String message) { + super(message); + } +} diff --git a/src/org/thoughtcrime/securesms/video/VideoSourceException.java b/src/org/thoughtcrime/securesms/video/VideoSourceException.java new file mode 100644 index 0000000000..88d702f396 --- /dev/null +++ b/src/org/thoughtcrime/securesms/video/VideoSourceException.java @@ -0,0 +1,12 @@ +package org.thoughtcrime.securesms.video; + +public final class VideoSourceException extends Exception { + + VideoSourceException(String message) { + super(message); + } + + VideoSourceException(String message, Exception inner) { + super(message, inner); + } +}