如何在 Exoplayer 上显示 HLS 嵌入字幕

2024-02-24

如何使用 Exoplayer、ExoMedia 或其他播放器启用并选择 HLS 格式的 Vimeo 视频中嵌入的不同字幕? 在 iOS 中,同一个视频已经提供了原生字幕选项,但在 Android 中我找不到实现它的方法。


我在这里的答案看起来很像this one https://stackoverflow.com/questions/45835562/quality-selector-for-exoplayer-2/45844705#45844705,所以你可能想先检查一下那个。

ExoPlayer 是您想要的 Android 库。显示字幕是一项艰巨的任务,但是demo app https://github.com/google/ExoPlayer因为该库拥有处理 HLS 视频所需的所有代码。更具体地说PlayerActivity https://github.com/google/ExoPlayer/blob/release-v2/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java班级。您可以在演示应用程序中转到 HLS ->“Apple 16x9 基本流”,该视频有大量字幕(又名“文本轨道”)。

只是为了简化他们的代码,以便它不依赖于助手(这样你就可以看到它是如何工作的just关于隐藏式字幕)我在下面编写/记录了他们的一些代码。

private static class ClosedCaptionManager {

    ClosedCaptionManager(MappingTrackSelector mappingTrackSelector, SimpleExoPlayer player) {
        this.player = player;
        this.trackSelector = mappingTrackSelector;
    }

    SimpleExoPlayer player;
    MappingTrackSelector trackSelector;

    // These two could be fields OR passed around
    int textTrackIndex;
    TrackGroupArray trackGroups;

    ArrayList<Pair<Integer, Integer>> pairTrackList = new ArrayList<>();

    private boolean checkAndSetClosedCaptions() {
        // This is the body of the logic  for see if there are even video tracks
        // It also does some field setting
        MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
        if (mappedTrackInfo == null) {
            return false;
        }
        for (int i = 0; i < mappedTrackInfo.length; i++) {
            trackGroups = mappedTrackInfo.getTrackGroups(i);
            if (trackGroups.length != 0) {
                switch (player.getRendererType(i)) {
                    case C.TRACK_TYPE_TEXT:
                        textTrackIndex = i;
                        return true;
                }
            }
        }
        return false;
    }

    private void buildTrackList() {
        // This next part is actually about getting the list.
        // Below you'd be building up items in a list. This just does
        // views directly, but you could just have a list of track names (with indexes)
        for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
            TrackGroup group = trackGroups.get(groupIndex);
            for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
                if (trackIndex == 0) {
                    // Beginning of a new set, the demo app adds a divider
                }
                //CheckedTextView trackView = ...; // The TextView to show in the list
                // The below points to a util which extracts the quality from the TrackGroup
                //trackView.setText(DemoUtil.buildTrackName(group.getFormat(trackIndex)));
                Log.e("Thing", DemoUtil.buildTrackName(group.getFormat(trackIndex)));
                pairTrackList.add(new Pair<>(groupIndex, trackIndex));
            }
        }
    }

    private void onTrackViewClick(Pair<Integer, Integer> trackPair) {
        // Assuming you tagged the view with the groupIndex and trackIndex, you
        // can build your override with that info.
        Pair<Integer, Integer> tag = trackPair;
        int groupIndex = tag.first;
        int trackIndex = tag.second;
        // This is the override you'd use for something that isn't adaptive.
        // `override = new SelectionOverride(FIXED_FACTORY, groupIndex, trackIndex);`
        // Otherwise they call their helper for adaptives (HLS/DASH), which roughly does:
        int[] tracks = getTracksAdding(new MappingTrackSelector.SelectionOverride(
                        new FixedTrackSelection.Factory(), groupIndex, trackIndex),
                trackIndex
        );
        TrackSelection.Factory factory = tracks.length == 1
                ? new FixedTrackSelection.Factory()
                : new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);

        MappingTrackSelector.SelectionOverride override =
                new MappingTrackSelector.SelectionOverride(factory, groupIndex, tracks);

        // Then we actually set our override on the selector to switch the text track
        trackSelector.setSelectionOverride(textTrackIndex, trackGroups, override);
    }

    private static int[] getTracksAdding(MappingTrackSelector.SelectionOverride override, int addedTrack) {
        int[] tracks = override.tracks;
        tracks = Arrays.copyOf(tracks, tracks.length + 1);
        tracks[tracks.length - 1] = addedTrack;
        return tracks;
    }
}

然后,如果您将以下代码发布到其末尾initializePlayer()方法,您将了解这些部分如何组合在一起。

    final ClosedCaptionManager closedCaptionManager = new ClosedCaptionManager(trackSelector, player);

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            boolean hasTracks = closedCaptionManager.checkAndSetClosedCaptions();
            if (hasTracks) {
                closedCaptionManager.buildTrackList();
                closedCaptionManager.onTrackViewClick(closedCaptionManager.pairTrackList.get(4));
            }
        }
    }, 2000);

上面的代码非常草率,但它至少应该能让您朝着正确的方向开始。我不建议使用所写的任何内容 - 它主要应该是为了了解不同的部分如何组合在一起。他们在演示应用程序中的内容要好一些,因为他们的代码对于不同的轨道选择类型非常可重用(因为您可以拥有视频、音频和文本轨道)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Exoplayer 上显示 HLS 嵌入字幕 的相关文章

