튜토리얼: S3 Batch Operations로 비디오 일괄 트랜스코딩하기

튜토리얼: S3 Batch Operations로 비디오 일괄 트랜스코딩하기

비디오를 보는 사람들의 기기 종류는 정말 다양해요. 화면 크기, 형식, 비트레이트가 제각각이라서 영상을 하나의 형식으로만 제공할 수 없죠. 특히 변환해야 할 비디오 수가 많으면 이 작업은 더 어려워져요. 이 튜토리얼에서는 S3 Batch Operations가 S3 소스 버킷에 있는 기존 비디오에 대해 Lambda 함수를 호출하고, Lambda 함수가 AWS Elemental MediaConvert를 호출해 대규모 트랜스코딩을 수행하는 구조를 단계별로 만들어 볼게요.

출처: 문서

본문

영상 소비자들은 모양, 크기, 연식이 제각각인 기기를 사용해 미디어 콘텐츠를 즐겨요. 이처럼 다양한 기기는 콘텐츠 제작자와 배포자에게 도전 과제를 줘요. 비디오는 하나의 보편적 형식(one-size-fits-all)으로 제공되는 대신, 넓은 범위의 크기·형식·비트레이트를 아우르도록 변환되어야 하니까요. 변환해야 할 비디오 수가 많을 때는 이 변환 작업이 더 까다로워져요.

AWS는 다음과 같은 확장 가능하고 분산된 아키텍처를 구축할 방법을 제공해요.

  • 입력 비디오를 수집(ingest)한다
  • 광범위한 기기에서 재생되도록 비디오를 처리한다
  • 트랜스코딩된 미디어 파일을 저장한다
  • 수요에 맞춰 출력 미디어 파일을 전달한다

Amazon S3에 방대한 비디오 저장소가 있다면, 이 비디오들을 소스 형식에서 특정 비디오 플레이어나 기기가 필요로 하는 크기·해상도·형식의 여러 파일 유형으로 트랜스코딩할 수 있어요. 특히 S3 Batch Operations는 S3 소스 버킷에 있는 기존 입력 비디오에 대해 AWS Lambda 함수를 호출하는 솔루션을 제공해요. 그러면 Lambda 함수가 AWS Elemental MediaConvert를 호출해 대규모 비디오 트랜스코딩 작업을 수행합니다. 변환된 출력 미디어 파일은 S3 대상 버킷에 저장돼요.

이 튜토리얼에서는 S3 소스 버킷에 저장된 비디오를 일괄 트랜스코딩하기 위해 S3 Batch Operations가 Lambda 함수를 호출하도록 설정하는 방법을 배워요. Lambda 함수는 MediaConvert를 호출해 비디오를 트랜스코딩해요. S3 소스 버킷의 각 비디오 출력은 다음과 같아요.

  • 여러 크기와 다양한 대역폭의 기기에서 재생할 수 있는 HTTP Live Streaming(HLS) 적응형 비트레이트 스트림

  • MP4 비디오 파일

  • 일정 간격으로 수집된 썸네일 이미지

  • 사전 요구 사항

  • 1단계: 출력 미디어 파일용 S3 버킷 만들기

  • 2단계: MediaConvert용 IAM 역할 만들기

  • 3단계: Lambda 함수용 IAM 역할 만들기

  • 4단계: 비디오 트랜스코딩용 Lambda 함수 만들기

  • 5단계: S3 소스 버킷용 Amazon S3 Inventory 구성

  • 6단계: S3 Batch Operations용 IAM 역할 만들기

  • 7단계: S3 Batch Operations 작업 만들기 및 실행

  • 8단계: S3 대상 버킷에서 출력 미디어 파일 확인

  • 9단계: 정리(Clean up)

  • 다음 단계

사전 요구 사항

이 튜토리얼을 시작하기 전에 트랜스코딩할 비디오가 이미 저장된 Amazon S3 소스 버킷(예: amzn-s3-demo-source-bucket)이 있어야 해요.

원한다면 버킷에 다른 이름을 지정할 수 있어요. Amazon S3의 버킷 이름에 대한 자세한 내용은 General purpose bucket naming rules 문서를 참고하세요.

S3 소스 버킷의 경우 이 버킷에 대한 Block Public Access 설정은 기본값으로 유지하세요(모든 공개 액세스 차단이 활성화됨). 자세한 내용은 Creating a general purpose bucket 문서를 참고하세요.

S3 소스 버킷에 비디오를 업로드하는 방법은 Uploading objects 문서를 참고하세요. 큰 비디오 파일을 S3에 많이 업로드한다면 Amazon S3 Transfer Acceleration을 사용해 빠르고 안전한 파일 전송을 구성할 수도 있어요. Transfer Acceleration은 더 큰 비디오를 장거리 전송할 때 S3 버킷으로의 비디오 업로드를 빠르게 해 줄 수 있어요. 자세한 내용은 Configuring fast, secure file transfers using Amazon S3 Transfer Acceleration 문서를 참고하세요.

1단계: 출력 미디어 파일용 S3 버킷 만들기

이 단계에서는 변환된 출력 미디어 파일을 저장할 S3 대상 버킷을 만들어요. 또한 S3 대상 버킷에 저장된 트랜스코딩 미디어 파일에 대한 교차 출처 접근을 허용하는 CORS(Cross Origin Resource Sharing) 구성도 만들어요.

  • 출력 미디어 파일용 버킷 만들기
  • S3 출력 버킷에 CORS 구성 추가

출력 미디어 파일용 버킷 만들기

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Buckets를 선택해요.
  3. Create bucket을 선택해요.
  4. Bucket name에 버킷 이름을 입력해요(예: amzn-s3-demo-destination-bucket1).
  5. Region에서 버킷을 둘 AWS 리전을 선택해요.
  6. 출력 미디어 파일에 대한 공개 접근을 보장하려면 Block Public Access settings for this bucket에서 Block all public access를 해제해요.

경고 이 단계를 완료하기 전에 Blocking public access to your Amazon S3 storage 문서를 검토해 공개 액세스를 허용할 때의 위험을 이해하고 수용하는지 확인하세요. Block Public Access 설정을 꺼서 버킷을 공개하면 인터넷의 누구나 버킷에 접근할 수 있어요. 버킷에 대한 모든 공개 액세스를 차단하는 것을 권장해요. Block Public Access 설정을 해제하고 싶지 않다면 Amazon CloudFront를 사용해 트랜스코딩된 미디어 파일을 시청자(최종 사용자)에게 전달할 수 있어요. 자세한 내용은 Tutorial: Hosting on-demand streaming video with Amazon S3, Amazon CloudFront, and Amazon Route 53 문서를 참고하세요.

  1. I acknowledge that the current settings might result in this bucket and the objects within becoming public 옆의 확인란을 선택해요.
  2. 나머지 설정은 기본값으로 유지해요.
  3. Create bucket을 선택해요.

S3 출력 버킷에 CORS 구성 추가

JSON CORS 구성은 한 도메인에서 로드된 클라이언트 웹 애플리케이션(여기서는 비디오 플레이어)이 다른 도메인의 트랜스코딩된 출력 미디어 파일을 재생하는 방법을 정의해요.

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Buckets를 선택해요.
  3. Buckets 목록에서 이전에 만든 버킷 이름(예: amzn-s3-demo-destination-bucket1)을 선택해요.
  4. Permissions 탭을 선택해요.
  5. Cross-origin resource sharing (CORS) 섹션에서 Edit을 선택해요.
  6. CORS configuration 텍스트 상자에 다음 CORS 구성을 복사해 붙여 넣어요. CORS 구성은 JSON 형식이어야 해요. 이 예제에서 AllowedOrigins 속성은 와일드카드 문자(*)를 사용해 모든 출처를 지정해요. 특정 출처를 알고 있다면 AllowedOrigins 속성을 특정 플레이어 URL로 제한할 수 있어요. 이 속성과 다른 속성 구성에 대한 자세한 내용은 Elements of a CORS configuration 문서를 참고하세요.
[
    {
        "AllowedOrigins": [
            "*"
        ],
        "AllowedMethods": [
            "GET"
        ],
        "AllowedHeaders": [
            "*"
        ],
        "ExposeHeaders": []
    }
]
  1. Save changes를 선택해요.

2단계: MediaConvert용 IAM 역할 만들기

