サポート サポート問い合わせ先 | システムステータス システムステータス

ダイナミックインジェストリクエストのステータスを取得する

あなたが使用している場合 Dynamic Ingest API あなたにビデオを追加する Video Cloud アカウントで最も知りたいのは、動画が処理されたときと、レンディションが正常に作成されたかどうかです。

概要

こちらのドキュメントでは、CMS API へステータスリクエストを行うか、Dynamic Ingest API 通知。 また、プロセスを自動化するサンプルダッシュボードアプリも提供しています

取り込みジョブの状況は、過去7日に投入されたジョブについてのみ使用可能であることに注意してください。

リクエストのステータス

これらの CMS API エンドポイント を使用して、Dynamic Ingest ジョブ(インジェスト、置換、または再トランスコード)のステータスを取得します - これらのエンドポイントは Dynamic Delivery ジョブでのみ機能することに注意してください::

すべてのジョブのステータスを取得する

    https://cms.api.brightcove.com/v1/accounts/{account_id}/videos/{video_id}/ingest_jobs

応答は次のようになります。

     [
      {
        "id": "ac49b1db-e6e1-477f-a2c1-70b9cd3107cb",
        "state": "finished",
        "account_id": "57838016001",
        "video_id": "5636411346001",
        "error_code": null,
        "error_message": null,
        "updated_at": "2017-11-07T13:56:51.505Z",
        "started_at": "2017-11-07T13:56:12.510Z",
        "priority": "normal",
        "submitted_at": "2017-11-07T13:56:12.435Z"
      },
      {
        "id": "10605652-8b6f-4f22-b190-01bd1938677b",
        "state": "processing",
        "account_id": "57838016001",
        "video_id": "5636411346001",
        "error_code": null,
        "error_message": null,
        "updated_at": null,
        "started_at": null,
        "priority": "low",
        "submitted_at": "2017-11-07T14:06:35.000Z"
      }
    ]

特定のジョブのステータスを取得する

    https://cms.api.brightcove.com/v1/accounts/{account_id}/videos/{video_id}/ingest_jobs/{job_id}

応答は次のようになります。

    {
        "id": "ac49b1db-e6e1-477f-a2c1-70b9cd3107cb",
        "state": "finished",
        "account_id": "57838016001",
        "video_id": "5636411346001",
        "error_code": null,
        "error_message": null,
        "updated_at": "2017-11-07T13:56:51.505Z",
        "started_at": "2017-11-07T13:56:12.510Z",
        "priority": "normal",
        "submitted_at": "2017-11-07T13:56:12.435Z"
      }

state には次の値があります:

  • processing:処理中、ビデオはまだ再生可能ではありません
  • publishing:少なくとも一つのレンディションが作成され、動画再生の準備がされています
  • published:少なくとも一つのレンディションが再生可能です
  • finished:すべての処理が完了しています
  • failed:処理に失敗しました; 何が問題なのかわからない場合はサポートにお問い合わせください

通知を受け取る

上記で説明したリクエストステータスメソッドが実行されている間、あなたが特定のstate(published or finished)、これらのイベントが発生したときにブライトコーブに通知することをお勧めします。探している答えが得られるまでステータスを尋ね続ける必要はありません。 次に、通知の処理を中心にアプリを構築する方法を見ていきます。

Dynamic Ingest の通知には、あなたが知る必要があるすべての情報が動画の準備ができたときに表示されます - あなたはただ、どの情報を探しているかと..."ready" があなたのシステムにとってどう定義されているかを知る必要があります。こちらの図は、ワークフローをまとめたものです:

インジケータステータスワークフロー
インジケータステータスワークフロー

Dynamic Ingest の通知

ダイナミックインジェスト通知サービスは、いくつかの種類のイベントの通知を送信します。 ビデオが「準備完了」であるときを把握するのに最も有用な2つは、特定のレンディションが作成されたことを示すものと、すべての処理が完了したことを示すものです。 それぞれの例を以下に示します。

Dynamic Ingest の作成通知

    {
      "entity": "default/video3800",
      "entityType": "DYNAMIC_RENDITION",
      "version": "1",
      "action": "CREATE",
      "jobId": "d3ef8751-2b88-4141-95d5-83f0393aca07",
      "videoId": "5660367449001",
      "dynamicRenditionId": "default\/video3800",
      "bitrate": 3804,
      "width": 1920,
      "height": 1080,
      "accountId": "57838016001",
      "status": "SUCCESS"
    }
    
    
