以程式設計方式實作提示點

在本主題中,您將了解Brightcove Player的提示點。然後,您將看到如何以編程方式創建提示點並在分發提示點時進行處理。

概覽

可以為視頻設置提示點。在視頻播放期間,當擊中每個提示點時將調度一個事件。

播放以下視頻,以查看播放器在前滾,中滾(5秒,10秒,12秒)和後滾時間顯示提示點信息。

 

******** 提示點資訊 ********

 

****** 結束提示點資訊 ******

播放此視頻,您將看到播放器下方顯示的四個提示點信息。

 

 

關鍵概念

必須理解一些概念才能有效地使用Brightcove Player中的提示點。這些概念在文檔的此部分中說明。必須理解以下概念才能有效地使用Brightcove Player中的提示點。

Video Cloud目錄提示點

要理解的第一個概念與術語有關。在Brightcove Player中,根據HTML標準,提示點存儲為文本跟踪元素。這意味著,當使用視頻雲視頻時,任何“視頻雲樣式”提示點都將轉換為文本軌道。

這些“視頻雲樣式”提示點也可以稱為“目錄”提示點,因為它們是從視頻雲目錄中讀取的(請參閱玩家目錄文檔以獲取有關目錄的更多信息)。進行此轉換時,目錄提示點中的某些信息(如類型和提示點時間)將轉換為文本軌道。

目錄提示點結構

下一個要理解的概念是目錄提示點和HTML標准在結構上有顯著差異。區別在於HTML提示點可以具有持續時間。這意味著對於每個提示點,將調度兩個提示點更改事件:一個在提示點的開始,一個在提示點的結束。

在轉換過程中,每個目錄提示點都將轉換為具有相同開始和停止時間的提示點。這意味著,對於每個目錄提示點,將調度兩個提示點事件,並且必須在代碼中進行說明。

activecues數組

另一個一個在處理HTML提示點時要理解的重要概念點是activeCues數組。所有提示點都在數組中定義。還有另一個數組,activeCues,其中包含提示點,這些提示點處於“活動狀態”,這意味著播放時間介於提示點的開始時間和停止時間之間。

使用目錄提示點時,開始時間和停止時間相同,因此它們僅在定義的第二個時間有效。同樣,對於目錄提示點,由於兩個提示點不會重疊,因此極不可能同時激活兩個提示點。

提示點類型

在本文檔中,您將看到帶有type屬性分配了一個值。在Studio用戶界面中創建提示點時,將分配這些類型值。有兩種類型的提示點,但兩種提示點都只是向type屬性。僅當在處理提示點信息時在自定義JavaScript中使用該值時,該值才有用。類型在這裡詳細說明:

  • 廣告 -分配的字符串值ADtype屬性
  • -分配的字符串值CODEtype屬性

視頻雲提示點

在文檔的此部分中,您將學習設置目錄提示點並偵聽目錄提示點事件調度。

設置視頻雲提示點

可以使用Video Cloud Studio以及其他多種方式將Video Cloud提示點與視頻相關聯,詳細信息請參見本文檔:在媒體模塊中使用提示點

在視頻雲提示點上行動-視頻靜態綁定到播放器

在本部分中,您將學習將視頻靜態綁定到播放器時處理目錄提示點的情況,這意味著視頻已在Studio中或直接使用Player Management API加載到了播放器中。

為了避免在提示點加載之前嘗試處理提示點的競爭狀況,您需要使用loadedmetadata在處理提示點之前要調度的事件。讀取正確的文本軌道後,請使用oncuechange偵聽提示點事件以調度事件。

