AI데이터 구축 일자리 참여

장면 분할 API

장면 분할 API 란?

동영상에서 장면이 변화하는 시점을 탐지하여, 동영상을 썸네일로 요약하거나 편집을 용이하게 하는 포인트를 제공합니다. 동영상의 각 프레임의 특성 추출 후 특성이 시간적으로 크게 변화하는 시점을 탐지하여 출력합니다. 장면 분할 API는 HTTP 기반의 REST API 인터페이스로 JSON 포맷 기반의 입력 및 출력을 지원하며 ETRI에서 제공하는 API Key 인증을 통해 사용할 수 있는 Open API 입니다.

API 호출 1일 허용량
기술명 API명 1일 허용량
  • 동영상의 최대 용량은 50MB까지 업로드할 수 있습니다.
  • 동영상의 영상 길이는 최소 5초 이상되어야 합니다.
  • 동영상의 영상 길이는 최대 5분 미만이어야 합니다.
  • 동영상은 최대 100개의 장면으로 분할이 가능합니다.
장면 분할 API 사용하기

장면 분할 API는 파일 업로드 API이며, 동영상 경로와 확장자를 HTTP 통신으로 ETRI Open API 서버에 전달하면 됩니다. 서버가 제공하는 파일 업로드 API의 URI는 다음과 같으며 POST 방식으로 호출해야 합니다.

http://aiopen.etri.re.kr:8000/VideoParse

HTTP 요청으로 장면 분할을 요청할 때 사전 준비 사항에서 발급받은 API Key정보를 요청 본문에 포함시켜야 합니다. 다음은 HTTP 요청 메시지 예입니다.

[HTTP Request Header]

Content-Type:multipart/form-data; boundary=----[파일 구분자 문자열]

[HTTP Request Body]
------[파일 구분자 문자열]
Content-Disposition: form-data; name="json"
{ "request_id": "reserved field", "access_key": “YOUR_ACCESS_KEY”, "argument": {} }

------[파일 구분자 문자열]
Content-Disposition: form-data; name="uploadfile"; filename="[파일 명]"
Content-Type: [파일 타입]

[파일의 Byte 문자열]
------[파일 구분자 문자열]--
							

위와 같은 HTTP 요청을 ETRI Open API 서버로 전달하면 ETRI Open API 서버는 JSON 형태의 Text 데이터를 HTTP 응답 메시지로 반환합니다. 다음은 HTTP 응답 예제 입니다.

[HTTP Respone Header]
Access-Control-Allow-Origin:*
Connection:close
Content-Length:0
Content-Type:application/json; charset=UTF-8

[HTTP Respone Body]
{
	"request_id": "reserved field",
	"result": 0,
	"return_type": "com.google.gson.internal.LinkedTreeMap",
	"return_object": {
		"file_id": {비디오 파일 ID}
	}
}
							
장면 분할 상태 체크 API 사용하기

장면 분할 상태 체크 API는 REST API이며, 장면 분할 API 결과로 전달 받은 비디오 파일 ID를 HTTP 통신으로 ETRI Open API 서버에 전달하면 됩니다. 서버가 제공하는 REST API의 URI는 다음과 같으며 POST 방식으로 호출해야 합니다.

http://aiopen.etri.re.kr:8000/VideoParse/status

HTTP 요청으로 장면 분할을 요청할 때 사전 준비 사항에서 발급받은 API Key정보를 요청 본문에 포함시켜야 합니다. 다음은 HTTP 요청 메시지 예입니다.

[HTTP Request Body]
{
	"request_id": "reserved field",
	"access_key": “YOUR_ACCESS_KEY”,
	"argument": {
		"file_id": {비디오 파일 파일 ID}
	}
}
							

위와 같은 HTTP 요청을 ETRI Open API 서버로 전달하면 ETRI Open API 서버는 JSON 형태의 Text 데이터를 HTTP 응답 메시지로 반환합니다. 다음은 HTTP 응답 예제 입니다.

[HTTP Respone Header]
Access-Control-Allow-Origin:*
Connection:close
Content-Length:0
Content-Type:application/json; charset=UTF-8

