[이렇게 사용하세요!] 동영상 서비스 자동화 하기 : 네이버 클라우드 플랫폼 VOD Station + Cloud Functions 활용

NAVER Cloud
NAVER Cloud
Published in
23 min readJan 24, 2023

안녕하세요, 네이버클라우드 팀입니다.

온라인 쇼핑 후 리뷰 한 번 쯤 남겨보셨죠? 최근에는 생생한 정보 전달을 위해 사진 뿐만 아니라 영상도 올릴 수 있도록 지원하는 추세인데요.

최근 한 온라인 유통사에서 동영상 리뷰 기능 도입 문의를 주셨습니다. 네이버 클라우드 플랫폼 ncloud.com에도 동영상 업로드와 스트리밍 서비스가 있기에 ‘동영상 서비스를 자동화하는’ 테스트를 진행해 보았습니다.

사용자 관점에서의 흐름은 다음과 같습니다.

  1. 리뷰 영상을 업로드하면
  2. 영상의 품질을 보정하고 다양한 해상도로 인코딩 하는 과정을 거쳐
  3. 콘텐츠를 빠르게 재생해주는 CDN에 연결하여
  4. 업로드한 영상을 끊김없이 다른 사용자가 볼 수 있게 됩니다.

영상이 원활하게 재생되기 위해선 위 과정들이 매끄럽게 처리되어야 하는데요. 어떤 스트리밍 솔루션을 사용하는지에 따라 재생 퀄리티속도에 차이가 생기게 됩니다.

네이버 클라우드 플랫폼 (Ncloud)의 미디어 서비스 중 동영상 스트리밍 서비스 VOD Station를 활용하여 동영상 서비스 자동화 과정을 구현 및 테스트해 보았습니다.

시나리오

VOD Station과 함께 서버리스 컴퓨팅 서비스인 Cloud Functions을 활용하였습니다. 테스트 시나리오는 다음과 같습니다.

  1. 갤럭시 스토어 서비스의 동영상 리뷰가 올라오면 Object Storage에 저장합니다.
  2. Cloud Functions에서 Object Storage의 파일 생성 이벤트를 감지하여 실시간으로 VOD 인코딩을 실행합니다. 인코딩을 실행하기 위해선 VOD Station 내에서 ‘카테고리 (Category)’와 ‘채널 (Channel)’을 미리 생성해 두어야 합니다. (👉가이드 보기 : 카테고리 생성 / 채널 설정)
  3. VOD Station에서 인코딩이 완료된 파일은 Object Storage ‘Output’ 폴더에 저장되며, 동시에 CDN HLS 송출을 실행합니다.
  4. VOD 인코딩이 완료되면 Cloud Functions의 callback 서비스를 호출하여 인코딩 완료 소식을 관리자에게 SMS 메시지로 전달하여 알립니다.
  5. 사용자는 비디오 플레이어 서비스 Video Player에서 접속 환경에 최적화된 화질로 영상을 보게 됩니다. (‘Adaptive Bitrate HLS 스트리밍’)

위 과정을 이미지로 나타내면 아래와 같습니다.

(잠깐!) Cloud Functions 를 활용한 이유?

VOD Station 서비스는 Object Storage 버킷(저장소)과 연동하여 인코딩 기능을 수행하지만, 버킷에 파일이 업로드 되었는지 여부를 감지하여 자동 인코딩하는 기능을 제공하지 않습니다. 대신, Object Storage의 ‘이벤트 관리 기능’과 Cloud Functions를 활용하면 업로드부터 인코딩으로 이어지는 절차를 자동화 할 수 있습니다.

Object Storage의 파일 생성/삭제 이벤트를 Trigger로 사용하여 이벤트가 발생할 때 마다 Cloud Functions를 호출하도록 하고, Cloud Functions의 비지니스 로직 안에서 파이썬 (python) 등 언어를 이용하여 VOD Station의 인코딩 관련 API를 호출 하도록 합니다. VOD Station의 인코딩 결과를 받기 위해서 별도의 Web 서버를 운영할 수도 있으나, API G/W와 Cloud Functions를 사용하여 간단히 구성할 수 있습니다.

