mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 17:29:32 +01:00
Streamable Video.
This commit is contained in:
committed by
Nicholas Tinsley
parent
099c94c215
commit
64babe2e42
@@ -1,24 +1,29 @@
|
||||
package org.thoughtcrime.securesms.video.exo;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.datasource.DataSource;
|
||||
import androidx.media3.datasource.DataSpec;
|
||||
import androidx.media3.datasource.TransferListener;
|
||||
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.libsignal.protocol.InvalidMessageException;
|
||||
import org.signal.libsignal.protocol.incrementalmac.ChunkSizeChoice;
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.mms.PartUriParser;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.whispersystems.signalservice.api.crypto.AttachmentCipherInputStream;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
@@ -28,14 +33,13 @@ import java.util.Map;
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
class PartDataSource implements DataSource {
|
||||
|
||||
private final @NonNull Context context;
|
||||
private final String TAG = Log.tag(PartDataSource.class);
|
||||
private final @Nullable TransferListener listener;
|
||||
|
||||
private Uri uri;
|
||||
private InputStream inputSteam;
|
||||
private InputStream inputStream;
|
||||
|
||||
PartDataSource(@NonNull Context context, @Nullable TransferListener listener) {
|
||||
this.context = context.getApplicationContext();
|
||||
PartDataSource(@Nullable TransferListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@@ -47,13 +51,42 @@ class PartDataSource implements DataSource {
|
||||
public long open(DataSpec dataSpec) throws IOException {
|
||||
this.uri = dataSpec.uri;
|
||||
|
||||
AttachmentTable attachmentDatabase = SignalDatabase.attachments();
|
||||
PartUriParser partUri = new PartUriParser(uri);
|
||||
Attachment attachment = attachmentDatabase.getAttachment(partUri.getPartId());
|
||||
AttachmentTable attachmentDatabase = SignalDatabase.attachments();
|
||||
PartUriParser partUri = new PartUriParser(uri);
|
||||
DatabaseAttachment attachment = attachmentDatabase.getAttachment(partUri.getPartId());
|
||||
|
||||
if (attachment == null) throw new IOException("Attachment not found");
|
||||
|
||||
this.inputSteam = attachmentDatabase.getAttachmentStream(partUri.getPartId(), dataSpec.position);
|
||||
final boolean hasIncrementalDigest = attachment.getIncrementalDigest() != null;
|
||||
final boolean inProgress = attachment.isInProgress();
|
||||
final String attachmentKey = attachment.getKey();
|
||||
final boolean hasData = attachment.hasData();
|
||||
if (inProgress && !hasData && hasIncrementalDigest && attachmentKey != null && FeatureFlags.instantVideoPlayback()) {
|
||||
final byte[] decode = Base64.decode(attachmentKey);
|
||||
final File transferFile = attachmentDatabase.getOrCreateTransferFile(attachment.getAttachmentId());
|
||||
try {
|
||||
this.inputStream = AttachmentCipherInputStream.createForAttachment(transferFile, attachment.getSize(), decode, attachment.getDigest(), attachment.getIncrementalDigest());
|
||||
|
||||
long skipped = 0;
|
||||
while (skipped < dataSpec.position) {
|
||||
skipped += this.inputStream.read();
|
||||
}
|
||||
|
||||
Log.d(TAG, "Successfully loaded partial attachment file.");
|
||||
|
||||
} catch (InvalidMessageException e) {
|
||||
throw new IOException("Error decrypting attachment stream!", e);
|
||||
}
|
||||
} else if (!inProgress || hasData) {
|
||||
this.inputStream = attachmentDatabase.getAttachmentStream(partUri.getPartId(), dataSpec.position);
|
||||
|
||||
Log.d(TAG, "Successfully loaded completed attachment file.");
|
||||
} else {
|
||||
throw new IOException("Ineligible " + attachment.getAttachmentId().toString()
|
||||
+ "\nTransfer state: " + attachment.getTransferState()
|
||||
+ "\nIncremental Digest Present: " + hasIncrementalDigest
|
||||
+ "\nAttachment Key Non-Empty: " + (attachmentKey != null && !attachmentKey.isEmpty()));
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onTransferStart(this, dataSpec, false);
|
||||
@@ -66,7 +99,7 @@ class PartDataSource implements DataSource {
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] buffer, int offset, int readLength) throws IOException {
|
||||
int read = inputSteam.read(buffer, offset, readLength);
|
||||
int read = inputStream.read(buffer, offset, readLength);
|
||||
|
||||
if (read > 0 && listener != null) {
|
||||
listener.onBytesTransferred(this, null, false, read);
|
||||
@@ -87,6 +120,6 @@ class PartDataSource implements DataSource {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
inputSteam.close();
|
||||
if (inputStream != null) inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ import okhttp3.OkHttpClient;
|
||||
@Override
|
||||
public @NonNull SignalDataSource createDataSource() {
|
||||
return new SignalDataSource(new DefaultDataSourceFactory(context, "GenericUserAgent", null).createDataSource(),
|
||||
new PartDataSource(context, listener),
|
||||
new PartDataSource(listener),
|
||||
new BlobDataSource(context, listener),
|
||||
okHttpClient != null ? new ChunkedDataSource(okHttpClient, listener) : null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user