以下代碼顯示偵聽提示點並顯示提示點中的數據。請注意,在此示例中,視頻是靜態綁定到播放器的。

  • 第 11 行:建立段落元素做為插入動態建立 HTML 的位置。
  • 第 18,30 行:使用one()為該事件添加事件偵聽器的方法loadedmetadata事件僅一次。事件處理常式函數是以匿名方式定義的。
  • 第 19 行:使用該textTracks()方法擷取 TextTrack 陣列,然後將保留提示點的第零個元素指派給變數tt。請注意,在某些實現中可能提示點可能位於不同的數組元素中。如需詳細資訊,請參閱下方的「尋找正確軌道」一節。
  • 第 20,28 行:設定傳送事件時的oncuechange事件處理常式函數。
  • 第二十一行:檢查以確保獲得第一個(第零個數組元素)提示點分派。如果沒有這種情況,您將看到每個提示點都會被作用兩次。請注意,如果您使用的是具有重疊持續時間的提示點,則此條件必須不同。
  • 第 22-26 行:使用提示點的資訊動態建立 HTML,並將其注入 HTML 頁面。
  • 第 29 行:播放視訊。
<video-js id="myPlayerID"
  data-account="1507807800001"
  data-player="zN3V18ZPEu"
  data-embed="default"
  controls=""
  data-video-id="1507781667001"
  data-playlist-id=""
  data-application-id=""
  width="960" height="540"></video-js>

<p id="insertionPoint"></p>

<script src="https://players.brightcove.net/1507807800001/zN3V18ZPEu_default/index.min.js"></script>

<script>
  videojs.getPlayer('myPlayerID').ready(function() {
    var player = this;
    player.one("loadedmetadata", function () {
      var tt = player.textTracks()[0];
      tt.oncuechange = function () {
        if (tt.activeCues[0] !== undefined) {
          var dynamicHTML = "id: " + tt.activeCues[0].id + ", ";
          dynamicHTML += "text: " + tt.activeCues[0].text + ", ";
          dynamicHTML += "startTime: " + tt.activeCues[0].startTime + ",  ";
          dynamicHTML += "endTime: " + tt.activeCues[0].endTime;
          document.getElementById("insertionPoint").innerHTML += dynamicHTML + "<br/>";
        }
      }
      player.play();
    });
  });
</script>

對視頻雲提示點採取行動-在播放器中動態加載視頻

在本節中,您將學習使用以下命令將視頻動態加載到播放器中時處理目錄提示點的方法。catalog.getVideo()catalog.load()方法。

使用播放器目錄獲取和加載視頻時,處理提示點要比使用靜態綁定的視頻時要容易一些,因為您無需使用loadedmetadata事件。

  • 第 11 行:建立段落元素做為插入動態建立 HTML 的位置。
  • 第 17,31 行:使用catalog.getVideo()檢索視頻的方法。回調函數在此處匿名定義。
  • 第 19 行:使用catalog.load()將視頻加載到播放器的方法。
  • 第二十一行:使用該textTracks()方法擷取 TextTrack 陣列,然後將保留提示點的第零個元素指派給變數tt。請注意,在某些實現中可能提示點可能位於不同的數組元素中。如需詳細資訊,請參閱下方的「尋找正確軌道」一節。
  • 第 22-30 行:設定傳送事件時的oncuechange事件處理常式函數。
  • 第 23 行:檢查以確保定義了第一個(第零個數組元素)提示點。如果沒有這種條件,您將看到每個提示點都會被執行兩次,第二次在提示中沒有定義元素activecues數組(因為第二個提示更改是針對提示點結束的)。請注意,如果您使用的是具有重疊持續時間的提示點,則此條件必須不同。
  • 第 24-28 行:使用提示點的資訊動態建立 HTML,並將其注入 HTML 頁面。
  • 第32行:播放視訊。
<video-js id="myPlayerID"
  data-account="1507807800001"
  data-player="zN3V18ZPEu"
  data-embed="default"
  controls=""
  data-video-id=""
  data-playlist-id=""
  data-application-id=""
  width="960" height="540"></video-js>

<p id="insertionPoint"></p>