아래는 상세한 테스트 과정입니다.

[Step 1] Object Storage, VOD Station 설정

1.1. Object Storage 설정

먼저 Object Storage에서 영상을 업로드할 버킷과, 인코딩이 완료된 결과물 (아웃풋)을 저장할 버킷을 생성합니다.

업로드용 버킷명은 ‘Movie-Upload’으로 설정하고, 아웃풋 저장용 버킷명은 ‘jinkyu-obj/1784’으로 설정하였습니다.

Object Storage > Bucket Management 화면

1.2. VOD Station 설정

다음은 Vod Station 카테고리채널을 설정하는 방법입니다.

먼저 카테고리 생성 화면에서 SD, HD, FHD, UHD 으로 인코딩 될 수 있도록 설정하고, 아웃풋 파일 경로는 앞서 생성한 Object Stoarge 버킷 ‘jinkyu-obj/1784’으로 지정합니다.

카테고리 생성 화면

아웃풋 경로를 지정하면 설정한 카테고리명으로 하위 폴더가 자동 생성되어 인코딩 완료된 파일이 저장됩니다. (👉가이드 보기 : 카테고리 생성)

아웃풋 파일 경로 지정 화면

다음으로 채널을 생성합니다. 이 때 CDN도 함께 생성되는데, 스트리밍 설정에 최적화된 설정으로 자동 생성됩니다. (👉가이드 보기 : 채널 설정)

운영 중인 채널 정보 조회 화면

[Step 2] Cloud Function 트리거, 액션 생성

2.1 Cloud Functions 개요

Cloud Functions는 서버 관리에 대한 부담 없이 손쉽게 원하는 비즈니스 로직을 제공하는 시스템입니다.

  • 서버를 확장성 있게 구성하거나 관리할 필요 없이 비즈니스 로직 코드 작성에 집중할 수 있으며
  • 사용한 컴퓨팅 시간만큼 비용을 지불하고 효율적으로 서비스를 운영할 수 있다는 장점이 있습니다.
네이버 클라우드 플랫폼 콘솔 Cloud Functions 소개 화면

다음은 메뉴별 소개입니다.

  • Dashboard : Cloud Fuction의 상태, 기간별 실행, 월간 사용량, 실행 비율, 기간별 액션 실행 결과를 직관적이며 가시적으로 확인할 수 있습니다.
  • Action : 실질적으로 실행되는 코드와 런타임 정보 등을 생성 및 설정할 수 있습니다. 여러 Action을 생성할 때 공통적으로 사용되는 파라미터가 있다면 하나의 패키지 (Package)로 묶어 관리할 수 있습니다.
  • Trigger : Cloud Functions에서 제공하는 리소스 중 트리거를 생성하여 관리할 수 있으며, 사용할 수 있는 트기러의 종류는 Basic, Cron, GitHub 이벤트, Cloud Insight, Object Storage, Cloud IoT Core가 있습니다.

※ 각 용어에 대한 개념을 이해 하시려면, 여기 (가이드 문서 링크)를 클릭해 주세요.

2.2. Object Storage 트리거 생성

동영상을 업로드하기 위한 트리거 (Trigger)를 생성합니다.

  • 이름 : upload_vod
  • 종류 : Object Storage
  • Object Storage 연결 이벤트 : Object Create (put, post, complete_upload)
  • 필터 : [.mp4]접미사 체크
  • 연결 액션 : vod-station-autoencoding/seq_categoryid_encoding_add_file
Trigger 생성 화면

Object Storage 트리거 실행 후 아래와 같이 결과를 조회할 수 있습니다.

[자세히 보기] 버튼을 누르면 트리거 실행 시 설정한 런타임 파라미터를 비롯한 상세한 기록을 볼 수 있습니다.

2.3. VOD 인코딩 액션 생성

다음은 인코딩 수행을 위한 액션을 생성하는 단계입니다.

패키지 생성

