【问题标题】:Android + exoplayer: play AES encrypted videos, locallyAndroid + exoplayer:本地播放AES加密视频
【发布时间】: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()
    }
}

所以问题:

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

【问题讨论】:

    标签: android encryption aes exoplayer2.x


    【解决方案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()
            }
        }
    

    【讨论】:

    • 不错的解决方案。首先,它确实有效。你能具体了解一下跳过等的调整吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2022-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多