참고: VOD Streaming Server 구축 1 (AWS)
참고: VOD Streaming Server 구축 2 (AWS)
참고: VOD Streaming Server 구축 3 (AWS)
VOD Streaming Server 구축 3 (AWS) 에서 lambda function을 만들고 trigger 및 권한 설정하는 과정을 완료하였다.
지금부터는 lambda function을 수정하여 event를 받아 media convert에 job을 생성할 수 있도록 수정해 보도록 한다.
MediaConvert로 이동한다.
파란 부분을 선택해서 detail page로 들어가게 되면 View JSON버튼을 볼 수 있다.
Copy버튼을 눌러서 전체를 복사한다. 시재로 관심이 있는 부분은 Settings 부분이다.
Settings 안쪽만 남기고 나머지 부분은 모두 삭제한다.
job.json file
{
"TimecodeConfig":{
"Source":"ZEROBASED"
},
"OutputGroups":[
{
"Name":"Apple HLS",
"Outputs":[
{
"ContainerSettings":{
"Container":"M3U8",
"M3u8Settings":{
}
},
"VideoDescription":{
"Width":720,
"Height":480,
"CodecSettings":{
"Codec":"H_264",
"H264Settings":{
"MaxBitrate":1500000,
"RateControlMode":"QVBR",
"SceneChangeDetect":"TRANSITION_DETECTION"
}
}
},
"AudioDescriptions":[
{
"CodecSettings":{
"Codec":"AAC",
"AacSettings":{
"Bitrate":96000,
"CodingMode":"CODING_MODE_2_0",
"SampleRate":48000
}
}
}
],
"OutputSettings":{
"HlsSettings":{
}
},
"NameModifier":"720x480_1.5mbps_qvbr"
},
{
"ContainerSettings":{
"Container":"M3U8",
"M3u8Settings":{
}
},
"VideoDescription":{
"Width":1280,
"Height":720,
"CodecSettings":{
"Codec":"H_264",
"H264Settings":{
"MaxBitrate":4000000,
"RateControlMode":"QVBR",
"SceneChangeDetect":"TRANSITION_DETECTION"
}
}
},
"AudioDescriptions":[
{
"CodecSettings":{
"Codec":"AAC",
"AacSettings":{
"Bitrate":96000,
"CodingMode":"CODING_MODE_2_0",
"SampleRate":48000
}
}
}
],
"OutputSettings":{
"HlsSettings":{
}
},
"NameModifier":"1280x720_4mbps_qvbr"
},
{
"ContainerSettings":{
"Container":"M3U8",
"M3u8Settings":{
}
},
"VideoDescription":{
"Width":1920,
"Height":1080,
"CodecSettings":{
"Codec":"H_264",
"H264Settings":{
"MaxBitrate":8000000,
"RateControlMode":"QVBR",
"SceneChangeDetect":"TRANSITION_DETECTION"
}
}
},
"AudioDescriptions":[
{
"CodecSettings":{
"Codec":"AAC",
"AacSettings":{
"Bitrate":96000,
"CodingMode":"CODING_MODE_2_0",
"SampleRate":48000
}
}
}
],
"OutputSettings":{
"HlsSettings":{
}
},
"NameModifier":"1920x1080_8mbps_qvbr"
}
],
"OutputGroupSettings":{
"Type":"HLS_GROUP_SETTINGS",
"HlsGroupSettings":{
"SegmentLength":10,
"Destination":"s3://output/vod/hls/",
"MinSegmentLength":0
}
}
}
],
"Inputs":[
{
"AudioSelectors":{
"Audio Selector 1":{
"DefaultSelection":"DEFAULT"
}
},
"VideoSelector":{
},
"TimecodeSource":"ZEROBASED",
"FileInput":"s3://input/vod/mp4/Wood Anemones-112429.mp4"
}
]
}
new file
파일 생성완료.
이제 미리 준비해놓았던 json 파일 내용을 복사해서 붙여넣는다.
저장을 위해서 deploy버튼을 눌러준다.
혹시 이 권한이 생각나지 않는 사람들을 위해 아래에 설명을 해 놓았다.
VOD Streaming Server 구축 3 (AWS) 에서 role_lambda_vod_execution 만들 때 지정했던 권한
위의 권한을 지정해 주지 않으면 권한 문제로 프로그램이 실행되지 않는다.
Template를 이용해서 S3에 파일이 추가될 때 발생하는 Event를 미리 선언해서 테스트 해 볼 수 있다.
각자 자유롭게 설정 가능
{
"Records": [
{
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "us-east-1",
"eventTime": "1970-01-01T00:00:00.000Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "EXAMPLE"
},
"requestParameters": {
"sourceIPAddress": "127.0.0.1"
},
"responseElements": {
"x-amz-request-id": "EXAMPLE123456789",
"x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "testConfigRule",
"bucket": {
"name": "input",
"ownerIdentity": {
"principalId": "EXAMPLE"
},
"arn": "arn:aws:s3:::input"
},
"object": {
"key": "vod/dev/mp4/1/174e7217-bd3e-4aa2-a72b-a24b4eb6e3e4/Anime-84574.mp4",
"size": 1024,
"eTag": "0123456789abcdef0123456789abcdef",
"sequencer": "0A1B2C3D4E5F678901"
}
}
}
]
}
Save버튼 클릭
import json
import os
import uuid
import boto3
import urllib.parse
def lambda_handler(event, context):
print('event: ')
print(event)
status_code = 200
body = {'messgae': 'Job 생성이 완료되었습니다.'}
# Source ---------------------------------------------------
# input
source_s3_bucket = event['Records'][0]['s3']['bucket']['name']
# vod/dev/mp4/1/174e7217-bd3e-4aa2-a72b-a24b4eb6e3e4/Anime-84574.mp4
source_s3_key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
# s3://input/vod/dev/mp4/1/174e7217-bd3e-4aa2-a72b-a24b4eb6e3e4/Anime-84574.mp4
source_s3 = 's3://' + source_s3_bucket + '/' + source_s3_key
# Anime-84574
source_s3_base_name = os.path.splitext(os.path.basename(source_s3))[0] # Anime-84574
# Destination ---------------------------------------------------
# s3://output
destination_s3 = 's3://' + os.environ['DestinationBucket']
# output
destination_s3_base_name = os.path.splitext(os.path.basename(destination_s3))[0]
# arn:aws:iam::123456:role/service-role/mediaconvert_mp4_to_hls_role
media_convert_role = os.environ['MediaConvertRole']
# ap-northeast-2 (서울)
region = os.environ['AWS_DEFAULT_REGION']
# Job 생성 ---------------------------------------------------
job_metadata = {}
splitted = source_s3_key.split('/')
if len(splitted) == 6:
base_folder = splitted[0] # vod
server_type = splitted[1] # dev (qa, prod etc)
file_type = splitted[2] # mp4
member_seq = splitted[3] # 1
uuid = splitted[4] # 174e7217-bd3e-4aa2-a72b-a24b4eb6e3e4
file_name = splitted[5] # Anime-84574.mp4
job_metadata['assetID'] = uuid
job_metadata['baseFolder'] = base_folder
job_metadata['serverType'] = server_type
job_metadata['fileType'] = file_type
job_metadata['memberSeq'] = member_seq
job_metadata['fileName'] = file_name
# vod/dev/hls/174e7217-bd3e-4aa2-a72b-a24b4eb6e3e4/Anime-84574
job_metadata['outputPath'] = job_metadata['baseFolder'] + '/' + job_metadata['serverType'] + '/' + 'hls/' + job_metadata['assetID'] + '/' + source_s3_base_name
job_metadata['outputExtension'] = '.m3u8'
else:
status_code = 400
body['message'] = '지정된 규칙과 일치하지 않습니다. \n vod/서버종류/파일종류/맴버시퀀스/UUID/파일이름 \n ex)vod/dev/mp4/1/174e7217-bd3e-4aa2-a72b-a24b4eb6e3e4/Anime-84574.mp4 '
return {
'status_code': status_code,
'headers': {'Content-Type':'application/json', 'Access-Control-Allow-Origin': '*'},
'body': body
}
print('job_metadata: ')
print(job_metadata)
try:
with open('job.json') as file:
job_settings = json.load(file)
mc_client = boto3.client('mediaconvert', region_name=region)
endpoints = mc_client.describe_endpoints()
client = boto3.client('mediaconvert',
region_name=region,
endpoint_url=endpoints['Endpoints'][0]['Url'], # https://bnklbqvoa.mediaconvert.ap-northeast-2.amazonaws.com
verify=False)
# change input file name
# s3://input/vod/dev/mp4/1/174e7217-bd3e-4aa2-a72b-a24b4eb6e3e4/Anime-84574.mp4
job_settings['Inputs'][0]['FileInput'] = source_s3
# vod/dev/hls/174e7217-bd3e-4aa2-a72b-a24b4eb6e3e4/Anime-84574
s3_key_hls = job_metadata['outputPath']
# s3:out/vod/dev/hls/174e7217-bd3e-4aa2-a72b-a24b4eb6e3e4/Anime-84574
destination_s3_final = destination_s3 + '/' + s3_key_hls
# change output path
job_settings['OutputGroups'][0]['OutputGroupSettings']['HlsGroupSettings']['Destination'] = destination_s3_final
job = client.create_job(Role=media_convert_role,
UserMetadata=job_metadata,
Settings=job_settings)
except Exception as error:
print('Exception: ')
print(error)
status_code = 500
body['message'] = 'MediaConvert Job 생성중 에러발생'
raise
finally:
return {
'status_code': status_code,
'headers': {'Content-Type':'application/json', 'Access-Control-Allow-Origin': '*'},
'body': body
}
return {
'status_code': status_code,
'headers': {'Content-Type':'application/json', 'Access-Control-Allow-Origin': '*'},
'body': body
}
Test버튼을 눌러서 테스트를 실행한다.
테스트가 완료되는 response를 확인할 수 있다.
JOB이 잘 생성된 것을 확인할 수 있다.
여기에서 Error가 발생한 이유는 Input파일이 존재하지 않는 경로를 넣어주었기 때문이다.
규칙
vod/dev/mp4/1/5a17bf91-06e9-11ed-affd-0242ac110002/
나중에 Backend server에서 vod 파일을 올릴 때는 위의 규칙에 맞게 소프트웨어로 생성해 줄 수 있지만 지금은 안되니 이렇게 미리 폴더를 수동으로 만들어 놓았다.
이제 여기에 동영상 파일을 하나 올리자
Seoul - 21985.mp4 라는 파일을 올렸다.
변환 진행 중
변환 완료
의도했던 것처럼 m3u8 형식의 index파일과 일정 시간 단위로 나누어진 ts 파일이 생성된 것을 확인할 수 있다.
생성된 CloudFront를 보면 Domain name을 확인할 수 있다.
HLS 파일을 Play 하려면 Akamai Player의 도움이 필요하다.
현재 https 관련 설정을 하지 않았기 때문에 akamai player도 http로 접속해야 한다. (http://players.akamai.com/players/hlsjs)
파일 이름을 클릭한다.
상세화면 Object URL에서 힌트를 얻을 수 있다.
http://[cloudfront-domain-name]/vod/dev/hls/5a17bf91-06e9-11ed-affd-0242ac110002/Seoul+-+21985.m3u8 을 주소창에 입력하면 결과를 동영상이 다운받아져서 동작하는 것을 확인할 수 있다.
감사합니다!