mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-07-08 23:14:17 +01:00
Ensure video send UX uses same max video constraint as transcoding.
This commit is contained in:
committed by
jeffrey-signal
parent
cdb73d4b8a
commit
f22567e4fb
@@ -259,7 +259,7 @@ public final class AttachmentCompressionJob extends BaseJob {
|
||||
}
|
||||
}
|
||||
|
||||
StreamingTranscoder transcoder = new StreamingTranscoder(dataSource, options, constraints.getVideoTranscodingSettings(), constraints.getCompressedVideoMaxSize(context), RemoteConfig.allowAudioRemuxing());
|
||||
StreamingTranscoder transcoder = new StreamingTranscoder(dataSource, options, constraints.getVideoTranscodingSettings(), constraints.getCompressedVideoMaxSize(), RemoteConfig.allowAudioRemuxing());
|
||||
|
||||
if (transcoder.isTranscodeRequired()) {
|
||||
Log.i(TAG, "Compressing with streaming muxer");
|
||||
@@ -407,13 +407,13 @@ public final class AttachmentCompressionJob extends BaseJob {
|
||||
ImageCompressionUtil.Result result = null;
|
||||
|
||||
try {
|
||||
for (int size : mediaConstraints.getImageDimensionTargets(context)) {
|
||||
for (int size : mediaConstraints.getImageDimensionTargets()) {
|
||||
result = ImageCompressionUtil.compressWithinConstraints(context,
|
||||
attachment.contentType,
|
||||
new DecryptableUri(uri),
|
||||
size,
|
||||
mediaConstraints.getImageMaxSize(context),
|
||||
mediaConstraints.getImageCompressionQualitySetting(context));
|
||||
mediaConstraints.getImageMaxSize(),
|
||||
mediaConstraints.getImageCompressionQualitySetting());
|
||||
if (result != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -81,9 +81,7 @@ class AttachmentUploadJob private constructor(
|
||||
@JvmStatic
|
||||
val maxPlaintextSize: Long
|
||||
get() {
|
||||
val maxCipherTextSize = RemoteConfig.maxAttachmentSizeBytes
|
||||
val maxPaddedSize = AttachmentCipherStreamUtil.getPlaintextLength(maxCipherTextSize)
|
||||
return PaddingInputStream.getMaxUnpaddedSize(maxPaddedSize)
|
||||
return AttachmentCipherStreamUtil.getMaxPlaintextSizeForCiphertext(RemoteConfig.maxAttachmentSizeBytes)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ class MediaSelectionRepository(context: Context) {
|
||||
return Single.fromCallable {
|
||||
val populatedMedia = mediaRepository.getPopulatedMedia(context, media)
|
||||
|
||||
val result = MediaValidator.filterMedia(context, populatedMedia, mediaConstraints, maxSelection, isStory)
|
||||
val result = MediaValidator.filterMedia(populatedMedia, mediaConstraints, maxSelection, isStory)
|
||||
result
|
||||
}.subscribeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
+2
-2
@@ -165,7 +165,7 @@ class MediaSelectionViewModel(
|
||||
.subscribe { filterResult ->
|
||||
if (filterResult.filteredMedia.isNotEmpty()) {
|
||||
store.update {
|
||||
val maxDuration = it.calculateMaxVideoDurationUs(getMediaConstraints().getVideoMaxSize())
|
||||
val maxDuration = it.calculateMaxVideoDurationUs(getMediaConstraints().getEditorVideoMaxSize())
|
||||
val initializedVideoEditorStates = filterResult.filteredMedia.filterNot { media -> it.editorStateMap.containsKey(media.uri) }
|
||||
.filter { media -> MediaUtil.isNonGifVideo(media) }
|
||||
.associate { video: Media ->
|
||||
@@ -359,7 +359,7 @@ class MediaSelectionViewModel(
|
||||
val durationEdited = clampedStartTime > 0 || endTimeUs < totalDurationUs
|
||||
val isEntireDuration = startTimeUs == 0L && endTimeUs == totalDurationUs
|
||||
val endMoved = !isEntireDuration && data.endTimeUs != endTimeUs
|
||||
val maxVideoDurationUs: Long = it.calculateMaxVideoDurationUs(getMediaConstraints().getVideoMaxSize())
|
||||
val maxVideoDurationUs: Long = it.calculateMaxVideoDurationUs(getMediaConstraints().getEditorVideoMaxSize())
|
||||
val preserveStartTime = unedited || !endMoved
|
||||
val videoTrimData = VideoTrimData(durationEdited, totalDurationUs, clampedStartTime, endTimeUs)
|
||||
val updatedData = clampToMaxClipDuration(videoTrimData, maxVideoDurationUs, preserveStartTime)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.thoughtcrime.securesms.mediasend.v2
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.WorkerThread
|
||||
import org.signal.core.models.media.Media
|
||||
import org.signal.core.util.Util
|
||||
@@ -11,8 +10,8 @@ import org.thoughtcrime.securesms.util.MediaUtil
|
||||
object MediaValidator {
|
||||
|
||||
@WorkerThread
|
||||
fun filterMedia(context: Context, media: List<Media>, mediaConstraints: MediaConstraints, maxSelection: Int, isStory: Boolean): FilterResult {
|
||||
val filteredMedia = filterForValidMedia(context, media, mediaConstraints, isStory)
|
||||
fun filterMedia(media: List<Media>, mediaConstraints: MediaConstraints, maxSelection: Int, isStory: Boolean): FilterResult {
|
||||
val filteredMedia = filterForValidMedia(media, mediaConstraints, isStory)
|
||||
val isAllMediaValid = filteredMedia.size == media.size
|
||||
|
||||
var error: FilterError? = null
|
||||
@@ -49,27 +48,27 @@ object MediaValidator {
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun filterForValidMedia(context: Context, media: List<Media>, mediaConstraints: MediaConstraints, isStory: Boolean): List<Media> {
|
||||
private fun filterForValidMedia(media: List<Media>, mediaConstraints: MediaConstraints, isStory: Boolean): List<Media> {
|
||||
return media
|
||||
.filter { m -> isSupportedMediaType(m.contentType!!) }
|
||||
.filter { m ->
|
||||
MediaUtil.isImageAndNotGif(m.contentType!!) || isValidGif(context, m, mediaConstraints) || isValidVideo(context, m, mediaConstraints) || isValidDocument(context, m, mediaConstraints)
|
||||
MediaUtil.isImageAndNotGif(m.contentType!!) || isValidGif(m, mediaConstraints) || isValidVideo(m, mediaConstraints) || isValidDocument(m, mediaConstraints)
|
||||
}
|
||||
.filter { m ->
|
||||
!isStory || Stories.MediaTransform.getSendRequirements(m) != Stories.MediaTransform.SendRequirements.CAN_NOT_SEND
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValidGif(context: Context, media: Media, mediaConstraints: MediaConstraints): Boolean {
|
||||
return MediaUtil.isGif(media.contentType) && media.size < mediaConstraints.getGifMaxSize(context)
|
||||
private fun isValidGif(media: Media, mediaConstraints: MediaConstraints): Boolean {
|
||||
return MediaUtil.isGif(media.contentType) && media.size < mediaConstraints.getGifMaxSize()
|
||||
}
|
||||
|
||||
private fun isValidVideo(context: Context, media: Media, mediaConstraints: MediaConstraints): Boolean {
|
||||
return MediaUtil.isVideoType(media.contentType) && media.size < mediaConstraints.getUncompressedVideoMaxSize(context)
|
||||
private fun isValidVideo(media: Media, mediaConstraints: MediaConstraints): Boolean {
|
||||
return MediaUtil.isVideoType(media.contentType) && media.size < mediaConstraints.getUncompressedVideoMaxSize()
|
||||
}
|
||||
|
||||
private fun isValidDocument(context: Context, media: Media, mediaConstraints: MediaConstraints): Boolean {
|
||||
return MediaUtil.isDocumentType(media.contentType) && media.size < mediaConstraints.getDocumentMaxSize(context)
|
||||
private fun isValidDocument(media: Media, mediaConstraints: MediaConstraints): Boolean {
|
||||
return MediaUtil.isDocumentType(media.contentType) && media.size < mediaConstraints.getDocumentMaxSize()
|
||||
}
|
||||
|
||||
private fun isSupportedMediaType(mimeType: String): Boolean {
|
||||
|
||||
+1
-1
@@ -582,7 +582,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul
|
||||
videoTimeLine.unregisterDragListener()
|
||||
}
|
||||
val size: Long = tryGetUriSize(requireContext(), uri, Long.MAX_VALUE)
|
||||
val maxSend = sharedViewModel.getMediaConstraints().getVideoMaxSize()
|
||||
val maxSend = sharedViewModel.getMediaConstraints().getEditorVideoMaxSize()
|
||||
if (size > maxSend) {
|
||||
videoTimeLine.setTimeLimit(state.transcodingPreset.calculateMaxVideoUploadDurationInSeconds(maxSend), TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ object MediaSendV3Repository : MediaSendRepository {
|
||||
): MediaFilterResult = withContext(Dispatchers.IO) {
|
||||
val populated = MediaRepository().getPopulatedMedia(appContext, media)
|
||||
val constraints = PushMediaConstraints(null)
|
||||
val result = MediaValidator.filterMedia(appContext, populated, constraints, maxSelection, isStory)
|
||||
val result = MediaValidator.filterMedia(populated, constraints, maxSelection, isStory)
|
||||
|
||||
val error = mapFilterError(result.filterError, populated, constraints, maxSelection, isStory)
|
||||
MediaFilterResult(result.filteredMedia, error)
|
||||
@@ -134,7 +134,7 @@ object MediaSendV3Repository : MediaSendRepository {
|
||||
}
|
||||
|
||||
override fun getVideoMaxSizeBytes(): Long {
|
||||
return PushMediaConstraints(null).videoMaxSize
|
||||
return PushMediaConstraints(null).getEditorVideoMaxSize()
|
||||
}
|
||||
|
||||
override fun isVideoTranscodeAvailable(): Boolean {
|
||||
@@ -263,10 +263,10 @@ object MediaSendV3Repository : MediaSendRepository {
|
||||
val size = item.size
|
||||
|
||||
val isTooLarge = when {
|
||||
MediaUtil.isGif(contentType) -> size > constraints.getGifMaxSize(appContext)
|
||||
MediaUtil.isVideoType(contentType) -> size > constraints.getUncompressedVideoMaxSize(appContext)
|
||||
MediaUtil.isImageType(contentType) -> size > constraints.getImageMaxSize(appContext)
|
||||
MediaUtil.isDocumentType(contentType) -> size > constraints.getDocumentMaxSize(appContext)
|
||||
MediaUtil.isGif(contentType) -> size > constraints.getGifMaxSize()
|
||||
MediaUtil.isVideoType(contentType) -> size > constraints.getUncompressedVideoMaxSize()
|
||||
MediaUtil.isImageType(contentType) -> size > constraints.getImageMaxSize()
|
||||
MediaUtil.isDocumentType(contentType) -> size > constraints.getDocumentMaxSize()
|
||||
else -> true
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import org.thoughtcrime.securesms.util.RemoteConfig;
|
||||
import org.thoughtcrime.securesms.video.TranscodingPreset;
|
||||
import org.thoughtcrime.securesms.video.videoconverter.utils.DeviceCapabilities;
|
||||
import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil;
|
||||
import org.whispersystems.signalservice.internal.crypto.PaddingInputStream;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -33,27 +32,27 @@ public class PushMediaConstraints extends MediaConstraints {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageMaxWidth(Context context) {
|
||||
public int getImageMaxWidth() {
|
||||
return currentConfig.imageSizeTargets[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageMaxHeight(Context context) {
|
||||
return getImageMaxWidth(context);
|
||||
public int getImageMaxHeight() {
|
||||
return getImageMaxWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageMaxSize(Context context) {
|
||||
public int getImageMaxSize() {
|
||||
return (int) Math.min(currentConfig.maxImageFileSize, getMaxAttachmentSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getImageDimensionTargets(Context context) {
|
||||
public int[] getImageDimensionTargets() {
|
||||
return currentConfig.imageSizeTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGifMaxSize(Context context) {
|
||||
public long getGifMaxSize() {
|
||||
return Math.min(25 * MB, getMaxAttachmentSize());
|
||||
}
|
||||
|
||||
@@ -63,26 +62,25 @@ public class PushMediaConstraints extends MediaConstraints {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUncompressedVideoMaxSize(Context context) {
|
||||
public long getUncompressedVideoMaxSize() {
|
||||
return isVideoTranscodeAvailable() ? RemoteConfig.maxSourceTranscodeVideoSizeBytes()
|
||||
: getVideoMaxSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCompressedVideoMaxSize(Context context) {
|
||||
long maxCipherTextSize = RemoteConfig.videoTranscodeTargetSizeBytes();
|
||||
long maxPaddedSize = AttachmentCipherStreamUtil.getPlaintextLength(maxCipherTextSize);
|
||||
public long getCompressedVideoMaxSize() {
|
||||
long maxCompressedSize = AttachmentCipherStreamUtil.getMaxPlaintextSizeForCiphertext(RemoteConfig.videoTranscodeTargetSizeBytes());
|
||||
|
||||
return Math.min(PaddingInputStream.getMaxUnpaddedSize(maxPaddedSize), getMaxAttachmentSize());
|
||||
return Math.min(maxCompressedSize, getMaxAttachmentSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAudioMaxSize(Context context) {
|
||||
public long getAudioMaxSize() {
|
||||
return getMaxAttachmentSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDocumentMaxSize(Context context) {
|
||||
public long getDocumentMaxSize() {
|
||||
return getMaxAttachmentSize();
|
||||
}
|
||||
|
||||
@@ -92,7 +90,7 @@ public class PushMediaConstraints extends MediaConstraints {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageCompressionQualitySetting(@NonNull Context context) {
|
||||
public int getImageCompressionQualitySetting() {
|
||||
return currentConfig.qualitySetting;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
package org.thoughtcrime.securesms.profiles;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.thoughtcrime.securesms.jobs.AttachmentUploadJob;
|
||||
import org.signal.mediasend.MediaConstraints;
|
||||
|
||||
public class ProfileMediaConstraints extends MediaConstraints {
|
||||
@Override
|
||||
public int getImageMaxWidth(Context context) {
|
||||
public int getImageMaxWidth() {
|
||||
return 640;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageMaxHeight(Context context) {
|
||||
public int getImageMaxHeight() {
|
||||
return 640;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageMaxSize(Context context) {
|
||||
public int getImageMaxSize() {
|
||||
return 5 * 1024 * 1024;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getImageDimensionTargets(Context context) {
|
||||
return new int[] { getImageMaxWidth(context) };
|
||||
public int[] getImageDimensionTargets() {
|
||||
return new int[] { getImageMaxWidth() };
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGifMaxSize(Context context) {
|
||||
public long getGifMaxSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,12 +36,12 @@ public class ProfileMediaConstraints extends MediaConstraints {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAudioMaxSize(Context context) {
|
||||
public long getAudioMaxSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDocumentMaxSize(Context context) {
|
||||
public long getDocumentMaxSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,13 +41,13 @@ public class SystemProfileUtil {
|
||||
try {
|
||||
ImageCompressionUtil.Result result = null;
|
||||
|
||||
for (int size : mediaConstraints.getImageDimensionTargets(context)) {
|
||||
for (int size : mediaConstraints.getImageDimensionTargets()) {
|
||||
result = ImageCompressionUtil.compressWithinConstraints(context,
|
||||
ContentTypeUtil.IMAGE_JPEG,
|
||||
Uri.parse(photoUri),
|
||||
size,
|
||||
mediaConstraints.getImageMaxSize(context),
|
||||
mediaConstraints.getImageCompressionQualitySetting(context));
|
||||
mediaConstraints.getImageMaxSize(),
|
||||
mediaConstraints.getImageCompressionQualitySetting());
|
||||
if (result != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -217,8 +217,8 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu
|
||||
|
||||
MediaConstraints mediaConstraints = new PushMediaConstraints(SentMediaQuality.HIGH);
|
||||
|
||||
imageMaxWidth = mediaConstraints.getImageMaxWidth(requireContext());
|
||||
imageMaxHeight = mediaConstraints.getImageMaxHeight(requireContext());
|
||||
imageMaxWidth = mediaConstraints.getImageMaxWidth();
|
||||
imageMaxHeight = mediaConstraints.getImageMaxHeight();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -28,9 +28,9 @@ import kotlin.Pair;
|
||||
public abstract class MediaConstraints {
|
||||
private static final String TAG = Log.tag(MediaConstraints.class);
|
||||
|
||||
public abstract int getImageMaxWidth(Context context);
|
||||
public abstract int getImageMaxHeight(Context context);
|
||||
public abstract int getImageMaxSize(Context context);
|
||||
public abstract int getImageMaxWidth();
|
||||
public abstract int getImageMaxHeight();
|
||||
public abstract int getImageMaxSize();
|
||||
|
||||
public TranscodingPreset getVideoTranscodingSettings() {
|
||||
return TranscodingPreset.LEVEL_1;
|
||||
@@ -38,41 +38,43 @@ public abstract class MediaConstraints {
|
||||
|
||||
/**
|
||||
* Provide a list of dimensions that should be attempted during compression. We will keep moving
|
||||
* down the list until the image can be scaled to fit under {@link #getImageMaxSize(Context)}.
|
||||
* down the list until the image can be scaled to fit under {@link #getImageMaxSize()}.
|
||||
* The first entry in the list should match your max width/height.
|
||||
*/
|
||||
public abstract int[] getImageDimensionTargets(Context context);
|
||||
public abstract int[] getImageDimensionTargets();
|
||||
|
||||
public abstract long getGifMaxSize(Context context);
|
||||
public abstract long getGifMaxSize();
|
||||
public abstract long getVideoMaxSize();
|
||||
public abstract long getAudioMaxSize();
|
||||
public abstract long getDocumentMaxSize();
|
||||
public abstract long getMaxAttachmentSize();
|
||||
|
||||
public @IntRange(from = 0, to = 100) int getImageCompressionQualitySetting(@NonNull Context context) {
|
||||
public @IntRange(from = 0, to = 100) int getImageCompressionQualitySetting() {
|
||||
return 70;
|
||||
}
|
||||
|
||||
public long getUncompressedVideoMaxSize(Context context) {
|
||||
public long getUncompressedVideoMaxSize() {
|
||||
return getVideoMaxSize();
|
||||
}
|
||||
|
||||
public long getCompressedVideoMaxSize(Context context) {
|
||||
public long getCompressedVideoMaxSize() {
|
||||
return getVideoMaxSize();
|
||||
}
|
||||
|
||||
public abstract long getAudioMaxSize(Context context);
|
||||
public abstract long getDocumentMaxSize(Context context);
|
||||
|
||||
public abstract long getMaxAttachmentSize();
|
||||
public long getEditorVideoMaxSize() {
|
||||
return isVideoTranscodeAvailable() ? getCompressedVideoMaxSize() : getVideoMaxSize();
|
||||
}
|
||||
|
||||
public boolean isSatisfied(@NonNull Context context, @NonNull Uri uri, @NonNull String contentType, long size) {
|
||||
try {
|
||||
if (size > getMaxAttachmentSize()) {
|
||||
return false;
|
||||
}
|
||||
return (ContentTypeUtil.isGif(contentType) && size <= getGifMaxSize(context) && isWithinBounds(context, uri)) ||
|
||||
(ContentTypeUtil.isImageType(contentType) && size <= getImageMaxSize(context) && isWithinBounds(context, uri)) ||
|
||||
(ContentTypeUtil.isAudioType(contentType) && size <= getAudioMaxSize(context)) ||
|
||||
(ContentTypeUtil.isVideoType(contentType) && size <= getVideoMaxSize()) ||
|
||||
(ContentTypeUtil.isDocumentType(contentType) && size <= getDocumentMaxSize(context));
|
||||
return (ContentTypeUtil.isGif(contentType) && size <= getGifMaxSize() && isWithinBounds(context, uri)) ||
|
||||
(ContentTypeUtil.isImageType(contentType) && size <= getImageMaxSize() && isWithinBounds(context, uri)) ||
|
||||
(ContentTypeUtil.isAudioType(contentType) && size <= getAudioMaxSize()) ||
|
||||
(ContentTypeUtil.isVideoType(contentType) && size <= getVideoMaxSize()) ||
|
||||
(ContentTypeUtil.isDocumentType(contentType) && size <= getDocumentMaxSize());
|
||||
} catch (IOException ioe) {
|
||||
Log.w(TAG, "Failed to determine if media's constraints are satisfied.", ioe);
|
||||
return false;
|
||||
@@ -81,10 +83,10 @@ public abstract class MediaConstraints {
|
||||
|
||||
private boolean isWithinBounds(Context context, Uri uri) throws IOException {
|
||||
try {
|
||||
InputStream is = MediaSendDependencies.INSTANCE.getMediaSendRepository().getAttachmentStream(context, uri);
|
||||
InputStream is = MediaSendDependencies.INSTANCE.getMediaSendRepository().getAttachmentStream(context, uri);
|
||||
Pair<Integer, Integer> dimensions = BitmapUtil.getDimensions(is);
|
||||
return dimensions.getFirst() > 0 && dimensions.getFirst() <= getImageMaxWidth(context) &&
|
||||
dimensions.getSecond() > 0 && dimensions.getSecond() <= getImageMaxHeight(context);
|
||||
return dimensions.getFirst() > 0 && dimensions.getFirst() <= getImageMaxWidth() &&
|
||||
dimensions.getSecond() > 0 && dimensions.getSecond() <= getImageMaxHeight();
|
||||
} catch (BitmapDecodingException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
package org.signal.mediasend;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.video.videoconverter.utils.VideoConstants;
|
||||
@@ -15,8 +13,8 @@ public final class VideoUtil {
|
||||
|
||||
private VideoUtil() { }
|
||||
|
||||
public static int getMaxVideoRecordDurationInSeconds(@NonNull Context context, @NonNull MediaConstraints mediaConstraints) {
|
||||
long allowedSize = mediaConstraints.getCompressedVideoMaxSize(context);
|
||||
public static int getMaxVideoRecordDurationInSeconds(@NonNull MediaConstraints mediaConstraints) {
|
||||
long allowedSize = mediaConstraints.getCompressedVideoMaxSize();
|
||||
int duration = (int) Math.floor((float) allowedSize / VideoConstants.MAX_ALLOWED_BYTES_PER_SECOND);
|
||||
|
||||
return Math.min(duration, VideoConstants.VIDEO_MAX_RECORD_LENGTH_S);
|
||||
|
||||
@@ -298,7 +298,7 @@ class CameraXFragment : ComposeFragment(), CameraFragment {
|
||||
}
|
||||
|
||||
private fun getMaxVideoDurationInSeconds(): Int {
|
||||
var maxDuration = VideoUtil.getMaxVideoRecordDurationInSeconds(requireContext(), controller!!.mediaConstraints)
|
||||
var maxDuration = VideoUtil.getMaxVideoRecordDurationInSeconds(controller!!.mediaConstraints)
|
||||
val controllerMaxDuration = controller?.maxVideoDuration ?: 0
|
||||
if (controllerMaxDuration > 0) {
|
||||
maxDuration = controllerMaxDuration
|
||||
|
||||
+6
@@ -6,6 +6,7 @@
|
||||
package org.whispersystems.signalservice.api.crypto
|
||||
|
||||
import org.signal.core.util.stream.NullOutputStream
|
||||
import org.whispersystems.signalservice.internal.crypto.PaddingInputStream
|
||||
import java.io.InputStream
|
||||
|
||||
object AttachmentCipherStreamUtil {
|
||||
@@ -27,6 +28,11 @@ object AttachmentCipherStreamUtil {
|
||||
return ((ciphertextLength - 16 - 32) / 16 - 1) * 16
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getMaxPlaintextSizeForCiphertext(ciphertextMax: Long): Long {
|
||||
return PaddingInputStream.getMaxUnpaddedSize(getPlaintextLength(ciphertextMax))
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the SHA-256 digest of the ciphertext that would result from encrypting [plaintextStream] with the given [key] and [iv].
|
||||
* This includes the IV prefix and HMAC suffix that are part of the encrypted attachment format.
|
||||
|
||||
Reference in New Issue
Block a user