<script src="https://players.brightcove.net/1507807800001/zN3V18ZPEu_default/index.min.js"></script>
  <script>
  videojs.getPlayer('myPlayerID').ready(function() {
    var player = this;
    player.catalog.getVideo('1507781667001', function (error, video) {
      //deal with error
      player.catalog.load(video);
      player.one("loadedmetadata", function () {
        var tt = player.textTracks()[0];
        tt.oncuechange = function () {
          if (tt.activeCues[0] !== undefined) {
            var dynamicHTML = "id: " + tt.activeCues[0].id + ", ";
            dynamicHTML += "text: " + tt.activeCues[0].text + ", ";
            dynamicHTML += "startTime: " + tt.activeCues[0].startTime + ",  ";
            dynamicHTML += "endTime: " + tt.activeCues[0].endTime;
            document.getElementById("insertionPoint").innerHTML += dynamicHTML + "<br/>";
          }
        }
      });
      player.play();
    });
  });
</script>

檢索所有視頻雲提示點信息

您可能已經註意到,並非所有Video Cloud提示點信息都可以直接從activecues數組。這很容易解決,方法是從mediainfo屬性。

此解決方案的基本方法是:

  1. 等待loadstart的活動mediainfo要填充的屬性。
  2. 分配cue_points來自的數組mediainfo變量的屬性。此變量包含完整的Video Cloud提示點信息。
  3. 在提示點事件中,根據以下事件檢索相應的提示點數據:time適當的價值。這將使用幫助函數來完成,該函數根據對像中的屬性值從數組中獲取對象。
  4. 從提示點使用數據。

下圖顯示了整個提示點數組(左上),單個提示點數據集合(右上)以及該單個提示點數據集合的一個屬性(右下)。

提示點數據

在下面的代碼段中,將僅說明上述示例中的新代碼/更改過的代碼。

  • 452-463行:包括將用於從所有提示點的數組中提取單個提示點數據集合的函數。請注意,您將所有提示點的數組,要在其中搜索特定值的屬性以及最後要搜索的值傳遞給它。
  • 432行:偵聽事loadstart件。視頻開始加載後,mediainfo屬性已填充。
  • 434行:將所有Video Cloud提示點的數組分配給一個變量。
  • 第443行:在提示點調度事件處理程序中,將特定提示點的數據集合分配給變量。這是第一個項目符號中提到的函數的調用位置。使用的參數是:
    • cuePointAra:Video Cloud提示點的整個集合。
    • 'time':在其中搜索值的屬性。
    • tt.activeCues[0].startTime:提示點調度事件處理程序中當前正在處理的提示點的開始時間。
  • 444-445行:調試console.log()方法調用,應在生產代碼中將其刪除。
<script>
  videojs.getPlayer('myPlayerID').ready(function() {
    var myPlayer = this,
      cuePointAra = [],
      allCuePointData;
    myPlayer.on('loadstart', function () {
      //console.log('mediainfo', myPlayer.mediainfo);
      cuePointAra = myPlayer.mediainfo.cue_points;
      var tt = myPlayer.textTracks()[0];
      tt.oncuechange = function () {
        if (tt.activeCues[0] !== undefined) {
          var dynamicHTML = "id: " + tt.activeCues[0].id + ", ";
          dynamicHTML += "text: " + tt.activeCues[0].text + ", ";
          dynamicHTML += "startTime: " + tt.activeCues[0].startTime + ",  ";
          dynamicHTML += "endTime: " + tt.activeCues[0].endTime;
          document.getElementById("insertionPoint").innerHTML += dynamicHTML + "<br/>";
          allCuePointData = getSubArray(cuePointAra, 'time', tt.activeCues[0].startTime);
          console.log('cue point data:', allCuePointData);
          console.log('cue point metadata:', allCuePointData[0].metadata);
        }
      }
      myPlayer.play();
      myPlayer.muted(true);
    });

    function getSubArray(targetArray, objProperty, value) {
      var i, totalItems = targetArray.length,
        objFound = false,
        idxArr = [];
      for (i = 0; i < totalItems; i++) {
        if (targetArray[i][objProperty] === value) {
          objFound = true;
          idxArr.push(targetArray[i]);
        }
      }
      return idxArr;
    };
  });
</script>

HTML5標準提示點

HTML5標準提示點以指定格式存儲為跟踪元素。可以在以下HTML5 Rocks教程中找到良好的入門內容:Track元素入門。在本節中,您將學習WebVTT提示點文件的格式,然後學習如何處理這些提示點。

