如何使用 JWPlayer v8 在外部容器中显示字幕

How to show Captions in an external container using JWPlayer v8

我们的视频使用页面的下三分之一部分进行介绍等,就像电视新闻台所做的那样。当字幕打开时,他们会阻止所有这些,从而引起需要字幕的社区的大量投诉。我试过修改 CSS,但使用响应式布局时,调整播放器的大小会造成严重破坏,通常会使它们完全消失。

是否有可以更改的设置或可使用的技术,使字幕在调整大小时或在外部容器中保持在顶部和视图中?

最终解决方案: 外部字幕为draggable/resizable

所有功劳都归功于@Basildane,我研究了如何使用 VOD 扩展字幕,并使它们可拖动和调整大小,并进行了 CSS 考虑 ADA 的实验:

<!DOCTYPE html>
<html>
    <head>
        <title>JW External Captions</title>
        <meta http-equiv="Expires" content="Fri, Jan 01 1900 00:00:00 GMT">
        <meta http-equiv="Pragma" content="no-cache">
        <meta http-equiv="Cache-Control" content="no-cache">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta http-equiv="Lang" content="en">
        <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
        <script src="/jwplayer/v8.10/jwplayer.js"></script>
        <style type="text/css">
            #myPlayer {
                margin-bottom:5px;
            }
            .jw-captions {
                display: none !important;
            }
            #ccbuffer {
                color: white;
                background-color: black;
                opacity:.7;
                font: 22px bold san-serif;
                width: 100%;
                padding: 15px;
                height: 100%;
                position:relative;
            }
            .night {
                color:silver !important;
                background-color: black !important;
                opacity:1 !important;
                border-color:silver !important;
            }
            .highcontrast {
                color:white !   important;
                background-color: black !important;
                opacity:1 !important;
                border-color:white !important;
            }
            .highcontrast2 {
                color:black !important;
                background-color: yellow !important;
                opacity:1 !important;
                border-color:black !important;
            }
            .highcontrast3 {
                color:yellow !important;
                background-color: black !important;
                opacity:1 !important;
                border-color:yellow !important;
            }
            #ccContainer {
                position: absolute;
                z-index: 9;
                border: 1px solid inherit;
                overflow: hidden;
                resize: both;
                width: 640px;
                height: 180px;
                min-width: 120px;
                min-height: 90px;
                max-width: 960px;
                max-height: 300px;
            }
            #ccContainerheader {
                padding: 3px;
                cursor: move;
                z-index: 10;
                background-color: #2196F3;
                color: #fff;
                border:1px solid;
            }
        </style>
    </head>
    <body>
        <h3>JW Draggable Captions Container</h3>
        <div id="PlayerContainer" style="width:401px;">
            <div id="myPlayer">Loading video...</div>
        </div>
        <div id="ccContainer">
            <!-- Include a header DIV with the same name as the draggable DIV, followed by "header" -->
            <div style="float:right;">
                <form id="myform">
                    <select id="ccFontFamily">
                        <option value="sans-serif">Default Font</option>
                        <option value="serif">Serif</option>
                        <option value="monospace">Monospace</option>
                        <option value="cursive">Cursive </option>
                    </select>
                    <select id="ccFontSize" style="">
                        <option value="22">Default Size</option>
                        <option value="14">14</option>
                        <option value="18">18</option>
                        <option value="24">24</option>
                        <option value="32">32</option>
                    </select>
                    <select id="ccContrast" style="">
                        <option value="ccdefault">Default Contrast</option>
                        <option value="night">Night</option>
                        <option value="highcontrast">High Contrast</option>
                        <option value="highcontrast2">Black/Yellow</option>
                        <option value="highcontrast3">Yellow/Black</option>
                    </select>
                    <button id="ccFontReset">Reset</button>
                </form>
            </div>
            <div id="ccContainerheader">
                Captions (click to move)
            </div>
            <div id="ccbuffer"></div>
        </div>
        <script type="text/javascript">
            $(document).ready(function() {
                jwplayer.key = 'xxxxxxxxxxxxxxxxxxx';
                jwplayer('myPlayer').setup({
                    width: '100%', aspectratio: '16:9', repeat: 'false', autostart: 'false',
                    playlist: [{
                        sources: [ { file: 'https:www.example.com/video.mp4'}],
                        tracks: [ { file: 'https:www.example.com/video-captions.vtt', kind: 'captions', label: 'English', 'default': true } ]
                    }]
                })
                // External CC Container
                $('#ccContainer').hide();
                var position = $('#myPlayer').position();
                var width = $('#PlayerContainer').outerWidth();
                ccTop = position.top;
                ccLeft = (width+50)+'px'
                $('#ccContainer').css({'top':ccTop, left:ccLeft });
                var observer;
                jwplayer().on('captionsList', function (event) {
                    ccObserver(event);
                });
                jwplayer().on('captionsChanged', function (event) {
                    ccObserver(event);
                });
                videoplayer.on('fullscreen', function(event){
                    if(event.fullscreen){
                        $('.jw-captions').css('display','block');
                    }else{
             $('.jw-captions').css('display','none');
                    }
                });

                $("#ccFontFamily").change(function() {
                    $('#ccbuffer').css("font-family", $(this).val());
                });
                $("#ccFontSize").change(function() {
                    $('#ccbuffer').css("font-size", $(this).val() + "px");
                });
                $("#ccContrast").change(function() {
                    $('#ccContainer').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
                    $('#ccContainerheader').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
                    $('#ccbuffer').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
                    $('select').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
                    $('#ccFontReset').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
                });
                $('#ccFontReset').click(function() {
                    ccFontReset();
                });
                function ccFontReset(){
                    $("#ccFontFamily").val($("#ccFontFamily option:first").val()).trigger('change');
                    $("#ccFontSize").val($("#ccFontSize option:first").val()).trigger('change');
                    $("#ccContrast").val($("#ccContrast option:first").val()).trigger('change');
                }
                ccFontReset();
            });
            function ccObserver(event){
                if (event.track == 0) {
                    $('#ccContainer').hide('slow');
         $('.jw-captions').css('display','block'); // VERY important
                    if (observer != null){
                        observer.disconnect();
                    }
                }
                else {
                    $('#ccContainer').show('slow');
         $('.jw-captions').css('display','none');  // VERY important
                    var target = document.querySelector('.jw-captions');
                    observer = new MutationObserver(function(mutations) {
                        $('.jw-text-track-cue').each(function(i) {
                            if (i == 0)
                                $('#ccbuffer').html( $(this).text() );
                            else
                                $('#ccbuffer').append("<br/>" + $(this).text() );
                        });
                    });
                    var config = { attributes: true, childList: true, characterData: true }
                    observer.observe(target, config);
                }
            }
            // External CC Container - Make the DIV element draggable:
            dragElement(document.getElementById("ccContainer"));
            function dragElement(elmnt) {
                var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
                if (document.getElementById(elmnt.id + "header")) {
                    document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
                } else {
                    elmnt.onmousedown = dragMouseDown;
                }
                function dragMouseDown(e) {
                    e = e || window.event;
                    e.preventDefault();
                    pos3 = e.clientX;
                    pos4 = e.clientY;
                    document.onmouseup = closeDragElement;
                    document.onmousemove = elementDrag;
                }
                function elementDrag(e) {
                    e = e || window.event;
                    e.preventDefault();
                    pos1 = pos3 - e.clientX;
                    pos2 = pos4 - e.clientY;
                    pos3 = e.clientX;
                    pos4 = e.clientY;
                    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
                    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
                }
                function closeDragElement() {
                    document.onmouseup = null;
                    document.onmousemove = null;
                }
            }
        </script>
    </body>
