使用ExoPlayer再现加密视频 [英] Reproducing encrypted video using ExoPlayer

查看:1581
本文介绍了使用ExoPlayer再现加密视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Android中使用 ExoPlayer ,而我'试图重现本地存储的加密视频。



ExoPlayer的模块化允许创建可以注入到ExoPlayer中的自定义组件,这种情况似乎如此。事实上,经过一些研究,我意识到,为了完成任务,我可以创建一个自定义的DataSource并覆盖 open() read() close()



我还发现,但是实际上这里整个文件是在一个步骤中被解密并存储在一个清晰的输入流中的.org / android / android-play-encrypted-video-in-exoplayerrel =nofollow noreferrer这在很多情况下可以很好。但是如果我需要重现大文件怎么办?所以问题是:如何在ExoPlayer中再现加密的视频,即时解密内容(不解密整个文件)?这是可能的吗?



我尝试创建一个具有open()方法的自定义DataSource:

  @Override 
public long open(DataSpec dataSpec)throws FileDataSourceException {
try {
File file = new File(dataSpec.uri.getPath());

clearInputStream = new CipherInputStream(new FileInputStream(file),mCipher);

long skipped = clearInputStream.skip(dataSpec.position);
if(skipped< dataSpec.position){
throw new EOFException();
}
if(dataSpec.length!= C.LENGTH_UNBOUNDED){
bytesRemaining = dataSpec.length;
} else {
bytesRemaining = clearInputStream.available();
if(bytesRemaining == 0){
bytesRemaining = C.LENGTH_UNBOUNDED;
}
}
} catch(EOFException e){
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
}

opened = true;
if(listener!= null){
listener.onTransferStart();
}

return bytesRemaining;
}

这是read()方法:

  @Override 
public int read(byte [] buffer,int offset,int readLength)throws FileDataSourceException {
if(bytesRemaining == 0){
return -1;
} else {
int bytesRead = 0;

int bytesToRead = bytesRemaining == C.LENGTH_UNBOUNDED? readLength
:(int)Math.min(bytesRemaining,readLength);
try {
bytesRead = clearInputStream.read(buffer,offset,bytesToRead);
} catch(IOException e){
e.printStackTrace();
}

if(bytesRead> 0){
if(bytesRemaining!= C.LENGTH_UNBOUNDED){
bytesRemaining - = bytesRead;
}
if(listener!= null){
listener.onBytesTransferred(bytesRead);
}
}

return bytesRead;
}
}

如果不是编码文件,我传递一个清除文件,并且刚刚删除CipherInputStream部分,那么它工作正常,而是加密文件我得到这个错误:

 意外的异常加载流
java.lang.IllegalStateException:顶部位不为零:-1195853062
com.google.android.exoplayer.util.ParsableByteArray.readUnsignedIntToInt(ParsableByteArray.java:240)
在com.google $。$。 com.google.android.exoplayer.extractor.ExtractorSampleSource $ ExtractingLoadable.load(ExtractorSampleSource.java:745)
在com.google.android.exoplayer.upstream.Loader $ LoadTask.run(Loader.java:209)
在java.util.concurrent.Executors $ RunnableAdapter.call(Executors.java:423)
在java.util.concurrent.FutureTask.run(FutureTask .java:237)
在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
在java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:588)$


$ p $ <$ $编辑:



加密视频以这种方式生成:

 密码密码= Cipher.getInstance(AES / CBC / PKCS5Padding); 
SecretKeySpec keySpec = new SecretKeySpec(0123456789012345.getBytes(),AES);
IvParameterSpec ivSpec = new IvParameterSpec(0123459876543210.getBytes());
cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec);

outputStream = new CipherOutputStream(output_stream,cipher);

然后将outputStream保存到文件中。

解决方案

最终我找到了解决方案。



我以这种方式使用无填充的加密算法: / p>

  cipher = Cipher.getInstance(AES / CTR / NoPadding,BC); 

使加密文件的大小和清除文件大小保持不变。所以现在我创建了流:

  cipherInputStream = new CipherInputStream(inputStream,cipher){
@Override
public int available()throws IOException {
return in.available();
}
};

