Contacta con el soporte | Estado del sistema
Contenido de la página

    Obtener el estado de las solicitudes

    Cuando usa el API de ingesta dinámica para agregar videos a su cuenta de Video Cloud, lo que más desea saber es cuándo se procesó el video y si las representaciones se crearon correctamente. Este documento explica cómo puede hacer eso usando las notificaciones de la API de ingesta dinámica. También proporcionamos una aplicación de panel de control de muestra que automatiza el proceso. Tenga en cuenta que este documento se aplica solo al sistema de ingesta heredado; para Dynamic Delivery, consulte Obtener el estado de las solicitudes de ingesta dinámica.

    Obteniendo los datos

    Las notificaciones de Dynamic Ingest le brindan toda la información que necesita para saber cuando su video está listo; solo necesita saber qué buscar ... y definir qué significa "listo" para sus sistemas. Este diagrama resume el flujo de trabajo:

    Ingest Status Workflow
    Flujo de trabajo de estado de ingesta

    Notificaciones de ingesta dinámica

    El servicio de notificación Dynamic Ingest le envía notificaciones para varios tipos de eventos. Los tres que son más útiles para determinar cuándo el video está "listo" son los que indican que se han creado versiones particulares, los que indican que se ha creado un manifiesto y el que indica que todo el procesamiento está completo. Aquí hay ejemplos de cada uno:

    Notificación de reproducción creada

        {
            "entity": "5002412132001",
            "profileRefId": "ts7",
            "accountId": "57838016001",
            "entityType": "ASSET",
            "videoId": "5002361893001",
            "status": "SUCCESS",
            "version": "1",
            "action": "CREATE",
            "jobId": "bb316631-c58b-4bd4-a686-13c5f7a3a779"
        }
    Notificación de reproducción creada

    Tenga en cuenta en este ejemplo:

    • La videoId El valor le permite saber para qué video es la reproducción (en caso de que tenga varios trabajos de ingesta en ejecución)
    • La profileRefId valor es el ID de referencia para la interpretación especificada en el perfil de ingesta
    • Si el status El valor es "SUCCESS", la interpretación se creó correctamente.
    • Para un tipo segmentado como HLS o MPEG-DASH, la existencia de la interpretación no hace que se pueda reproducir; también necesita el manifiesto apropiado (consulte el siguiente ejemplo). Las versiones MP4 se pueden reproducir tan pronto como se crean.

    Notificación de manifiesto creado

        {
            "jobId": "31f0b112-9890-4567-adb5-0f4ed1673701",
            "status": "SUCCESS",
            "version": "1",
            "action": "CREATE",
            "entityType": "ASSET",
            "entity": "5002412528001",
            "videoId": "5002361895001",
            "profileRefId": "HlsManifest",
            "accountId": "57838016001"
        }
    Notificación de manifiesto creado

    Tenga en cuenta en este ejemplo:

    • La videoId El valor le permite saber para qué video es la reproducción (en caso de que tenga varios trabajos de ingesta en ejecución)
    • La profileRefId value es un código especial que le dice que el activo creado era un manifiesto HLS (los otros valores posibles son HdsManifest , DashManifest , y SmoothIsmManifest)
    • Para HLS y HDS, se creará un manifiesto, por lo que verá una notificación. Para DASH y SmoothIsm, se crean dos manifiestos (uno para usar en la API de medios heredada, el otro para la CMS API), por lo que verá dos notificaciones de este tipo.
    • Si el status el valor es "SUCCESS", el manifiesto se creó correctamente
    • Para un tipo segmentado como HLS o MPEG-DASH, no existe un orden definido para la creación de las representaciones y el manifiesto; estas representaciones no se pueden reproducir hasta que se crean ambas (o el video se ha procesado por completo; consulte el siguiente ejemplo).

    Procesando notificación completa

        {
            "entityType": "TITLE",
            "status": "SUCCESS",
            "accountId": "57838016001",
            "entity": "5002412652001",
            "action": "CREATE",
            "jobId": "3e98b3a0-f624-4f2d-81c1-4e43e1d04a0f",
            "version": "1",
            "videoId": "5002412652001"
        }
    Notificación de procesamiento completo

    Tenga en cuenta en este ejemplo:

    • La videoId El valor le permite saber para qué video es la reproducción (en caso de que tenga varios trabajos de ingesta en ejecución)
    • La profileRefId es no incluido en esta notificación
    • Si el status El valor es "SUCCESS", el video se procesó correctamente.

    Para recibir notificaciones, debe incluir un campo "devoluciones de llamada" en usted API de ingesta dinámica solicitudes, apuntando a una o más direcciones de devolución de llamada:

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

    Panel de control de muestra

    Esta sección explica cómo se pueden juntar las notificaciones para construir un tablero simple para la API de Dynamic Ingest. El controlador de notificaciones analiza las notificaciones del API de ingesta dinámica para identificar el procesamiento de notificaciones completas. Luego agrega las notificaciones de video en una matriz de objetos para cada video en un archivo JSON. El tablero en sí es una página HTML que importa el archivo JSON para obtener los datos de notificación. Utiliza los identificadores para realizar una solicitud al CMS API para obtener los metadatos del video. Puedes ver el tablero aquí.

    Todos los archivos de esta aplicación, junto con las instrucciones para configurarla para su cuenta, están en este repositorio.

    Aquí está la arquitectura de alto nivel de la aplicación:

    Ingest Dashboad Architecture
    Ingestión de la arquitectura del tablero

    Las partes de la aplicación

    El controlador de notificaciones está integrado en PHP: busca procesar notificaciones completas y agrega la identificación del video a una matriz en un archivo JavaScript separado:

        <? php // var para registrar errores, si los hay $ problem = "Sin errores"; // var para almacenar el índice de video actual $ videoIndex = -1; // obtener datos de entrada intentar { $json = file_get_contents('php://input'); $decoded = json_decode($json, true); } captura (Excepción $ e) { $problem = $e->getMessage(); echo $problem; } // obtener el contenido del archivo de datos y analizarlo intente { $notificationData = file_get_contents('di.json'); $notificationDataDecoded = json_decode($notificationData, true); } captura (Excepción $ e) { $problem = $e->getMessage(); echo $problem; } if (isset ($ decoded ["entityType"])) { $entityType = $decoded["entityType"]; // if the entity type is ASSET or TITLE, add it to notification data array if ($entityType == "ASSET" || $entityType == "TITLE") { array_push($notificationDataDecoded, $decoded); } // ahora reemplazaremos el contenido de di.json con lo que tenemos file_put_contents ('di.json', json_encode ($ notificationDataDecoded)); } echo "La aplicación de devolución de llamada Dynamic Ingest se está ejecutando"; var_dump ($ notificationData); ?> 

    Archivo JSON:

    El archivo JSON es inicialmente una matriz vacía ([] ): el controlador de notificaciones agrega los datos.

    Tablero

    El tablero incluye HTML y JavaScript para obtener los datos de notificación y datos de video adicionales del CMS API y escribe los resultados en una tabla:

        <!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>
        

    Apoderado

        <? php / ** * brightcove-learning-proxy.php - proxy para las API RESTful de Brightcove * obtiene un token de acceso, realiza la solicitud y devuelve la respuesta * Accediendo a: * URL: https://solutions.brightcove.com/ bcls / bcls-proxy / bcsl-proxy.php * (tenga en cuenta que debe * siempre * acceder al proxy a través de HTTPS) * Método: POST * * @post {string} url: la URL de la solicitud de API * @post {string} [requestType = GET]: método HTTP para la solicitud * @post {string} [requestBody = null]: datos JSON que se enviarán con solicitudes de escritura * * @returns {string} $ respuesta: respuesta JSON recibida de la API * / // encabezado de habilitación de CORS ("Access-Control-Allow-Origin: *"); // configurar la solicitud para el token de acceso $ data = array (); // // cambia los valores a continuación para usar este proxy con una cuenta diferente // $ 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_RETURNTRUEFER => TRUEANSFER , CURLOPT_SSL_VERIFYPEER => FALSE, CURLOPT_USERPWD => $ auth_string, CURLOPT_HTTPHEADER => array ('Tipo de contenido: aplicación / x-www-form-urlencoded',), CURLOPT_POSTFIELDS => $ respuesta) ); curl_close ($ ch); // Verifica si hay errores si ($ respuesta === FALSO) { die(curl_error($ch)); } // Decodifica la respuesta $ responseData = json_decode ($ response, TRUE); $ access_token = $ responseData ["access_token"]; // configurar la llamada a la API // obtener datos si ($ _POST ["requestBody"]) { $data = json_decode($_POST["requestBody"]); } demás { $data = array(); } // obtiene el tipo de solicitud o el valor predeterminado es GET if ($ _POST ["requestType"]) { $method = $_POST["requestType"]; } demás { $method = "GET"; } // obtener la URL y la información de autorización del formulario data $ request = $ _POST ["url"]; // envía la solicitud http $ ch = curl_init ($ request); curl_setopt_array ($ ch, array (CURLOPT_CUSTOMREQUEST => $ método, CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_SSL_VERIFYPEER => FALSE, CURLOPT_HTTPHEADER => array ('Content-type', application / Authorization Portador {$access_token}",), CURLOPT_POSTFIELDS => json_encode ($ data))); $ respuesta = curl_exec ($ ch); curl_close ($ ch); // Verifica si hay errores si ($ respuesta === FALSE) { echo "Error: "+$response; die(curl_error($ch)); } // Decodifica la respuesta // $ responseData = json_decode ($ response, TRUE); // devuelve la respuesta al llamador AJAX echo $ response; ?> 

    Limpiar el registro

    Esta sencilla aplicación PHP simplemente restaura el archivo JavaScript a su estado original, borrando los viejos identificadores de video:

        <? php $ logFileLocation = "di.json"; $ freshContent = array (); $ encodedContent = json_encode ($ freshContent); file_put_contents ($ logFileLocation, $ encodedContent); echo 'Archivo de registro borrado - <a href="di-log.html"> volver al panel </a>'; ?> 

    Página actualizada por última vez el 20 Aug 2022