Как транслировать загруженное видео с помощью AWS?
Основная задача - защитить видео от скачивания.
Для этого мы решили настроить потоковое видео с S3.
В проекте есть PHP API и клиент. API генерирует предварительно подписанный URL-адрес, по которому видео должно быть загружено в корзину S3. Затем клиент может запросить видео по URL-адресу CDN. Но с подписанными URL-адресами видео можно скачать с клиента.
Мы нашли подход, когда видео конвертируется в MPEG-DASH с помощью AWS Elemental MediaConverter. Задание для MediaConverter можно создать через API. Затем его следует транслировать через AWS Elemental MediaPackage и CloudFront.
Проблемы следующие:
- Как понять, когда загрузка видео завершена, чтобы запустить MediaConverter Job?
- Файл MPEG-DASH имеет манифест .mpd, но для MediaPackage требуется манифест .smil. Как автоматически сгенерировать этот файл из .mpd?
PS Если я где-то ошибаюсь, поправьте меня, пожалуйста.
2 ответа
Как понять, когда загрузка видео завершена, чтобы запустить MediaConverter Job?Этого можно добиться с помощью следующего рабочего процесса
- пользователь загружает видео в сегмент папки просмотра в S3
- событие s3: PutItem запускает функцию Lambda, которая вызывает MediaConvert для преобразования видео.
- Преобразованные видео хранятся в S3 с помощью MediaConvert.
Инструкции высокого уровня, как показано ниже.
создайте корзину Amazon S3 для загрузки конвертируемых видео. Пример названия корзины: vod-watchfolder-firstname-lastname
создать корзину Amazon S3 для хранения преобразованных видеовыходов из MediaConvert (обеспечивает общедоступное чтение, размещение статических веб-сайтов и CORS)
<?xml version="1.0" encoding="UTF-8"?> <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <MaxAgeSeconds>3000</MaxAgeSeconds> <AllowedHeader>*</AllowedHeader> </CORSRule> </CORSConfiguration>
создать роль IAM для передачи в MediaConvert. Используйте консоль IAM для создания новой роли. Назовите его MediaConvertRole и выберите AWS Lambda в качестве типа роли. Используйте встроенные политики для предоставления разрешений другим ресурсам, необходимым для выполнения лямбда-выражения.
Создайте роль IAM для вашей лямбда-функции. Используйте консоль IAM для создания роли. Назовите его VODLambdaRole и выберите AWS Lambda в качестве типа роли. Прикрепите управляемую политику под названием AWSLambdaBasicExecutionRole к этой роли, чтобы предоставить необходимые разрешения CloudWatch Logs. Используйте встроенные политики для предоставления разрешений другим ресурсам, необходимым для выполнения лямбда-выражения.
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*", "Effect": "Allow", "Sid": "Logging" }, { "Action": [ "iam:PassRole" ], "Resource": [ "ARNforMediaConvertRole" ], "Effect": "Allow", "Sid": "PassRole" }, { "Action": [ "mediaconvert:*" ], "Resource": [ "*" ], "Effect": "Allow", "Sid": "MediaConvertService" }, { "Action": [ "s3:*" ], "Resource": [ "*" ], "Effect": "Allow", "Sid": "S3Service" } ] }
Создайте лямбда-функцию для преобразования видео. Используйте консоль AWS Lambda, чтобы создать новую функцию Lambda с именем VODLambdaConvert, которая будет обрабатывать запросы API. Используйте предоставленный пример реализации convert.py для кода вашей функции.
#!/usr/bin/env python import glob import json import os import uuid import boto3 import datetime import random from urllib.parse import urlparse import logging from botocore.client import ClientError logger = logging.getLogger() logger.setLevel(logging.INFO) S3 = boto3.resource('s3') def handler(event, context): ''' Watchfolder handler - this lambda is triggered when video objects are uploaded to the SourceS3Bucket/inputs folder. It will look for two sets of file inputs: SourceS3Bucket/inputs/SourceS3Key: the input video to be converted SourceS3Bucket/jobs/*.json: job settings for MediaConvert jobs to be run against the input video. If there are no settings files in the jobs folder, then the Default job will be run from the job.json file in lambda environment. Ouput paths stored in outputGroup['OutputGroupSettings']['DashIsoGroupSettings']['Destination'] are constructed from the name of the job settings files as follows: s3://<MediaBucket>/<basename(job settings filename)>/<basename(input)>/<Destination value from job settings file> ''' assetID = str(uuid.uuid4()) sourceS3Bucket = event['Records'][0]['s3']['bucket']['name'] sourceS3Key = event['Records'][0]['s3']['object']['key'] sourceS3 = 's3://'+ sourceS3Bucket + '/' + sourceS3Key destinationS3 = 's3://' + os.environ['DestinationBucket'] mediaConvertRole = os.environ['MediaConvertRole'] application = os.environ['Application'] region = os.environ['AWS_DEFAULT_REGION'] statusCode = 200 jobs = [] job = {} # Use MediaConvert SDK UserMetadata to tag jobs with the assetID # Events from MediaConvert will have the assetID in UserMedata jobMetadata = {} jobMetadata['assetID'] = assetID jobMetadata['application'] = application jobMetadata['input'] = sourceS3 try: # Build a list of jobs to run against the input. Use the settings files in WatchFolder/jobs # if any exist. Otherwise, use the default job. jobInput = {} # Iterates through all the objects in jobs folder of the WatchFolder bucket, doing the pagination for you. Each obj # contains a jobSettings JSON bucket = S3.Bucket(sourceS3Bucket) for obj in bucket.objects.filter(Prefix='jobs/'): if obj.key != "jobs/": jobInput = {} jobInput['filename'] = obj.key logger.info('jobInput: %s', jobInput['filename']) jobInput['settings'] = json.loads(obj.get()['Body'].read()) logger.info(json.dumps(jobInput['settings'])) jobs.append(jobInput) # Use Default job settings in the lambda zip file in the current working directory if not jobs: with open('job.json') as json_data: jobInput['filename'] = 'Default' logger.info('jobInput: %s', jobInput['filename']) jobInput['settings'] = json.load(json_data) logger.info(json.dumps(jobInput['settings'])) jobs.append(jobInput) # get the account-specific mediaconvert endpoint for this region mediaconvert_client = boto3.client('mediaconvert', region_name=region) endpoints = mediaconvert_client.describe_endpoints() # add the account-specific endpoint to the client session client = boto3.client('mediaconvert', region_name=region, endpoint_url=endpoints['Endpoints'][0]['Url'], verify=False) for j in jobs: jobSettings = j['settings'] jobFilename = j['filename'] # Save the name of the settings file in the job userMetadata jobMetadata['settings'] = jobFilename # Update the job settings with the source video from the S3 event jobSettings['Inputs'][0]['FileInput'] = sourceS3 # Update the job settings with the destination paths for converted videos. We want to replace the # destination bucket of the output paths in the job settings, but keep the rest of the # path destinationS3 = 's3://' + os.environ['DestinationBucket'] + '/' \ + os.path.splitext(os.path.basename(sourceS3Key))[0] + '/' \ + os.path.splitext(os.path.basename(jobFilename))[0] for outputGroup in jobSettings['OutputGroups']: logger.info("outputGroup['OutputGroupSettings']['Type'] == %s", outputGroup['OutputGroupSettings']['Type']) if outputGroup['OutputGroupSettings']['Type'] == 'FILE_GROUP_SETTINGS': templateDestination = outputGroup['OutputGroupSettings']['FileGroupSettings']['Destination'] templateDestinationKey = urlparse(templateDestination).path logger.info("templateDestinationKey == %s", templateDestinationKey) outputGroup['OutputGroupSettings']['FileGroupSettings']['Destination'] = destinationS3+templateDestinationKey elif outputGroup['OutputGroupSettings']['Type'] == 'HLS_GROUP_SETTINGS': templateDestination = outputGroup['OutputGroupSettings']['HlsGroupSettings']['Destination'] templateDestinationKey = urlparse(templateDestination).path logger.info("templateDestinationKey == %s", templateDestinationKey) outputGroup['OutputGroupSettings']['HlsGroupSettings']['Destination'] = destinationS3+templateDestinationKey elif outputGroup['OutputGroupSettings']['Type'] == 'DASH_ISO_GROUP_SETTINGS': templateDestination = outputGroup['OutputGroupSettings']['DashIsoGroupSettings']['Destination'] templateDestinationKey = urlparse(templateDestination).path logger.info("templateDestinationKey == %s", templateDestinationKey) outputGroup['OutputGroupSettings']['DashIsoGroupSettings']['Destination'] = destinationS3+templateDestinationKey elif outputGroup['OutputGroupSettings']['Type'] == 'DASH_ISO_GROUP_SETTINGS': templateDestination = outputGroup['OutputGroupSettings']['DashIsoGroupSettings']['Destination'] templateDestinationKey = urlparse(templateDestination).path logger.info("templateDestinationKey == %s", templateDestinationKey) outputGroup['OutputGroupSettings']['DashIsoGroupSettings']['Destination'] = destinationS3+templateDestinationKey elif outputGroup['OutputGroupSettings']['Type'] == 'MS_SMOOTH_GROUP_SETTINGS': templateDestination = outputGroup['OutputGroupSettings']['MsSmoothGroupSettings']['Destination'] templateDestinationKey = urlparse(templateDestination).path logger.info("templateDestinationKey == %s", templateDestinationKey) outputGroup['OutputGroupSettings']['MsSmoothGroupSettings']['Destination'] = destinationS3+templateDestinationKey elif outputGroup['OutputGroupSettings']['Type'] == 'CMAF_GROUP_SETTINGS': templateDestination = outputGroup['OutputGroupSettings']['CmafGroupSettings']['Destination'] templateDestinationKey = urlparse(templateDestination).path logger.info("templateDestinationKey == %s", templateDestinationKey) outputGroup['OutputGroupSettings']['CmafGroupSettings']['Destination'] = destinationS3+templateDestinationKey else: logger.error("Exception: Unknown Output Group Type %s", outputGroup['OutputGroupSettings']['Type']) statusCode = 500 logger.info(json.dumps(jobSettings)) # Convert the video using AWS Elemental MediaConvert job = client.create_job(Role=mediaConvertRole, UserMetadata=jobMetadata, Settings=jobSettings) except Exception as e: logger.error('Exception: %s', e) statusCode = 500 raise finally: return { 'statusCode': statusCode, 'body': json.dumps(job, indent=4, sort_keys=True, default=str), 'headers': {'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*'} }
Обязательно сконфигурируйте свою функцию для использования роли IAM VODLambdaRole, которую вы создали в предыдущем разделе.
Создайте триггер события S3 для лямбда-выражения Convert. Используйте консоль AWS Lambda, чтобы добавить триггер putItem из корзины S3 vod-watchfolder-firstname-lastname в лямбда-выражение VODLambdaConvert.
протестировать автоматизацию папки наблюдения. Вы можете использовать собственное видео или видео test.mp4, находящееся в этой папке, для тестирования рабочего процесса.
Подробнее см. В этом документе https://github.com/aws-samples/aws-media-services-vod-automation/blob/master/MediaConvert-WorkflowWatchFolderAndNotification/README-tutorial.md.
Файл MPEG-DASH имеет манифест .mpd, но для MediaPackage требуется манифест .smil. Как автоматически сгенерировать этот файл из .mpd?
- на сегодняшний день в MediaConvert нет функции автоматического создания файла smil. Следовательно, вы можете рассмотреть возможность изменения вывода на HLS и загрузки на Mediapackage. Или, создав файл smil вручную. Справочный документ ниже
- Загрузка HLS VOD в Mediapackage: https://github.com/aws-samples/aws-media-services-simple-vod-workflow/blob/master/13-VODMediaPackage/README-tutorial.md
- Создание файла smil: https://docs.aws.amazon.com/mediapackage/latest/ug/supported-inputs-vod-smil.html
Как понять, когда загрузка видео завершена, чтобы запустить MediaConverter Job?
Я предлагаю вам прочитать эту статью, в которой показано, как автоматизировать рабочий процесс с помощью S3 и лямбда для запуска задания : медиа-преобразованияGitHub: aws-samples / aws-media-services-vod-automation
Файл MPEG-DASH имеет манифест .mpd, но для MediaPackage требуется манифест .smil. Как автоматически сгенерировать этот файл из .mpd?
Можно ли использовать изменение вывода mediaconvert в HLS и передачу в Mediapackage, а затем преобразовать вывод в MPEG-DASH клиенту? В этой статье показано, как настроить эту часть: GitHub: aws-samples / aws-media-services-simple-vod-workflow.
В противном случае вам необходимо создать файл SMIL - AWS Elemental MediaPackage.