</html>

问题:JW 播放器 608 实时字幕格式不干净。 要解决这个问题,请禁用 JW 字幕显示并格式化我们自己的 window,命名为 "ccbuffer"

<style type="text/css">
    .jw-captions {
           display: none !important;
    }
    #ccbuffer {
        border: 2px solid white !important;
        border-radius: 4px;
        background-color: black !important;
        display: flex;
        height: 120px;
        margin-top: 6px;
        font: 22px bold arial, sans-serif;
        color: white;
        justify-content: center;
        align-items: center;
    }
</style>

这里是我展示播放器的地方,ccbuffer 是 div 就在它下面

    <div id="myPlayer">
        <p style="color: #FFFFFF; font-weight: bold; font-size: x-large; border-style: solid; border-color: #E2AA4F">
            Loading video...
        </p>
    </div>
    <div id="ccbuffer" /> 

DOMSubtreeModified 已弃用。使用 MutationObserver,它对客户端的压力较小。 让我们从 JW 挂钩 'captionsChanged' 事件。如果 track 为 0,则不会选择任何字幕,并且我们会断开观察者。如果选择了字幕,那么我们使用 jquery 将文本从 jw-text-track-cue 元素中拉出,并将其格式化为漂亮的 3 行显示在我们的 ccbuffer window.

<script>
    var observer;

    jwplayer().on('captionsChanged', function (event) {
        if (event.track == 0) {
            observer.disconnect();
            $('#ccbuffer').hide('slow');
        }
        else {
            $('#ccbuffer').show('slow');

            // select the target node
            var target = document.querySelector('.jw-captions');

            // create an observer instance
            observer = new MutationObserver(function(mutations) {
                $('.jw-text-track-cue').each(function(i) {
                    if (i == 0)
                        $('#ccbuffer').html( $(this).text() );
                    else
                        $('#ccbuffer').append("<br/>" + $(this).text() );
                });
            });

            // configuration of the observer:
            var config = { attributes: true, childList: true, characterData: true }

            // pass in the target node, as well as the observer options
            observer.observe(target, config);
        }
    });

    $(document).ready(function () {
        $('#ccbuffer').hide();
    });

</script>

因此,当用户启用字幕时,ccbuffer window 将滑动打开并显示清晰的 3 行 CC 文本表示。