AWS Elemental MediaConvert를 사용해 S3 버킷에 저장된 입력 비디오를 트랜스코딩하려면, MediaConvert가 S3 소스 및 대상 버킷에서 비디오 파일을 읽고 쓰도록 권한을 부여하는 AWS Identity and Access Management(IAM) 서비스 역할이 있어야 해요. 트랜스코딩 작업을 실행할 때 MediaConvert 콘솔이 이 역할을 사용해요.

  1. 원하는 역할 이름으로 IAM 역할을 만들어요(예: tutorial-mediaconvert-role). 이 역할을 만들려면 AWS Elemental MediaConvert User Guide의 Create your MediaConvert role in IAM (console) 문서의 단계를 따라요.
  2. MediaConvert용 IAM 역할을 만든 후 Roles 목록에서 만든 MediaConvert 역할 이름(예: tutorial-mediaconvert-role)을 선택해요.
  3. Summary 페이지에서 arn:aws:iam::로 시작하는 Role ARN을 복사하고, 나중에 사용할 수 있도록 저장해요. ARN에 대한 자세한 내용은 AWS General Reference의 Amazon Resource Names (ARNs) 문서를 참고하세요.

3단계: Lambda 함수용 IAM 역할 만들기

MediaConvert와 S3 Batch Operations로 비디오를 일괄 트랜스코딩하려면, 이 두 서비스를 연결해 비디오를 변환하는 Lambda 함수를 사용해요. 이 Lambda 함수에는 MediaConvert와 S3 Batch Operations에 접근할 권한을 부여하는 IAM 역할이 있어야 해요.

  • Lambda 함수용 IAM 역할 만들기
  • Lambda 함수의 IAM 역할에 인라인 정책 포함

Lambda 함수용 IAM 역할 만들기

  1. AWS Management Console에 로그인하고 IAM 콘솔을 https://console.aws.amazon.com/iam/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Roles를 선택한 다음 Create role을 선택해요.
  3. AWS service 역할 유형을 선택하고 Common use cases 아래에서 Lambda를 선택해요.
  4. Next: Permissions를 선택해요.
  5. Attach permissions policies 페이지에서 Filter policies 상자에 AWSLambdaBasicExecutionRole을 입력해요. Amazon CloudWatch Logs에 대한 쓰기 권한을 부여하는 관리형 정책 AWSLambdaBasicExecutionRole을 이 역할에 연결하려면 AWSLambdaBasicExecutionRole 옆의 확인란을 선택해요.
  6. Next를 선택해요.
  7. Role name에 tutorial-lambda-transcode-role을 입력해요.
  8. (선택) 관리형 정책에 태그를 추가해요.
  9. Create role을 선택해요.

Lambda 함수의 IAM 역할에 인라인 정책 포함

Lambda 함수가 실행하는 데 필요한 MediaConvert 리소스 권한을 부여하려면 인라인 정책을 사용해야 해요.

  1. AWS Management Console에 로그인하고 IAM 콘솔을 https://console.aws.amazon.com/iam/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Roles를 선택해요.
  3. Roles 목록에서 Lambda 함수용으로 이전에 만든 IAM 역할 이름(예: tutorial-lambda-transcode-role)을 선택해요.
  4. Permissions 탭을 선택해요.
  5. Add inline policy를 선택해요.
  6. JSON 탭을 선택한 다음 다음 JSON 정책을 복사해 붙여 넣어요. JSON 정책에서 Resource의 예제 ARN 값을 2단계에서 만든 MediaConvert용 IAM 역할의 역할 ARN(예: tutorial-mediaconvert-role)으로 바꾸세요.
{
    "Version":"2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*",
            "Effect": "Allow",
            "Sid": "Logging"
        },
        {
            "Action": [
                "iam:PassRole"
            ],
            "Resource": [
                "arn:aws:iam::111122223333:role/tutorial-mediaconvert-role"
            ],
            "Effect": "Allow",
            "Sid": "PassRole"
        },
        {
            "Action": [
                "mediaconvert:*"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow",
            "Sid": "MediaConvertService"
        },
        {
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow",
            "Sid": "S3Service"
        }
    ]
}
  1. Review Policy를 선택해요.
  2. Name에 tutorial-lambda-policy를 입력해요.
  3. Create Policy를 선택해요. 인라인 정책을 만들면 자동으로 Lambda 함수의 IAM 역할에 포함돼요.

4단계: 비디오 트랜스코딩용 Lambda 함수 만들기

이 튜토리얼 절에서는 AWS SDK for Python(Boto3)을 사용해 S3 Batch Operations 및 MediaConvert와 통합되는 Lambda 함수를 만들어요. S3 소스 버킷에 이미 저장된 비디오 트랜스코딩을 시작하려면, S3 소스 버킷의 각 비디오에 대해 Lambda 함수를 직접 호출하는 S3 Batch Operations 작업을 실행해요. 그러면 Lambda 함수는 각 비디오에 대한 트랜스코딩 작업을 MediaConvert에 제출해요.

  • Lambda 함수 코드 작성 및 배포 패키지 만들기
  • 실행 역할로 Lambda 함수 만들기(콘솔)
  • .zip 파일 아카이브로 Lambda 함수 배포 및 Lambda 함수 구성(콘솔)

Lambda 함수 코드 작성 및 배포 패키지 만들기

  1. 로컬 머신에 batch-transcode라는 폴더를 만들어요.

  2. batch-transcode 폴더에 JSON 작업 설정 파일을 만들어요. 예를 들어 이 절에서 제공하는 설정을 사용하고 파일 이름을 job.json으로 지을 수 있어요. job.json 파일은 다음을 지정해요.

    • 어떤 파일을 트랜스코딩할지
    • 입력 비디오를 어떻게 트랜스코딩할지
    • 어떤 출력 미디어 파일을 만들지
    • 트랜스코딩된 파일의 이름을 무엇으로 할지
    • 트랜스코딩된 파일을 어디에 저장할지
    • 어떤 고급 기능을 적용할지 등

    이 튜토리얼에서는 다음 job.json 파일을 사용해 S3 소스 버킷의 각 비디오에 대해 다음 출력을 만들어요.

    • 여러 크기와 다양한 대역폭을 가진 여러 기기에서 재생할 수 있는 HTTP Live Streaming(HLS) 적응형 비트레이트 스트림
    • MP4 비디오 파일
    • 일정 간격으로 수집된 썸네일 이미지

    이 예제 job.json 파일은 QVBR(Quality-Defined Variable Bitrate)을 사용해 비디오 품질을 최적화해요. HLS 출력은 Apple 호환(오디오가 비디오에서 분리, 세그먼트 기간 6초, 자동 QVBR로 최적화된 비디오 품질)이에요. 여기 제공된 예제 설정을 사용하고 싶지 않으면 사용 사례에 기반해 job.json 사양을 생성할 수 있어요. 출력 간 일관성을 보장하려면 입력 파일이 비슷한 비디오 및 오디오 구성을 갖도록 하세요. 비디오·오디오 구성이 다른 입력 파일의 경우 별도의 자동화(고유한 job.json 설정)를 만드세요. 자세한 내용은 AWS Elemental MediaConvert User Guide의 Example AWS Elemental MediaConvert job settings in JSON 문서를 참고하세요.

