Android + exoplayer:本地播放AES加密视频

Posted

技术标签:

【中文标题】Android + exoplayer:本地播放AES加密视频【英文标题】:Android + exoplayer: play AES encrypted videos, locally 【发布时间】:2020-10-15 08:26:31 【问题描述】:

在一个 linux 机器上,我有一个用 openssl 加密的 MP4 视频:

openssl enc -aes-128-ecb -a -in video.mp4 -out video.enc -K `cat aes.key`

请注意,这是一个练习,算法的强度并不重要。

该文件已发送到 android 应用程序,我正在尝试使用 ExoPlayer 播放它。

我事先对文本文件进行了一些测试,以确保解密工作正常

fun decrypt(key: ByteArray, data: ByteArray): ByteArray 
    val spec = SecretKeySpec(key, "AES")
    val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
    cipher.init(Cipher.DECRYPT_MODE, spec)
    globalCipher.init(Cipher.DECRYPT_MODE, spec)
    return cipher.doFinal(data)


关于 ExoPlayer,AesCipherDataSourceAesCipherDataSinkSimpleCache 等之间有点压倒性。我无法组合一个简单的播放视频的方法。

fun playVideo() 
    val player = SimpleExoPlayer.Builder(this).build()
    playerView.player = player

    val dataSourceFactory = DefaultDataSourceFactory? // <-- what's the factory?
    val dataSource = AesCipherDataSource(globalCipher, ?) // <-- what's the data source?
    val extractorsFactory: ExtractorsFactory = DefaultExtractorsFactory()
    try 
        val uri = Uri.fromFile(File(path, "video.enc"))
        val videoSource =
                ExtractorMediaSource(uri, dataSourceFactory, extractorsFactory, null, null)
        player.prepare(videoSource)
        player.playWhenReady = true
     catch (e: Exception) 
        e.printStackTrace()
    

所以问题:

    如何实现在本地播放这段加密视频? 通过 HTTP 提供视频后,需要进行哪些更改? (需要添加清单吗?标头?)

【问题讨论】:

【参考方案1】:

这是解决方案。可能需要一些调整来处理跳帧、快进等,但这会播放AES/ECB/PKCS5Padding 加密视频

class EncryptedDataSourceFactory(
    private val key: String
) : DataSource.Factory 
    override fun createDataSource(): EncryptedDataSource =
        EncryptedDataSource(key)

class EncryptedDataSource(private val key: String) : DataSource 
    private var inputStream: CipherInputStream? = null
    private lateinit var uri: Uri

    override fun addTransferListener(transferListener: TransferListener) 

    override fun open(dataSpec: DataSpec): Long 
        uri = dataSpec.uri
        try 
            val file = File(uri.path)
            val skeySpec = SecretKeySpec(key.toByteArray(), KeyProperties.KEY_ALGORITHM_AES)
            val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
            cipher.init(Cipher.DECRYPT_MODE, skeySpec)
            inputStream = CipherInputStream(file.inputStream(), cipher)
         catch (e: Exception) 
            
        
        return dataSpec.length
    

    @Throws(IOException::class)
    override fun read(buffer: ByteArray, offset: Int, readLength: Int): Int =
        if (readLength == 0) 
            0
         else 
            inputStream?.read(buffer, offset, readLength) ?: 0
        

    override fun getUri(): Uri? =
        uri

    @Throws(IOException::class)
    override fun close() 
        inputStream?.close()
    

    private fun playVideo(key: String) 
        val player = SimpleExoPlayer.Builder(this).build()
        playerView.player = player

        val dataSourceFactory: DataSource.Factory = EncryptedDataSourceFactory(key)
        val extractorsFactory: ExtractorsFactory = DefaultExtractorsFactory()
        try 
            val uri = Uri.fromFile(video)
            val videoSource: MediaSource = ExtractorMediaSource(uri, dataSourceFactory, extractorsFactory, null, null)
            player.prepare(videoSource)
            player.playWhenReady = true
         catch (e: Exception) 
            e.printStackTrace()
        
    

【讨论】:

不错的解决方案。首先,它确实有效。你能具体了解一下跳过等的调整吗?

以上是关于Android + exoplayer:本地播放AES加密视频的主要内容,如果未能解决你的问题,请参考以下文章

android,Exoplayer实现视频播放器

Android ExoPlayer 无法播放 HLS(HTTP 直播)

Android音频开发:使用ExoPlayer播放音频

Android音频开发:使用ExoPlayer播放音频

Android音频开发:使用ExoPlayer播放音频

Android视频播放器Exoplayer自定义