- AWS MediaConvert SDK 사용 방법 (2) - Job 생성 코드2023년 08월 18일
- 알쓸개잡
- 작성자
- 2023.08.18.오전01:49
이전 포스팅에서는 MediaConvert 를 사용하기 위한 role 을 생성하는 방법에 대해서 알아 보았습니다. 이번 포스팅에서는 Spring Boot 프로젝트에 MediaConvert SDK 를 사용하여 Job 을 생성하는 샘플코드를 작성해 보겠습니다.
AWS MediaConvert 디펜던시
AWS MediaConvert SDK 를 사용하기 위해서는 software.amazon.awssdk:mediaconvert 디펜던시가 필요합니다.
샘플코드를 작성하기 이전에 트랜스코딩 대상 미디어 파일은 S3 에 업로드 되어 있다고 가정하겠습니다.
<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.20.87</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>io.awspring.cloud</groupId> <artifactId>spring-cloud-aws-dependencies</artifactId> <version>3.0.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> ... <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>mediaconvert</artifactId> </dependency> <dependency> <groupId>io.awspring.cloud</groupId> <artifactId>spring-cloud-aws-starter-sns</artifactId> </dependency> <dependency> <groupId>io.awspring.cloud</groupId> <artifactId>spring-cloud-aws-autoconfigure</artifactId> </dependency> ... </dependencies>
software.amazon.awssdk (AWS java SDK) 와 io.awspring.cloud 에 정의된 패키지들을 사용할 것입니다.
io.awspring.cloud (spring cloud AWS) 는 AWS 관련 서비스를 사용하기 위한 인프라 관련 코드를 최대한 피할 수 있도록 Spring 에서 제공하는 Spring 기반 통합 모듈입니다. 즉, AWS 서비스를 사용하기 위한 코드를 보다 간단한 설정으로 사용할 수 있게 해줍니다.
io.awspring.cloud 관련 내용은 아래 링크를 참고하시면 도움이 됩니다.
참고로 mediaconvert artifact 가 어떤 버전을 사용하는지 확인하려면
software.amazon.awssdk:bom 파일과 software.amazon.aswsdk:aws-sdk-java-pom 파일을 살펴보면 됩니다.
software.amazon.awssdk:bom 파일을 보면 아래와 같이 정의 되어 있습니다.
<parent> <groupId>software.amazon.awssdk</groupId> <artifactId>aws-sdk-java-pom</artifactId> <version>2.20.87</version> <relativePath>../pom.xml</relativePath> </parent> .... <dependencyManagement> <dependencies> ... ... <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>mediaconvert</artifactId> <version>${awsjavasdk.version}</version> </dependency> ... ... </dependencies> </dependencyManagement>
software.amazon.awssdk:aws-sdk-java-pom 파일에 보면 awsjavasdk.version 을 확인할 수 있습니다.
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>software.amazon.awssdk</groupId> <artifactId>aws-sdk-java-pom</artifactId> <version>2.20.87</version> <packaging>pom</packaging> <name>AWS Java SDK :: Parent</name> ... ... <properties> ... <awsjavasdk.version>${project.version}</awsjavasdk.version> ... </properties> ... ... </project>
예시에서 사용된 software.amazon.awssdk 의 project.version 은 2.20.87 임을 알 수 있습니다.
application.yml 설정
... spring: cloud: aws: credentials: access-key: ${AWS_ACCESS_KEY} secret-key: ${AWS_SECRET_KEY} region: static: ${AWS_REGION} media-convert: role-arn: <MediaConvert role arn 정보를 입력합니다> ...
spring.cloud.aws.credentials 는 spring cloud AWS 모듈에서 참조하는 정보로써 AWS 계정 인증 정보를 입력합니다.
예시에서는 AWS_ACCESS_KEY, AWS_SECRET_KEY, AWS_REGION 을 시스템 환경변수로 등록하여 설정한 것입니다. 환경 변수로 등록하지 않고 직접 값을 입력해도 됩니다.
media-convert.role-arn 에는 앞선 AWS MediaConvert SDK 사용 방법 (1) - role 생성하기 에서 생성한 role 의 arn 정보를 입력합니다.
MediaConvertClient Bean 생성
package global.voda.operator.config; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.regions.providers.AwsRegionProvider; import software.amazon.awssdk.services.mediaconvert.MediaConvertClient; import software.amazon.awssdk.services.mediaconvert.model.DescribeEndpointsRequest; import software.amazon.awssdk.services.mediaconvert.model.DescribeEndpointsResponse; import java.net.URI; @Slf4j @Configuration public class AwsMediaConvertConfig { @Bean public MediaConvertClient mediaConvertClient(AwsCredentialsProvider credentialsProvider, AwsRegionProvider regionProvider) { DescribeEndpointsResponse describeEndpointsResponse = MediaConvertClient.builder() .credentialsProvider(credentialsProvider) .region(regionProvider.getRegion()) .build() .describeEndpoints( //한번에 반환할 MediaConvert 서비스 endpoint 최대 개수 지정 DescribeEndpointsRequest.builder().maxResults(20).build() ); if (describeEndpointsResponse.endpoints().size() == 0) { log.error("cannot find MediaConvert service endpoint URL"); throw new RuntimeException("cannot find MediaConvert service endpoint URL"); } String endPointUrl = describeEndpointsResponse.endpoints().get(0).url(); if (log.isDebugEnabled()) { log.debug("MediaConvert endpoint URL: {}", endPointUrl); } //가져온 MediaConvert 서비스 endpoint URL 을 MediaConvertClient 에 셋팅하여 //MediaConvertClient Bean 을 생성 return MediaConvertClient.builder() .region(regionProvider.getRegion()) .endpointOverride(URI.create(endPointUrl)) .build(); } }
AwsCredentialsProvider, AwsRegionProvider 는 spring.cloud.aws.credentials 설정을 기반으로 자동 주입됩니다.
MediaConvert Job 생성 코드
package com.example.mediaconvert.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import software.amazon.awssdk.services.mediaconvert.MediaConvertClient; import software.amazon.awssdk.services.mediaconvert.model.*; @Service @Slf4j @RequiredArgsConstructor public class MediaConvertServiceEx { @Value("${media-convert.role-arn:}") private String roleArn; private final MediaConvertClient mediaConvertClient; /** * 동영상을 트랜스 코딩하기 위해서 media convert job 을 생성하는 메소드 * * @param s3InputPath 트랜스코딩 대상 영상 파일 S3 object 경로 * @param s3OutputPath 트랜스코딩 결과 파일 저장하기 위한 S3 object 경로 * @throws MediaConvertException MediaConvert 예외 */ public void videoConvert(String s3InputPath, String s3OutputPath) throws MediaConvertException { Output.Builder outputBuilder = commonOutputBuilder(); Output output = outputBuilder.videoDescription( VideoDescription.builder() .codecSettings(VideoCodecSettings.builder() //mp4 형식 출력 .codec(VideoCodec.H_264) .h264Settings(H264Settings.builder() .maxBitrate(1000000) .rateControlMode(H264RateControlMode.QVBR) .sceneChangeDetect(H264SceneChangeDetect.TRANSITION_DETECTION) .build()) .build()) .build() ).build(); OutputGroup.Builder outputGroupBuilder = commonOutputGroupBuilder(s3OutputPath); OutputGroup outputGroup = outputGroupBuilder .outputs(output) .build(); Input input = Input.builder() .timecodeSource(InputTimecodeSource.ZEROBASED) .fileInput(s3InputPath) .build(); executeMediaConvert(outputGroup, input); } /** * 이미지를 정지 영상으로 생성하기 위해서 media convert job 을 생성하는 메소드 * * @param s3InputPath 이미지 파일 S3 object 경로 * @param s3OutputPath 트랜스코딩 결과 파일 저장하기 위한 S3 object 경로 * @param width 이미지 파일 가로 해상도 * @param height 이미지 파일 세로 해상도 * @param timeDurationMs 트랜스 코딩된 영상 재생시간 (MS) * @throws MediaConvertException MediaConvert 예외 */ public void imageConvert(String s3InputPath, String s3OutputPath, int width, int height, int timeDurationMs) throws MediaConvertException { int outputWidth = (int) (Math.ceil((double) width / 2) * 2); int outputHeight = (int) (Math.ceil((double) height / 2) * 2); int framerateNumerator = 30; int framerateDenominator = 1; Output.Builder outputBuilder = commonOutputBuilder(); Output output = outputBuilder.videoDescription( VideoDescription.builder() .width(outputWidth) .height(outputHeight) .videoPreprocessors(VideoPreprocessor.builder() .imageInserter(ImageInserter.builder() .insertableImages(InsertableImage.builder() .imageX(0) .imageY(0) .layer(1) .imageInserterInput(s3InputPath) .opacity(100) .build()) .build()) .build()) .codecSettings(VideoCodecSettings.builder() .codec(VideoCodec.H_264) .h264Settings(H264Settings.builder() .maxBitrate(1000000) .framerateDenominator(framerateDenominator) .framerateControl(H264FramerateControl.SPECIFIED) .framerateNumerator(framerateNumerator) .rateControlMode(H264RateControlMode.QVBR) .sceneChangeDetect(H264SceneChangeDetect.TRANSITION_DETECTION) .build()) .build()) .build() ).build(); OutputGroup.Builder outputGroupBuilder = commonOutputGroupBuilder(s3OutputPath); OutputGroup outputGroup = outputGroupBuilder .outputs(output) .build(); double oneFrameTime = (double) framerateDenominator / framerateNumerator; int oneFrameTimeMs = (int)(oneFrameTime * 1000); //마지막에 1 frame 시간이 재생시간에 추가되기 때문에 재생시간에서 1 frame 만큼의 시간을 빼준다. Input input = Input.builder() .videoGenerator(InputVideoGenerator.builder() .duration(timeDurationMs - oneFrameTimeMs) .build()) .build(); executeMediaConvert(outputGroup, input); } private void executeMediaConvert(OutputGroup outputGroup, Input input) { try { JobSettings jobSettings = JobSettings.builder() .timecodeConfig(TimecodeConfig.builder() .source(TimecodeSource.ZEROBASED) .build()) .inputs(input) .outputGroups(outputGroup) .build(); CreateJobRequest createJobRequest = CreateJobRequest.builder() .role(roleArn) .settings(jobSettings) .build(); CreateJobResponse jobResponse = mediaConvertClient.createJob(createJobRequest); log.info("success to create image media convert job, id={}", jobResponse.job().id()); } catch (MediaConvertException e) { log.error("failure create image media convert job, {}", e.getMessage()); throw e; } } private OutputGroup.Builder commonOutputGroupBuilder(String s3OutputPath) { return OutputGroup.builder() .name("File Group") .outputGroupSettings(OutputGroupSettings.builder() .type(OutputGroupType.FILE_GROUP_SETTINGS) .fileGroupSettings(FileGroupSettings.builder() .destination(s3OutputPath) .build()) .build()); } private Output.Builder commonOutputBuilder() { return Output.builder() .containerSettings(ContainerSettings.builder() .container(ContainerType.MP4) .build()); } }
샘플 코드에는 동영상 파일을 트랜스코딩 하는 메소드와 이미지 파일을 정지된 동영상 파일로 트랜스코딩 하는 메소드가 있습니다.
이미지 파일 하나를 정지된 동영상 파일로 만드는 경우에는 MediaConvert Job Input 에 재생하고자 하는 시간 길이의 black video 를 생성하고 Output 에는 Encoding settings 에서 Image inserter 에 input 이미지를 지정해서 만듭니다.
MediaConvert Job 생성 샘플 코드
package com.example.mediaconvert; import com.example.mediaconvert.service.MediaConvertServiceEx; import lombok.RequiredArgsConstructor; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @RequiredArgsConstructor public class MediaconvertApplication implements CommandLineRunner { private final MediaConvertServiceEx mediaConvertServiceEx; public static void main(String[] args) { SpringApplication.run(MediaconvertApplication.class, args); } @Override public void run(String... args) throws Exception { //이미지 해상도 600 * 120 String input = "s3://my-media-convert-source/600x120.png"; String output = "s3://my-media-convert-target/600x120"; //출력 영상 재생시간은 15초 mediaConvertServiceEx.imageConvert(input, output, 600, 120, 15000); } }
참고로 이미지의 경우 해상도 정보는 tika 라이브러리를 통해서 이미지 해상도 정보를 얻어 올 수 있습니다.
위와 같이 실행해 봤을 때 생성된 MediaConvert Job id 는 아래와 같습니다.
AWS 관리 콘솔 상에서 Job 이 정상적으로 생성이 되었는지 확인해 봅니다.
MediaConvert Job 생성을 위한 셋팅 요소들이 많기 때문에 JOB 생성을 위한 SDK 를 사용하기 전에 AWS 관리 콘솔에서 JOB 을 직접 생성한 후에 Job 목록에서 해당 Job ID 의 상세 정보 페이지에서 [View JSON] 으로 Job 에 대한 명세를 보고 SDK 를 사용하면 많은 도움이 됩니다.
지금까지 MediaConvert SDK 를 이용하여 Job 을 생성하는 샘플코드를 작성해 봤습니다.
다음 포스팅에서는 AWS SNS 를 통해 요청된 Job 의 완료 이벤트를 REST API 기반으로 수신하는 방법에 대해서 알아 보겠습니다.
'AWS' 카테고리의 다른 글
bitbucket pipeline을 이용한 AWS ECS 애플리케이션 배포 (0) 2023.10.23 AWS MediaConvert SDK 사용 방법 (3) - SNS 연결하기 (0) 2023.08.18 AWS MediaConvert SDK 사용 방법 (1) - role 생성하기 (0) 2023.08.17 AWS SES 사용하기 (0) 2023.07.31 다음글이전글이전 글이 없습니다.댓글