{
  "OutputGroups": [
    {
      "CustomName": "HLS",
      "Name": "Apple HLS",
      "Outputs": [
        {
          "ContainerSettings": {
            "Container": "M3U8",
            "M3u8Settings": {
              "AudioFramesPerPes": 4,
              "PcrControl": "PCR_EVERY_PES_PACKET",
              "PmtPid": 480,
              "PrivateMetadataPid": 503,
              "ProgramNumber": 1,
              "PatInterval": 0,
              "PmtInterval": 0,
              "TimedMetadata": "NONE",
              "VideoPid": 481,
              "AudioPids": [
                482,
                483,
                484,
                485,
                486,
                487,
                488,
                489,
                490,
                491,
                492
              ]
            }
          },
          "VideoDescription": {
            "Width": 640,
            "ScalingBehavior": "DEFAULT",
            "Height": 360,
            "TimecodeInsertion": "DISABLED",
            "AntiAlias": "ENABLED",
            "Sharpness": 50,
            "CodecSettings": {
              "Codec": "H_264",
              "H264Settings": {
                "InterlaceMode": "PROGRESSIVE",
                "NumberReferenceFrames": 3,
                "Syntax": "DEFAULT",
                "Softness": 0,
                "GopClosedCadence": 1,
                "GopSize": 2,
                "Slices": 1,
                "GopBReference": "DISABLED",
                "MaxBitrate": 1200000,
                "SlowPal": "DISABLED",
                "SpatialAdaptiveQuantization": "ENABLED",
                "TemporalAdaptiveQuantization": "ENABLED",
                "FlickerAdaptiveQuantization": "DISABLED",
                "EntropyEncoding": "CABAC",
                "FramerateControl": "INITIALIZE_FROM_SOURCE",
                "RateControlMode": "QVBR",
                "CodecProfile": "MAIN",
                "Telecine": "NONE",
                "MinIInterval": 0,
                "AdaptiveQuantization": "HIGH",
                "CodecLevel": "AUTO",
                "FieldEncoding": "PAFF",
                "SceneChangeDetect": "TRANSITION_DETECTION",
                "QualityTuningLevel": "SINGLE_PASS_HQ",
                "FramerateConversionAlgorithm": "DUPLICATE_DROP",
                "UnregisteredSeiTimecode": "DISABLED",
                "GopSizeUnits": "SECONDS",
                "ParControl": "INITIALIZE_FROM_SOURCE",
                "NumberBFramesBetweenReferenceFrames": 2,
                "RepeatPps": "DISABLED"
              }
            },
            "AfdSignaling": "NONE",
            "DropFrameTimecode": "ENABLED",
            "RespondToAfd": "NONE",
            "ColorMetadata": "INSERT"
          },
          "OutputSettings": {
            "HlsSettings": {
              "AudioGroupId": "program_audio",
              "AudioRenditionSets": "program_audio",
              "SegmentModifier": "$dt$",
              "IFrameOnlyManifest": "EXCLUDE"
            }
          },
          "NameModifier": "_360"
        },
        {
          "ContainerSettings": {
            "Container": "M3U8",
            "M3u8Settings": {
              "AudioFramesPerPes": 4,
              "PcrControl": "PCR_EVERY_PES_PACKET",
              "PmtPid": 480,
              "PrivateMetadataPid": 503,
              "ProgramNumber": 1,
              "PatInterval": 0,
              "PmtInterval": 0,
              "TimedMetadata": "NONE",
              "TimedMetadataPid": 502,
              "VideoPid": 481,
              "AudioPids": [
                482,
                483,
                484,
                485,
                486,
                487,
                488,
                489,
                490,
                491,
                492
              ]
            }
          },
          "VideoDescription": {
            "Width": 960,
            "ScalingBehavior": "DEFAULT",
            "Height": 540,
            "TimecodeInsertion": "DISABLED",
            "AntiAlias": "ENABLED",
            "Sharpness": 50,
            "CodecSettings": {
              "Codec": "H_264",
              "H264Settings": {
                "InterlaceMode": "PROGRESSIVE",
                "NumberReferenceFrames": 3,
                "Syntax": "DEFAULT",
                "Softness": 0,
                "GopClosedCadence": 1,
                "GopSize": 2,
                "Slices": 1,
                "GopBReference": "DISABLED",
                "MaxBitrate": 3500000,
                "SlowPal": "DISABLED",
                "SpatialAdaptiveQuantization": "ENABLED",
                "TemporalAdaptiveQuantization": "ENABLED",
                "FlickerAdaptiveQuantization": "DISABLED",
                "EntropyEncoding": "CABAC",
                "FramerateControl": "INITIALIZE_FROM_SOURCE",
                "RateControlMode": "QVBR",
                "CodecProfile": "MAIN",
                "Telecine": "NONE",
                "MinIInterval": 0,
                "AdaptiveQuantization": "HIGH",
                "CodecLevel": "AUTO",
                "FieldEncoding": "PAFF",
                "SceneChangeDetect": "TRANSITION_DETECTION",
                "QualityTuningLevel": "SINGLE_PASS_HQ",
                "FramerateConversionAlgorithm": "DUPLICATE_DROP",
                "UnregisteredSeiTimecode": "DISABLED",
                "GopSizeUnits": "SECONDS",
                "ParControl": "INITIALIZE_FROM_SOURCE",
                "NumberBFramesBetweenReferenceFrames": 2,
                "RepeatPps": "DISABLED"
              }
            },
            "AfdSignaling": "NONE",
            "DropFrameTimecode": "ENABLED",
            "RespondToAfd": "NONE",
            "ColorMetadata": "INSERT"
          },
          "OutputSettings": {
            "HlsSettings": {
              "AudioGroupId": "program_audio",
              "AudioRenditionSets": "program_audio",
              "SegmentModifier": "$dt$",
              "IFrameOnlyManifest": "EXCLUDE"
            }
          },
          "NameModifier": "_540"
        },
        {
          "ContainerSettings": {
            "Container": "M3U8",
            "M3u8Settings": {
              "AudioFramesPerPes": 4,
              "PcrControl": "PCR_EVERY_PES_PACKET",
              "PmtPid": 480,
              "PrivateMetadataPid": 503,
              "ProgramNumber": 1,
              "PatInterval": 0,
              "PmtInterval": 0,
              "TimedMetadata": "NONE",
              "VideoPid": 481,
              "AudioPids": [
                482,
                483,
                484,
                485,
                486,
                487,
                488,
                489,
                490,
                491,
                492
              ]
            }
          },
          "VideoDescription": {
            "Width": 1280,
            "ScalingBehavior": "DEFAULT",
            "Height": 720,
            "TimecodeInsertion": "DISABLED",
            "AntiAlias": "ENABLED",
            "Sharpness": 50,
            "CodecSettings": {
              "Codec": "H_264",
              "H264Settings": {
                "InterlaceMode": "PROGRESSIVE",
                "NumberReferenceFrames": 3,
                "Syntax": "DEFAULT",
                "Softness": 0,
                "GopClosedCadence": 1,
                "GopSize": 2,
                "Slices": 1,
                "GopBReference": "DISABLED",
                "MaxBitrate": 5000000,
                "SlowPal": "DISABLED",
                "SpatialAdaptiveQuantization": "ENABLED",
                "TemporalAdaptiveQuantization": "ENABLED",
                "FlickerAdaptiveQuantization": "DISABLED",
                "EntropyEncoding": "CABAC",
                "FramerateControl": "INITIALIZE_FROM_SOURCE",
                "RateControlMode": "QVBR",
                "CodecProfile": "MAIN",
                "Telecine": "NONE",
                "MinIInterval": 0,
                "AdaptiveQuantization": "HIGH",
                "CodecLevel": "AUTO",
                "FieldEncoding": "PAFF",
                "SceneChangeDetect": "TRANSITION_DETECTION",
                "QualityTuningLevel": "SINGLE_PASS_HQ",
                "FramerateConversionAlgorithm": "DUPLICATE_DROP",
                "UnregisteredSeiTimecode": "DISABLED",
                "GopSizeUnits": "SECONDS",
                "ParControl": "INITIALIZE_FROM_SOURCE",
                "NumberBFramesBetweenReferenceFrames": 2,
                "RepeatPps": "DISABLED"
              }
            },
            "AfdSignaling": "NONE",
            "DropFrameTimecode": "ENABLED",
            "RespondToAfd": "NONE",
            "ColorMetadata": "INSERT"
          },
          "OutputSettings": {
            "HlsSettings": {
              "AudioGroupId": "program_audio",
              "AudioRenditionSets": "program_audio",
              "SegmentModifier": "$dt$",
              "IFrameOnlyManifest": "EXCLUDE"
            }
          },
          "NameModifier": "_720"
        },
        {
          "ContainerSettings": {
            "Container": "M3U8",
            "M3u8Settings": {}
          },
          "AudioDescriptions": [
            {
              "AudioSourceName": "Audio Selector 1",
              "CodecSettings": {
                "Codec": "AAC",
                "AacSettings": {
                  "Bitrate": 96000,
                  "CodingMode": "CODING_MODE_2_0",
                  "SampleRate": 48000
                }
              }
            }
          ],
          "OutputSettings": {
            "HlsSettings": {
              "AudioGroupId": "program_audio",
              "AudioTrackType": "ALTERNATE_AUDIO_AUTO_SELECT_DEFAULT"
            }
          },
          "NameModifier": "_audio"
        }
      ],
      "OutputGroupSettings": {
        "Type": "HLS_GROUP_SETTINGS",
        "HlsGroupSettings": {
          "ManifestDurationFormat": "INTEGER",
          "SegmentLength": 6,
          "TimedMetadataId3Period": 10,
          "CaptionLanguageSetting": "OMIT",
          "Destination": "s3://EXAMPLE-BUCKET/HLS/",
          "DestinationSettings": {
            "S3Settings": {
              "AccessControl": {
                "CannedAcl": "PUBLIC_READ"
              }
            }
          },
          "TimedMetadataId3Frame": "PRIV",
          "CodecSpecification": "RFC_4281",
          "OutputSelection": "MANIFESTS_AND_SEGMENTS",
          "ProgramDateTimePeriod": 600,
          "MinSegmentLength": 0,
          "DirectoryStructure": "SINGLE_DIRECTORY",
          "ProgramDateTime": "EXCLUDE",
          "SegmentControl": "SEGMENTED_FILES",
          "ManifestCompression": "NONE",
          "ClientCache": "ENABLED",
          "StreamInfResolution": "INCLUDE"
        }
      }
    },
    {
      "CustomName": "MP4",
      "Name": "File Group",
      "Outputs": [
        {
          "ContainerSettings": {
            "Container": "MP4",
            "Mp4Settings": {
              "CslgAtom": "INCLUDE",
              "FreeSpaceBox": "EXCLUDE",
              "MoovPlacement": "PROGRESSIVE_DOWNLOAD"
            }
          },
          "VideoDescription": {
            "Width": 1280,
            "ScalingBehavior": "DEFAULT",
            "Height": 720,
            "TimecodeInsertion": "DISABLED",
            "AntiAlias": "ENABLED",
            "Sharpness": 100,
            "CodecSettings": {
              "Codec": "H_264",
              "H264Settings": {
                "InterlaceMode": "PROGRESSIVE",
                "ParNumerator": 1,
                "NumberReferenceFrames": 3,
                "Syntax": "DEFAULT",
                "Softness": 0,
                "GopClosedCadence": 1,
                "HrdBufferInitialFillPercentage": 90,
                "GopSize": 2,
                "Slices": 2,
                "GopBReference": "ENABLED",
                "HrdBufferSize": 10000000,
                "MaxBitrate": 5000000,
                "ParDenominator": 1,
                "EntropyEncoding": "CABAC",
                "RateControlMode": "QVBR",
                "CodecProfile": "HIGH",
                "MinIInterval": 0,
                "AdaptiveQuantization": "AUTO",
                "CodecLevel": "AUTO",
                "FieldEncoding": "PAFF",
                "SceneChangeDetect": "ENABLED",
                "QualityTuningLevel": "SINGLE_PASS_HQ",
                "UnregisteredSeiTimecode": "DISABLED",
                "GopSizeUnits": "SECONDS",
                "ParControl": "SPECIFIED",
                "NumberBFramesBetweenReferenceFrames": 3,
                "RepeatPps": "DISABLED",
                "DynamicSubGop": "ADAPTIVE"
              }
            },
            "AfdSignaling": "NONE",
            "DropFrameTimecode": "ENABLED",
            "RespondToAfd": "NONE",
            "ColorMetadata": "INSERT"
          },
          "AudioDescriptions": [
            {
              "AudioTypeControl": "FOLLOW_INPUT",
              "AudioSourceName": "Audio Selector 1",
              "CodecSettings": {
                "Codec": "AAC",
                "AacSettings": {
                  "AudioDescriptionBroadcasterMix": "NORMAL",
                  "Bitrate": 160000,
                  "RateControlMode": "CBR",
                  "CodecProfile": "LC",
                  "CodingMode": "CODING_MODE_2_0",
                  "RawFormat": "NONE",
                  "SampleRate": 48000,
                  "Specification": "MPEG4"
                }
              },
              "LanguageCodeControl": "FOLLOW_INPUT",
              "AudioType": 0
            }
          ]
        }
      ],
      "OutputGroupSettings": {
        "Type": "FILE_GROUP_SETTINGS",
        "FileGroupSettings": {
          "Destination": "s3://EXAMPLE-BUCKET/MP4/",
          "DestinationSettings": {
            "S3Settings": {
              "AccessControl": {
                "CannedAcl": "PUBLIC_READ"
              }
            }
          }
        }
      }
    },
    {
      "CustomName": "Thumbnails",
      "Name": "File Group",
      "Outputs": [
        {
          "ContainerSettings": {
            "Container": "RAW"
          },
          "VideoDescription": {
            "Width": 1280,
            "ScalingBehavior": "DEFAULT",
            "Height": 720,
            "TimecodeInsertion": "DISABLED",
            "AntiAlias": "ENABLED",
            "Sharpness": 50,
            "CodecSettings": {
              "Codec": "FRAME_CAPTURE",
              "FrameCaptureSettings": {
                "FramerateNumerator": 1,
                "FramerateDenominator": 5,
                "MaxCaptures": 500,
                "Quality": 80
              }
            },
            "AfdSignaling": "NONE",
            "DropFrameTimecode": "ENABLED",
            "RespondToAfd": "NONE",
            "ColorMetadata": "INSERT"
          }
        }
      ],
      "OutputGroupSettings": {
        "Type": "FILE_GROUP_SETTINGS",
        "FileGroupSettings": {
          "Destination": "s3://EXAMPLE-BUCKET/Thumbnails/",
          "DestinationSettings": {
            "S3Settings": {
              "AccessControl": {
                "CannedAcl": "PUBLIC_READ"
              }
            }
          }
        }
      }
    }
  ],
  "AdAvailOffset": 0,
  "Inputs": [
    {
      "AudioSelectors": {
        "Audio Selector 1": {
          "Offset": 0,
          "DefaultSelection": "DEFAULT",
          "ProgramSelection": 1
        }
      },
      "VideoSelector": {
        "ColorSpace": "FOLLOW"
      },
      "FilterEnable": "AUTO",
      "PsiControl": "USE_PSI",
      "FilterStrength": 0,
      "DeblockFilter": "DISABLED",
      "DenoiseFilter": "DISABLED",
      "TimecodeSource": "EMBEDDED",
      "FileInput": "s3://EXAMPLE-INPUT-BUCKET/input.mp4"
    }
  ]
}
  1. batch-transcode 폴더에 Lambda 함수가 있는 파일을 만들어요. 다음 Python 예제를 사용하고 파일 이름을 convert.py로 지을 수 있어요. S3 Batch Operations는 특정 태스크 데이터를 Lambda 함수로 보내고 결과 데이터를 다시 요구해요. Lambda 함수의 요청·응답 예제, 응답·결과 코드 정보, S3 Batch Operations용 예제 Lambda 함수는 Invoke AWS Lambda function 문서를 참고하세요.
