如何在 android 中玩 SRT(安全可靠传输)?

How to play a SRT (Secure Reliable Transfer) in android?

我想知道是否可以使用安全可靠传输协议播放视频。这种类型的视频以 srt:// 开头。我知道 VideoView 只支持 https 和另一个我不记得但不支持 srt 的协议。

谷歌搜索的任何尝试都会产生关于 srt 字幕文件的结果,这不是我要找的。

有谁知道如何在 android 上播放 srt 视频?

如果有人来这里寻找答案,这就是我为使其正常工作所做的工作。我的方法是用于直播,但可以对其进行修改以处理单一文件类型的视频。

我设法实现了一个自定义的 ExoPlayer 数据源,它适用于实时流式传输 SRT。

Uses srtdroid library

工厂

class SrtLiveStreamDataSourceFactory(
    private val srtUrl: String,
    private val port: Int,
    private val passPhrase: String? = null
) :
    DataSource.Factory {
    override fun createDataSource(): DataSource {
        return SrtLiveStreamDataSource(srtUrl, port, passPhrase)
    }
}

数据源

const val PAYLOAD_SIZE = 1316


class SrtLiveStreamDataSource(
    private val srtUrl: String,
    private val port: Int,
    private val passPhrase: String?

) :
    BaseDataSource(/*isNetwork*/true) {

    private var socket: Socket? = null
    private val byteQueue: Queue<Byte> = LinkedList()


    override fun open(dataSpec: DataSpec): Long {
        socket = Socket()
        socket?.setSockFlag(SockOpt.TRANSTYPE, Transtype.LIVE)
        socket?.setSockFlag(SockOpt.PAYLOADSIZE, PAYLOAD_SIZE)
        if(passPhrase != null){
            socket?.setSockFlag(SockOpt.PASSPHRASE, passPhrase)
        }
        socket?.connect(srtUrl, port)
        return C.LENGTH_UNSET.toLong()
    }


    /**
     * Receives from SRT socket and feeds into a queue. Depending on the length requested
     * from exoplayer, that amount of bytes is polled from queue and onto the buffer with the given offset.
     *
     * You cannot directly receive at the given length from the socket, because SRT uses a
     * predetermined payload size that cannot be dynamic
     */
    override fun read(buffer: ByteArray, offset: Int, length: Int): Int {
        if (length == 0) {
            return 0
        }
        var bytesReceived = 0
        if (socket != null) {
            val received = socket!!.recv(PAYLOAD_SIZE)
            for (byte in received.second /*received byte array*/) {
                byteQueue.offer(byte)
            }
            repeat(length) { index ->
                val byte = byteQueue.poll()
                if (byte != null) {
                    buffer[index + offset] = byte
                    bytesReceived++
                }
            }
            return bytesReceived
        }
        throw IOException("Couldn't read bytes at offset: $offset")
    }

    override fun getUri(): Uri? {
        return Uri.parse("srt://$srtUrl:$port")
    }

    override fun close() {
        socket?.close()
        socket = null
    }
}

简单用法

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)


        val url = SRT_URL_HERE (exclude srt://)
        val port = PORT_HERE

        val source = ProgressiveMediaSource.Factory(
            SrtLiveStreamDataSourceFactory(
                url,
                port,
            ),
        ).createMediaSource(MediaItem.fromUri(Uri.EMPTY))


        val player = ExoPlayer.Builder(this)
            .build()
        player.setMediaSource(source)
        binding.playerView.player = player


        player.prepare()
        player.play()
        player.playWhenReady = true

    }
}