패키지 (Package)는 단일 또는 다수의 액션을 분류, 관리하는 목적의 단위로 아래와 같이 생성합니다.

  • 이름 : vod-station-autoencoding
  • 공통 파라미터 : (공통으로 사용하는 파라미터 값을 미리 정의)
{
"API_URL":"https://vodstation.apigw.ntruss.com",
"NCLOUD_ACCESS_KEY":"*********************",
"NCLOUD_SECRET_KEY":"****************************",
"REGION":"KR"
}

get-category-id Action 생성

VOD 인코딩 API 호출시 Category ID가 필요합니다. 앞서 VOD Staiton에서 생성한 카테고리명으로 Category ID를 가져올 수 있도록 get-category-id Action을 생성합니다.

순서는 다음과 같습니다.

  • Object Storage 파일 업로드시 앞서 생성한 트리거에 의해 호출됨
  • 디폴트 파라미터와 Object Storage에 업로드된 파일 정보가 전달됨
  • 리턴값 : return {“category_id” : category_id, “file_name” : file_name}

액션 종류는 python 3.7이며, 디폴트 파라미터 (세부 URI) 정의는 다음과 같습니다.

{"API_URI":"/api/v2/category","CATEGORY_NAME":"1784"}

아래는 액션 소스입니다.

import hashlib
import hmac
import base64
import requests
import time
import json
import sys


def main(args):

print ("start")
access_key = args["NCLOUD_ACCESS_KEY"]
secret_key = args["NCLOUD_SECRET_KEY"]
REGION = args["REGION"]
api_server = args["API_URL"]
api_uri = args["API_URI"]
category_name = args["CATEGORY_NAME"]
file_name = args["object_name"]


timestamp = int(time.time() * 1000)
timestamp = str(timestamp)

secret_key = bytes(secret_key, 'UTF-8')

method = "GET"
uri = api_uri + "?pageNo=1&pageSizeNo=1"

message = method + " " + uri + "\n" + timestamp + "\n" + access_key
message = bytes(message, 'UTF-8')
signingKey = base64.b64encode(hmac.new(secret_key, message, digestmod=hashlib.sha256).digest())

http_header = {
'x-ncp-apigw-signature-v2': signingKey,
'x-ncp-apigw-timestamp': timestamp,
'x-ncp-iam-access-key': access_key,
'X-NCP-REGION_CODE': "KR",
'cache-control': "no-cache",
'pragma': 'no-cache',
'Content-Type': 'application/json'
}

response = requests.get(api_server + uri, headers=http_header)
data = json.loads(response.text)

for i in data['content']:
category_id = str(i["id"])
#print("Category_ID : " + category_id)
#print("file_name : " + file_name)

return {"category_id" : category_id, "file_name" : file_name}

vod_encoding_add_file 생성

다음은 VOD 인코딩을 위한 액션입니다. 액션 생성 순서는 다음과 같습니다.

  • CategoryID와 업로드 된 동영상 파일 이름, 경로를 파라미터로 전달 받는다.
  • VOD 인코딩 완료 후 SMS 완료 정보를 받기 위해 notificationUrl 정보를 body에 추가한다.

body = {
"bucketName": "movie-upload",
"pathList": [
file_name
],
"notificationUrl" : "https://nkvn154klb.apigw.ntruss.com/vod-addfile-callback/V1/RQwMorEEXA" #콜백 URL 정의
}

액션 종류는 python 3.7이며, 디폴트 파라미터 (세부 URI) 정의는 다음과 같습니다.

{"API_URI":"/api/v2/category/{category_id}/add-files" }

액션 소스는 다음과 같습니다.

import hashlib
import hmac
import base64
import requests
import time
import json
import sys

def main(args):
print(args)
access_key = args["NCLOUD_ACCESS_KEY"]
secret_key = args["NCLOUD_SECRET_KEY"]
REGION = args["REGION"]
api_server = args["API_URL"]
api_uri = args["API_URI"]
category_name = args["CATEGORY_NAME"]
category_id = str(args["category_id"])
file_name = args["file_name"]
content_type="application/json"
#print ("Category_ID : " + category_id)

api_uri = api_uri.replace("{category_id}",category_id)
#print ("api_uri : " + api_uri)


timestamp = int(time.time() * 1000)
timestamp = str(timestamp)
secret_key = bytes(secret_key, 'UTF-8')
method = "PUT"

