diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java index 843c4c1d6c..5bc9c6f3c0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java @@ -258,7 +258,7 @@ public final class AttachmentCompressionJob extends BaseJob { } if (FeatureFlags.useStreamingVideoMuxer()) { - StreamingTranscoder transcoder = new StreamingTranscoder(dataSource, options, constraints.getCompressedVideoMaxSize(context)); + StreamingTranscoder transcoder = new StreamingTranscoder(dataSource, options, constraints.getCompressedVideoMaxSize(context), FeatureFlags.allowAudioRemuxing()); if (transcoder.isTranscodeRequired()) { Log.i(TAG, "Compressing with streaming muxer"); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java index 0b4474cb28..585e540801 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java @@ -120,6 +120,7 @@ public final class FeatureFlags { private static final String CALLING_RAISE_HAND = "android.calling.raiseHand"; private static final String USE_ACTIVE_CALL_MANAGER = "android.calling.useActiveCallManager.2"; private static final String GIF_SEARCH = "global.gifSearch"; + private static final String AUDIO_REMUXING = "android.media.audioRemux"; /** * We will only store remote values for flags in this set. If you want a flag to be controllable @@ -192,7 +193,8 @@ public final class FeatureFlags { CALLING_RAISE_HAND, PHONE_NUMBER_PRIVACY, USE_ACTIVE_CALL_MANAGER, - GIF_SEARCH + GIF_SEARCH, + AUDIO_REMUXING ); @VisibleForTesting @@ -693,6 +695,11 @@ public final class FeatureFlags { return getBoolean(GIF_SEARCH, true); } + /** Allow media converters to remux audio instead of transcoding it. */ + public static boolean allowAudioRemuxing() { + return getBoolean(AUDIO_REMUXING, false); + } + /** Only for rendering debug info. */ public static synchronized @NonNull Map getMemoryValues() { return new TreeMap<>(REMOTE_VALUES); diff --git a/video/app/src/main/java/org/thoughtcrime/video/app/transcode/TranscodeWorker.kt b/video/app/src/main/java/org/thoughtcrime/video/app/transcode/TranscodeWorker.kt index 9e3329a759..0b4136d25a 100644 --- a/video/app/src/main/java/org/thoughtcrime/video/app/transcode/TranscodeWorker.kt +++ b/video/app/src/main/java/org/thoughtcrime/video/app/transcode/TranscodeWorker.kt @@ -86,9 +86,9 @@ class TranscodeWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker( } val transcoder = if (resolution > 0 && desiredBitrate > 0) { - StreamingTranscoder(datasource, null, desiredBitrate, resolution) + StreamingTranscoder(datasource, null, desiredBitrate, resolution, false) } else { - StreamingTranscoder(datasource, null, DEFAULT_FILE_SIZE_LIMIT) + StreamingTranscoder(datasource, null, DEFAULT_FILE_SIZE_LIMIT, true) } setForeground(createForegroundInfo(-1, notificationId)) diff --git a/video/lib/src/main/java/org/thoughtcrime/securesms/video/StreamingTranscoder.java b/video/lib/src/main/java/org/thoughtcrime/securesms/video/StreamingTranscoder.java index d5e8ea11ab..99d27fd8a5 100644 --- a/video/lib/src/main/java/org/thoughtcrime/securesms/video/StreamingTranscoder.java +++ b/video/lib/src/main/java/org/thoughtcrime/securesms/video/StreamingTranscoder.java @@ -39,17 +39,20 @@ public final class StreamingTranscoder { private final boolean transcodeRequired; private final long fileSizeEstimate; private final @Nullable TranscoderOptions options; + private final boolean allowAudioRemux; /** * @param upperSizeLimit A upper size to transcode to. The actual output size can be up to 10% smaller. */ public StreamingTranscoder(@NonNull MediaDataSource dataSource, @Nullable TranscoderOptions options, - long upperSizeLimit) + long upperSizeLimit, + boolean allowAudioRemux) throws IOException, VideoSourceException { this.dataSource = dataSource; this.options = options; + this.allowAudioRemux = allowAudioRemux; final MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); try { @@ -81,11 +84,13 @@ public final class StreamingTranscoder { public StreamingTranscoder(@NonNull MediaDataSource dataSource, @Nullable TranscoderOptions options, int videoBitrate, - int shortEdge) + int shortEdge, + boolean allowAudioRemux) throws IOException, VideoSourceException { - this.dataSource = dataSource; - this.options = options; + this.dataSource = dataSource; + this.options = options; + this.allowAudioRemux = allowAudioRemux; final MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); try { @@ -142,7 +147,7 @@ public final class StreamingTranscoder { final long startTime = System.currentTimeMillis(); - final MediaConverter converter = new MediaConverter(); + final MediaConverter converter = new MediaConverter(); converter.setInput(new MediaDataSourceMediaInput(dataSource)); final CountingOutputStream outStream; @@ -155,6 +160,7 @@ public final class StreamingTranscoder { converter.setVideoResolution(targetQuality.getOutputResolution()); converter.setVideoBitrate(targetQuality.getTargetVideoBitRate()); converter.setAudioBitrate(targetQuality.getTargetAudioBitRate()); + converter.setAllowAudioRemux(allowAudioRemux); if (options != null) { if (options.endTimeUs > 0) { diff --git a/video/lib/src/main/java/org/thoughtcrime/securesms/video/videoconverter/AudioTrackConverter.java b/video/lib/src/main/java/org/thoughtcrime/securesms/video/videoconverter/AudioTrackConverter.java index 036d62b10d..a597702d83 100644 --- a/video/lib/src/main/java/org/thoughtcrime/securesms/video/videoconverter/AudioTrackConverter.java +++ b/video/lib/src/main/java/org/thoughtcrime/securesms/video/videoconverter/AudioTrackConverter.java @@ -41,7 +41,6 @@ final class AudioTrackConverter { private final MediaCodec mAudioDecoder; private final MediaCodec mAudioEncoder; - private final boolean skipTrancode; private final ByteBuffer instanceSampleBuffer = ByteBuffer.allocateDirect(SAMPLE_BUFFER_SIZE); private final MediaCodec.BufferInfo instanceBufferInfo = new MediaCodec.BufferInfo(); @@ -57,8 +56,9 @@ final class AudioTrackConverter { boolean mAudioExtractorDone; private boolean mAudioDecoderDone; boolean mAudioEncoderDone; + private boolean skipTrancode; - private int mOutputAudioTrack = -1; + private int mOutputAudioTrack = -1; private int mPendingAudioDecoderOutputBufferIndex = -1; long mMuxingAudioPresentationTime; @@ -164,8 +164,13 @@ final class AudioTrackConverter { void step() throws IOException { if (skipTrancode && mEncoderOutputAudioFormat != null) { - extractAndRemux(); - return; + try { + extractAndRemux(); + return; + } catch (IllegalArgumentException e) { + Log.w(TAG, "Remuxer threw an exception! Disabling remux.", e); + skipTrancode = false; + } } // Extract audio from file and feed to decoder. diff --git a/video/lib/src/main/java/org/thoughtcrime/securesms/video/videoconverter/MediaConverter.java b/video/lib/src/main/java/org/thoughtcrime/securesms/video/videoconverter/MediaConverter.java index d4465d92d4..7d780d50ea 100644 --- a/video/lib/src/main/java/org/thoughtcrime/securesms/video/videoconverter/MediaConverter.java +++ b/video/lib/src/main/java/org/thoughtcrime/securesms/video/videoconverter/MediaConverter.java @@ -63,6 +63,7 @@ public final class MediaConverter { private int mVideoBitrate = 2000000; // 2Mbps private @VideoCodec String mVideoCodec = VIDEO_CODEC_H264; private int mAudioBitrate = 128000; // 128Kbps + private boolean mAllowAudioRemux = false; private Listener mListener; private boolean mCancelled; @@ -131,6 +132,10 @@ public final class MediaConverter { mListener = listener; } + public void setAllowAudioRemux(boolean allow) { + mAllowAudioRemux = allow; + } + @WorkerThread @RequiresApi(23) public void convert() throws EncodingException, IOException { @@ -144,7 +149,7 @@ public final class MediaConverter { muxer = mOutput.createMuxer(); videoTrackConverter = VideoTrackConverter.create(mInput, mTimeFrom, mTimeTo, mVideoResolution, mVideoBitrate, mVideoCodec); - audioTrackConverter = AudioTrackConverter.create(mInput, mTimeFrom, mTimeTo, mAudioBitrate, muxer.supportsAudioRemux()); + audioTrackConverter = AudioTrackConverter.create(mInput, mTimeFrom, mTimeTo, mAudioBitrate, mAllowAudioRemux && muxer.supportsAudioRemux()); if (videoTrackConverter == null && audioTrackConverter == null) { throw new EncodingException("No video and audio tracks");