in source/controlplaneapi/runtime/app.py [0:0]
def add_or_update_medialive_output_group(name, program, profile, channel_id):
print(
f"Describing the MediaLive channel '{channel_id}' to get existing InputAttachments, Destinations, and EncoderSettings")
try:
response = medialive_client.describe_channel(
ChannelId=channel_id
)
if response["State"] != "IDLE":
raise BadRequestError(f"MediaLive channel '{channel_id}' is not in 'IDLE' state")
last_known_medialive_config = response
input_attachments = response["InputAttachments"]
destinations = response["Destinations"]
encoder_settings = response["EncoderSettings"]
profile_table = ddb_resource.Table(PROFILE_TABLE_NAME)
response = profile_table.get_item(
Key={
"Name": profile
},
ProjectionExpression="#Name, #ChunkSize",
ExpressionAttributeNames={
"#Name": "Name",
"#ChunkSize": "ChunkSize"
},
ConsistentRead=True
)
if "Item" not in response:
raise NotFoundError(f"Profile '{profile}' not found")
chunk_size = response["Item"]["ChunkSize"]
is_destination_create = True
for index, destination in enumerate(destinations):
if destination["Id"] == "awsmre":
print(f"Updating the existing MRE destination present in the MediaLive channel '{channel_id}'")
destinations[index]["Settings"][0][
"Url"] = f"s3ssl://{MEDIALIVE_S3_BUCKET}/{channel_id}/{program}/{name}/{profile}/{program}_{name}"
is_destination_create = False
break
if is_destination_create:
print(f"Creating a new destination for MRE in the MediaLive channel '{channel_id}'")
mre_destination = {
"Id": "awsmre",
"Settings": [
{
"Url": f"s3ssl://{MEDIALIVE_S3_BUCKET}/{channel_id}/{program}/{name}/{profile}/{program}_{name}"
}
]
}
# Append MRE destination to the existing channel destinations
destinations.append(mre_destination)
audio_descriptions = encoder_settings["AudioDescriptions"] if "AudioDescriptions" in encoder_settings else []
if not audio_descriptions:
# At this time, MRE automatically picks the first input attached to the MediaLive channel
# to get the AudioSelectors information. In a future update, this input picking could be user driven
audio_selectors = input_attachments[0]["InputSettings"]["AudioSelectors"] if "AudioSelectors" in \
input_attachments[0][
"InputSettings"] else []
audio_selectors_name_list = [audio_selector["Name"] for audio_selector in audio_selectors]
for audio_selector_name in audio_selectors_name_list:
audio_descriptions.append(
{
"AudioSelectorName": audio_selector_name,
"AudioTypeControl": "FOLLOW_INPUT",
"LanguageCodeControl": "FOLLOW_INPUT",
"Name": f"audio_{uuid.uuid4().hex}"
}
)
# Include AudioDescriptions in the EncoderSettings
encoder_settings["AudioDescriptions"] = audio_descriptions
audio_description_name_list = [audio_description["Name"] for audio_description in audio_descriptions]
output_groups = encoder_settings["OutputGroups"]
is_new_output_group = True
for index, output_group in enumerate(output_groups):
if "HlsGroupSettings" in output_group["OutputGroupSettings"] and \
output_group["OutputGroupSettings"]["HlsGroupSettings"]["Destination"][
"DestinationRefId"] == "awsmre":
print(f"Updating the existing OutputGroup for MRE in the MediaLive channel '{channel_id}'")
output_groups[index]["OutputGroupSettings"]["HlsGroupSettings"]["SegmentLength"] = int(chunk_size)
output_groups[index]["OutputGroupSettings"]["HlsGroupSettings"]["ProgramDateTimePeriod"] = int(
chunk_size)
output_groups[index]["Outputs"][0]["AudioDescriptionNames"] = audio_description_name_list
is_new_output_group = False
break
if is_new_output_group:
mre_output_group = {
"OutputGroupSettings": {
"HlsGroupSettings": {
"AdMarkers": [],
"CaptionLanguageMappings": [],
"CaptionLanguageSetting": "OMIT",
"ClientCache": "ENABLED",
"CodecSpecification": "RFC_4281",
"Destination": {
"DestinationRefId": "awsmre"
},
"DirectoryStructure": "SINGLE_DIRECTORY",
"DiscontinuityTags": "INSERT",
"HlsId3SegmentTagging": "DISABLED",
"IFrameOnlyPlaylists": "DISABLED",
"IncompleteSegmentBehavior": "AUTO",
"IndexNSegments": 10,
"InputLossAction": "PAUSE_OUTPUT",
"IvInManifest": "INCLUDE",
"IvSource": "FOLLOWS_SEGMENT_NUMBER",
"KeepSegments": 21,
"ManifestCompression": "NONE",
"ManifestDurationFormat": "FLOATING_POINT",
"Mode": "VOD",
"OutputSelection": "VARIANT_MANIFESTS_AND_SEGMENTS",
"ProgramDateTime": "INCLUDE",
"ProgramDateTimePeriod": int(chunk_size),
"RedundantManifest": "DISABLED",
"SegmentLength": int(chunk_size),
"SegmentationMode": "USE_SEGMENT_DURATION",
"SegmentsPerSubdirectory": 10000,
"StreamInfResolution": "INCLUDE",
"TimedMetadataId3Frame": "PRIV",
"TimedMetadataId3Period": 10,
"TsFileMode": "SEGMENTED_FILES"
}
},
"Outputs": [
{
"AudioDescriptionNames": audio_description_name_list,
"CaptionDescriptionNames": [],
"OutputName": "awsmre",
"OutputSettings": {
"HlsOutputSettings": {
"H265PackagingType": "HVC1",
"HlsSettings": {
"StandardHlsSettings": {
"AudioRenditionSets": "program_audio",
"M3u8Settings": {
"AudioFramesPerPes": 4,
"AudioPids": "492-498",
"NielsenId3Behavior": "NO_PASSTHROUGH",
"PcrControl": "PCR_EVERY_PES_PACKET",
"PmtPid": "480",
"ProgramNum": 1,
"Scte35Behavior": "NO_PASSTHROUGH",
"Scte35Pid": "500",
"TimedMetadataBehavior": "NO_PASSTHROUGH",
"TimedMetadataPid": "502",
"VideoPid": "481"
}
}
},
"NameModifier": "_1"
}
},
"VideoDescriptionName": "video_awsmre"
}
]
}
# Append MRE output group to the existing channel output groups
output_groups.append(mre_output_group)
encoder_settings["OutputGroups"] = output_groups
video_descriptions = encoder_settings["VideoDescriptions"]
is_new_video_description = True
for index, video_description in enumerate(video_descriptions):
if video_description["Name"] == "video_awsmre":
print(
f"Skipping the addition of new video description for MRE as it already exists in the MediaLive channel '{channel_id}'")
is_new_video_description = False
break
if is_new_video_description:
mre_video_description = {
"CodecSettings": {
"H264Settings": {
"AdaptiveQuantization": "AUTO",
"AfdSignaling": "NONE",
"Bitrate": 5000000,
"BufSize": 5000000,
"ColorMetadata": "INSERT",
"EntropyEncoding": "CABAC",
"FlickerAq": "ENABLED",
"ForceFieldPictures": "DISABLED",
"FramerateControl": "INITIALIZE_FROM_SOURCE",
"GopBReference": "DISABLED",
"GopClosedCadence": 1,
"GopNumBFrames": 2,
"GopSize": 1,
"GopSizeUnits": "SECONDS",
"Level": "H264_LEVEL_AUTO",
"LookAheadRateControl": "MEDIUM",
"MaxBitrate": 5000000,
"NumRefFrames": 1,
"ParControl": "INITIALIZE_FROM_SOURCE",
"Profile": "HIGH",
"QvbrQualityLevel": 8,
"RateControlMode": "QVBR",
"ScanType": "PROGRESSIVE",
"SceneChangeDetect": "DISABLED",
"SpatialAq": "ENABLED",
"SubgopLength": "FIXED",
"Syntax": "DEFAULT",
"TemporalAq": "ENABLED",
"TimecodeInsertion": "DISABLED"
}
},
"Name": "video_awsmre",
"RespondToAfd": "NONE",
"ScalingBehavior": "DEFAULT",
"Sharpness": 50
}
# Append MRE video description to the existing channel video descriptions
video_descriptions.append(mre_video_description)
encoder_settings["VideoDescriptions"] = video_descriptions
# Update the MediaLive channel with modified Destinations and EncoderSettings
print(f"Updating the MediaLive channel '{channel_id}' with modified Destinations and EncoderSettings")
medialive_client.update_channel(
ChannelId=channel_id,
Destinations=destinations,
EncoderSettings=encoder_settings
)
except medialive_client.exceptions.NotFoundException as e:
print(f"MediaLive channel '{channel_id}' not found")
raise Exception(e)
except Exception as e:
print(
f"Unable to add a new or update an existing OutputGroup for MRE in the MediaLive channel '{channel_id}': {str(e)}")
raise Exception(e)
else:
return last_known_medialive_config