如何在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提供内存内容,无长度限制:
- 实现自定义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 }
- 在
AndroidManifest.xml中注册Provider:
<provider android:name=".InMemorySubtitleProvider" android:authorities="com.yourpackage.inmemorysubtitleprovider" android:exported="false" />
- 使用示例:
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
相关产品推荐
相关产品推荐

