如何解决如何在android studio中播放本地存储的加密视频文件
我有一个使用 AES 算法加密的视频文件,但我需要在播放视频视图之前解密视频。问题是解密视频所花费的时间太多了。有什么办法可以做到。
更新:
E/ExoPlayerImplInternal:播放错误 com.google.android.exoplayer2.ExoPlaybackException:源错误 在 com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:579) 在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:164) 在 android.os.HandlerThread.run(HandlerThread.java:65) 引起:com.google.android.exoplayer2.source.UnrecognizedInputFormatException: 没有可用的提取器(FragmentedMp4Extractor、Mp4Extractor、FlvExtractor、FlacExtractor、WavExtractor、AmrExtractor、PsExtractor、OggExtractor、TsExtractor、ActsExtractor、Actskap3Extractor、Mp4Extractor、 ) 可以读取流。 在 com.google.android.exoplayer2.source.BundledExtractorsAdapter.init(BundledExtractorsAdapter.java:92) 在 com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:1026) 在 com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:415) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 在 java.lang.Thread.run(Thread.java:764)
解决方法
当文件存储在本地时,您可能根本不需要对其进行加密。用户或任何其他应用程序都看不到 andorid 中的本地文件存储。只有您的应用可以访问存储空间,因此您无需担心用户会读取机密数据。
编辑:因为我刚刚看到你最近对本地的评论,你的意思是在设备上。您可以将视频保存在内部存储中,除您的应用外,其他任何人都无法访问该存储空间。看看纪录片:https://developer.android.com/training/data-storage/app-specific
,给你。我不知道它是否有效,但它应该:
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.BaseDataSource;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.SecretKeySpec;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min;
public class EncryptedFileDataSource extends BaseDataSource {
public static class EncryptedFileDataSourceException extends IOException {
public EncryptedFileDataSourceException(Throwable cause) {
super(cause);
}
public EncryptedFileDataSourceException(String message,IOException cause) {
super(message,cause);
}
}
/**
* {@link DataSource.Factory} for {@link EncryptedFileDataSource} instances.
*/
public static final class Factory implements DataSource.Factory {
@Nullable
private TransferListener listener;
private byte[] key;
private String transformation;
public Factory() {
this(null,null);
}
public Factory(byte[] key) {
this(key,null);
}
public Factory(byte[] key,String transformation) {
setKey(key);
setTransformation(transformation);
}
public void setKey(byte[] key) {
if (key == null) {
return;
}
this.key = key;
}
public void setTransformation(String transformation) {
if (transformation == null) {
transformation = "AES/ECB/PKCS5Padding";
}
this.transformation = transformation;
}
/**
* Sets a {@link TransferListener} for {@link EncryptedFileDataSource} instances created by this factory.
*
* @param listener The {@link TransferListener}.
* @return This factory.
*/
public Factory setListener(@Nullable TransferListener listener) {
this.listener = listener;
return this;
}
@Override
public EncryptedFileDataSource createDataSource() {
EncryptedFileDataSource dataSource = new EncryptedFileDataSource(key,transformation);
if (listener != null) {
dataSource.addTransferListener(listener);
}
return dataSource;
}
}
@Nullable
private RandomAccessFile file;
@Nullable
private Uri uri;
private long bytesRemaining;
private boolean opened;
private byte[] key;
private String transformation;
private Cipher cipher;
private byte[] tmpBuffer;
private EncryptedFileDataSource(byte[] key,String transformation) {
super(false);
setKey(key);
setTransformation(transformation);
}
public void setKey(byte[] key) {
this.key = key;
}
public void setTransformation(String transformation) {
this.transformation = transformation;
}
@Override
public long open(@NonNull DataSpec dataSpec) throws EncryptedFileDataSourceException {
try {
byte[] key = this.key;
String transformation = this.transformation;
Uri uri = dataSpec.uri;
this.uri = uri;
transferInitializing(dataSpec);
if (key != null && transformation != null) {
SecretKeySpec keySpec = new SecretKeySpec(key,"AES");
cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.DECRYPT_MODE,keySpec);
}
this.file = openLocalFile(uri);
file.seek(dataSpec.position);
bytesRemaining = dataSpec.length == C.LENGTH_UNSET ? file.length() - dataSpec.position
: dataSpec.length;
if (bytesRemaining < 0) {
throw new EOFException();
}
} catch (IOException
| NoSuchPaddingException
| NoSuchAlgorithmException
| InvalidKeyException e) {
throw new EncryptedFileDataSourceException(e);
}
opened = true;
transferStarted(dataSpec);
return bytesRemaining;
}
@Override
public int read(@NonNull byte[] buffer,int offset,int readLength) throws EncryptedFileDataSourceException {
if (readLength == 0) {
return 0;
} else if (bytesRemaining == 0) {
return C.RESULT_END_OF_INPUT;
} else {
int bytesRead,bytesStored;
try {
int length = (int) min(bytesRemaining,readLength);
Cipher cipher = this.cipher;
if (cipher != null) {
tmpBuffer = resize(tmpBuffer,length);
bytesRead = castNonNull(file).read(tmpBuffer,length);
bytesStored = cipher.doFinal(tmpBuffer,length,buffer,offset);
} else {
bytesStored = bytesRead = castNonNull(file).read(buffer,offset,length);
}
} catch (IOException
| BadPaddingException
| IllegalBlockSizeException
| ShortBufferException e) {
throw new EncryptedFileDataSourceException(e);
}
if (bytesRead > 0) {
bytesRemaining -= bytesRead;
bytesTransferred(bytesRead);
}
return bytesStored;
}
}
@Nullable
@Override
public Uri getUri() {
return uri;
}
@Override
public void close() throws EncryptedFileDataSourceException {
uri = null;
try {
if (file != null) {
file.close();
}
} catch (IOException e) {
throw new EncryptedFileDataSourceException(e);
} finally {
file = null;
key = null;
transformation = null;
cipher = null;
if (opened) {
opened = false;
transferEnded();
}
byte[] tmpBuffer = this.tmpBuffer;
this.tmpBuffer = null;
if (tmpBuffer != null) {
for (int i = tmpBuffer.length - 1; i >= 0; i -= 2) {
tmpBuffer[i] = (byte) 0;
}
}
}
}
static byte[] resize(byte[] b,int newLen) {
if (newLen < 0) return b;
if (b == null || b.length < newLen) {
return new byte[newLen];
} else return b;
}
private static RandomAccessFile openLocalFile(Uri uri) throws FileDataSource.FileDataSourceException {
try {
return new RandomAccessFile(Assertions.checkNotNull(uri.getPath()),"r");
} catch (FileNotFoundException e) {
if (!TextUtils.isEmpty(uri.getQuery()) || !TextUtils.isEmpty(uri.getFragment())) {
throw new FileDataSource.FileDataSourceException(
String.format(
"uri has query and/or fragment,which are not supported. Did you call Uri.parse()"
+ " on a string containing '?' or '#'? Use Uri.fromFile(new File(path)) to"
+ " avoid this. path=%s,query=%s,fragment=%s",uri.getPath(),uri.getQuery(),uri.getFragment()),e);
}
throw new FileDataSource.FileDataSourceException(e);
}
}
}
像这样使用它:
public void playVideo(Uri uri,byte[] key,@Nullable String transformation) {
playVideo(MediaItem.fromUri(uri),key,transformation);
}
public void playVideo(MediaItem media,@Nullable String transformation) {
ExoPlayer player = new SimpleExoPlayer.Builder(this).build();
playerView.setPlayer(player);
try {
DataSource.Factory dataSourceFactory = new EncryptedFileDataSource.Factory(key,transformation);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
ProgressiveMediaSource.Factory progressiveFactory = new ProgressiveMediaSource.Factory(
dataSourceFactory,extractorsFactory
);
ProgressiveMediaSource mediaSource = progressiveFactory.createMediaSource(media);
player.setMediaSource(mediaSource);
//player.setMediaSource(mediaSource,startPositionMs: long);
//player.setMediaSource(mediaSource,resetPosition: boolean);
player.setPlayWhenReady(true);
} catch (Exception e) {
e.printStackTrace();
}
}
我使用以下资源来制作此内容:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。