7

我正在编写一个基本的视频选框,其中一个关键要求是视频需要能够在保持播放器全屏显示的同时前进。

使用 Video.js (4.1.0) 我已经能够让一切正常工作,只是在切换到另一个视频时我无法更改字幕。

在第一次创建播放器 HTML 时插入“轨道”标签或在播放器初始化时向“选项”对象添加轨道是我可以让播放器显示“CC”按钮并显示标题的唯一方法。但是,我无法在全屏模式下重新初始化播放器,因此以这种方式更改曲目将不起作用。

我已经尝试过 addTextTrack 和 addTextTracks 并且两者都显示已添加曲目 - 使用类似 console.log(videoObject.textTracks()) 的东西 - 但播放器从未显示它们或“CC”按钮。

这是我的代码,非常感谢任何帮助:

;(function(window,undefined) {

    // VIDEOS OBJECT
    var videos = [
        {"volume":"70","title":"TEST 1","url":"test1.mp4","type":"mp4"},
        {"volume":"80","title":"TEST 2","url":"test2.mp4","type":"mp4"},
        {"volume":"90","title":"TEST 3","url":"test3.mp4","type":"mp4"}
    ];

    // CONSTANTS
    var VIDEO_BOX_ID = "jbunow_marquee_video_box", NAV_TEXT_ID = "jbunow_marquee_nav_text", NAV_ARROWS_ID = "jbunow_marquee_nav_arrows", VIDEO_OBJ_ID = "jbunow_marquee_video", NAV_PREV_ID = "jbunow_nav_prev", NAV_NEXT_ID = "jbunow_nav_next";

    // GLOBAL VARIABLS
    var videoObject;
    var currentTrack = 0;
    var videoObjectCreated = false;
    var controlBarHideTimeout;

    jQuery(document).ready(function(){
        // CREATE NAV ARROWS AND LISTENERS, THEN START MARQUEE
        var navArrowsHtml = "<div id='" + NAV_PREV_ID + "' title='Play Previous Video'></div>";
        navArrowsHtml += "<div id='" + NAV_NEXT_ID + "' title='Play Next Video'></div>";
        jQuery('#' + NAV_ARROWS_ID).html(navArrowsHtml);
        jQuery('#' + NAV_PREV_ID).on('click',function() { ChangeVideo(GetPrevVideo()); });
        jQuery('#' + NAV_NEXT_ID).on('click',function() { ChangeVideo(GetNextVideo()); });

        ChangeVideo(currentTrack);
    });

    var ChangeVideo = function(newIndex) {
        var videoBox = jQuery('#' + VIDEO_BOX_ID);
        if (!videoObjectCreated) {
            // LOAD PLAYER HTML
            videoBox.html(GetPlayerHtml());

            // INITIALIZE VIDEO-JS
            videojs(VIDEO_OBJ_ID, {}, function(){
                videoObject = this;

                // LISTENERS
                videoObject.on("ended", function() { ChangeVideo(GetNextVideo()); });
                videoObject.on("loadeddata", function () { videoObject.play(); });

                videoObjectCreated = true;
                PlayVideo(newIndex);
            });

        } else { PlayVideo(newIndex); }
    }

    var PlayVideo = function(newIndex) {

        // TRY ADDING MULTIPLE TRACKS
        videoObject.addTextTracks([{ kind: 'captions', label: 'English2', language: 'en', srclang: 'en', src: 'track2.vtt' }]);

        // TRY ADDING HTML
        //jQuery('#' + VIDEO_OBJ_ID + ' video').eq(0).append("<track kind='captions' src='track2.vtt' srclang='en' label='English' default />");

        // TRY ADDING SINGLE TRACK THEN SHOWING USING RETURNED ID
        //var newTrack = videoObject.addTextTrack('captions', 'English2', 'en', { kind: 'captions', label: 'English2', language: 'en', srclang: 'en', src: 'track2.vtt' });
        //videoObject.showTextTrack(newTrack.id_, newTrack.kind_);        

        videoObject.volume(parseFloat(videos[newIndex]["volume"]) / 100); // SET START VOLUME
        videoObject.src({ type: "video/" + videos[newIndex]["type"], src: videos[newIndex]["url"] }); // SET NEW SRC
        videoObject.load();

        videoObject.ready(function () {
            videoObject.play();

            clearTimeout(controlBarHideTimeout);
            controlBarHideTimeout = setTimeout(function() { videoObject.controlBar.fadeOut(); }, 2000);

            jQuery('#' + NAV_TEXT_ID).fadeOut(150, function() {
                currentTrack = newIndex;
                var navHtml = "";
                navHtml += "<h1>Now&nbsp;Playing</h1><h2>" + videos[newIndex]["title"] + "</h2>";
                if (videos.length > 1) { navHtml += "<h1>Up&nbsp;Next</h1><h2>" + videos[GetNextVideo()]["title"] + "</h2>"; }
                jQuery('#' + NAV_TEXT_ID).html(navHtml).fadeIn(250);
            });
        });
    }

    var GetPlayerHtml = function() {
        var playerHtml = "";        
        playerHtml += "<video id='" + VIDEO_OBJ_ID + "' class='video-js vjs-default-skin' controls='controls' preload='auto' width='560' height='315'>";
        playerHtml += "<source src='' type='video/mp4' />";
        //playerHtml += "<track kind='captions' src='track.vtt' srclang='en' label='English' default='default' />";
        playerHtml += "</video>";
        return playerHtml;
    }

    var GetNextVideo = function() {
        if (currentTrack >= videos.length - 1) { return 0; }
        else { return (currentTrack + 1); }
    }

    var GetPrevVideo = function() {
        if (currentTrack <= 0) { return videos.length - 1; }
        else { return (currentTrack - 1); }
    }

})(window);
4

