【问题标题】:How to show HLS embedded captions on Exoplayer如何在 Exoplayer 上显示 HLS 嵌入式字幕
【发布时间】:2017-12-11 12:12:21
【问题描述】:

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

【问题讨论】:

    标签: android vimeo http-live-streaming caption exoplayer


    【解决方案1】:

    我在这里的答案看起来很像this one,所以你可能想先检查一下。

    ExoPlayer 是您想要的 Android 库。让字幕显示是一项不平凡的任务,但该库的demo app 拥有让他们处理 HLS 视频所需的所有代码。更具体地说,PlayerActivity 类。您可以在演示应用程序中转到 HLS ->“Apple 16x9 基本流”,该视频有大量字幕(又名“文本轨道”)。

    只是为了简化他们的代码,使其不依赖于帮助程序(这样您就可以在隐藏字幕上看到它的工作原理只是)我在下面编写/记录了他们的一些代码.

    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);
    

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

    【讨论】:

    • 似乎这段代码不再有效,没有方法。 setSelectionOverride
    【解决方案2】:

    这很好用!

    TrackGroupArray trackGroups = mappedTrackInfo.getTrackGroups(rendererIndex);   
    
    TrackSelectionArray currentTrackGroups = player.getCurrentTrackSelections();
    TrackSelection currentTrackSelection = currentTrackGroups.get(rendererIndex);
    
    
        for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
    
            TrackGroup group = trackGroups.get(groupIndex);
    
            for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
                Format trackFormat = group.getFormat(trackIndex);
    
    
                if(currentTrackSelection!=null && currentTrackSelection.getSelectedFormat()==trackFormat){
                    //THIS ONE IS SELECTED
                }
    
    
    
    
            }
        }
    

    rendererIndex0 用于视频,1 用于音频,2 用于字幕/文本

    【讨论】:

    • 如果有人想知道如何获取mappedInfoTrack MappedTrackInfo mappedInfoTrack = trackSelector.getCurrentMappedTrackInfo()
    • 我不明白这是如何显示字幕的,以及这是如何回答的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 2023-02-15
    • 1970-01-01
    • 2018-06-19
    • 2017-04-20
    • 2022-06-20
    相关资源
    最近更新 更多