message = method + " " + api_uri + "\n" + timestamp + "\n" + access_key
message = bytes(message, 'UTF-8')
signingKey = base64.b64encode(hmac.new(secret_key, message, digestmod=hashlib.sha256).digest())

http_header = {
'x-ncp-apigw-signature-v2': signingKey,
'x-ncp-apigw-timestamp': timestamp,
'x-ncp-iam-access-key': access_key,
'x-ncp-region_code':'KR',
'accept':'application/json; charset=utf-8',
'Content-Type':'application/json; charset=utf-8'
}

body = {
"bucketName": "movie-upload",
"pathList": [
file_name
],
"notificationUrl" : "https://nkvn154klb.apigw.ntruss.com/vod-addfile-callback/V1/RQwMorEEXA" #콜백 URL 정의
}

response = requests.put(api_server + api_uri, headers = http_header, json = body)

data = json.loads(response.text)
#print (data)

return data

seq_categoryid_encoding_add_file Action 생성

두 액션을 순차적으로 실행하기 위해 ‘시퀀스 액션’으로 묶어주는 과정입니다.

  • 첫 액션의 실행 결과가 다음 액션의 input 파라미터로 전달됩니다.
  • Object Storage 파일 업로드 트리거 (‘upload_vod’)와 연결됩니다.

[Step 3] VOD 인코딩 완료 후 Call Back 처리

VOD 인코딩 API 호출 시 파일 크기와 인코딩 진행 상황에 따라 결괏값을 받기까지 시간이 오래 걸릴 수 있습니다. 따라서 인코딩 진행 상태와 완료 결과를 SMS 문자메시지로 받아보면 편리한데요. 결과를 전달 받기 위해서는 VOD 인코딩 호출시 Call Back 함수를 지정하면 됩니다. (앞서 소개한 ‘vod_encoding_add_file Action 생성’ 파트에서 notificationUrl을 추가한 부분을 참고해 주세요.)

Call Back 받은 인코딩 진행 상태와 인코딩 결과 값은 DataBase에 업로드하거나 추가로 필요할 작업을 진행하게 되는데, 이번 테스트 코드에서는 담당자에게 SMS로 결과를 전달하도록 합니다.

SENS (Simple & Easy Notification Service) 설정

담당자에게 SMS 발송을 위해서는 SENS (Simple & Easy Notification Service) 사용을 위한 서비스 신청이 되어 있어야 합니다. SENS서비스는 별도의 메시지 서버 구축 없이 SMS, PUSH, 알림톡 등을 통해 메시지 알림 기능을 구현할 수 있는 서비스이며, Simple & Easy Notification Service 소개 가이드 문서(링크)를 참고하시면 손쉽게 설정할 수 있습니다.

Simple & Easy Notification Service 소개 페이지

vod-notification-callback Action 생성

VOD 인코딩 완료 후 Call Back으로 알림을 받는 과정입니다.

  • Call Back 받은 내용을 SMS 로 관리자에게 전달
  • contents = “VOD ENCODING STATUS :: “ + status
    contents = contents + “\n” + “File Path : “ + filePath
  • 콜백 함수는 Web API를 호출해야 하기 때문에 API G/W 추가 필수

이 액션을 호출할 수 있는 URL은 ‘외부 연결 주소 생성하기’ 기능으로 바로 생성합니다.

액션 종류는 python 3.7이며, 디폴트 파라미터 (세부 URI) 정보는 다음과 같습니다.


{"API_URL":"https://ncloud.apigw.ntruss.com" }

액션 소스는 다음과 같습니다.

import hashlib
import hmac
import base64
import requests
import time
import json
import sys
def main(args):

categoryId = str(args.get("categoryId"))
categoryName = args.get("categoryName")
encodingOptionId = str(args.get("encodingOptionId"))
filePath = args.get("filePath")
outputType = args.get("outputType")
status = args.get("status")
contents = "VOD ENCODING STATUS :: " + status
contents = contents + "\n" + "File Path : " + filePath

#print ("message : " + contents )