WebVTT提示點的文件格式

WebVTT文件格式是嚴格定義的。對於提示點,文件的組成如下:

  • 字符串WebVTT作為文件的第一行
  • 一個空白行
  • 特定提示點的標識符
  • 表格中的持續時間00:00:00.000-> 00:00:00.000 ;這是hours:minutes:seconds.milliseconds格式,並且經過嚴格分析;如有必要,數字必須補零
  • 持續時間之後的字符到下一個空白行將放置在文本值;如果您想在此處存儲多個不同的值,JSON可以很好地工作,因為它可以輕鬆地進行解析
  • 一個空白行
  • 可以使用標識符/持續時間/文本/空白行格式添加多個提示點

以下是有效的WebVTT提示點文檔,該文檔定義了兩個提示點,一個提示點的持續時間為2-5秒,另一個提示點的持續時間為10-15秒:

WEBVTT

Carry
00:00:03.000 --> 00:00:09.000
{
"id": "First cue point",
"title": "Carry the rim",
"description": "Getting ready to mount a tire on the rim."
}

Balance
00:00:10.000 --> 00:00:15.000
{
"id": "Second cue point",
"title": "Balance the tire and rim",
"description": "Spin the mounted tire to check the balance."
}

播放以下視頻時,您將看到上面顯示的提示點WebVTT文件。在提示點的開頭,您會看到動態創建的HTML注入頁面,然後是來自的解析的JSON。文本領域。提示點末尾的消息提示點持續時間超過被陳列。

******** 提示點資訊 ********

 

****** 結束提示點資訊 ******

流程提示點概述

使用HTML5標準提示點的基本步驟是:

  1. 使用讀取包含提示點的WebVTT文件<track>標籤嵌套為<video-js>標籤。
  2. 在一個loadedmetadata事件處理程序,檢索正確的文本跟踪元素。
  3. 在同一事件處理程序中,為oncuechange提示點事件。
  4. 在裡面oncuechange事件處理程序,請檢查activecues數組對象定義了第零個元素,如果是,則對提示點開始進行操作。
  5. 在裡面oncuechange事件處理程序,請檢查activecues數組對象定義了第零個元素,如果沒有,則在提示點停止位置上動作。

處理提示點代碼

 

  • 第 11 行:使用<track>標籤讀取 WebVTT 檔案來建立文字軌。
  • 第 15 行:創建一個<預></預>元素作為註入動態創建的 HTML 的位置。請注意,一個<pre></pre>使用元素代替段落元素,因此可以使用 JavaScript 5 反引號表示法。
  • 第 22,50 行:使用該one()方法只偵聽一次loadedmetadata事件。事件處理函數在這裡定義為箭頭函數。
  • 第 23 行:分配tt變量由 WebVTT 文件定義的文本軌道。數據結構如下所示:
    提示點數據結構
  • 第 31,49 行:設定傳送事件時的oncuechange事件處理常式函數。
  • 第 35,38 行:如果沒有激活的提示,這是提示點停止,所以顯示提示點持續時間結束。
  • 第 40-48 行:使用提示點的資訊動態建立 HTML,並將其注入 HTML 頁面。這包括解析 JSON 和顯示該 JSON 的各種字段。請注意,它使用的是 JavaScript 5 反引號表示法。
<video-js id="myPlayerID"
  data-account="1752604059001"
  data-player="default"
  data-embed="default"
  controls=""
  data-video-id="4607357817001"
  data-playlist-id=""
  data-application-id=""
  width="640" height="360">

  <track kind="metadata" label="external-metadata-vtt" src="https://solutions.brightcove.com/bcls/brightcove-player/cuepoints/cuepoints-2022.vtt" />

</video-js>

<pre id="insertionPoint"></pre>

<script src="https://players.brightcove.net/1752604059001/default_default/index.min.js"></script>