import json
import os
from urllib.parse import urlparse
import uuid
import boto3

"""
When you run an S3 Batch Operations job, your job
invokes this Lambda function. Specifically, the Lambda function is
invoked on each video object listed in the manifest that you specify
for the S3 Batch Operations job in Step 5.

Input parameter "event": The S3 Batch Operations event as a request
                         for the Lambda function.

Input parameter "context": Context about the event.

Output: A result structure that Amazon S3 uses to interpret the result
        of the operation. It is a job response returned back to S3 Batch Operations.
"""
def handler(event, context):

    invocation_schema_version = event['invocationSchemaVersion']
    invocation_id = event['invocationId']
    task_id = event['tasks'][0]['taskId']

    source_s3_key = event['tasks'][0]['s3Key']
    source_s3_bucket = event['tasks'][0]['s3BucketArn'].split(':::')[-1]
    source_s3 = 's3://' + source_s3_bucket + '/' + source_s3_key

    result_list = []
    result_code = 'Succeeded'
    result_string = 'The input video object was converted successfully.'

    # The type of output group determines which media players can play
    # the files transcoded by MediaConvert.
    # For more information, see Creating outputs with AWS Elemental MediaConvert.
    output_group_type_dict = {
        'HLS_GROUP_SETTINGS': 'HlsGroupSettings',
        'FILE_GROUP_SETTINGS': 'FileGroupSettings',
        'CMAF_GROUP_SETTINGS': 'CmafGroupSettings',
        'DASH_ISO_GROUP_SETTINGS': 'DashIsoGroupSettings',
        'MS_SMOOTH_GROUP_SETTINGS': 'MsSmoothGroupSettings'
    }

    try:
        job_name = 'Default'
        with open('job.json') as file:
            job_settings = json.load(file)

        job_settings['Inputs'][0]['FileInput'] = source_s3

        # The path of each output video is constructed based on the values of
        # the attributes in each object of OutputGroups in the job.json file.
        destination_s3 = 's3://{0}/{1}/{2}' \
            .format(os.environ['amzn-s3-demo-destination-bucket'],
                    os.path.splitext(os.path.basename(source_s3_key))[0],
                    os.path.splitext(os.path.basename(job_name))[0])

        for output_group in job_settings['OutputGroups']:
            output_group_type = output_group['OutputGroupSettings']['Type']
            if output_group_type in output_group_type_dict.keys():
                output_group_type = output_group_type_dict[output_group_type]
                output_group['OutputGroupSettings'][output_group_type]['Destination'] = \
                    "{0}{1}".format(destination_s3,
                                    urlparse(output_group['OutputGroupSettings'][output_group_type]['Destination']).path)
            else:
                raise ValueError("Exception: Unknown Output Group Type {}."
                                 .format(output_group_type))

        job_metadata_dict = {
            'assetID': str(uuid.uuid4()),
            'application': os.environ['Application'],
            'input': source_s3,
            'settings': job_name
        }

        region = os.environ['AWS_DEFAULT_REGION']
        endpoints = boto3.client('mediaconvert', region_name=region) \
            .describe_endpoints()
        client = boto3.client('mediaconvert', region_name=region,
                               endpoint_url=endpoints['Endpoints'][0]['Url'],
                               verify=False)

        try:
            client.create_job(Role=os.environ['MediaConvertRole'],
                              UserMetadata=job_metadata_dict,
                              Settings=job_settings)
        # You can customize error handling based on different error codes that
        # MediaConvert can return.
        # For more information, see MediaConvert error codes.
        # When the result_code is TemporaryFailure, S3 Batch Operations retries
        # the task before the job is completed. If this is the final retry,
        # the error message is included in the final report.
        except Exception as error:
            result_code = 'TemporaryFailure'
            raise

    except Exception as error:
        if result_code != 'TemporaryFailure':
            result_code = 'PermanentFailure'
        result_string = str(error)

    finally:
        result_list.append({
            'taskId': task_id,
            'resultCode': result_code,
            'resultString': result_string,
        })

    return {
        'invocationSchemaVersion': invocation_schema_version,
        'treatMissingKeyAs': 'PermanentFailure',
        'invocationId': invocation_id,
        'results': result_list
    }
  1. convert.py와 job.json을 lambda.zip이라는 .zip 파일로 묶은 배포 패키지를 만들려면 로컬 터미널에서 이전에 만든 batch-transcode 폴더를 열고 다음 명령을 실행해요.
    • macOS 사용자 – 다음 명령을 실행해요.
      zip -r lambda.zip convert.py job.json
      
    • Windows 사용자 – 다음 명령을 실행해요.
      powershell Compress-Archive convert.py lambda.zip
      
      powershell Compress-Archive -update job.json lambda.zip
      

