今日のデジタル環境では、さまざまなデバイスやネットワーク条件で高品質のビデオ コンテンツを配信することが、これまで以上に重要になっています。ストリーミング プラットフォーム、オンライン学習ポータル、ソーシャル メディア アプリ、ビデオ再生を必要とするアプリケーションなどを開発する場合でも、シームレスなビデオ ストリーミングは最適なユーザー エクスペリエンスを実現するために不可欠です。
クラウドベースのエンコーディング サービスを使用してビデオ変換を自動化すると、アダプティブ ストリームを簡単に生成して、インフラストラクチャの複雑さを軽減しながらユーザーに最高のビデオ品質を提供できます。このソリューションを実装してアプリケーションの要求を満たす方法を検討してみましょう。私たちの目標は、簡単に導入でき、メンテナンスが不要で、拡大するユーザー ベースをサポートするソリューションを作成することです。
ここでは、最も人気のあるビデオ ストリーミング プロトコルの 1 つである HLS (HTTP Live Streaming) に焦点を当てます。HLS では、エンコードとセグメンテーションが使用されます。元のビデオは、異なるビットレートと解像度を持つ複数のバージョンにエンコードされます。エンコードされたこれらのバージョンは、通常 2 ~ 10 秒の長さの小さなチャンクに分割され、各チャンクは個別のファイルとして保存されます。次に、プレイリストが作成されます。まず、ビデオのエンコードされたバージョンごとに、個々のチャンクの URL を含むプレイリストが生成されます。
次に、ストリームのさまざまなバージョン (および対応するプレイリスト) とその解像度とビットレートを参照する単一のマスター プレイリストが作成されます。この設定により、クライアント アプリはクライアントのデバイスの解像度、ビューポートのサイズ、ネットワークの状態などの要素に基づいて最適なストリームを選択できるため、必要なセグメントのみがダウンロードされます。
動画から HLS ストリームを作成するためのツールは数多くあります。FFmpeg を直接実行したり、クラウドベースのサービスを使用して変換を処理し、インフラストラクチャ管理を回避したりすることができます。このようなサービスの例としては、AWS Elemental MediaConvert、Google Cloud Transcoder、Bitmovin などがあります。この記事では、MediaConvert に焦点を当てます。以下は、アップロードされた動画を HLS に自動的に変換し、ストリームをユーザーが利用できるようにするためのワークフローの例です。ワークフローを進める際には、各ステップにラベルが付けられた添付の図を参照してください。
ユーザーは、モバイルまたは Web クライアント アプリを使用して、ビデオを S3 バケットにアップロードします。
Lambda 関数は、Video Uploads S3 バケットの ObjectCreate イベントによってトリガーされます。この関数は、指定された設定を使用して MediaConvert ジョブを作成し、終了します (ビデオ変換が完了するまで待機しません)。MediaConvert API は、コーデックの選択、ビットレート、品質、オーディオ処理など、さまざまな設定を提供します。また、360p、720p、1080p など、異なる圧縮設定で複数のバージョンのストリームを生成することもできます。
エンコード設定の選択はこの記事の範囲外ですが、コードサンプルには、1 Mbps ビットレートの 1 つのレンディションを含む基本的な HLS パッケージングジョブが含まれています。設定は、各アプリケーションの要件に合わせて簡単に拡張できます。IAM 権限に関しては、この機能には、ソース S3 バケットへの読み取りアクセス、宛先 S3 バケットへの書き込みアクセス、および MediaConvert API へのアクセスが必要です。
import boto3 import re output_bucket_name = 'converted-videos-bucket' mediaconvert_role_arn = 'arn:aws:iam::123456789012:role/MediaConvertRole' # output bucket access s3_client = boto3.client('s3') mediaconvert_client = boto3.client('mediaconvert') hls_main_playlist_suffix = '-hls.m3u8' # regex used to normalize the object key for the client request token client_request_token_symbols_to_skip = r'[^a-zA-Z0-9-_]' def lambda_handler(event, context): # get S3 bucket name and object key from the event bucket_name = event['Records'][0]['s3']['bucket']['name'] object_key = event['Records'][0]['s3']['object']['key'] # also used as media id # normalize the object key for the client request token client_request_token_obj_key = re.sub(client_request_token_symbols_to_skip, '_', object_key) # call MediaConvert to transcode the video create_job_response = mediaconvert_client.create_job( Role=mediaconvert_role_arn, ClientRequestToken=client_request_token_obj_key, Settings={ 'Inputs': [ { 'FileInput': f's3://{bucket_name}/{object_key}', 'AudioSelectors': { 'Audio Selector 1': { 'DefaultSelection': 'DEFAULT', }, }, } ], 'OutputGroups': [ { 'Name': 'DefaultOutputGroup', 'OutputGroupSettings': { 'Type': 'HLS_GROUP_SETTINGS', 'HlsGroupSettings': { 'Destination': f's3://{output_bucket_name}/{object_key}-hls', 'DirectoryStructure': 'SUBDIRECTORY_PER_STREAM', 'SegmentLength': 5, 'MinSegmentLength': 2, 'SegmentsPerSubdirectory': 500, 'ProgressiveWriteHlsManifest': 'DISABLED', }, }, 'Outputs': [ { 'NameModifier': '-h264', 'ContainerSettings': { 'Container': 'M3U8', }, 'VideoDescription': { 'CodecSettings': { 'Codec': 'H_264', 'H264Settings': { 'RateControlMode': 'VBR', 'Bitrate': 1000000, }, }, }, 'AudioDescriptions': [ { 'AudioSourceName': 'Audio Selector 1', 'CodecSettings': { 'Codec': 'AAC', 'AacSettings': { 'Bitrate': 96000, 'CodingMode': 'CODING_MODE_2_0', 'SampleRate': 48000, }, }, }, ], }, ], } ], }, ) print('Created a MediaConvert job:', create_job_response) return { 'statusCode': 200, 'body': 'OK', }
MediaConvert はビデオを処理し、出力 S3 バケットに HLS プレイリストとビデオ セグメントを生成します。出力バケットは、プレイリストとビデオ セグメントをキャッシュする CDN に接続されます。この例では Cloudfront を使用していますが、S3 と互換性のある任意の CDN を使用できます。
別の Lambda 関数は、出力バケットの ObjectCreate イベントによってトリガーされます。オブジェクト名フィルターがそのトリガーにアタッチされ、プレイリスト ファイルが作成された場合にのみ関数が実行されるようにします (セグメント ファイルは無視されます)。
この関数は、プレイリストの URL をデータベースのメディア レコードに追加します。ストレージ レイヤーについてはこの記事の範囲外であるため、コード サンプルでは URL を単に出力しています。
import boto3 s3_client = boto3.client('s3') def lambda_handler(event, context): # this function is triggered only when a playlist file # with object key that looks like this '<video_id>-hls.m3u8' # is created in the S3 bucket # get object key from the event object_key = event['Records'][0]['s3']['object']['key'] # extract video id from the object key video_id = object_key.replace('-hls.m3u8', '') print(f'HLS playlist {object_key} created for video {video_id}') # TODO: update the video record in the database return { 'statusCode': 200, 'body': 'OK', }
ユーザーがクライアント アプリの UI でビデオを開くと、クライアント アプリは API を使用してデータベースからメディア レコードを取得します。このメディア レコードには、マスター プレイリストの URL が含まれています。
ビデオ プレーヤーは CDN からマスター プレイリストを取得し、ビューポートのサイズ、画面解像度、ネットワークの状態などの要素に基づいて再生するストリームを決定します。次に、CDN からストリーム プレイリストとビデオ セグメントを取得し、ビデオの再生を開始します。
このソリューションは導入が非常に簡単で、メンテナンスも必要ありません。多くのユーザーにとってのスケーラビリティに関して、デフォルトでは MediaConvert ジョブが 1 つのキューに追加され、100~200 本のビデオを同時に処理できることに注意することが重要です (リージョンによって異なります)。追加のキューを作成でき (リージョンごとに最大 10 個)、キューに追加するときにジョブに優先順位を割り当てることができます。AWS にクォータの増加を要求するオプションもあります。
結論として、AWS Elemental MediaConvert などのクラウドベースのサービスを使用してビデオ変換を自動化することは、複雑なインフラストラクチャを管理する負担なしに、デバイス間で高品質のストリーミング コンテンツを配信する効果的な方法です。このアプローチは、ビデオのエンコード プロセスを簡素化するだけでなく、スケーラビリティも強化し、プラットフォームが増大する需要に対応できるようにします。
S3、Lambda 関数、CloudFront などのツールを MediaConvert と組み合わせて活用することで、適応型 HLS ストリームを効率的に生成して配信し、ユーザーに最適化された視聴エクスペリエンスを提供できます。