这是因为Java文档关于 ChiperInputStream.available() code>


此方法应该被覆盖


,实际上我认为它更像是必须的,因为从该方法检索的值通常很奇怪。



那就是!现在它的效果很好。


I'm using ExoPlayer, in Android, and I'm trying to reproduce an encrypted video stored locally.

The modularity of ExoPlayer allows to create custom components that can be injected in the ExoPlayer, and this seems the case. Indeed, after some researches I realized that for achive that task I could create a custom DataSource and overriding open(), read() and close().

I have also found this solution, but actually here the entire file is decrypted in one step and stored in a clear inputstream. This can be good in many situation. But what if I need to reproduce big file?

So the question is: how can I reproduce encrypted video in ExoPlayer, decrypting content "on-fly" (without decrypting the entire file)? Is this possibile?

I tried creating a custom DataSource that has the open() method:

@Override
    public long open(DataSpec dataSpec) throws FileDataSourceException {
        try {
            File file = new File(dataSpec.uri.getPath());

            clearInputStream = new CipherInputStream(new FileInputStream(file), mCipher);

            long skipped = clearInputStream.skip(dataSpec.position);
            if (skipped < dataSpec.position) {
                throw new EOFException();
            }
            if (dataSpec.length != C.LENGTH_UNBOUNDED) {
                bytesRemaining = dataSpec.length;
            } else {
                bytesRemaining = clearInputStream.available();
                if (bytesRemaining == 0) {
                    bytesRemaining = C.LENGTH_UNBOUNDED;
                }
            }
        } catch (EOFException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        opened = true;
        if (listener != null) {
            listener.onTransferStart();
        }

        return bytesRemaining;
    }

And this is the read() method:

@Override
public int read(byte[] buffer, int offset, int readLength) throws FileDataSourceException {
        if (bytesRemaining == 0) {
            return -1;
        } else {
            int bytesRead = 0;

                int bytesToRead = bytesRemaining == C.LENGTH_UNBOUNDED ? readLength
                        : (int) Math.min(bytesRemaining, readLength);
            try {
                bytesRead = clearInputStream.read(buffer, offset, bytesToRead);
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (bytesRead > 0) {
                if (bytesRemaining != C.LENGTH_UNBOUNDED) {
                    bytesRemaining -= bytesRead;
                }
                if (listener != null) {
                    listener.onBytesTransferred(bytesRead);
                }
            }

            return bytesRead;
        }
    }

If instead of an encoded file I pass a clear file, and just remove the CipherInputStream part, then it works fine, instead with encrypted file I obtain this error:

    Unexpected exception loading stream
java.lang.IllegalStateException: Top bit not zero: -1195853062
at com.google.android.exoplayer.util.ParsableByteArray.readUnsignedIntToInt(ParsableByteArray.java:240)
at com.google.android.exoplayer.extractor.mp4.Mp4Extractor.readSample(Mp4Extractor.java:331)
at com.google.android.exoplayer.extractor.mp4.Mp4Extractor.read(Mp4Extractor.java:122)
at com.google.android.exoplayer.extractor.ExtractorSampleSource$ExtractingLoadable.load(ExtractorSampleSource.java:745)
at com.google.android.exoplayer.upstream.Loader$LoadTask.run(Loader.java:209)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)

EDIT:

the encrypted video is generated in this way:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec("0123456789012345".getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec("0123459876543210".getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

outputStream = new CipherOutputStream(output_stream, cipher);

Then the outputStream is saved into a File.

解决方案

Eventually I found the solution.

I used a no-padding for the encryption algorithm, in this way:

cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");

so that the size of the encrypted file and the clear file size remain the same. So now I created the stream:

cipherInputStream = new CipherInputStream(inputStream, cipher) {
    @Override
    public int available() throws IOException {
         return in.available();
    }
};

This is because the Java documentation says about ChiperInputStream.available() that

This method should be overriden

and actually I think is it more like a MUST, because the values retrieved from that method are often really strange.

And that is it! Now it works perfectly.

这篇关于使用ExoPlayer再现加密视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