mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-26 05:58:09 +00:00
Expose StreamingTranscoder configuration options in sample app.
This commit is contained in:
committed by
Greyson Parrelli
parent
c7609f9a2a
commit
caa5e233df
@@ -9,13 +9,8 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.libsignal.media.Mp4Sanitizer;
|
||||
import org.signal.libsignal.media.ParseException;
|
||||
import org.signal.libsignal.media.SanitizedMetadata;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
||||
@@ -47,15 +42,16 @@ import org.thoughtcrime.securesms.video.InMemoryTranscoder;
|
||||
import org.thoughtcrime.securesms.video.StreamingTranscoder;
|
||||
import org.thoughtcrime.securesms.video.TranscoderCancelationSignal;
|
||||
import org.thoughtcrime.securesms.video.TranscoderOptions;
|
||||
import org.thoughtcrime.securesms.video.exceptions.VideoPostProcessingException;
|
||||
import org.thoughtcrime.securesms.video.exceptions.VideoSourceException;
|
||||
import org.thoughtcrime.securesms.video.postprocessing.Mp4FaststartPostProcessor;
|
||||
import org.thoughtcrime.securesms.video.exceptions.VideoSourceException;
|
||||
import org.thoughtcrime.securesms.video.videoconverter.EncodingException;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -289,23 +285,17 @@ public final class AttachmentCompressionJob extends BaseJob {
|
||||
100,
|
||||
100));
|
||||
|
||||
InputStream transcodedFileStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, file, 0);
|
||||
SanitizedMetadata metadata = null;
|
||||
try {
|
||||
metadata = Mp4Sanitizer.sanitize(transcodedFileStream, file.length());
|
||||
} catch (ParseException e) {
|
||||
Log.e(TAG, "Could not parse MP4 file.", e);
|
||||
}
|
||||
final Mp4FaststartPostProcessor postProcessor = new Mp4FaststartPostProcessor(() -> {
|
||||
try {
|
||||
return ModernDecryptingPartInputStream.createFor(attachmentSecret, file, 0);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}, file.length());
|
||||
|
||||
if (metadata != null && metadata.getSanitizedMetadata() != null) {
|
||||
try (MediaStream mediaStream = new MediaStream(new SequenceInputStream(new ByteArrayInputStream(metadata.getSanitizedMetadata()), ByteStreams.limit(ModernDecryptingPartInputStream.createFor(attachmentSecret, file, metadata.getDataOffset()), metadata.getDataLength())), MimeTypes.VIDEO_MP4, 0, 0, true)) {
|
||||
attachmentDatabase.updateAttachmentData(attachment, mediaStream, true);
|
||||
faststart = true;
|
||||
}
|
||||
} else {
|
||||
try (MediaStream mediaStream = new MediaStream(ModernDecryptingPartInputStream.createFor(attachmentSecret, file, 0), MimeTypes.VIDEO_MP4, 0, 0)) {
|
||||
attachmentDatabase.updateAttachmentData(attachment, mediaStream, true);
|
||||
}
|
||||
try (MediaStream mediaStream = new MediaStream(postProcessor.process(), MimeTypes.VIDEO_MP4, 0, 0, true)) {
|
||||
attachmentDatabase.updateAttachmentData(attachment, mediaStream, true);
|
||||
faststart = true;
|
||||
}
|
||||
} finally {
|
||||
if (!file.delete()) {
|
||||
@@ -360,6 +350,12 @@ public final class AttachmentCompressionJob extends BaseJob {
|
||||
}
|
||||
} catch (IOException | MmsException e) {
|
||||
throw new UndeliverableMessageException("Failed to transcode", e);
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getCause() instanceof IOException) {
|
||||
throw new UndeliverableMessageException("Failed to transcode", e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return attachment;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.media.DecryptableUriMediaInput;
|
||||
import org.thoughtcrime.securesms.mms.VideoSlide;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.video.TranscodingQuality;
|
||||
import org.thoughtcrime.securesms.video.VideoBitRateCalculator;
|
||||
import org.thoughtcrime.securesms.video.VideoUtil;
|
||||
import org.thoughtcrime.securesms.video.videoconverter.VideoThumbnailsRangeSelectorView;
|
||||
@@ -134,7 +135,7 @@ public final class VideoEditorHud extends LinearLayout {
|
||||
public VideoThumbnailsRangeSelectorView.Quality getQuality(long clipDurationUs, long totalDurationUs) {
|
||||
int inputBitRate = VideoBitRateCalculator.bitRate(size, TimeUnit.MICROSECONDS.toMillis(totalDurationUs));
|
||||
|
||||
VideoBitRateCalculator.Quality targetQuality = videoBitRateCalculator.getTargetQuality(TimeUnit.MICROSECONDS.toMillis(clipDurationUs), inputBitRate);
|
||||
TranscodingQuality targetQuality = videoBitRateCalculator.getTargetQuality(TimeUnit.MICROSECONDS.toMillis(clipDurationUs), inputBitRate);
|
||||
return new VideoThumbnailsRangeSelectorView.Quality(targetQuality.getFileSizeEstimate(), (int) (100 * targetQuality.getQuality()));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,9 +7,7 @@ import android.media.MediaMetadataRetriever;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.libsignal.media.Mp4Sanitizer;
|
||||
@@ -17,18 +15,18 @@ import org.signal.libsignal.media.ParseException;
|
||||
import org.signal.libsignal.media.SanitizedMetadata;
|
||||
import org.thoughtcrime.securesms.mms.MediaStream;
|
||||
import org.thoughtcrime.securesms.util.MemoryFileDescriptor;
|
||||
import org.thoughtcrime.securesms.video.exceptions.VideoPostProcessingException;
|
||||
import org.thoughtcrime.securesms.video.exceptions.VideoSizeException;
|
||||
import org.thoughtcrime.securesms.video.exceptions.VideoSourceException;
|
||||
import org.thoughtcrime.securesms.video.postprocessing.Mp4FaststartPostProcessor;
|
||||
import org.thoughtcrime.securesms.video.videoconverter.EncodingException;
|
||||
import org.thoughtcrime.securesms.video.videoconverter.MediaConverter;
|
||||
import org.thoughtcrime.securesms.video.videoconverter.mediadatasource.MediaDataSourceMediaInput;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -37,17 +35,17 @@ public final class InMemoryTranscoder implements Closeable {
|
||||
|
||||
private static final String TAG = Log.tag(InMemoryTranscoder.class);
|
||||
|
||||
private final Context context;
|
||||
private final MediaDataSource dataSource;
|
||||
private final long upperSizeLimit;
|
||||
private final long inSize;
|
||||
private final long duration;
|
||||
private final int inputBitRate;
|
||||
private final VideoBitRateCalculator.Quality targetQuality;
|
||||
private final long memoryFileEstimate;
|
||||
private final boolean transcodeRequired;
|
||||
private final long fileSizeEstimate;
|
||||
private final @Nullable TranscoderOptions options;
|
||||
private final Context context;
|
||||
private final MediaDataSource dataSource;
|
||||
private final long upperSizeLimit;
|
||||
private final long inSize;
|
||||
private final long duration;
|
||||
private final int inputBitRate;
|
||||
private final TranscodingQuality targetQuality;
|
||||
private final long memoryFileEstimate;
|
||||
private final boolean transcodeRequired;
|
||||
private final long fileSizeEstimate;
|
||||
private final @Nullable TranscoderOptions options;
|
||||
|
||||
private @Nullable MemoryFileDescriptor memoryFile;
|
||||
|
||||
@@ -148,13 +146,6 @@ public final class InMemoryTranscoder implements Closeable {
|
||||
|
||||
memoryFile.seek(0);
|
||||
|
||||
SanitizedMetadata metadata = null;
|
||||
try {
|
||||
metadata = Mp4Sanitizer.sanitize(new FileInputStream(memoryFileFileDescriptor), memoryFile.size());
|
||||
} catch (ParseException e) {
|
||||
Log.e(TAG, "Could not parse MP4 file.", e);
|
||||
}
|
||||
|
||||
// output details of the transcoding
|
||||
long outSize = memoryFile.size();
|
||||
float encodeDurationSec = (System.currentTimeMillis() - startTime) / 1000f;
|
||||
@@ -179,14 +170,30 @@ public final class InMemoryTranscoder implements Closeable {
|
||||
throw new VideoSizeException("Size constraints could not be met!");
|
||||
}
|
||||
|
||||
try {
|
||||
final Mp4FaststartPostProcessor postProcessor = new Mp4FaststartPostProcessor(() -> {
|
||||
try {
|
||||
memoryFile.seek(0);
|
||||
return new FileInputStream(memoryFileFileDescriptor);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "IOException thrown while creating FileInputStream.", e);
|
||||
throw new VideoPostProcessingException("Exception while opening InputStream!", e);
|
||||
}
|
||||
}, memoryFile.size());
|
||||
|
||||
if (metadata != null && metadata.getSanitizedMetadata() != null) {
|
||||
memoryFile.seek(metadata.getDataOffset());
|
||||
return new MediaStream(new SequenceInputStream(new ByteArrayInputStream(metadata.getSanitizedMetadata()), ByteStreams.limit(new FileInputStream(memoryFileFileDescriptor), metadata.getDataLength())), MimeTypes.VIDEO_MP4, 0, 0, true);
|
||||
} else {
|
||||
memoryFile.seek(0);
|
||||
return new MediaStream(new FileInputStream(memoryFileFileDescriptor), MimeTypes.VIDEO_MP4, 0, 0);
|
||||
return new MediaStream(postProcessor.process(), MimeTypes.VIDEO_MP4, 0, 0, true);
|
||||
} catch (VideoPostProcessingException e) {
|
||||
Log.w(TAG, "Exception thrown during post processing.", e);
|
||||
final Throwable cause = e.getCause();
|
||||
if (cause instanceof IOException) {
|
||||
throw (IOException) cause;
|
||||
} else if ( cause instanceof EncodingException) {
|
||||
throw (EncodingException) cause;
|
||||
}
|
||||
}
|
||||
|
||||
memoryFile.seek(0);
|
||||
return new MediaStream(new FileInputStream(memoryFileFileDescriptor), MimeTypes.VIDEO_MP4, 0, 0);
|
||||
}
|
||||
|
||||
public boolean isTranscodeRequired() {
|
||||
|
||||
Reference in New Issue
Block a user