使用 Captionator 从 HTML5 <video> 的 <track> 读取元数据

Posted

技术标签:

【中文标题】使用 Captionator 从 HTML5 <video> 的 <track> 读取元数据【英文标题】:Reading metadata from the <track> of an HTML5 <video> using Captionator 【发布时间】:2012-03-11 07:58:54 【问题描述】:

我无法获得一个从 WebVTT 文件中读取元数据的工作示例,该文件由 html5 页面中 &lt;video&gt;&lt;track&gt; 元素指定。需要明确的是,我不是在谈论从视频文件本身中读取元数据(例如,您会使用 MPEG 传输流)。我所说的是用于为视频添加字幕的&lt;track&gt; 元素。 &lt;track&gt; 的属性之一是kind,可以指定为以下任意值:

字幕 说明 字幕 导航 章节 元数据

我正在尝试使用 元数据 类型来访问存储在相应 WebVTT 文件中的文本,我打算使用 javascript 对其进行操作。我知道这是可能的,因为它是 mentioned by Silvia Pfeiffer 和 by the maker of Captionator,这是我用来实现解释 &lt;track&gt; 标签功能的 JavaScript 填充程序。但是,我就是无法让它工作。

我的代码基于Captionator 文档的标题示例。我添加了一个按钮来检索元数据并在单击该按钮时显示它。不幸的是,它一直显示“未定义”而不是元数据。有什么想法我可能做错了吗?或者,有谁知道我可以查看的工作示例在哪里?我在任何地方都找不到。

如果您想看看我的代码,我已将其包含在下面:

<!DOCTYPE html>
<html>
    <head>
        <title>HTML5 Video Closed Captioning Example</title>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" media="screen" href="js/Captionator-v0.5-12/css/captions.css"/>
    </head>
    <body>
        <h1>HTML5 Video Closed Captioning Example</h1>
        <div>
            <p id="metadataText">Metadata text should appear here</p>
            <input type='button' onclick='changeText()' value='Click here to display the metadata text'/>
        </div>

        <video controls autobuffer id="videoTest"  >
            <source src="http://localhost:8080/Videos/testVideo.webm" type="video/webm" />
            <source src="http://localhost:8080/Videos/testVideo.mp4" type="video/mp4" />

            <!-- WebVTT Track Metadata Example -->
            <track label="Metadata Track" kind="metadata" src="http://localhost:8080/Videos/Timed_Text_Tracks/testVideo_metadata.vtt" type="text/webvtt" srclang="en" />
        </video>

        <!-- Include Captionator -->
        <script type="text/javascript" src="js/Captionator-v0.5-12/js/captionator.js"></script>

        <!-- Example Usage -->
        <script type="text/javascript" src="js/Captionator-v0.5-12/js/captionator-example-api.js"></script>
        <script type="text/javascript">
            window.addEventListener("load",function() 
                captionator.captionify(null,null,
                    debugMode: !!window.location.search.match(/debug/i),
                    sizeCuesByTextBoundingBox: !!window.location.search.match(/boundingBox/i),
                    enableHighResolution: !!window.location.search.match(/highres/i),
                );

                var videoObject = document.getElementsByTagName("video")[0];
                videoObject.volume = 0;
                document.body.appendChild(generateMediaControls(videoObject));  
            ,false);

            function changeText() 
                document.getElementById('metadataText').innerHTML = testVar;
                var cueText = document.getElementById("video").tracks[0].activeCues[0].getCueAsSource();
                document.getElementById('metadataText').innerHTML = cueText;
            
        </script>
    </body>
</html>

我的 WebVTT 文件如下所示:

WEBVTT

0
00:00.000 --> 00:04.000
Testing 1 2 3 . . .

【问题讨论】:

嘿 - 我是 Captionator 的开发人员,乍一看您所做的似乎是正确的。我正在调查您是否发现了错误 - 我将根据我的发现发布答案。 :) 【参考方案1】:

您访问提示的方式是正确的 - 没有问题(尽管 Captionator 0.6 中的 .tracks 属性将更改为 .textTracks 属性以更符合规范。如果您可以承受偶尔出现的错误,我建议使用 0.6 以实现更高的标准合规性 - 我编写了以下代码以使用 .textTracks - 如果您想继续使用稳定分支,请替换 .tracks。)

问题与文本轨道本身的加载有关。目前,您实际上并没有告诉 Captionator 加载曲目。因为这是异步发生的,并且在请求时,在其内容不可用时不可避免地会出现延迟,因此您需要以适应加载时间和潜在加载错误的方式编写代码。

您也不必等待 Captionator 本身加载 - 用户可能会在此之前不知情地点击按钮 - 触发令人讨厌的 JavaScript 错误。在您的本地机器上进行测试时,这不会是一个问题,但是一旦您部署到互联网,您就会看到各种竞争条件和其他讨厌的东西。考虑禁用该按钮,直到页面和标题数据都加载完毕。


我已尝试使 Captionator API 尽可能接近实际的 JS API,后者很快就会登陆浏览器 - 所以将来这将与您与本机浏览器功能交互的方式相同。只要该功能在本机可用,Captionator 就会退出,您的代码应该(假设他们不再更改 API!)只需使用本机 API。

首先,您需要实际请求 Captionator 加载内容。这是我将曲目的“显示模式”设置为SHOWING2

