기존 프로젝트에서 사용했던 Elastic Transcoder는 Rekognition API(FaceSearch)를 통해 비디오에서 특정얼굴이 탐색된 구간(timestamp)들을 하나로 묶어주는 'Clip Stitching'을 수행하기 위해 포함되던 서비스였다.
최근 확인한 바로 Elastic Transcoder가 2025년 11월로 서비스 종료한다는 이슈가 있었다.
그에 따라 이 서비스를 대체할 것을 찾아야했고, 공식에서 대체 서비스로 추천해주는 MediaConvert를 찾게되었다.
MediaConvert는 기존의 Elastic Transcoder가 지원했던 영상관련 트랜스코딩 등의 기능을 그대로 가지고 있고, 자막이나 워터마크같이 더 확장된 기능들을 지원하고있다.
기존 Elastic Transcoder에서 전환하기 비교적 간단하다고 판단했기에 MediaConvert를 선택하게 되었다.
로직 변경
아래는 기존에 Rekognition 탐지 결과로 Elastic Transcoder Job을 생성하는 부분이다.
# face search timestamp를 Transcoder에 맞게 변환
detected_timestamp_str = []
for scene in scene_timestamp:
start, end = scene
input = {
'Key' : sns_message['Video']['S3ObjectName'],
'TimeSpan': {
'StartTime': str(start/1000.),
'Duration': str((end-start)/1000.)
},
}
detected_timestamp_str.append(input)
try:
# elastic transcoder Job 생성
transcoder_job = tscoder.create_job(
PipelineId=pipeline_id,
Inputs=detected_timestamp_str,
Output={
'Key': job_id + '.mp4',
}
)
transjob_id = transcoder_job['Job']['Id']
transjob_status = transcoder_job['Job']['Status']
logger.info(f'Transcoder job : {transjob_id}')
logger.info(f'Transcoder job status : {transjob_status}')
dynamo.update_item(
TableName=TABLE_NAME,
Key={
'job_id': {'S': job_id}
},
UpdateExpression="SET job_status = :job_status, transcode_start = :transcode_start",
ExpressionAttributeValues={
':job_status': {'S': 'TRANSCODING'},
':transcode_start': {'S': str(datetime.now())}
}
)
이 부분은 MediaConvert를 사용하도록 전환해야하는데, MediaConvert도 마찬가지로 영상처리 Job을 생성해서 비동기로 처리하는 방식이다.
변경되는 부분은 크게 2가지다.
- Input(클립 구간 시간) 지정
- 작업 상태 확인
Input(클립 구간 시간) 지정
사실 MediaConvert와 Elastic Transcoder 둘다 job을 생성할때 설정값들을 JSON 파라미터 방식으로 입력해준다. 그리고 둘다 동일하게 Input과 Output 세팅을 통해 작업의 대상과 결과물에 대한 설정을 한다.
이 프로젝트의 clip stitching에서 달라지는 부분은 input으로 주는 탐지결과 구간들의 timestamp 형식이 있다.
Elastic Transcoder에서는 아래와 같이 `HH:mm:ss.SSS`나 `sssss.SSS`같은 timestamp 형식으로 TimeSpan에 StartTime과 Duration을 지정해준다.
detected_timestamp_str = []
for scene in scene_timestamp:
start, end = scene
input = {
'Key' : sns_message['Video']['S3ObjectName'],
'TimeSpan': {
'StartTime': str(start/1000.),
'Duration': str((end-start)/1000.)
},
}
detected_timestamp_str.append(input)
MediaConvert에서는 각 클립 구간의 시작과 끝 지점을 `Timecode`라는 포맷으로 입력한다.
Timecode는 `HH:MM:SS:FF`나 `HH:MM:SS;FF`로 표현하고, HH는 시간, MM은 분, SS는 초, FF는 프레임 번호를 입력한다.
def ms_to_timecode(ms):
total_seconds = ms // 1000
h = total_seconds // 3600
m = (total_seconds % 3600) // 60
s = total_seconds % 60
ms_remainder = ms % 1000
return f"{h:02d}:{m:02d}:{s:02d}.{ms_remainder:03d}"
...
# MediaConvert 형식으로 변환
input_clippings = []
for start_ms, end_ms in scene_timestamp:
input_clippings.append({
'StartTimecode': ms_to_timecode(start_ms),
'EndTimecode': ms_to_timecode(end_ms)
})
job_settings = {
'Inputs': [
{
'FileInputs': f's3://{OUTPUT_BUCKET}/videos/{video_name}',
'InputClippings': input_clippings
}
],
'OutputGroups': [
{
'Name': 'File Group',
'OutputGroupSettings': {
'Type': 'FILE_GROUP_SETTINGS',
'FileGroupSettings': {
'Destination': f's3://{OUTPUT_BUCKET}/results/'
}
},
'Outputs': [
.......
mediaconvert의 job과 관련된 API의 자세한 파라미터들은 아래 첨부된 Docs를 참고한다. (스압 주의)
Jobs - AWS Elemental MediaConvert API Reference
docs.aws.amazon.com
작업 상태 확인
Elastic Transcoder에서 Job을 생성할때에는 Job을 담는 Pipeline에 SNS Topic을 지정해서 작업이 완료되면 Topic으로 메시지를 전달해주는 구조였다.
MediaConvert에서는 Job을 담는 Queue 객체가 있다.
하지만 Queue에 SNS Topic을 직접적으로 연결하는 것이 아닌, EventBridge를 통해 작업 상태 변경 이벤트를 발생시킨다. 그리고 이를 SNS나 Lambda로 연결하는 구조를 지원한다. (그리고 Cloudwatch로도 MediaConvert의 Job의 Metric을 수집도 가능하다고 한다.)
Using EventBridge with AWS Elemental MediaConvert - MediaConvert
EventBridge delivers each event from the MediaConvert event stream at least once. MediaConvert does not require any additional permissions to deliver events to EventBridge.
docs.aws.amazon.com
아래와 같이 Eventbridge Rule을 작성해서 Status의 변화가 발생했을때 MediaConvert가 보내주는 이벤트를 감지할 수 있다.
{
"source": ["aws.mediaconvert"],
"detail-type": ["MediaConvert Job State Change"],
"detail": {
"status": ["PROGRESSING"]
}
}
MediaConvert의 Job은 아래와 같은 흐름을 가지고 Elastic Transcoder에 비해 조금 확장된 Status들을 가진다.
그리고 MediaConvert Job의 Status에 따라 발생할 수 있는 이벤트 종류는 아래와 같다. Eventbridge에서 이러한 이벤트 이름을 통해 앞서 제시해준 포맷을 통해 rule을 생성할 수 있다.
이 중에서 STATUS_UPDATE는 MediaConvert에 Job이 생성된지 약 1분 후부터 주기적으로 발생되는 이벤트인데, 이 이벤트 속에는 현재 Job이 무슨 상태에 있는지 비교적 정확하게 작성되어있다.
(참고로, STATUS_UPDATE의 발생주기는 job setting에서 `StatusUpdateInterval`을 통해 변경할 수 있다.)
{
"version": "0",
"id": "1234abcd-12ab-34cd-56ef-1234567890ab",
"detail-type": "MediaConvert Job State Change",
"source": "aws.mediaconvert",
"account": "111122223333",
"time": "2022-12-19T19:21:21Z",
"region": "us-west-2",
"resources": [
"arn:aws:mediaconvert:us-west-2:111122223333:jobs/1671477617078-2886ye"
],
"detail": {
"timestamp": 1671477681737,
"accountId": "111122223333",
"queue": "arn:aws:mediaconvert:us-west-2:111122223333:queues/Default",
"jobId": "1671477617078-2886ye",
"status": "STATUS_UPDATE",
"userMetadata": {},
"framesDecoded": 353,
"jobProgress": { # 상세한 Progress를 볼 수 있다
"phaseProgress": {
"PROBING": {
"status": "COMPLETE", # Job에 사용할 정보들을 다 읽은 상태
"percentComplete": 100
},
"TRANSCODING": {
"status": "PROGRESSING", # Transcoding 작업을 진행중
"percentComplete": 2
},
"UPLOADING": {
"status": "PENDING",
"percentComplete": 0
}
},
"jobPercentComplete": 7, # 전체 작업 중 완료된 비율, 사용자 단에는 이 값을 보여주면될듯
"currentPhase": "TRANSCODING",
"retryCount": 0
}
}
}