실행 역할로 Lambda 함수 만들기(콘솔)

  1. AWS Lambda 콘솔을 https://console.aws.amazon.com/lambda/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Functions를 선택해요.
  3. Create function을 선택해요.
  4. Author from scratch를 선택해요.
  5. Basic information 아래에서 다음을 수행해요.
    • Function name에 tutorial-lambda-convert를 입력해요.
    • Runtime에서 Python 3.13을 선택해요.
  6. Change default execution role을 선택하고 Execution role 아래에서 Use an existing role을 선택해요.
  7. Existing role 아래에서 3단계에서 Lambda 함수용으로 만든 IAM 역할 이름(예: tutorial-lambda-transcode-role)을 선택해요.
  8. 나머지 설정은 기본값으로 유지해요.
  9. Create function을 선택해요.

.zip 파일 아카이브로 Lambda 함수 배포 및 Lambda 함수 구성(콘솔)

  1. 만든 Lambda 함수(예: tutorial-lambda-convert) 페이지의 Code Source 섹션에서 Upload from과 .zip file을 선택해요.
  2. Upload를 선택해 로컬 .zip 파일을 선택해요.
  3. 이전에 만든 lambda.zip 파일을 선택하고 Open을 선택해요.
  4. Save를 선택해요.
  5. Runtime settings 섹션에서 Edit을 선택해요.
  6. Lambda 런타임이 Lambda 함수 코드에서 호출할 핸들러 메서드를 알려 주도록 Handler 필드에 convert.handler를 입력해요. Python에서 함수를 구성할 때 handler 설정의 값은 파일 이름과 핸들러 모듈 이름을 점(.)으로 구분한 것이에요. 예를 들어 convert.handler는 convert.py 파일에 정의된 handler 메서드를 호출해요.
  7. Save를 선택해요.
  8. Lambda 함수 페이지에서 Configuration 탭을 선택해요. Configuration 탭의 왼쪽 탐색 창에서 Environment variables를 선택하고 Edit을 선택해요.
  9. Add environment variable을 선택한 다음 각 환경 변수에 대해 지정된 Key와 Value를 입력해요.
    • Key: DestinationBucket, Value: amzn-s3-demo-destination-bucket1. 이 값은 1단계에서 만든 출력 미디어 파일용 S3 버킷이에요.
    • Key: MediaConvertRole, Value: arn:aws:iam::111122223333:role/tutorial-mediaconvert-role. 이 값은 2단계에서 만든 MediaConvert용 IAM 역할의 ARN이에요. 이 ARN을 실제 IAM 역할 ARN으로 바꾸는 것을 잊지 마세요.
    • Key: Application, Value: Batch-Transcoding. 이 값은 애플리케이션의 이름이에요.
  10. Save를 선택해요.
  11. (선택) Configuration 탭의 왼쪽 탐색 창에 있는 General configuration 섹션에서 Edit을 선택해요. Timeout 필드에 2 min 0 sec을 입력한 다음 Save를 선택해요. Timeout은 중지하기 전에 Lambda가 한 번 호출에 대해 함수를 실행할 수 있는 시간이에요. 기본값은 3초예요. 요금은 구성된 메모리 양과 코드 실행 시간에 따라 달라져요. 자세한 내용은 AWS Lambda pricing 문서를 참고하세요.

5단계: S3 소스 버킷용 Amazon S3 Inventory 구성

트랜스코딩 Lambda 함수를 설정한 후, 비디오 집합을 트랜스코딩할 S3 Batch Operations 작업을 만들어요. 먼저 S3 Batch Operations가 지정된 트랜스코딩 작업을 실행할 입력 비디오 객체 목록이 필요해요. 입력 비디오 객체 목록을 얻으려면 S3 소스 버킷(예: amzn-s3-demo-source-bucket)에 대해 S3 Inventory 보고서를 생성할 수 있어요.

  • 입력 비디오용 S3 Inventory 보고서 버킷 만들기 및 구성
  • S3 비디오 소스 버킷용 Amazon S3 Inventory 구성
  • S3 비디오 소스 버킷의 인벤토리 보고서 확인

입력 비디오용 S3 Inventory 보고서 버킷 만들기 및 구성

S3 소스 버킷의 객체를 나열하는 S3 Inventory 보고서를 저장하려면 S3 Inventory 대상 버킷을 만들고, 인벤토리 파일을 S3 소스 버킷에 쓸 수 있도록 버킷에 대한 버킷 정책을 구성해요.

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Buckets를 선택해요.
  3. Create bucket을 선택해요.
  4. Bucket name에 버킷 이름을 입력해요(예: amzn-s3-demo-destination-bucket2).
  5. AWS Region에서 버킷을 둘 AWS 리전을 선택해요. 인벤토리 대상 버킷은 S3 Inventory를 설정하는 소스 버킷과 같은 AWS 리전이어야 해요. 인벤토리 대상 버킷은 다른 AWS 계정에 있을 수 있어요.
  6. Block Public Access settings for this bucket에서 기본 설정을 유지해요(Block all public access가 활성화됨).
  7. 나머지 설정은 기본값으로 유지해요.
  8. Create bucket을 선택해요.
  9. Buckets 목록에서 방금 만든 버킷 이름(예: amzn-s3-demo-destination-bucket2)을 선택해요.
  10. Amazon S3에 인벤토리 보고서 데이터를 S3 Inventory 대상 버킷에 쓸 권한을 부여하려면 Permissions 탭을 선택해요.
  11. Bucket policy 섹션까지 아래로 스크롤해 Edit을 선택해요. Bucket policy 페이지가 열려요.
  12. S3 Inventory 권한을 부여하려면 Policy 필드에 다음 버킷 정책을 붙여 넣어요. 다음 세 개의 예제 값을 다음 값으로 바꾸세요.
    • 인벤토리 보고서를 저장하도록 만든 버킷 이름(예: amzn-s3-demo-destination-bucket2)
    • 입력 비디오를 저장하는 소스 버킷 이름(예: amzn-s3-demo-source-bucket)
    • S3 비디오 소스 버킷을 만드는 데 사용한 AWS 계정 ID(예: 111122223333)
{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Sid":"InventoryAndAnalyticsExamplePolicy",
      "Effect":"Allow",
      "Principal": {"Service": "s3.amazonaws.com"},
      "Action":"s3:PutObject",
      "Resource":["arn:aws:s3:::amzn-s3-demo-destination-bucket2/*"],
      "Condition": {
          "ArnLike": {
              "aws:SourceArn": "arn:aws:s3:::amzn-s3-demo-source-bucket"
           },
         "StringEquals": {
             "aws:SourceAccount": "111122223333",
             "s3:x-amz-acl": "bucket-owner-full-control"
          }
       }
    }
  ]
}
  1. Save changes를 선택해요.