[HTTP Respone Body]
{
	"result": [{
			"num": {처리 번호},
			"code": {결과 코드},
			"msg": {결과 메시지},
			"frame": {구분된 프레임 정보},
			"time": {구분된 시간 정보}
	}]
}
							
구현 예제
Java

JSON parsing을 위해 Gson 라이브러리를 사용하여 제공하고 있습니다. Gson 라이브러리에 대한 자세한 설명은 https://github.com/google/gson 에서 확인 하실 수 있습니다.

multipart/form-data file upload를 위해 Apache HttpCore 및 Apache HttpClient 라이브러리를 사용하여 제공하고 있습니다. Apache HttpCore 라이브러리에 대한 자세한 설명은 http://hc.apache.org/에서 확인 하실 수 있습니다.

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import com.google.gson.Gson;

public class Example {

	static public void main ( String[] args ) {
		String openApiURL = "http://aiopen.etri.re.kr:8000/VideoParse";
		String accessKey = "YOUR_ACCESS_KEY";	// 발급받은 API Key
		String type = "VIDEO_FILE_TYPE";  	// 비디오 파일 확장자
		String file = "VIDEO_FILE_PATH";  	// 비디오 파일 경로
		Gson gson = new Gson();

		Map<String, Object> request = new HashMap<>();
		Map<String, String> argument = new HashMap<>();
		MultipartEntityBuilder builder = MultipartEntityBuilder.create();

		FileBody fileBody = new FileBody(new File(file));

		request.put("access_key", accessKey);
		request.put("argument", argument);

		builder.addPart("uploadfile", fileBody);
		builder.addTextBody("json", gson.toJson(request));

		Integer responseCode = null;
		String responBody = null;
		try {
			CloseableHttpClient http = HttpClients.createDefault();
			HttpPost post = new HttpPost(openApiURL);
			post.setEntity(builder.build());
			CloseableHttpResponse response = http.execute(post);
			StatusLine status;
			try{
				StringBuffer result = new StringBuffer();
				status = response.getStatusLine();
				HttpEntity res = response.getEntity();
				BufferedReader br = new BufferedReader(new InputStreamReader(res.getContent(), Charset.forName("UTF-8")));

				String buffer = null;
				while( (buffer = br.readLine())!=null ){
					result.append(buffer).append("\r\n");
				}

				responseCode = status.getStatusCode();
				responBody = result.toString();
			}finally{
				response.close();
			}

			System.out.println("[responseCode] " + responseCode);
			System.out.println("[responBody]");
			System.out.println(responBody);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
										
PHP
<?php
	$openApiURL = "http://aiopen.etri.re.kr:8000/VideoParse";
	$accessKey = "YOUR_ACCESS_KEY";
	$filePath = "VIDEO_FILE_PATH";

	$uploadfile = file_get_contents($filePath);
	$request = array(
		"access_key" => $accessKey,
			"argument" => array ()
		);

	try {
		$boundary = uniqid();
		$body = '';
		$eol = "\r\n";
		$delimiter = '-------------'.$boundary;
		$body .= "--".$delimiter.$eol
			.'Content-Disposition: form-data; name="json"'.$eol.$eol
			.json_encode($request).$eol;

		$body .= "--".$delimiter.$eol
			.'Content-Disposition: form-data; name="uploadfile"; filename="'.basename($filePath).'"' . $eol
			.'Content-Transfer-Encoding: binary'.$eol;

		$body .= $eol;
		$body .= $uploadfile.$eol;

		$body .= "--" . $delimiter . "--".$eol;

		$server_output = "";
		$ch = curl_init();

		$header = array(
			"Content-Type: multipart/form-data; boundary=" . $delimiter,
				"Content-Length: " . strlen($body)
		);

		curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
		curl_setopt($ch, CURLOPT_URL, $openApiURL);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
		curl_setopt($ch, CURLOPT_VERBOSE, true);
		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $body );

		$server_output = curl_exec ($ch);
		if($server_output === false) {
			echo "Error Number:".curl_errno($ch)."\n";
			echo "Error String:".curl_error($ch)."\n";
		}

		curl_close ($ch);
	} catch ( Exception $e ) {
		echo $e->getMessage ();
	}

	echo "result = " . var_dump($server_output);
?>
										
C++

JSON parsing을 위해 jsoncpp 라이브러리를 사용하여 제공하고 있습니다. jsoncpp 라이브러리에 대한 자세한 설명은 https://github.com/open-source-parsers/jsoncpp 에서 확인 하실 수 있습니다.

HTTP 통신을 위해 curl 라이브러리를 사용하여 제공하고 있습니다. curl 라이브러리에 대한 자세한 설명은 https://curl.haxx.se/libcurl 에서 확인 하실 수 있습니다.

컴파일을 위해서는 아래와 같이 추가된 LIB에 대한 옵션을 추가해야 합니다.
g++ (c++파일명) (JSONCPP)/json/json.h (JSONCPP)/jsoncpp.cpp -lcurl -lstdc++fs

#include <curl/curl.h>
#include <json/json.h>
#include <iostream>
#include <string>
#include <memory.h>
#include <fstream>
#include <math.h>
#include <cstdlib>
#include <filesystem>

using namespace std;

size_t writeDataFunc(void *ptr, size_t size, size_t nmemb, string stream);

int main() {
	char* openApiURL = (char*)"http://aiopen.etri.re.kr:8000/VideoParse";
	char* videoFilePath = (char*)"VIDEO_FILE_PATH";
	string accessKey = "YOUR_ACCESS_KEY";

	Json::Value request;
	Json::Value argument;

	request["access_key"] = accessKey;
	request["argument"] = argument;

	CURL *curl;
	curl_slist* responseHeaders = NULL;
	curl = curl_easy_init();

	if( curl == NULL ) {
	} else {
		string body;
		long bodySize = 0L;

		// read file
		ifstream fl(videoFilePath, ios::binary | ios::ate);
		size_t fileSize = fl.tellg();
		string fileContent(fileSize, '\0');
		fl.seekg(0);
		fl.read(&fileContent[0], fileSize);
		fl.close();

		string CRLF = "\r\n";
		srand((unsigned int)time(NULL));
		string BOUNDARY = std::to_string( rand() );
		string DELIMITER = "-------------" + BOUNDARY;


		body.append("--"+DELIMITER+CRLF);
		body.append("Content-Disposition: form-data; name=\"json\""+CRLF+CRLF);
		body.append(CRLF);
		body.append(request.toStyledString()+CRLF);

		// now we add the file
		string fileName = fs::path(videoFilePath).filename();
		body.append("--"+DELIMITER+CRLF);
		body.append("Content-Disposition: form-data; name=\"uploadfile\"; filename=\""+fileName+"\""+CRLF);
		body.append("Content-Transfer-Encoding: binary"+CRLF+CRLF);

		string bodyEnd = CRLF+"--"+DELIMITER+"--"+CRLF;

		body.append(fileContent);
		body.append(bodyEnd);

		char *bodyChars = &body[0];
		bodySize = strlen(body.c_str()) + fileSize + strlen(bodyEnd.c_str());

		responseHeaders = curl_slist_append(responseHeaders, ("Content-Type: multipart/form-data; boundary="+DELIMITER).c_str());
		responseHeaders = curl_slist_append(responseHeaders, ("Content-Length: " + to_string(bodySize)).c_str() ) ;

		long statusCode;
		string response;
		
		curl_easy_setopt(curl, CURLOPT_URL, openApiURL);
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, responseHeaders ) ;
		curl_easy_setopt(curl, CURLOPT_POST, 1);
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
		curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10);
		curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bodyChars);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, bodySize);

		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeDataFunc);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);

		curl_easy_perform(curl);

		curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode);
		curl_easy_cleanup(curl);
		
		cout << "[responseCode] " << statusCode << endl;
		cout << "[responBody]" << endl;
		cout << response << endl;
	}

	return 0;
}