<script type="text/javascript">
  const player = videojs.getPlayer('myPlayerID');
    player.ready(() => {
      player.one("loadedmetadata", () => {
        const tt = [].find.call(player.textTracks(), ({ label }) => label === 'external-metadata-vtt');

        if (!tt) {
          return;
        }

        tt.mode = 'hidden';

        tt.oncuechange = () => {
          const outputEl = document.getElementById("insertionPoint");
          const activeCue = tt.activeCues[0];

          if (!activeCue) {
            outputEl.innerHTML += `Cue point duration over\n\n`;
            return;
          }

          const { id, text, startTime, endTime } = activeCue;
          outputEl.innerHTML += `id: ${id}\ntext: ${text}\nstartTime: ${startTime}, endTime: ${endTime}\n`;
    
          try {
            const { title, description } = JSON.parse(text);
            outputEl.innerHTML += `${title}: ${description}\n\n`
          } catch (e) {
            //ignore
          }
      }
    });
  });
</script>

處理提示點代碼

 

  • 第270行:使用<track>標籤讀取 WebVTT 檔案來建立文字軌。
  • 273行:建立段落元素做為插入動態建立 HTML 的位置。
  • 285,309行:使用該one()方法只偵聽一次loadedmetadata事件。事件處理常式函數是以匿名方式定義的。
  • 286行:將上次載入文字軌的索引指定給變數。
  • 287行:使用上一個步驟中確定的索引將陣列的最後一個元素指定給變數的textTracks()方法擷取 TextTrack 陣列。如需此邏輯的變化,請參閱下面的「尋找正確軌道」一節。
  • 289,301行:設定傳送事件時的oncuechange事件處理常式函數。
  • 290行:檢查以確定 ActiveCUES 陣列中已定義第一個 (第零個陣列元素) 提示點。這會告訴您這是起始提示點事件。
  • 第291-294行:使用提示點的資訊動態建立 HTML,並將其注入 HTML 頁面。這包括解析 JSON 和顯示該 JSON 的各種字段。
  • 第295-297行:顯示已到達提示點終點的附註。
  • 第 302 行:播放視訊。

 

可以假設您可以使用以下命令以編程方式添加WebVTT文件addRemoteTextTrack()方法。在這種情況下,這將是不可靠的,因為您可能會遇到一種競爭狀況,即在嘗試使用提示點之前,提示點將無法準備就緒。使用以下命令添加WebVTT文件是安全的<track>標籤,如圖所示。

找到正確的軌道

如果多個文本軌道與播放器相關聯,則在本文檔中的許多地方都可能發生問題。假定播放器僅與一個文本軌道相關聯,因此使用了以下代碼:var tt = myPlayer.textTracks()[0];。選擇第零個數組元素將假定與播放器關聯的單個文本軌道。

文本軌道不僅用於提示點,還用於其他類型的數據。的屬性可以包含以下值:

  • 副標題
  • 字幕
  • 描述
  • 章節
  • 中繼資料

這意味著很有可能將多個文本軌道與播放器關聯,並且需要一種方法來為您的應用程序邏輯找到正確的文本軌道。以下代碼循環遍歷可用的文本軌道,直到元數據找到(提示點)值:

<script type="text/javascript">
  videojs.getPlayer('myPlayerID').ready(function() {
    var myPlayer = this,
      allTextTacks,
      attLength,
      tt;
    myPlayer.one("loadedmetadata", function () {
      allTextTacks = myPlayer.textTracks();
      attLength = allTextTacks.length;
      for (var i = 0; i < attLength; i++) {
        if (allTextTacks[i].kind === 'metadata') {
          tt = allTextTacks[i];
          break;
        };
      };
    });
  });
</script>

然後,可以使用前面示例中的邏輯來使用tt變量,其中包含所需的文本軌道。

程序化提示點

可以以編程方式添加提示點。關鍵方法來自HTML5 VTTCue接口。您可以使用以下語法創建提示點:

new VTTCue( startTime, endTime, text )