S3 비디오 소스 버킷용 Amazon S3 Inventory 구성

비디오 객체와 메타데이터의 플랫 파일 목록을 생성하려면 S3 비디오 소스 버킷에 대해 S3 Inventory를 구성해야 해요. 이 예약된 인벤토리 보고서는 버킷의 모든 객체를 포함하거나 공유 접두사로 그룹화된 객체를 포함할 수 있어요. 이 튜토리얼에서 S3 Inventory 보고서는 S3 소스 버킷의 모든 비디오 객체를 포함해요.

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Buckets를 선택해요.
  3. S3 소스 버킷의 입력 비디오에 대한 S3 Inventory 보고서를 구성하려면 Buckets 목록에서 S3 소스 버킷 이름(예: amzn-s3-demo-source-bucket)을 선택해요.
  4. Management 탭을 선택해요.
  5. Inventory configurations 섹션까지 아래로 스크롤해 Create inventory configuration을 선택해요.
  6. Inventory configuration name에 구성 이름을 입력해요(예: tutorial-inventory-config).
  7. Inventory scope에서 This bucket을 선택하고(이 튜토리얼 기본값), Object versions에서 Current를 선택해요. 이 설정은 S3 소스 버킷의 현재 버전 비디오 객체만 보고하게 해요.
  8. Destination 아래에서 Destination bucket에 이전에 만든 인벤토리 대상 버킷 이름(예: amzn-s3-demo-destination-bucket2)을 입력해요.
  9. Frequency에서 Daily를 선택해요.
  10. Output format에서 CSV를 선택해요.
  11. Server-side encryption 섹션에서 이 튜토리얼의 경우 Disable을 선택해요. 자세한 내용은 Configuring inventory by using the S3 console 및 Granting Amazon S3 permission to use your customer managed key for encryption 문서를 참고하세요.
  12. Additional fields - optional 섹션에서 Size, Last modified, Storage class를 선택해요.
  13. Create를 선택해요.

자세한 내용은 Configuring inventory by using the S3 console 문서를 참고하세요.

S3 비디오 소스 버킷의 인벤토리 보고서 확인

인벤토리 보고서가 게시되면 매니페스트 파일이 S3 Inventory 대상 버킷으로 전송돼요.

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Buckets를 선택해요.
  3. Buckets 목록에서 비디오 소스 버킷 이름(예: amzn-s3-demo-source-bucket)을 선택해요.
  4. Management를 선택해요.
  5. 7단계에서 S3 Batch Operations 작업을 만들 수 있도록 S3 Inventory 보고서가 준비되었는지 확인하려면 Inventory configurations 아래에서 Create job from manifest 버튼이 활성화되어 있는지 확인해요.

참고 첫 번째 인벤토리 보고서가 전달되는 데 최대 48시간이 걸릴 수 있어요. Create job from manifest 버튼이 비활성화되어 있으면 첫 번째 인벤토리 보고서가 아직 전달되지 않은 것이에요. 7단계에서 S3 Batch Operations 작업을 만들기 전에 첫 번째 인벤토리 보고서가 전달되고 Create job from manifest 버튼이 활성화될 때까지 기다리세요.

  1. S3 Inventory 보고서(manifest.json)를 확인하려면 Destination 열에서 인벤토리 보고서를 저장하기 위해 이전에 만든 인벤토리 대상 버킷 이름(예: amzn-s3-demo-destination-bucket2)을 선택해요.
  2. Objects 탭에서 S3 소스 버킷 이름(예: amzn-s3-demo-source-bucket)이 있는 기존 폴더를 선택해요. 그런 다음 이전에 인벤토리 구성을 만들 때 Inventory configuration name에 입력한 이름(예: tutorial-inventory-config)을 선택해요. 보고서 생성 날짜를 이름으로 가진 폴더 목록을 볼 수 있어요.
  3. 특정 날짜의 일별 S3 Inventory 보고서를 확인하려면 해당 생성 날짜 이름의 폴더를 선택한 다음 manifest.json을 선택해요.
  4. 특정 날짜의 인벤토리 보고서 세부 정보를 확인하려면 manifest.json 페이지에서 Download 또는 Open을 선택해요.

6단계: S3 Batch Operations용 IAM 역할 만들기

S3 Batch Operations를 사용해 일괄 트랜스코딩을 하려면 먼저 Amazon S3에 S3 Batch Operations를 수행할 권한을 주는 IAM 역할을 만들어야 해요.

  • S3 Batch Operations용 IAM 정책 만들기
  • S3 Batch Operations IAM 역할 만들기 및 권한 정책 연결

S3 Batch Operations용 IAM 정책 만들기