size_t writeDataFunc(void *ptr, size_t size, size_t nmemb, string stream) {
	size_t realsize = size * nmemb;
	string temp(static_cast<const char*>(ptr), realsize);
	stream.append(temp);
	return realsize;
}
							
Python

python 3.0을 기준으로 작성되었습니다.

HTTP 통신을 위해 urllib3 라이브러리를 사용하여 제공하고 있습니다. Python 3.0 이하의 버전에서 예제를 실행하기 위해서는 별도로 urllib3의 설치가 필요합니다. 설치에 대한 설명은 https://pypi.python.org/pypi/urllib3 를 참고하시기 바랍니다.
urllib3 라이브러리에 대한 자세한 설명은 https://urllib3.readthedocs.io/en/latest/ 에서 확인 하실 수 있습니다.

#-*- coding:utf-8 -*-
import urllib3
import json
import os

openApiURL = "http://aiopen.etri.re.kr:8000/VideoParse"
accessKey = "YOUR_ACCESS_KEY"
videoFilePath = "VIDEO_FILE_PATH"

file = open(videoFilePath,'rb')
fileContent = file.read()
file.close();

requestJson = {
	"access_key": accessKey,
	"argument": {}
}

http = urllib3.PoolManager()
response = http.request(
	"POST",
	openApiURL,
	fields={
		'json': json.dumps(requestJson),
		'uploadfile': (os.path.basename(file.name), fileContent)
	}
)

