You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ExoPlayer中直接使用SRT格式字符串作为字幕(无需本地存储)

解决ExoPlayer直接使用内存SRT字符串作为字幕的方案

不需要将SRT字符串写入本地文件,以下几种方案可以直接生成可用的subtitleUri或绕开Uri限制实现字幕加载:

方案1:使用Data URI(简单直接)

Data URI可直接将字符串编码后嵌入Uri,无需本地文件,适合中小体积字幕:

import android.net.Uri
import android.util.Base64
import com.google.android.exoplayer2.util.MimeTypes

const val SRT_STRING = "1\n00:01:52,042 --> 00:01:57,917\nWhen the child was a child,\nit walked with its arms swinging.\n\n2\n00:01:58,125 --> 00:02:02,833\nIt wanted the stream to be a river,\nthe river a torrent..."

// 将SRT字符串编码为Base64
val srtBase64 = Base64.encodeToString(SRT_STRING.toByteArray(), Base64.NO_WRAP)
// 构造符合规范的Data URI
val subtitleUri = Uri.parse("data:text/plain;base64,$srtBase64")

// 构建字幕配置
val subtitleConfig = SubtitleConfiguration.Builder(subtitleUri)
    .setMimeType(MimeTypes.TEXT_SRT) // 指定SRT的MIME类型
    .build()

注意:若字幕文件过大,Data URI可能存在长度限制,但常规字幕场景完全适用。

方案2:自定义ContentProvider(适合多字幕管理)

如果需要频繁处理内存中的字幕字符串,可自定义ContentProvider提供内存内容,无长度限制:

  1. 实现自定义ContentProvider:
import android.content.ContentProvider
import android.content.ContentValues
import android.database.Cursor
import android.net.Uri
import android.os.ParcelFileDescriptor
import com.google.android.exoplayer2.util.MimeTypes
import java.io.ByteArrayInputStream
import java.io.FileInputStream
import java.io.FileOutputStream

class InMemorySubtitleProvider : ContentProvider() {
    companion object {
        const val AUTHORITY = "com.yourpackage.inmemorysubtitleprovider"
        // 生成对应字幕的Uri
        fun getUriForSubtitle(subtitleContent: String): Uri {
            val subtitleId = subtitleContent.hashCode().toString()
            return Uri.parse("content://$AUTHORITY/subtitles/$subtitleId")
        }
        // 内存缓存字幕内容
        private val subtitleCache = hashMapOf<String, String>()
        fun addSubtitle(subtitleId: String, content: String) {
            subtitleCache[subtitleId] = content
        }
    }

    override fun onCreate(): Boolean = true

    override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
        val subtitleId = uri.lastPathSegment ?: return null
        val content = subtitleCache[subtitleId] ?: return null
        // 创建管道供ExoPlayer读取内存内容
        val pipe = ParcelFileDescriptor.createPipe()
        FileOutputStream(pipe.fileDescriptor).use {
            it.write(content.toByteArray())
        }
        return ParcelFileDescriptor(pipe.fileDescriptor, ParcelFileDescriptor.MODE_READ_ONLY)
    }

    override fun getType(uri: Uri): String? = MimeTypes.TEXT_SRT
    // 以下方法返回默认值即可
    override fun query(uri: Uri, projection: Array<String>?, selection: String?, selectionArgs: Array<String>?, sortOrder: String?): Cursor? = null
    override fun insert(uri: Uri, values: ContentValues?): Uri? = null
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int = 0
    override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int = 0
}
  1. 在AndroidManifest.xml中注册Provider:
<provider
    android:name=".InMemorySubtitleProvider"
    android:authorities="com.yourpackage.inmemorysubtitleprovider"
    android:exported="false" />
  1. 使用示例:
val subtitleId = SRT_STRING.hashCode().toString()
InMemorySubtitleProvider.addSubtitle(subtitleId, SRT_STRING)
val subtitleUri = InMemorySubtitleProvider.getUriForSubtitle(SRT_STRING)

val subtitleConfig = SubtitleConfiguration.Builder(subtitleUri)
    .setMimeType(MimeTypes.TEXT_SRT)
    .build()

方案3:直接使用SubtitleSource(绕开Uri参数)

若无需严格依赖subtitleUri参数,可直接构造SubtitleSource实现字幕加载:

import com.google.android.exoplayer2.source.SubtitleSource
import com.google.android.exoplayer2.text.SubtitleDecoderFactory
import com.google.android.exoplayer2.text.srt.SrtDecoder
import com.google.android.exoplayer2.upstream.ByteArrayDataSource
import com.google.android.exoplayer2.util.MimeTypes

// 直接用字节数组构造数据源
val dataSource = ByteArrayDataSource(SRT_STRING.toByteArray())
// 构建SRT字幕源
val subtitleSource = object : SubtitleSource(null) {
    override fun prepareSourceInternal() {}

    override fun getDecoderFactory(): SubtitleDecoderFactory {
        return SubtitleDecoderFactory { _, mimeType ->
            if (MimeTypes.TEXT_SRT == mimeType) SrtDecoder() else null
        }
    }

    override fun getDataSource() = dataSource

    override fun releaseSourceInternal() {
        dataSource.close()
    }
}

// 将subtitleSource添加到ExoPlayer的轨道配置中即可

内容的提问来源于stack exchange,提问作者Roony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 05:00:30