var video = document.getElementByID("myVideo");
video.textTracks[0].mode = 2; // SHOWING

或者,您可以将轨道的状态分配给HIDDEN (1) - 这仍会触发加载,并且 cueChange 事件仍将触发 - 但不会将提示绘制到屏幕上。在 Captionator 中,我根本不会将元数据轨道绘制到屏幕上,但开发中的(有缺陷的)WebKit API 会。

video.textTracks[0].mode = 1; // HIDDEN

然后你需要监听 cue 何时加载并可用:

video.textTracks[0].onload = function()  /* Your Code Here... */ 

或者当出现问题时:

video.textTracks[0].onerror = function()  /* Whoah, something went wrong... */ 

加载内容后,您可以访问TextTrack.cues 数组(嗯,技术上是TextTrackCueList。)在加载发生之前,TextTrack.cues 属性将为null

var myCueText = video.textTracks[0].cues[0].text;

请注意,Captionator 会解析每个提示的提示文本除非轨道类型为 metadata - 因此请确保分配正确的轨道类型。您最终可能会丢弃 Captionator 认为“无效”的数据或标签。您也可以通过将processCueHTML 选项设置为false 来关闭此检查以获取常规提示。


考虑到这一点,下面是我重写代码的方式:

<div>
    <p id="metadataText">Metadata text should appear here</p>
    <input type='button' onclick='changeText()' value='Click here to display the metadata text' id="changetext" disabled />
</div>

<video controls autobuffer id="videoTest"  >
    <!-- Your video sources etc... -->

    <!-- The metadata track -->
    <track label="Metadata Track" kind="metadata" src="metadata.vtt" type="text/webvtt" srclang="en" />
</video>

<!-- Include Captionator -->
<script type="text/javascript" src="captionator.js"></script>
<script type="text/javascript">
    document.addEventListener("readystatechange",function(event) 
        if (document.readyState === "complete") 
            captionator.captionify();

            document.querySelectorAll("#changetext")[0].removeAttribute("disabled");
        
    ,false);

    function changeText() 
        // Get the metadataText paragraph
        var textOutput = document.querySelectorAll("#metadataText")[0];

        // Get the metadata text track
        var metadataTrack = document.querySelectorAll("video")[0].textTracks[0];

        if (metadataTrack.readyState === captionator.TextTrack.LOADED) 
            // The cue is already ready to be displayed!
            textOutput.innerHTML = metadataTrack.cues[0].text;

         else 
            // We check to see whether we haven't already assigned the mode.
            if (metadataTrack.mode !== captionator.TextTrack.SHOWING) 
                textOutput.innerHTML = "Caption loading...";

                // The file isn't loaded yet. Load it in!
                metadataTrack.mode = captionator.TextTrack.SHOWING; // You can use captionator.TextTrack.HIDDEN too.

                metadataTrack.onload = function() 
                    textOutput.innerHTML = metadataTrack.cues[0].text;
                

                metadataTrack.onerror = function() 
                    textOutput.innerHTML = "Error loading caption!";
                
            
        
    

</script>

在这里,我们禁用了该按钮,以防止连接速度较慢的用户(或者只是反应速度非常快的人!)在 Captionator 或元数据轨道准备好之前点击它,并监听加载事件 - 此时我们重新启用按钮,并且可以正常检索提示文本。

【讨论】:

非常感谢克里斯托弗的详细回复。这是一个很大的帮助!【参考方案2】:

您可能需要通过 Ajax 加载元数据 VTT 文件并自行解析和显示。

我从HTML5 Doctors' article on video subtitling 中查看了example。他们使用的是Playr,所以我查看了它的源代码,他们肯定是在异步请求 VTT 文件并在加载后解析内容。

我能够使用以下代码加载 VTT 文件的内容并将其转储到指定的元素中:

function changeText() 
    var track = document.getElementById("videoTest").querySelector("track");
    var req_track = new XMLHttpRequest();
    req_track.open('GET', track.getAttribute("src"));
    req_track.onreadystatechange = function()
        if(req_track.readyState == 4 && (req_track.status == 200 || req_track.status == 0))
            if(req_track.responseText != '')
              document.getElementById("metadataText").innerHTML = req_track.responseText;
            
        
    
    req_track.send(null);

我对 Captionator 不熟悉,但它似乎具有将 VTT 文件解析为某种数据结构的功能,即使它不一定支持 metadata 轨道类型。也许您可以将此代码与 Captionator 现有的 VTT 解析器结合使用?

【讨论】:

感谢您的帮助,您的代码对我有用。我觉得这有点违背了使用 WebVTT 和 polyfill 的目的,但我认为目前确实没有一个好的解决方案,因为似乎还没有人实现对 metadata &lt;track&gt; 的支持。 好像是这样。如果您想出一些好的东西,您可以随时将其贡献给 Captionator。 @Steph 我可以向您保证 Captionator 确实支持 metadata 轨道类型。 :)

以上是关于使用 Captionator 从 HTML5 <video> 的 <track> 读取元数据的主要内容,如果未能解决你的问题,请参考以下文章

前端基础入门第二阶段-HTML5基础+HTML语义化

前端基础入门第二阶段-HTML5基础+HTML语义化

如何使用html5

使用 html5 分块上传文件

使用 Jquery 停止音频标签 HTML5

使用 TTML 添加 HTML5 视频字幕