print("[responseCode] " + str(response.status))
print("[responBody]")
print(response.data)
							
Node.js
var fs = require('fs');
var path = require("path");

var openApiURL = 'http://aiopen.etri.re.kr:8000/VideoParse';
var accessKey = 'YOUR_ACCESS_KEY';
var videoFilePath = 'VIDEO_FILE_PATH';
var videoData;

var videoData = fs.readFileSync(videoFilePath);

var requestJson = {
	'access_key': accessKey,
	'argument': {}
};

var BOUNDARY = Math.random() * Date.now();
var DELIMITER = "-------------" + BOUNDARY;
var CRLF = "\r\n";

// request json data
var data = "--" + DELIMITER + CRLF;
data += "Content-Disposition: form-data; name=\"json\""+CRLF+CRLF;
data += JSON.stringify(requestJson)+CRLF;

// request file data
data += "--" + DELIMITER + CRLF;
data += "Content-Disposition: form-data; name=\"uploadfile\"; filename=\""+path.basename(videoFilePath)+"\""+CRLF;
data += "Content-Transfer-Encoding: binary"+CRLF+CRLF

var payload = Buffer.concat([
	new Buffer(data),
	new Buffer(videoData, 'binary'),
	new Buffer(CRLF+"--"+DELIMITER+"--"+CRLF)
]);

var request = require('request');
var options = {
	url: openApiURL,
	body: payload,
	headers: {"Content-Type": "multipart/form-data; boundary=" + DELIMITER}
};

request.post(options, function (error, response, body) {
	console.log('responseCode = ' + response.statusCode);
	console.log('responseBody = ' + body);
});
										
장면 분할 API 레퍼런스
요청 파라미터

장면 분할 API에 필요한 요청 본문에 다음과 같은 파라미터를 작성해야 합니다.

[HTTP Request Header]

Content-Type:multipart/form-data; boundary=----[파일 구분자 문자열]

[HTTP Request Body]
------[파일 구분자 문자열]
Content-Disposition: form-data; name="json"
{ "request_id": "reserved field", "access_key": “YOUR_ACCESS_KEY”, "argument": {} }

------[파일 구분자 문자열]
Content-Disposition: form-data; name="uploadfile"; filename="[파일 명]"
Content-Type: [파일 타입]

[파일의 Byte 문자열]
------[파일 구분자 문자열]--
										

다음은 파라미터에 대한 설명입니다.

Field 명 타입 필수 여부 설명
json String API 사용을 위해 ETRI에서 발급한 사용자 API Key 정보가 포함된 json 문자열
uploadfile File API 사용 요청 시 분석을 위해 전달할 비디오 파일
업로드 응답

장면 분할 API는 동영상의 장면 분할 요청 결과를 JSON 형태의 Text 데이터로 반환합니다.

다음은 정상적인 요청 처리에 대한 HTTP 응답 예입니다.

[HTTP Respone Header]
Access-Control-Allow-Origin:*
Connection:close
Content-Length:50783
Content-Type:application/json; charset=UTF-8

[HTTP Respone Body]
{
	"request_id": "reserved field",
	"result": 0,
	"return_type": "com.google.gson.internal.LinkedTreeMap",
	"return_object": {
		"file_id": {비디오 파일 파일 ID}
	}
}
													