입력 매니페스트를 읽고, Lambda 함수를 호출하고, S3 Batch Operations 작업 완료 보고서를 쓸 권한을 S3 Batch Operations에 주는 IAM 정책을 만들어야 해요.

  1. AWS Management Console에 로그인하고 IAM 콘솔을 https://console.aws.amazon.com/iam/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Policies를 선택해요.
  3. Create policy를 선택해요.
  4. JSON 탭을 선택해요.
  5. JSON 텍스트 필드에 다음 JSON 정책을 붙여 넣어요. JSON 정책에서 다음 네 개의 예제 값을 다음 값으로 바꾸세요.
    • 입력 비디오를 저장하는 소스 버킷의 이름(예: amzn-s3-demo-source-bucket)
    • 5단계에서 manifest.json 파일을 저장하도록 만든 인벤토리 대상 버킷의 이름(예: amzn-s3-demo-destination-bucket2)
    • 1단계에서 출력 미디어 파일을 저장하도록 만든 버킷 이름(예: amzn-s3-demo-destination-bucket1). 이 튜토리얼에서는 작업 완료 보고서를 출력 미디어 파일용 대상 버킷에 넣어요.
    • 4단계에서 만든 Lambda 함수의 역할 ARN. Lambda 함수의 역할 ARN을 찾아 복사하려면 다음을 수행해요. 새 브라우저 탭에서 Lambda 콘솔의 Functions 페이지를 https://console.aws.amazon.com/lambda/home#/functions 에서 열어요. Functions 목록에서 4단계에서 만든 Lambda 함수 이름(예: tutorial-lambda-convert)을 선택해요. Copy ARN을 선택해요.
{
    "Version":"2012-10-17",
    "Statement": [
        {
            "Sid": "S3Get",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": [
                "arn:aws:s3:::amzn-s3-demo-source-bucket/*",
                "arn:aws:s3:::amzn-s3-demo-destination-bucket2/*"
            ]
        },
        {
            "Sid": "S3PutJobCompletionReport",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::amzn-s3-demo-destination-bucket1/*"
        },
        {
            "Sid": "S3BatchOperationsInvokeLambda",
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": [
                "arn:aws:lambda:us-west-2:111122223333:function:tutorial-lambda-convert"
            ]
        }
    ]
}
  1. Next: Tags를 선택해요.
  2. Next: Review를 선택해요.
  3. Name 필드에 tutorial-s3batch-policy를 입력해요.
  4. Create policy를 선택해요.

S3 Batch Operations IAM 역할 만들기 및 권한 정책 연결

  1. AWS Management Console에 로그인하고 IAM 콘솔을 https://console.aws.amazon.com/iam/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Roles를 선택한 다음 Create role을 선택해요.
  3. AWS service 역할 유형을 선택한 다음 S3 서비스를 선택해요.
  4. Select your use case 아래에서 S3 Batch Operations를 선택해요.
  5. Next를 선택해요.
  6. Attach permissions 아래에서 검색 상자에 이전에 만든 IAM 정책 이름(예: tutorial-s3batch-policy)을 입력해 정책 목록을 필터링해요. 정책 이름 옆의 확인란을 선택해요(예: tutorial-s3batch-policy).
  7. Next를 선택해요.
  8. Role name에 tutorial-s3batch-role을 입력해요.
  9. Create role을 선택해요. S3 Batch Operations용 IAM 역할을 만들면 다음 신뢰 정책이 역할에 자동으로 연결돼요. 이 신뢰 정책은 S3 Batch Operations 서비스 주체가 IAM 역할을 맡을 수 있게 해 줘요.
{
   "Version":"2012-10-17",
   "Statement":[
      {
         "Effect":"Allow",
         "Principal":{
            "Service":"batchoperations.s3.amazonaws.com"
         },
         "Action":"sts:AssumeRole"
      }
   ]
}

7단계: S3 Batch Operations 작업 만들기 및 실행

S3 소스 버킷의 입력 비디오를 처리할 S3 Batch Operations 작업을 만들려면 이 특정 작업에 대한 매개변수를 지정해야 해요.

참고 S3 Batch Operations 작업 만들기를 시작하기 전에 Create job from manifest 버튼이 활성화되어 있는지 확인해요. 자세한 내용은 Check the inventory report for your S3 video source bucket 문서를 참고하세요. Create job from manifest 버튼이 비활성화되어 있으면 첫 번째 인벤토리 보고서가 아직 전달되지 않은 것이므로 버튼이 활성화될 때까지 기다려야 해요. 5단계에서 S3 소스 버킷에 대해 Amazon S3 Inventory를 구성한 후 첫 번째 인벤토리 보고서가 전달되는 데 최대 48시간이 걸릴 수 있어요.

  • S3 Batch Operations 작업 만들기
  • Lambda 함수를 호출하도록 S3 Batch Operations 작업 실행
  • (선택) 완료 보고서 확인
  • (선택) Lambda 콘솔에서 각 Lambda 호출 모니터링
  • (선택) MediaConvert 콘솔에서 각 MediaConvert 비디오 트랜스코딩 작업 모니터링

S3 Batch Operations 작업 만들기

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Batch Operations를 선택해요.
  3. Create job을 선택해요.
  4. AWS Region에서 작업을 만들 리전을 선택해요. 이 튜토리얼에서 S3 Batch Operations 작업으로 Lambda 함수를 호출하려면 매니페스트에 참조된 객체가 위치한 S3 비디오 소스 버킷과 같은 리전에서 작업을 만들어야 해요.
  5. Manifest 섹션에서 다음을 수행해요.
    • Manifest format에서 S3 Inventory report (manifest.json) 를 선택해요.
    • Manifest object에서 Browse S3를 선택해 인벤토리 보고서를 저장하기 위해 5단계에서 만든 버킷(예: amzn-s3-demo-destination-bucket2)을 찾아요.
    • Manifest object 페이지에서 특정 날짜에 대한 manifest.json 파일을 찾을 때까지 객체 이름을 탐색해요. 이 파일은 일괄 트랜스코딩할 모든 비디오에 대한 정보를 나열해요. 사용하려는 manifest.json 파일을 찾으면 옆의 옵션 버튼을 선택한 다음 Choose path를 선택해요.
    • (선택) Manifest object version ID - optional에서 최신 버전이 아닌 다른 버전을 사용하려면 매니페스트 객체의 버전 ID를 입력해요.
  6. Next를 선택해요.
  7. 선택한 manifest.json 파일에 나열된 모든 객체를 트랜스코딩하도록 Lambda 함수를 사용하려면 Operation type 아래에서 Invoke AWS Lambda function을 선택해요.
  8. Invoke Lambda function 섹션에서 다음을 수행해요.
    • Choose from functions in your account를 선택해요.
    • Lambda function에서 4단계에서 만든 Lambda 함수(예: tutorial-lambda-convert)를 선택해요.
    • Lambda function version에서 기본값 $LATEST를 유지해요.
  9. Next를 선택해요. Configure additional options 페이지가 열려요.
  10. Additional options 섹션에서 기본 설정을 유지해요. 이 옵션에 대한 자세한 내용은 Batch Operations job request elements 문서를 참고하세요.
  11. Completion report 섹션에서 Path to completion report destination에 대해 Browse S3를 선택해요. 1단계에서 출력 미디어 파일용으로 만든 버킷(예: amzn-s3-demo-destination-bucket1)을 찾아요. 버킷 이름 옆의 옵션 버튼을 선택한 다음 Choose path를 선택해요. 나머지 Completion report 설정은 기본값으로 유지해요. 완료 보고서 설정에 대한 자세한 내용은 Batch Operations job request elements 문서를 참고하세요. 완료 보고서는 작업의 세부 정보와 수행된 작업의 기록을 유지해요.
  12. Permissions 섹션에서 Choose from existing IAM roles을 선택해요. IAM role에서 6단계에서 만든 S3 Batch Operations 작업용 IAM 역할(예: tutorial-s3batch-role)을 선택해요.
  13. Next를 선택해요.
  14. Review 페이지에서 설정을 검토한 다음 Create job을 선택해요. S3가 S3 Batch Operations 작업의 매니페스트 읽기를 마치면 작업의 Status가 Awaiting your confirmation to run으로 설정돼요. 작업 상태 업데이트를 보려면 페이지를 새로고침해요. 작업 상태가 Awaiting your confirmation to run이 될 때까지 작업을 실행할 수 없어요.

Lambda 함수를 호출하도록 S3 Batch Operations 작업 실행

비디오 트랜스코딩을 위해 Lambda 함수를 호출하도록 Batch Operations 작업을 실행해요. 작업이 실패하면 완료 보고서를 확인해 원인을 파악할 수 있어요.

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Batch Operations를 선택해요.
  3. Jobs 목록에서 첫 번째 행에 있는 작업의 Job ID를 선택해요. 이것이 이전에 만든 S3 Batch Operations 작업이에요.
  4. Run job을 선택해요.
  5. 작업 매개변수를 다시 검토하고 Total objects listed in manifest 값이 매니페스트의 객체 수와 같은지 확인한 다음 Run job을 선택해요. S3 Batch Operations 작업 페이지가 열려요.
  6. 작업이 실행되기 시작한 후 작업 페이지에서 Status 아래에 S3 Batch Operations 작업의 진행 상황을 확인해요. 예를 들어 Status, % Complete, Total succeeded (rate), Total failed (rate), Date terminated, Reason for termination 등을 확인해요. S3 Batch Operations 작업이 완료되면 작업 페이지의 데이터를 확인해 작업이 예상대로 끝났는지 확인해요. S3 Batch Operations 작업의 객체 작업 중 50% 이상이 1,000개가 넘는 작업을 시도한 후에 실패하면 작업이 자동으로 실패해요. 실패 원인을 파악하기 위해 완료 보고서를 확인하려면 다음 선택 절차를 사용해요.

(선택) 완료 보고서 확인

완료 보고서를 사용해 어떤 객체가 실패했고 실패 원인이 무엇인지 확인할 수 있어요.

  1. S3 Batch Operations 작업 페이지에서 Completion report 섹션까지 아래로 스크롤해 Completion report destination 아래의 링크를 선택해요. S3 출력 대상 버킷의 페이지가 열려요.
  2. Objects 탭에서 이전에 만든 S3 Batch Operations 작업의 작업 ID로 끝나는 이름의 폴더를 선택해요.
  3. results/를 선택해요.
  4. .csv 파일 옆의 확인란을 선택해요.
  5. 작업 보고서를 보려면 Open 또는 Download를 선택해요.

(선택) Lambda 콘솔에서 각 Lambda 호출 모니터링

S3 Batch Operations 작업이 실행되기 시작하면 작업은 각 입력 비디오 객체에 대해 Lambda 함수를 호출해요. S3는 각 Lambda 호출의 로그를 CloudWatch Logs에 기록해요. Lambda 콘솔의 모니터링 대시보드를 사용해 Lambda 함수를 모니터링할 수 있어요.

  1. AWS Lambda 콘솔을 https://console.aws.amazon.com/lambda/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Functions를 선택해요.
  3. Functions 목록에서 4단계에서 만든 Lambda 함수 이름(예: tutorial-lambda-convert)을 선택해요.
  4. Monitor 탭을 선택해요.
  5. Metrics 아래에서 Lambda 함수의 런타임 지표를 확인해요.
  6. Logs 아래에서 CloudWatch Logs Insights를 통해 각 Lambda 호출의 로그 데이터를 확인해요.

참고 S3 Batch Operations를 Lambda 함수와 사용하면 Lambda 함수가 각 객체에 대해 호출돼요. S3 Batch Operations 작업이 크면 동시에 여러 Lambda 함수를 호출해 Lambda 동시성(concurrency)이 급증할 수 있어요. 각 AWS 계정에는 리전별 Lambda 동시성 할당량이 있어요. 자세한 내용은 AWS Lambda Developer Guide의 AWS Lambda Function Scaling 문서를 참고하세요. S3 Batch Operations와 Lambda 함수를 사용하는 모범 사례는 Lambda 함수 자체에 동시성 제한을 설정하는 것이에요. 동시성 제한을 설정하면 작업이 Lambda 동시성 대부분을 소비하고 계정의 다른 함수가 스로틀링될 가능성을 방지할 수 있어요. 자세한 내용은 AWS Lambda Developer Guide의 Managing Lambda reserved concurrency 문서를 참고하세요.

(선택) MediaConvert 콘솔에서 각 MediaConvert 비디오 트랜스코딩 작업 모니터링

MediaConvert 작업은 미디어 파일 트랜스코딩 작업을 수행해요. S3 Batch Operations 작업이 각 비디오에 대해 Lambda 함수를 호출하면, 각 Lambda 함수 호출이 각 입력 비디오에 대한 MediaConvert 트랜스코딩 작업을 만들어요.

  1. AWS Management Console에 로그인하고 MediaConvert 콘솔을 https://console.aws.amazon.com/mediaconvert/ 에서 열어요.
  2. MediaConvert 소개 페이지가 나타나면 Get started를 선택해요.
  3. Jobs 목록에서 각 행을 확인해 각 입력 비디오의 트랜스코딩 작업을 모니터링해요.
  4. 확인하려는 작업의 행을 식별하고 Job ID 링크를 선택해 작업 세부 정보 페이지를 열어요.
  5. Job summary 페이지의 Outputs 아래에서 브라우저가 지원하는 것에 따라 HLS, MP4 또는 Thumbnails 출력의 링크를 선택해 출력 미디어 파일용 S3 대상 버킷으로 이동해요.
  6. S3 출력 대상 버킷의 해당 폴더(HLS, MP4 또는 Thumbnails)에서 출력 미디어 파일 객체 이름을 선택해요. 객체 상세 페이지가 열려요.
  7. 객체 상세 페이지의 Object overview 아래에서 Object URL 아래의 링크를 선택해 트랜스코딩된 출력 미디어 파일을 시청해요.

8단계: S3 대상 버킷에서 출력 미디어 파일 확인

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Buckets를 선택해요.
  3. Buckets 목록에서 1단계에서 만든 출력 미디어 파일용 S3 대상 버킷 이름(예: amzn-s3-demo-destination-bucket1)을 선택해요.
  4. Objects 탭에서 각 입력 비디오에는 입력 비디오 이름을 가진 폴더가 있어요. 각 폴더에는 한 입력 비디오에 대한 트랜스코딩된 출력 미디어 파일이 들어 있어요. 입력 비디오의 출력 미디어 파일을 확인하려면 다음을 수행해요.
    • 확인하려는 입력 비디오 이름을 가진 폴더를 선택해요.
    • Default/ 폴더를 선택해요.
    • 트랜스코딩된 형식 폴더(이 튜토리얼에서는 HLS, MP4 또는 thumbnails)를 선택해요.
    • 출력 미디어 파일 이름을 선택해요.
    • 트랜스코딩된 파일을 시청하려면 객체 상세 페이지에서 Object URL 아래의 링크를 선택해요.
    • HLS 형식의 출력 미디어 파일은 짧은 세그먼트로 분할돼요. 이 비디오를 재생하려면 .m3u8 파일의 객체 URL을 호환되는 플레이어에 포함시켜요.

9단계: 정리(Clean up)

S3 Batch Operations, Lambda, MediaConvert를 학습 목적으로만 사용해 비디오를 트랜스코딩했다면, 할당한 AWS 리소스를 삭제해 더 이상 요금이 발생하지 않도록 해요.

  • S3 소스 버킷의 S3 Inventory 구성 삭제
  • Lambda 함수 삭제
  • CloudWatch 로그 그룹 삭제
  • 인라인 정책과 함께 IAM 역할 삭제
  • 고객 관리형 IAM 정책 삭제
  • S3 버킷 비우기
  • S3 버킷 삭제

S3 소스 버킷의 S3 Inventory 구성 삭제

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Buckets를 선택해요.
  3. Buckets 목록에서 소스 버킷 이름(예: amzn-s3-demo-source-bucket)을 선택해요.
  4. Management 탭을 선택해요.
  5. Inventory configurations 섹션에서 5단계에서 만든 인벤토리 구성(예: tutorial-inventory-config) 옆의 옵션 버튼을 선택해요.
  6. Delete를 선택한 다음 Confirm을 선택해요.

Lambda 함수 삭제

  1. AWS Lambda 콘솔을 https://console.aws.amazon.com/lambda/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Functions를 선택해요.
  3. 4단계에서 만든 함수(예: tutorial-lambda-convert) 옆의 확인란을 선택해요.
  4. Actions를 선택한 다음 Delete를 선택해요.
  5. Delete function 대화 상자에서 Delete를 선택해요.

CloudWatch 로그 그룹 삭제

  1. CloudWatch 콘솔을 https://console.aws.amazon.com/cloudwatch/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Logs를 선택한 다음 Log groups를 선택해요.
  3. 4단계에서 만든 Lambda 함수(예: tutorial-lambda-convert)로 이름이 끝나는 로그 그룹 옆의 확인란을 선택해요.
  4. Actions를 선택한 다음 Delete log group(s) 를 선택해요.
  5. Delete log group(s) 대화 상자에서 Delete를 선택해요.

인라인 정책과 함께 IAM 역할 삭제

2단계, 3단계, 6단계에서 만든 IAM 역할을 삭제하려면 다음을 수행해요.

  1. AWS Management Console에 로그인하고 IAM 콘솔을 https://console.aws.amazon.com/iam/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Roles를 선택하고 삭제하려는 역할 이름 옆의 확인란을 선택해요.
  3. Delete를 선택해요.
  4. 확인 대화 상자에서 프롬프트에 따라 텍스트 입력 필드에 필요한 응답을 입력하고 Delete를 선택해요.

고객 관리형 IAM 정책 삭제

6단계에서 만든 고객 관리형 IAM 정책을 삭제하려면 다음을 수행해요.

  1. AWS Management Console에 로그인하고 IAM 콘솔을 https://console.aws.amazon.com/iam/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Policies를 선택해요.
  3. 6단계에서 만든 정책(예: tutorial-s3batch-policy) 옆의 옵션 버튼을 선택해요. 검색 상자로 정책 목록을 필터링할 수 있어요.
  4. Actions를 선택한 다음 Delete를 선택해요.
  5. 텍스트 필드에 정책 이름을 입력해 이 정책을 삭제할 것임을 확인한 다음 Delete를 선택해요.

S3 버킷 비우기

사전 요구 사항, 1단계, 5단계에서 만든 S3 버킷을 비우려면 다음을 수행해요.

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Buckets를 선택해요.
  3. Buckets 목록에서 비우려는 버킷 이름 옆의 옵션 버튼을 선택한 다음 Empty를 선택해요.
  4. Empty bucket 페이지에서 텍스트 필드에 permanently delete를 입력해 버킷을 비울 것임을 확인한 다음 Empty를 선택해요.

S3 버킷 삭제

사전 요구 사항, 1단계, 5단계에서 만든 S3 버킷을 삭제하려면 다음을 수행해요.

  1. AWS Management Console에 로그인하고 Amazon S3 콘솔을 https://console.aws.amazon.com/s3/ 에서 열어요.
  2. 왼쪽 탐색 창에서 Buckets를 선택해요.
  3. Buckets 목록에서 삭제하려는 버킷 이름 옆의 옵션 버튼을 선택해요.
  4. Delete를 선택해요.
  5. Delete bucket 페이지에서 텍스트 필드에 버킷 이름을 입력해 버킷을 삭제할 것임을 확인한 다음 Delete bucket을 선택해요.

다음 단계

이 튜토리얼을 완료한 후 다른 관련 사용 사례를 더 탐색할 수 있어요.

  • Amazon CloudFront를 사용해 트랜스코딩된 미디어 파일을 전 세계 시청자에게 스트리밍할 수 있어요. 자세한 내용은 Tutorial: Hosting on-demand streaming video with Amazon S3, Amazon CloudFront, and Amazon Route 53 문서를 참고하세요.
  • 비디오를 S3 소스 버킷에 업로드하는 순간 트랜스코딩할 수 있어요. 그러려면 Amazon S3 이벤트 트리거를 구성해 MediaConvert로 S3의 새 객체를 트랜스코딩하는 Lambda 함수를 자동으로 호출할 수 있어요. 자세한 내용은 AWS Lambda Developer Guide의 Tutorial: Using an Amazon S3 trigger to invoke a Lambda function 문서를 참고하세요.