2 回答 2

6

当前的 VideoJS 实现(4.4.2)在播放器本身的初始化时间加载各种文本轨道(字幕、标题、章节),因此它仅正确抓取那些在<video> 标记之间定义的内容。

编辑:我的意思是它在调用 addTextTrack 时会加载它们,但播放器 UI 在初始化时间后将永远不会更新,并且将始终显示初始化时间文本轨道。

一种可能的解决方法是,如果您在刷新<video>标签之间的内容后销毁完整的 videojs 播放器并在视频源更改时重新创建它。因此,您无需通过 videojs 播放器更新源,而是通过动态添加所需的 DOM 元素并在它们上初始化新播放器。可能此解决方案会导致一些 UI 闪烁,并且对于该问题非常不理想。这是一个关于销毁videojs播放器的链接

第二种选择是将动态文本轨道处理添加到现有代码中,如果知道在哪里查找,这并不像听起来那么难(我只为章节做了,但对于其他文本轨道也可能类似)。下面的代码适用于最新的官方版本 4.4.2。请注意,我使用 jQuery 来删除文本轨道元素,因此如果有人按原样应用这些更改,则需要在 videojs 之前加载 jQuery。

编辑 video.dev.js 文件如下:

1:给Player添加clearTextTracks函数

vjs.Player.prototype.clearTextTracks = function() {
    var tracks = this.textTracks_ = this.textTracks_ || [];
    for (var i = 0; i != tracks.length; ++i)
        $(tracks[i].el()).remove();
    tracks.splice(0, tracks.length);
    this.trigger("textTracksChanged");
};

2:在现有 addTextTrack 方法的末尾添加新的 'textTracksChanged' 事件触发器

vjs.Player.prototype.addTextTrack = function(kind, label, language, options) {
    ...
    this.trigger("textTracksChanged");
}

3:在TextTrackButton构造函数中处理新事件

vjs.TextTrackButton = vjs.MenuButton.extend({
  /** @constructor */
    init: function(player, options) {
        vjs.MenuButton.call(this, player, options);
        if (this.items.length <= 1) {
            this.hide();
        }
        player.on('textTracksChanged', vjs.bind(this, this.refresh));
    }
});

4:在TextTrackButton上实现刷新方法

// removes and recreates the texttrack menu
vjs.TextTrackButton.prototype.refresh = function () {
    this.removeChild(this.menu);
    this.menu = this.createMenu();
    this.addChild(this.menu);
    if (this.items && this.items.length <= this.kind_ == "chapters" ? 0 : 1) {
        this.hide();
    } else
        this.show();
};

对不起,但现在我无法链接到一个真正的工作示例,我希望上面的片段足以作为任何对此感兴趣的人的起点。

当您将源更新为新视频时,您可以使用此代码。只需调用 clearTextTracks 方法,并使用 addTextTrack 方法添加新的文本轨道,菜单现在应该会自行更新。

于 2014-03-13T20:42:00.323 回答
1

做完全相同的事情(或者说不做完全相同的事情)......确实需要弄清楚如何动态更改/添加字幕轨道。

这可以通过底层 HTML5 播放,但它不显示 videojs CC 按钮:

document.getElementById("HtmlFiveMediaPlayer_html5_api").innerHTML = '<track label="English Captions" srclang="en" kind="captions" src="http://localhost/media/captiontest/demo_Brian/demo_h264_1.vtt" type="text/vtt" default />';
于 2014-02-13T17:23:27.353 回答