access_key = "************************"
secret_key = "*********************************"
REGION = "KR"
api_server = "https://sens.apigw.ntruss.com"
api_uri = "/sms/v2/services/ncp:sms:kr:253456297010:my-sens-proj-22/messages"
content_type="application/json"

timestamp = int(time.time() * 1000)
timestamp = str(timestamp)
secret_key = bytes(secret_key, 'UTF-8')
method = "POST"

message = method + " " + api_uri + "\n" + timestamp + "\n" + access_key
message = bytes(message, 'UTF-8')
signingKey = base64.b64encode(hmac.new(secret_key, message, digestmod=hashlib.sha256).digest())

http_header = {
'x-ncp-apigw-signature-v2': signingKey,
'x-ncp-apigw-timestamp': timestamp,
'x-ncp-iam-access-key': access_key,
'x-ncp-region_code':'KR',
'accept':'application/json; charset=utf-8',
'Content-Type':'application/json; charset=utf-8'
}

body = {
"type":"MMS",
"contentType":"COMM",
"countryCode":"82",
"from":"010XXXXXXXXXXX",
"subject":"vod-encoding-status",
"content":"vod upload success !!!",
"messages":[
{
"to":"010XXXXXXXXXXX",
"subject":"vod-encoding-status",
"content":contents
}
]
}

#print ("url :: " + api_server + api_uri)
response = requests.post(api_server + api_uri, headers = http_header, json = body)

data = json.loads(response.text)

return data

[Step 4] Video Player로 Adaptive HSL 스트리밍

업로드한 영상을 다른 사용자가 보는 단계입니다. 네이버 클라우드 플랫폼의 동영상 플레이어 Video Player를 활용하였습니다. (👉참고자료 : Video Player Demo 가이드)

ABR(Adaptive bitrate) 형식의 HLS 비디오는 사용자의 네트워크 상태에 따라 자동으로 초기 화질이 결정되며, 동영상 재생 중 원하는 해상도로 조정할 수 있습니다.

adaptive_bitrate.html 코드 예제

https://kr.object.ncloudstorage.com/demo-web/adaptive-bitrate.html

<!doctype html>
<html lang="kr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Video Player Sample</title>

//script src에 objectstorage에 저장된 ncpPlayer 주소 입력
// ex) https://kr.object.ncloudstorage.com/jinkyu-obj/player/ncplayer-1.3.0.umd.min-44df71b4.js
<script src="ncpPlayer 주소"></script>
</head>

<body>


<H1>Demo : video player 를 이용한 데모</H1>
<br>
참고 URL : (https://guide.ncloud-docs.com/docs/videoplayer-videoplayerdemo)
<br><br>
Source file : https://rprtgvsiljrc14805644.cdn.ntruss.com/hls/Rk0HNHrNCwfIt7DGBTcOzw__/media/1784/NAVER_1784_AVC_,UHD,FHD,HD,SD,_1Pass_30fps.mp4.smil/master.m3u8s
<br>

<div style="text-align:center">
<div id="divVideoPlayer" name="divVideoPlayer"></div>
</div>

<script>

var player = new ncplayer('divVideoPlayer', {
controls: true,
autostart: false,
mute: true,
width: 1024,
playlist: [
{
autostart: true, // for test
file: 'https://rprtgvsiljrc14805644.cdn.ntruss.com/hls/Rk0HNHrNCwfIt7DGBTcOzw__/media/1784/NAVER_1784_AVC_,UHD,FHD,HD,SD,_1Pass_30fps.mp4.smil/master.m3u8',

},
],
});

player.play();

</script>

</body>
</html>

맺음말

지금까지 네이버 클라우드 플랫폼 VOD StationCloud Functions를 활용하여 서버리스 방식으로 동영상 업로드, 인코딩 과정을 자동화하는 방법을 알아보았습니다.

​소개한 예제를 따라하는 데 어려움이 있으시면 댓글 또는 페이스북 유저 그룹, 오픈채팅방 (카톡)에 남겨주시기 바랍니다.

* 이 글은 네이버클라우드 Solution Architect 윤진규 님의 기여로 작성되었습니다.

--

--

NAVER Cloud
NAVER Cloud

We provide cloud-based information technology services for industry leaders from startups to enterprises.