assistance Contacter le support | Étatétat du système du système
Contenu de la page

    Obtenir l'état des demandes

    Lorsque vous utilisez le Dynamic Ingest API pour ajouter des vidéos à votre compte Video Cloud, ce que vous voulez le plus savoir est quand la vidéo a été traitée et si les formats associés ont été créés ou non avec succès. Ce document explique comment vous pouvez le faire à l'aide Dynamic Ingest API des notifications. Nous fournissons également un exemple d'application de tableau de bord qui automatise le processus. Notez que ce document s'applique uniquement au système d'ingeste hérité. Pour la livraison dynamique, voir Obtenir l'état des demandes d'ingest dynamique

    Obtention des données

    Les notifications Dynamic Ingest vous donnent toutes les informations dont vous avez besoin lorsque votre vidéo est prête - il vous suffit de savoir ce qu'il faut rechercher... et de définir ce que « prêt » signifie pour vos systèmes. Ce diagramme résume le flux de travail :

    Workflow d'état d'ingest
    Workflow d'état d'ingest

    Notifications d'ingestion dynamique

    Le service de notification d'ingestion dynamique vous envoie des notifications pour plusieurs types d'événements. Les trois qui sont les plus utiles pour déterminer quand la vidéo est « prête » sont ceux qui indiquent que des rendus particuliers ont été créés, ceux qui indiquent qu'un manifeste a été créé et celui qui indique que tout le traitement est terminé. Voici des exemples de chacun :

    Notification créée dans le format associé

        {
            "entity": "5002412132001",
            "profileRefId": "ts7",
            "accountId": "57838016001",
            "entityType": "ASSET",
            "videoId": "5002361893001",
            "status": "SUCCESS",
            "version": "1",
            "action": "CREATE",
            "jobId": "bb316631-c58b-4bd4-a686-13c5f7a3a779"
        }
    Notification pour le format associé créé

    Notez dans cet exemple :

    • La videoId valeur vous permet de savoir à quelle vidéo le format associé est destiné (au cas où vous avez plusieurs tâches d'ingeste en cours d'exécution)
    • La profileRefId valeur est l'identifiant de référence pour le format associé spécifié dans le profil d'ingest
    • si la status valeur est « SUCCESS », le format associé a été créé avec succès
    • Pour un type segmenté comme HLS ou MPEG-DASH, l'existence du rendu ne le rend pas jouable - vous avez également besoin du manifeste approprié (voir l'exemple suivant). Les renditons MP4 sont jouables dès qu'ils sont créés.

    Notification créée par le manifeste

        {
            "jobId": "31f0b112-9890-4567-adb5-0f4ed1673701",
            "status": "SUCCESS",
            "version": "1",
            "action": "CREATE",
            "entityType": "ASSET",
            "entity": "5002412528001",
            "videoId": "5002361895001",
            "profileRefId": "HlsManifest",
            "accountId": "57838016001"
        }
    Notification pour le manifeste créé

    Notez dans cet exemple :

    • La videoId valeur vous permet de savoir à quelle vidéo le format associé est destiné (au cas où vous avez plusieurs tâches d'ingeste en cours d'exécution)
    • le profileRefId value est un code spécial qui vous indique que l'actif créé était un manifeste HLS (les autres valeurs possibles sont HdsManifest , DashManifest , et SmoothIsmManifest)
    • Pour HLS et HDS, un manifeste sera créé, de sorte que vous verrez une notification. Pour DASH et SmoothISM, deux manifestes sont créés (l'un pour une utilisation dans l'API média héritée, l'autre pour l'API CMS), vous verrez donc deux notifications de ce type.
    • Si la status valeur est « SUCCESS », le manifeste a été créé avec succès
    • Pour un type segmenté comme HLS ou MPEG-DASH, il n'y a pas d'ordre précis pour la création des rendus et du manifeste - ces rendus ne sont pas lisibles tant que les deux ne sont pas créés (ou que la vidéo a été entièrement traitée - voir l'exemple suivant).

    Traitement de la notification complète

        {
            "entityType": "TITLE",
            "status": "SUCCESS",
            "accountId": "57838016001",
            "entity": "5002412652001",
            "action": "CREATE",
            "jobId": "3e98b3a0-f624-4f2d-81c1-4e43e1d04a0f",
            "version": "1",
            "videoId": "5002412652001"
        }
    Notification de traitement terminée

    Notez dans cet exemple :

    • La videoId valeur vous permet de savoir à quelle vidéo le format associé est destiné (au cas où vous avez plusieurs tâches d'ingeste en cours d'exécution)
    • le profileRefId est ne pas inclus dans cette notification
    • Si la status valeur est « SUCCESS », la vidéo a été traitée avec succès

    Pour recevoir des notifications, vous devez inclure un champ « callbacks » dans vos Dynamic Ingest API demandes, pointant vers une ou plusieurs adresses de rappel :

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

    Tableau de bord exemple

    Cette section explique comment les remarques peuvent être assemblées pour créer un tableau de bord simple pour l'API Dynamic Ingest. Le gestionnaire des notifications analyse les notifications de la pour Dynamic Ingest API identifier le traitement des notifications complètes. Il ajoute ensuite les notifications vidéo dans un tableau d'objets pour chaque vidéo dans un fichier JSON. Le tableau de bord lui-même est une page HTML qui importe le fichier JSON pour obtenir les données de notification. Il utilise les identifiants pour faire une demande à l' API CMS pour obtenir les métadonnées vidéo. Vous pouvez voir le tableau de bord ici.

    Tous les fichiers de cette application, ainsi que les instructions pour la configurer pour votre compte, se trouvent dans ce référentiel.

    Voici l'architecture de haut niveau de l'application :

    Ingérer l'architecture Dashboad
    Ingérer l'architecture Dashboad

    Les parties de l'application

    Le gestionnaire de notifications est construit en PHP - il recherche le traitement des notifications complètes et ajoute l'id vidéo à un tableau dans un fichier JavaScript séparé :

        <?php
        //var pour consigner les erreurs, le cas échéant
        $problem = "No errors";
        //var pour stocker l'index vidéo actuel
        $videoIndex = -1 ;
        
        //récupère les données d'entrée
        essayez {
            $json    = file_get_contents('php://input');
            $decoded = json_decode($json, true);
        } capture (Exception $e) {
            $problem = $e->getMessage();
            echo $problem ;
        }
        
        //récupère le contenu du fichier de données et les analyse
        essayez {
            $NotificationData = file_get_contents ('di.json') ;
            $NotificationDataRecoded = json_decode ($NotificationData, true) ;
        } capture (Exception $e) {
            $problem = $e->getMessage();
            echo $problem ;
        }
        
        
            if (isset($decoded["entityType"])) {
                $entityType = $decoded["entityType"];
                //si le type d'entité est ASSET ou TITLE, ajoutez-le au tableau de données de notification
                if ($entityType == « ASSET » || $entityType == « TITLE ») {
                    array_push ($NotificationDataRecoded, $ décodé) ;
                }
                //maintenant nous allons remplacer le contenu de di.json par ce que nous avons
                file_put_contents ('di.json', json_encode ($NotificationDataRecoded)) ;
        
            }
        
        echo « L'application de rappel Dynamic Ingest est en cours d'exécution » ;
        var_dump ($NotificationData) ;
        
        ?>
        

    JSON fichier :

    Le fichier JSON est initialement un tableau vide ([]) - les données sont ajoutées par le gestionnaire de notification.

    Tableau de bord

    Le tableau de bord inclut le code HTML et JavaScript pour récupérer les données de notification et les données vidéo supplémentaires à partir du CMS API et écrire les résultats dans un tableau :

        <!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>HLS Manifests Created</th>
                                <th>HLS Renditions Created</th>
                                <th>MP4 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;
        
                        /**
                         * Logging function - safe for IE
                         * @param  {string} context - description of the data
                         * @param  {*} message - the data to be logged by the console
                         * @return {}
                         */
                        function bclslog(context, message) {
                            if (window["console"] && console["log"]) {
                              console.log(context, message);
                            }
                            return;
                        }
        
                        /**
                         * 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.hlsManifests = 0;
                            obj.hlsRenditions = 0;
                            obj.mp4Renditions = 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 === 'ASSET') {
                                    // if it's a rendition or manifest, there will be a profileRefId
                                    if (isDefined(notificationObj.profileRefId)) {
                                        // see if it's an HLS manifest
                                        if (notificationObj.profileRefId === 'HlsManifest') {
                                            // increment the hls manifest count
                                            videoDataArray[objIndex].hlsManifests++;
                                        } else if (notificationObj.profileRefId.charAt(0) === 't') {
                                            // increment the hls rendition count
                                            videoDataArray[objIndex].hlsRenditions++;
                                        } else if (notificationObj.profileRefId.charAt(0) === 'm') {
                                            // increment the mp4 rendition count
                                            videoDataArray[objIndex].mp4Renditions++;
                                        }
                                    }
                                } 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...';
                            /* just showing HLS and MP4 renditions, because
                             * that's all that will be produced in this account,
                             * but you could modify the notification handler and
                             * this page to handle other formats
                             */
                            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.hlsManifests + '</td><td>' + item.hlsRenditions + '</td><td>' + item.mp4Renditions + '</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);
                                                bclslog('dataArray', dataArray);
                                                // process the notifications
                                                kMax = dataArray.length;
                                                for (k = 0; k < kMax; k++) {
                                                    processNotification(dataArray[k]);
                                                }
                                                getVideoInfo();
                                                break;
                                                case 'video':
                                                parsedData = JSON.parse(responseData);
                                                bclslog('parsedData', parsedData);
                                                videoDataArray[currentIndex].reference_id = parsedData.reference_id;
                                                videoDataArray[currentIndex].name = parsedData.name;
                                                currentIndex++;
                                                if (currentIndex < iMax) {
                                                    currentVideo = videoDataArray[currentIndex];
                                                    setVideoRequestOptions();
                                                } else {
                                                    writeReport();
                                                }
                                                break;
                                            }
                                          } else {
                                            bclslog("There was a problem with the request. Request returned " + httpRequest.status);
                                            if (type === 'video') {
                                                setVideoRequestOptions();
                                            } else {
                                                setSourcesRequestOptions();
                                            }
                                          }
                                        }
                                      }
                                      catch(e) {
                                        bclslog('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>
        

    Proxy

        <?php
        /**
         * brightcove-learning-proxy.php - proxy pour les API RESTful Brightcove
         * obtient un jeton d'accès, fait la requête et renvoie la réponse
         * Accès :
         * URL : https://solutions.brightcove.com/bcls/bcls-proxy/bcsl-proxy.php
         * (notez que vous devriez *toujours* accéder au proxy via HTTPS)
         * Méthode : POSTE
         *
         * @post {string} url - l'URL de la requête API
         * @post {string} [requestType=get] - méthode HTTP pour la requête
         * @post {string} [requestBody=null] - Données JSON à envoyer avec des requêtes d'écriture
         *
         * @returns {string} $response - Réponse JSON reçue de l'API
         */
        
        //Activation CORS
        en-tête (« Access-Control-Allow-Origin :* ») ;
        
        //configuration de la demande de jeton d'accès
        $data = array();
        //
        //changer les valeurs ci-dessous pour utiliser ce proxy avec un autre compte
        //
        $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) ;
        
        //Vérification des erreurs
        if ($response === FALSE) {
            die (curl_error ($ch)) ;
        }
        
        //Décode la réponse
        $responseData = json_decode($response, TRUE);
        $access_token = $responseData["access_token"];
        
        //configuration de l'appel d'API
        //Obtenir des données
        if ($_POST["requestBody"]) {
            $data = json_decode($_POST["requestBody"]);
        } else {
            $data = array();
        }
        //Obtenir le type de requête ou par défaut à GET
        if ($_POST["requestType"]) {
            $method = $_POST["requestType"];
        } else {
            $method = "GET";
        }
        
        //récupère l'URL et les informations d'autorisation à partir des données du formulaire
        $request = $_POST["url"];
        
        //envoyer la requête http
        $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',
                    « Autorisation : Porteur {$access_token} »,
                ),
                CURLOPT_POSTFIELDS => json_encode($data)
            ))) ;
        $response = curl_exec($ch);
        curl_close ($ch) ;
        
        //Vérification des erreurs
        if ($response === FALSE) {
            echo « Erreur : « +$réponse ;
            die (curl_error ($ch)) ;
        }
        
        //Décode la réponse
        //$responseData = json_decode ($response, TRUE) ;
        //retourne la réponse à l'appelant AJAX
        echo $ réponse ;
        ?>
        

    Effacer le journal

    Cette application PHP simple restaure juste le fichier JavaScript à son état d'origine, effacant les anciens identifiants vidéo :

        <?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>';
        ?>