随机推荐

  • 从 php 运行蹩脚

    我正在尝试从 php 脚本运行蹩脚 我已经尝试过这些 但没有运气 我没有得到任何回报 有任何想法吗 system lame returnarr system lame help returnarr exec lame returnarr p
  • 如何使用索引访问ListView中的委托属性

    我想访问委托属性ListView 我尝试过contentItem但有时是undefined 这是我的代码 ListModel id modeldata ListElement name don rank 1 ListElement name
  • 如何从领域数据库中查询具有不同结果的java

    我有一个Realm对象类 并在其中存储大量数据 想象我有一个String uid 场地 我想获取 uid 名称 但相同的 uid 名称只能获取一次 例如 uid AA AA BB CC DD BB BB 我想得到只是 AA BB CC DD
  • 具有两个或多个参数的 ITransformableFilterValues 接口 [SharePoint WebParts]

    我使用 Sharepoint 并尝试使用多个参数连接 Web 部件 我的问题是如何将多个参数从自定义 Web 部件传递到另一个参数 我可以通过在自定义 webpart 中实现 ITransformableFilterValues 接口来传递
  • eclipse 在无限循环中开始“构建工作区”

    是否可以在 Eclipse 中调试哪个进程触发了 构建工作区 我有一个带有一些 BIRT 报告的 Java 项目 当该项目打开时 Eclipse 将无限循环地重新启动 构建工作区 我正在使用 Eclipse 3 6 1 和 BIRT 2 6
  • 理解“随机性”

    我无法理解这个问题 哪个更随机 rand OR rand rand 我发现这是一个真正的脑筋急转弯 你能帮我吗 EDIT 直觉上我知道数学答案是它们同样随机 但我忍不住认为 如果你在将两者相乘时 运行随机数算法 两次 你会创建比仅仅做更随机
  • 为什么 String.match( / \d*/ ) 返回空字符串?

    有人可以帮助我理解为什么使用 d 返回包含空字符串的数组 而使用 d 返回 100 如预期 我明白为什么 d 有效 但不明白为什么 d 不起作用 使用 是否会导致它返回零长度匹配 这到底是如何工作的 var str one to 100 v
  • 实体框架:跳过/接受功能

    我只是好奇 Skip 和 Take 函数如何在 Entity Framework 中工作 使用 EF 6 1 If I do db Events OrderByDescending x gt x Date Take maxPageSize
  • Zend Framework 不允许我包含 Google Maps API

    我遇到这个问题 我想使用引导程序中的 HeadScript Helper 将 Google Maps API 添加到我的 Zend Framework 应用程序中 view gt headScript gt appendFile stati
  • 使用 Masm 的浮点数据示例

    有人能给我一个如何在 MASM 数据部分定义浮点数或常量的例子吗 或者至少有一些关于它的信息 我认为已经完成了 data myVar REAL4 1 0f code Masm 中的浮点值为 REAL4 REAL8 或 REAL10 表达式
  • 全局 PHP CONSTANT 在类文件中可用吗?

    全局 PHP CONSTANT 在类文件中可用吗 define SITE PATH C webserver htdocs somefolder 然后在我的班级文件中我尝试这个 public debug file SITE PATH debu
  • Aurelia 委托与触发器:您如何知道何时使用委托或触发器?

    我正在尝试学习如何使用 Aurelia 框架 这样做时 我正在阅读文档here https github com aurelia documentation blob master old English docs md event mod
  • GNU GCC 编译器更新

    我正在使用 gnu gcc 编译器的代码块 但是当我尝试编译开始的范围基础时 它给出了许多错误 所以我认为编译器不支持C 0x 所以我想知道如何知道我正在使用的编译器版本以及如何将其正确更新到 C 0x 支持版本 我使用的是Windows
  • 编译 opencv 框架时出现未知错误:未定义符号:“_CGImageDestinationCreateWithURL”

    Xcode 给了我以下错误 我真的不知道该怎么做 这让我发疯 我正在导入 OpenCV 框架 因此问题可能存在或与编译器相关 谁能告诉我该怎么做或寻找什么 Undefined symbols CGImageDestinationCreate
  • Access 2010 的 INSERT INTO 语句中的语法错误

    我的 INSERT 语句显然有语法错误 有人可以解释一下为什么会这样吗 Private Sub Register Click 1 ByVal sender As System Object ByVal e As System EventAr
  • [空手道][独立]错误:无法找到或读取文件

    我只使用最新的独立空手道 jar 在配置了 JRE 的 docker 容器上测试我的 API 并且没有任何 Java 代码 目前 在我的一项功能中 我有这个 read file json 当资源文件与功能文件位于同一目录时 它可以正常工作
  • C# winforms numericupdown 控件

    我正在使用 numericupdown 控件 当以编程方式分配值或用户更改值时 将触发 ValueChanged 事件 我希望仅当用户更改值时触发事件 而不是在我设置最小值和最大值时触发 如何做呢 基于 TheVillageIdiot 的答
  • spring-boot 从 1.3.2 升级到 1.3.3:logback 问题

    从 spring boot 1 3 2 升级到最近发布的 1 3 3 时 我们遇到了一个问题 我们的应用程序一直在使用以下依赖项 每个都是最新的 没有问题
  • Android 同步日历功能与自己的日历

    我已经展示了如何为我们自己的帐户设置自己的sync calendar功能以及我们如何将我们自己的事件同步到 的技术 在清单中授予读取和写入日历的权限
  • 如何在 Exoplayer 上显示 HLS 嵌入字幕

    如何使用 Exoplayer ExoMedia 或其他播放器启用并选择 HLS 格式的 Vimeo 视频中嵌入的不同字幕 在 iOS 中 同一个视频已经提供了原生字幕选项 但在 Android 中我找不到实现它的方法 我在这里的答案看起来很