데이터 가져오기
Dynamic Ingest 알림은 비디오가 준비되었을 때 알아야 할 모든 정보를 제공합니다. 무엇을 찾아야 하는지...그리고 시스템에서 "준비"가 의미하는 바를 정의하기만 하면 됩니다. 이 다이어그램은 워크플로를 요약합니다.
동적 수집 알림
Dynamic Ingest 알림 서비스는 여러 종류의 이벤트에 대한 알림을 보냅니다. 비디오가 "준비"된 시점을 파악하는 데 가장 유용한 세 가지는 특정 변환이 생성되었음을 나타내는 것, 매니페스트가 생성되었음을 나타내는 것, 모든 처리가 완료되었음을 나타내는 것입니다. 다음은 각각의 예입니다.
변환 생성 알림
이 예에서 참고:
- NS
videoId
값을 통해 변환이 어떤 비디오인지 알 수 있습니다(여러 수집 작업이 실행 중인 경우). - NS
profileRefId
값은 수집 프로필에 지정된 변환에 대한 참조 ID입니다. - 만약
status
값이 "SUCCESS"이고 변환이 성공적으로 생성되었습니다. - HLS 또는 MPEG-DASH와 같은 분할 유형의 경우 변환이 있다고 해서 재생 가능한 것은 아닙니다. 적절한 매니페스트도 필요합니다(다음 예 참조). MP4 렌디톤은 생성되는 즉시 재생할 수 있습니다.
매니페스트 생성 알림
이 예에서 참고:
- NS
videoId
값을 통해 변환이 어떤 비디오인지 알 수 있습니다(여러 수집 작업이 실행 중인 경우). - NS
profileRefId
값은 생성된 자산이 HLS 매니페스트임을 알려주는 특수 코드입니다(다른 가능한 값은HdsManifest
,DashManifest
, 그리고SmoothIsmManifest
) - HLS 및 HDS의 경우 하나의 매니페스트가 생성되므로 하나의 알림이 표시됩니다. DASH 및 SmoothIsm의 경우 두 개의 매니페스트가 생성되므로(하나는 레거시 Media API용이고 다른 하나는 CMS API용) 이 유형의 두 가지 알림이 표시됩니다.
- 만약
status
값이 "SUCCESS"이고 매니페스트가 성공적으로 생성되었습니다. - HLS 또는 MPEG-DASH와 같은 분할 유형의 경우 변환 및 매니페스트 생성에 대한 명확한 순서가 없습니다. 이러한 변환은 둘 다 생성될 때까지(또는 비디오가 완전히 처리될 때까지 재생할 수 없습니다. 다음 예 참조).
처리 완료 알림
이 예에서 참고:
- NS
videoId
값을 통해 변환이 어떤 비디오인지 알 수 있습니다(여러 수집 작업이 실행 중인 경우). - NS
profileRefId
~이다 ~ 아니다이 알림에 포함 - 만약
status
값이 "SUCCESS"이고 비디오가 성공적으로 처리되었습니다.
알림을 받으려면 "콜백" 필드를 포함해야 합니다. Dynamic Ingest API하나 이상의 콜백 주소를 가리키는 요청:
{
"master": {
"url": "https://s3.amazonaws.com/bucket/mysourcevideo.mp4"
}, "profile": "high-resolution",
"callbacks": ["http://host1/path1”, “http://host2/path2”]
}
샘플 대시보드
이 섹션에서는 알림을 조합하여 Dynamic Ingest API에 대한 간단한 대시보드를 구축하는 방법을 설명합니다. 알림 처리기에서 알림을 구문 분석합니다. Dynamic Ingest API처리 완료 알림을 식별합니다. 그런 다음 JSON 파일의 각 비디오에 대한 객체 배열에 비디오 알림을 추가합니다. 대시보드 자체는 알림 데이터를 가져오기 위해 JSON 파일을 가져오는 HTML 페이지입니다. id를 사용하여 요청합니다. CMS API동영상 메타데이터를 가져옵니다. 대시보드를 볼 수 있습니다여기 .
계정에 대한 설정 지침과 함께 이 앱의 모든 파일은 다음 위치에 있습니다. 이 저장소 .
다음은 앱의 상위 수준 아키텍처입니다.
앱 부품
알림 핸들러는 PHP로 빌드되었습니다. - 완전한 알림 처리를 찾고 별도의 JavaScript 파일에 있는 배열에 비디오 ID를 추가합니다.
<?php // 오류를 기록하는 var $problem = "오류 없음"; // 현재 비디오 인덱스를 저장할 var $videoIndex = -1; // 입력 데이터 가져오기 시도{ $json = file_get_contents('php://input'); $decoded = json_decode($json, true); }잡기(예외 $e) { $problem = $e->getMessage(); echo $problem; } // 데이터 파일 내용을 가져와 구문 분석합니다. { $notificationData = file_get_contents('di.json'); $notificationDataDecoded = json_decode($notificationData, true); }잡기(예외 $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); } // 이제 di.json의 내용을 file_put_contents('di.json', json_encode($notificationDataDecoded)); } echo "동적 수집 콜백 앱이 실행 중입니다"; var_dump($notificationData); ?>
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>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>
대리
<?php /** * brightcove-learning-proxy.php - Brightcove RESTful API용 프록시 * 액세스 토큰을 가져오고, 요청하고, 응답을 반환합니다. * 액세스: * URL: https://solutions.brightcove.com/ bcls/bcls-proxy/bcsl-proxy.php * (*항상* HTTPS를 통해 프록시에 액세스해야 함) * 방법: 포스트 * * @포스트{string} url - API 요청의 URL * @post {string} [requestType=GET] - 요청에 대한 HTTP 메소드 * @post {string} [requestBody=null] - 쓰기 요청과 함께 보낼 JSON 데이터 * * @returns {string} $response - API에서 받은 JSON 응답 */ // CORS enablement header("Access-Control-Allow-Origin: *"); // 액세스 토큰 요청 설정 $data = array(); // // 이 프록시를 다른 계정으로 사용하도록 아래 값을 변경합니다. // $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( '콘텐츠 유형: application/x-www-form-urlencoded', ), CURLOPT_POSTFIELDS => $data$)), $response = 컬 ); curl_close($ch); // ($response === FALSE)인 경우 오류 확인{ die(curl_error($ch)); } // 응답 디코딩 $responseData = json_decode($response, TRUE); $access_token = $responseData["access_token"]; // API 호출 설정 // 데이터 가져오기 if ($_POST["requestBody"]) { $data = json_decode($_POST["requestBody"]); }또 다른{ $data = array(); } // 요청 유형을 가져오거나 기본적으로 GET if ($_POST["requestType"]) { $method = $_POST["requestType"]; }또 다른{ $method = "GET"; } // 양식 데이터에서 URL 및 인증 정보를 가져옵니다. $request = $_POST["url"]; // http 요청을 보냅니다. $ch = curl_init($request); curl_setopt_array($ch, array( CURLOPT_CUSTOMREQUEST => $method, CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_SSL_VERIFYPEER => FALSE, CURLOPT_HTTPHEADER => array( '콘텐츠 유형: 애플리케이션/json', "인증: 교군꾼{$access_token} ", ), CURLOPT_POSTFIELDS => json_encode($data) )); $response = curl_exec($ch); curl_close($ch); // ($response === FALSE)인 경우 오류 확인{ echo "Error: "+$response; die(curl_error($ch)); } // 응답 디코딩 // $responseData = json_decode($response, TRUE); // AJAX 호출자에게 응답을 반환합니다. echo $response; ?>
로그 지우기
이 간단한 PHP 앱은 이전 비디오 ID를 지우고 JavaScript 파일을 원래 상태로 복원합니다.
<?php $logFileLocation = "di.json"; $freshContent = 배열(); $encodedContent = json_encode($freshContent); file_put_contents($logFileLocation, $encodedContent); echo '로그 파일 삭제됨 - <a href="di-log.html">대시보드로 돌아가기</a>'; ?>