다음은 오류가 발생한 요청 처리에 대한 HTTP 응답 예입니다.

[HTTP Respone Header]
Access-Control-Allow-Origin:*
Connection:close
Content-Length:0
Content-Type:application/json; charset=UTF-8

[HTTP Respone Body]
{
	"request_id": "reserved field",
	"result": -1,
	"reason": {오류 메시지}
}
										

분석된 결과는 다음과 같은 내용이 포함되어 있습니다.

구분 JSON Key 이름 설명
장면 분할
기본정보
file_id 장면분할처리를 위한 file의 ID
상태 체크 응답

장면 분할 API는 동영상의 장면 분할 분석 결과를 JSON 형태의 Text 데이터로 반환합니다.

다음은 정상적인 요청 처리에 대한 HTTP 응답 예입니다.

[HTTP Respone Header]
Access-Control-Allow-Origin:*
Connection:close
Content-Length:0
Content-Type:application/json; charset=UTF-8

[HTTP Respone Body]
{
	"result": [{
			"num": {처리 번호},
			"code": {결과 코드},
			"msg": {결과 메시지},
			"frame": {구분된 프레임 정보},
			"time": {구분된 시간 정보}
	}]
}
										

다음은 오류가 발생한 요청 처리에 대한 HTTP 응답 예입니다.

[HTTP Respone Header]
Access-Control-Allow-Origin:*
Connection:close
Content-Length:0
Content-Type:application/json; charset=UTF-8

[HTTP Respone Body]
{
	"request_id": "reserved field",
	"result": -1,
	"reason": {오류 메시지}
}
										

분석된 결과는 다음과 같은 내용이 포함되어 있습니다.

구분 JSON Key 이름 설명
장면 분할
기본정보
num 장면분할의 처리 번호
code 장면분할의 처리 결과 코드
msg 장면분할의 처리 결과 메시지
frame 장면분할의 결과로 나온 총 분할시점의 숫자
time 분할된 구간의 시작 시점 (초)

장면 분할이 제대로 이루어지지 않았을 경우에는 장면 분할 결과 대신 오류 메시지가 반환됩니다.

JSON Key 오류 메시지 설명
error Video file does not exist 비디오 파일이 없는 경우 (업로드 오류 등으로 인해 파일이 없는 경우)
This file type is not allowed 비디오 파일의 확장자가 맞지 않는 경우
This file is the corrupted file 파일이 있고 확장자가 맞지만, 파일이 읽을 수 없는 비디오일 경우 (파일 손상)
Video length is too long 비디오 길이가 제한 길이보다 긴 경우
Video length is too short 비디오 길이가 너무 짧은 경우
This file is not allowed file type 파일 타입(확장자)이 ‘avi’, ‘mp4’, ‘png’, ‘bmp’가 아닐 경우
This file is not an available video file 파일 타입(확장자)은 맞지만 입력된 파일이 코덱이나 업로드 등으로 비디오를 읽을 수 없는 경우
오류 코드

장면 분할 API의 오류 코드 목록은 다음과 같습니다.

http status code result reason 설명
400 -1 Required arguments is empty 필수 파라미터의 값이 없는 경우
400 -1 One or more arguments are not valid 파라미터의 값이 유효하지 않는 경우
413 -1 Request Entity Too Large 요청 문장 또는 어휘의 크기가 서버가 처리 할 수 있는 것보다 큰 경우
429 -1 Too Many Requests 사용자가 주어진 시간 내에 서버에 너무 많은 요청을 하는 경우
404 -1 Unknown Handler 등록되지 않는 서비스를 요청한 경우
408 -1 Handler Timeout 서버의 요청 대기가 시간을 초과한 경우
500 -1 ETRI service server connection refused ETRI 분석 서버에서 요청을 받지 못하는 경우
500 -1 ETRI service server is not exists 수행 가능한 ETRI 분석 서버가 없는 경우
500 -1 Recipient Failure ETRI 분석 서버에서 요청을 처리하지 못하는 경우
500 -1 Unknown ReplyFailure API 요청에 알 수 없는 내부 오류가 발생한 경우
500 -1 Unknown Exception 알 수 없는 내부 오류가 발생한 경우