作成されたレンディションの通知

こちらの例の注意点:

  • 挽き目 videoId の値からレンディションがどの動画のものなのかがわかります(あなたが複数のインジェストジョブを実行している場合)
  • 挽き目 entity の値はダイナミックレンディションの作成タイプです
  • もし status の値が "SUCCESS" の場合、レンディションは正常に作成されています

処理完了通知

    {
      "entity": "5660367449001",
      "entityType": "TITLE",
      "version": "1",
      "action": "CREATE",
      "jobId": "d3ef8751-2b88-4141-95d5-83f0393aca07",
      "videoId": "5660367449001",
      "accountId": "57838016001",
      "status": "SUCCESS"
    }
    
    
処理完了通知

こちらの例の注意点:

  • 挽き目 videoId jobId の値により、これがどの動画のものであるかがわかります(複数の取り込みジョブを実行している場合)
  • もし status の値が "SUCCESS" の場合、動画は正常に処理されています

通知を受け取るには、一つまたはそれ以上のコールバックアドレスを指す "callbacks" フィールドを Dynamic Ingest API リクエストに含める必要があります:

    {
      "master": {
      "url": "https://s3.amazonaws.com/bucket/mysourcevideo.mp4"
      }, "profile": "multi-platform-extended-static",
      "callbacks": ["http://host1/path1”, “http://host2/path2”]
    }
    
    

サンプルダッシュボード

このセクションでは、通知をまとめて簡単なダッシュボードを構築する方法について説明します。 Dynamic Ingest API。 通知のハンドラは、 Dynamic Ingest API 処理完了通知を識別します。 次に、JSONファイル内の各ビデオのオブジェクトの配列にビデオ通知を追加します。 ダッシュボード自体は、JSONファイルをインポートして通知データを取得するHTMLページです。 IDを使用して、 CMS API にリクエストをし、動画のメタデータを取得します。

こちらはこのアプリケーションの高水準なアーキテクチャです:

Ingest Dashboadのアーキテクチャ
Ingest Dashboadのアーキテクチャ

アプリパーツ

通知のハンドラは PHP で構築されています - 処理完了の通知を探し、ビデオ ID を別の JavaScript ファイルの配列に追加します:

    <?php
      // POST won't work for JSON data
      $problem = "No errors";
      try {
        $json    = file_get_contents('php://input');
        $decoded = json_decode($json, true);
      } catch (Exception $e) {
        $problem = $e->getMessage();
        echo $problem;
      }
    
      // full notification
      $notification = json_encode($decoded, JSON_PRETTY_PRINT);
    
      // Begin by extracting the useful parts of the notification
      // for Dynamic Delivery, look for 'videoId'
      // for the legacy ingest system, the video id is the 'entity'
    
      if (isset($decoded["videoId"])) {
        $videoId = $decoded["videoId"];
      } elseif (isset($decoded["entity"])) {
        $videoId = $decoded["entity"];
      } else {
        $videoId = null;
      }
    
      if (isset($decoded["entityType"])) {
        $entityType = $decoded["entityType"];
      } else {
        $entityType = null;
      }
    
      if (isset($decoded["status"])) {
        $status = $decoded["status"];
      } else {
        $status = null;
      }
    
      if (isset($decoded["action"])) {
        $action = $decoded["action"];
      } else {
        $action = null;
      }
    
      // if notification is for completed title, act
    
      if (($entityType == 'TITLE') && ($action == 'CREATE')) {
        if (($status == 'SUCCESS') || ($status == 'FAILED')) {
          $newLine = "\nvideoIdArray.unshift(".$videoId.");";
          // Tell PHP where it can find the log file and tell PHP to open it
          // and add the string we created earlier to it.
          $logFileLocation = "video-ids.js";
          $fileHandle      = fopen($logFileLocation, 'a') or die("-1");
          chmod($logFileLocation, 0777);
          fwrite($fileHandle, $newLine);
          fclose($fileHandle);
        }
      }
    
      // save full notification for audit trail
      $logEntry = $notification.",\n";
    
      $logFileLocation = "full-log.txt";
      $fileHandle      = fopen($logFileLocation, 'a') or die("-1");
      chmod($logFileLocation, 0777);
      fwrite($fileHandle, $logEntry);
      fclose($fileHandle);
    
    
      echo "Dynamic Ingest callback app is running";
      ?>
      
      

JSON ファイル:

JSON ファイルは、最初は空の配列 ( [] ) です - データは通知ハンドラによって追加されます。

ダッシュボード

ダッシュボードには HTML と JavaScript が含まれており、CMS API から通知データと追加のビデオデータを取得し、その結果を表に書き込みます:

      <!DOCTYPE html>
      <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Dynamic Ingest Log</title>
        <style>
        body {
        font-family: sans-serif;
        margin: 5em;
        }
        .hide {
        display: none;
        }
        .show {
        display: block;
        }
        table {
        border-collapse: collapse;
        border: 1px #999999 solid;
        }
        th {
        background-color: #666666;
        color: #f5f5f5;
        padding: .5em;
        font-size: .7em;
        }
        td {
        border: 1px #999999 solid;
        font-size: .7em;
        padding: .5em
        }
        .hidden {
        display: none;
        }
        </style>
      </head>
      <body>
        <h1>Dynamic Ingest Log</h1>
        <h2>Account: Brightcove Learning (57838016001)</h2>
        <p style="width:70%">
          Videos are listed in order of processing completion time, newest to oldest. The reference id (generated by the <a href="./di-tester.html">Dynamic Ingest tester</a>) is a combination of the date/time that the Dynamic Ingest job was initiated and the ingest profile that was used. You can add additional videos using the <a href="./di-tester.html">Dynamic Ingest tester</a>. New videos will appear in this log after processing is complete.
        </p>
        <p>
          <button id="clearLogBtn">Clear the log</button>
        </p>
        <div id="videoLogBlock">
          <table>
            <thead>
              <tr>
                <th>Video ID</th>
                <th>Name</th>
                <th>Reference ID</th>
                <th>Renditions Created</th>
                <th>Processing Complete</th>
              </tr>
            </thead>
            <tbody id="logBody"></tbody>
          </table>
          <h4 id="loadingMessage">Loading data, please wait...</h4>
        </div>
        <script>
        var BCLS = ( function (window, document) {
          // to use another account, set the account_id value appropriately
          // the client_id and client_secret will also need to be changed in the proxy
          var my_account_id = 57838016001,
            account_id = my_account_id,
            logBody = document.getElementById('logBody'),
            loadingMessage = document.getElementById('loadingMessage'),
            clearLogBtn = document.getElementById('clearLogBtn'),
            i = 0,
            iMax,
            // set the proxyURL to the location of the proxy app that makes Brightcove API requests
            proxyURL = './brightcove-learning-proxy.php',
            dataFileURL = './di.json',
            videoDataArray = [],
            requestOptions = {},
            currentVideo,
            currentIndex = 0;
          /**
          * tests for all the ways a variable might be undefined or not have a value
          * @param {*} x the variable to test
          * @return {Boolean} true if variable is defined and has a value
          */
          function isDefined(x) {
            if ( x === '' || x === null || x === undefined || x === NaN) {
            return false;
          }
          return true;
          }
          /**
          * find index of an object in array of objects
          * based on some property value
          *
          * @param {array} targetArray - array to search
          * @param {string} objProperty - object property to search
          * @param {string|number} value - value of the property to search for
          * @return {integer} index of first instance if found, otherwise returns null
          */
          function findObjectInArray(targetArray, objProperty, value) {
            var i, totalItems = targetArray.length, objFound = false;
            for (i = 0; i < totalItems; i++) {
              if (targetArray[i][objProperty] === value) {
                objFound = true;
                return i;
              }
            }
            if (objFound === false) {
              return null;
            }
          }
          /**
          * factory for new video objects
          * @param {String} videoId the video id
          * @return {object} the new object
          */
          function makeVideoDataObject(videoId) {
            var obj = {};
            obj.id = videoId;
            obj.name = '';
            obj.reference_id = '';
            obj.renditions = 0;
            obj.complete = 'no';
            return obj;
          }
          /**
          * processes notification objects
          * creates a new object in the videoDataArray if it doesn't exist
          * and updates the videoDataArray object based on the notification
          * @param {Object} notificationObj the raw notification object
          */
          function processNotification(notificationObj) {
            var objIndex, videoObj;
            // if notification object contains a video id, find the corresponding
            // object in the videoDataArray or create it if it's not there
            if (isDefined(notificationObj) && isDefined(notificationObj.videoId)) {
              objIndex = findObjectInArray(videoDataArray, 'id', notificationObj.videoId);
              // if not found, create one
              if (!isDefined(objIndex)) {
                videoObj = makeVideoDataObject(notificationObj.videoId);
                videoDataArray.push(videoObj);
                objIndex = videoDataArray.length - 1;
              }
              // now update properties based on what's in the notification
              if (notificationObj.entityType === 'DYNAMIC_RENDITION') {
                // increment the renditions account
                videoDataArray[objIndex].renditions++;
              }
            } else if (notificationObj.entityType === 'TITLE') {
              // overall processing notification - checked for SUCCESS / FAILED
              if (notificationObj.status === 'SUCCESS') {
                // mark complete
                videoDataArray[objIndex].complete = 'yes';
              } else if (notificationObj.status === 'FAILED') {
                // mark failed
                videoDataArray[objIndex].complete = 'failed';
              }
            }
            return;
          }
          /**
          * creates the dashboard table body
          */
          function writeReport() {
            var j,
              jMax = videoDataArray.length,
              item,
              t;
            loadingMessage.textContent = 'This page will refresh in 1 minute...';
            for (j = 0; j < jMax; j++) {
              item = videoDataArray[j];
              if (item.id !== undefined) {
                logBody.innerHTML += '<tr><td>' + item.id + '</td><td>' + item.name + '</td><td>' + item.reference_id + '</td><td>' + item.renditons + '</td><td>' + item.complete + '</td></tr>';
              }
            }
            // set timeout for refresh
            t = window.setTimeout(init, 60000);
          };
          // function to set up the notification data request
          function setJSONRequestOptions() {
            submitRequest(null, dataFileURL, 'notificationData');
          }
          // function to set up video data request
          function setVideoRequestOptions() {
            requestOptions = {};
            requestOptions.url = 'https://cms.api.brightcove.com/v1/accounts/' + account_id + '/videos/' + currentVideo.id;
            submitRequest(requestOptions, proxyURL, 'video');
          }
          /**
          * initiates the cms api requests
          */
          function getVideoInfo() {
            iMax = videoDataArray.length;
            if (currentIndex < iMax) {
              currentVideo = videoDataArray[currentIndex];
              setVideoRequestOptions();
            } else {
              loadingMessage.innerHTML = 'No videos have been ingested - you can add some using the <a href="./di-tester.html">Dynamic Ingest tester</a>';
            }
          }
          /**
          * make the cms api requests
          * @param {Object} options request options
          * @param (String) url URL to send request to
          * @param (String) type the request type
          */
          function submitRequest(options, url, type) {
            var httpRequest = new XMLHttpRequest(),
              requestData,
              responseData,
              videoDataObject,
              parsedData,
              getResponse = function () {
              try {
                if (httpRequest.readyState === 4) {
                  if (httpRequest.status === 200) {
                    responseData = httpRequest.responseText;
                    switch (type) {
                      case 'notificationData':
                          var k, kMax, dataArray;
                          dataArray = JSON.parse(responseData);
                          // process the notifications
                          kMax = dataArray.length;
                          for (k = 0; k < kMax; k++) {
                          processNotification(dataArray[k]);
                        }
                        getVideoInfo();
                        break;
                      case 'video':
                        parsedData = JSON.parse(responseData);
                        videoDataArray[currentIndex].reference_id = parsedData.reference_id;
                        videoDataArray[currentIndex].name = parsedData.name;
                        currentIndex++;
                        if (currentIndex < iMax) {
                        currentVideo = videoDataArray[currentIndex];
                        setVideoRequestOptions();
                        } else {
                        writeReport();
                        }
                        break;
                    }
                  } else {
                    console.log('There was a problem with the request. Request returned '', httpRequest.status);
                    if (type === 'video') {
                      setVideoRequestOptions();
                    } else {
                      setSourcesRequestOptions();
                    }
                  }
                }
              }
              catch(e) {
              console.log('Caught Exception: ', e);
              }
            };
            // notifications data is a special case
            if (type === 'notificationData') {
              // set response handler
              httpRequest.onreadystatechange = getResponse;
              // open the request
              httpRequest.open("GET", url);
              // set headers
              httpRequest.setRequestHeader("Content-Type", "application/json");
              // open and send request
              httpRequest.send();
            } else {
              // requests via proxy
              // set up request data
              requestData = "url=" + encodeURIComponent(options.url) + "&requestType=GET";
              // set response handler
              httpRequest.onreadystatechange = getResponse;
              // open the request
              httpRequest.open("POST", url);
              // set headers
              httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
              // open and send request
              httpRequest.send(requestData);
            }
          };
          // event handlers
          clearLogBtn.addEventListener('click', function () {
            if (window.confirm('Are you sure? This action cannot be undone!')) {
            // if your clear-log app resides in another location, change the URL
            window.location.href = 'clear-log.php';
            }
          });
          // get things started
          function init() {
            // clear table and the video data array
            logBody.innerHTML = "";
            videoDataArray = [];
            setJSONRequestOptions();
          }
          // kick off the app
          init();
        })(window, document);
        </script>
      </body>
    </html>
    
    

プロキシ

    <?php
    /**
    * brightcove-learning-proxy.php - proxy for Brightcove RESTful APIs
    * gets an access token, makes the request, and returns the response
    * Accessing:
    *     URL: https://solutions.brightcove.com/bcls/bcls-proxy/bcsl-proxy.php
    *         (note you should *always* access the proxy via HTTPS)
    *     Method: POST
    *
    * @post {string} url - the URL for the API request
    * @post {string} [requestType=GET] - HTTP method for the request
    * @post {string} [requestBody=null] - JSON data to be sent with write requests
    *
    * @returns {string} $response - JSON response received from the API
    */
    // CORS enablement
    header("Access-Control-Allow-Origin: *");
    // set up request for access token
    $data = array();
    //
    // change the values below to use this proxy with a different account
    //
    $client_id     = "YOUR_CLIENT_ID_HERE";
    $client_secret = "YOUR_CLIENT_SECRET_HERE";
    $auth_string   = "{$client_id}:{$client_secret}";
    $request       = "https://oauth.brightcove.com/v4/access_token?grant_type=client_credentials";
    $ch            = curl_init($request);
    curl_setopt_array($ch, array(
    CURLOPT_POST           => TRUE,
    CURLOPT_RETURNTRANSFER => TRUE,
    CURLOPT_SSL_VERIFYPEER => FALSE,
    CURLOPT_USERPWD        => $auth_string,
    CURLOPT_HTTPHEADER     => array(
    'Content-type: application/x-www-form-urlencoded',
    ),
    CURLOPT_POSTFIELDS => $data
    ));
    $response = curl_exec($ch);
    curl_close($ch);
    // Check for errors
    if ($response === FALSE) {
    die(curl_error($ch));
    }
    // Decode the response
    $responseData = json_decode($response, TRUE);
    $access_token = $responseData["access_token"];
    // set up the API call
    // get data
    if ($_POST["requestBody"]) {
    $data = json_decode($_POST["requestBody"]);
    } else {
    $data = array();
    }
    // get request type or default to GET
    if ($_POST["requestType"]) {
    $method = $_POST["requestType"];
    } else {
    $method = "GET";
    }
    // get the URL and authorization info from the form data
    $request = $_POST["url"];
    //send the http request
    $ch = curl_init($request);
    curl_setopt_array($ch, array(
    CURLOPT_CUSTOMREQUEST  => $method,
    CURLOPT_RETURNTRANSFER => TRUE,
    CURLOPT_SSL_VERIFYPEER => FALSE,
    CURLOPT_HTTPHEADER     => array(
    'Content-type: application/json',
    "Authorization: Bearer {$access_token}",
    ),
    CURLOPT_POSTFIELDS => json_encode($data)
    ));
    $response = curl_exec($ch);
    curl_close($ch);
    // Check for errors
    if ($response === FALSE) {
    echo "Error: "+$response;
    die(curl_error($ch));
    }
    // Decode the response
    // $responseData = json_decode($response, TRUE);
    // return the response to the AJAX caller
    echo $response;
    ?>
    
    

ログを消去する

こちらのシンプルな PHP アプリケーションは JavaScript ファイルを元の状態に戻し、古い動画の ID を消去します:

    <?php
    $logFileLocation = "di.json";
    $freshContent = array ();
    $encodedContent = json_encode($freshContent);
    file_put_contents($logFileLocation, $encodedContent);
    echo 'Log file cleared - <a href="di-log.html">go back to the dashboard</a>';
    ?>
    
    

ページの最終更新日:12年2020月XNUMX日