處理提示點的邏輯與前面的示例非常相似,因此僅詳細描述與上面使用的代碼不同的代碼。

  • 第43,44行:添加一個textTrack使用玩家的addRemoteTextTrack()方法。指定kind成為元數據label, 在這種情況下定時提示點

  • 45-48行:等待10毫秒,然後使用播放器的提示創建兩個提示點addCue()方法。提示點使用HTML5的實例化VTTCue()構造函數。

  • 第22行:偵聽事addtrack件。
  • 第 23 行:檢索與播放器關聯的所有文本軌道。
  • 第 24 行:設置attLength可變為文本軌道的數量。該值將在下一個代碼段的循環中使用。
  • 第25-30行:循環遍歷每個文本軌道,檢查是否存在label等於正確的值。找到後,將當前文本軌道分配給變量,然後退出循環。
<video-js id="myPlayerID"
  data-video-id="4607746980001"
  data-account="1507807800001"
  data-player="default"
  data-embed="default"
  width="640" height="360"
  controls=""></video-js>

<script src="https://players.brightcove.net/1507807800001/default_default/index.min.js"></script>

<p id="insertionPoint"></p>

<script type="text/javascript">
  videojs.getPlayer("myPlayerID").ready(function () {
    var myPlayer = this,
      textTrack = [],
      allTextTacks,
      attLength,
      tt;
    myPlayer.one("loadedmetadata", function () {
      myPlayer.textTracks().addEventListener('addtrack', function () {
        allTextTacks = myPlayer.textTracks();
        attLength = allTextTacks.length;
        for (var i = 0; i < attLength; i++) {
          if (allTextTacks[i].label === 'Timed Cue Point') {
            tt = allTextTacks[i];
            break;
          }
        }
        tt.oncuechange = function () {
          if (tt.activeCues[0] !== undefined) {
            var dynamicHTML = "id: " + tt.activeCues[0].id + ", ";
            dynamicHTML += "text: <strong>" + tt.activeCues[0].text + "</strong>, ";
            dynamicHTML += "startTime: <strong>" + tt.activeCues[0].startTime + "</strong>,  ";
            dynamicHTML += "endTime: <strong>" + tt.activeCues[0].endTime + "</strong>";
            document.getElementById("insertionPoint").innerHTML += dynamicHTML + "<br/><br/>";
          } else {
            document.getElementById("insertionPoint").innerHTML += "Cue point duration over" + "<br/><br/>";
          }
        }; //end oncuechange
      }); // end playing
      textTrack = myPlayer.addRemoteTextTrack({kind: 'metadata', label: 'Timed Cue Point', mode: 'hidden'}, false);
      textTrack.track.mode = 'hidden';
      setTimeout(function(){
        textTrack.track.addCue(new window.VTTCue(2, 5, 'cue point 1 text'));
        textTrack.track.addCue(new window.VTTCue(10, 15, 'cue point 2 text'));
      }, 10);
    }); //end on loadedmetadata
  }); //end ready
</script>

該代碼生成輸出,如以下屏幕截圖所示。注意ID在使用VTTCue()構造方法。

動態提示點

ID3和媒體提示點

如果您有與媒體關聯的ID3提示點或媒體提示點,則可以使用id3CuePointsTrack()mediaCuePointsTrack()方法。例如,要偵聽提示點更改,可以使用以下命令:

videojs.getPlayer('myPlayerID').ready(function () {
  var myPlayer = this;
  myPlayer.one("canplay", function () {
    myPlayer.id3CuePointsTrack().on('cuechange', function () {
      // process cue point here
    });
  });
});

ID3詳細信息

以下內容提供了有關使用ID3提示點的更多信息:

  • ID3標籤可用於將定時的元數據插入流中。
  • 每個段可以有多個ID3幀。
  • Brightcove Player使用前面提到的方法解析ID3提示點並將其顯示為文本軌道id3CuePointsTrack()方法。
  • 最好的做法是等待canplay事件或嘗試訪問它時有可能無法檢索該軌道。
  • 每個標籤支持多幀。

已知問題

  • 在Safari上,如果結束時間等於開始時間,則提示點不會觸發。因此,如果Safari兼容性是一個問題,提示點需要的持續時間必須大於零。