AWS MediaConvert转码HLS无音频问题排查求助
HLS转码后无音频问题的排查与解决
问题背景
使用AWS MediaConvert将视频转码为DASH和HLS格式,DASH输出音视频播放正常,但HLS输出仅能播放视频、无音频。S3存储桶的输出目录中已生成.aac音频文件、.ts视频文件及.m3u8清单文件。
相关代码与配置
MediaConvert服务类代码(Python)
class MediaConvertService: aws_region = settings.AWS_REGION_NAME role_arn = settings.MEDIA_CONVERT_ROLE_ARN job_template = settings.MEDIA_CONVERT_JOB_TEMPLATE @classmethod def get_client(cls): return boto3.client("mediaconvert", region_name=cls.aws_region) @classmethod def prepare_media_convert_job_settings(cls, s3_url, bucket_name, object_key): job_settings = { "Role": cls.role_arn, "JobTemplate": cls.job_template, "Settings": { "Inputs": [ { "FileInput": s3_url, "VideoSelector": { "ColorSpace": "FOLLOW", }, "AudioSelectors": { "Audio Selector 1": {"DefaultSelection": "DEFAULT"} }, "TimecodeSource": "ZEROBASED", } ], "OutputGroups": [ { "CustomName": "CF-AEMC-GRP", "Name": "DASH ISO", "OutputGroupSettings": { "Type": "DASH_ISO_GROUP_SETTINGS", "DashIsoGroupSettings": { "Destination": f"s3://{bucket_name}/output/DASH/{object_key}/", "FragmentLength": 2, "SegmentLength": 30, "AudioChannelConfigSchemeIdUri": "MPEG_CHANNEL_CONFIGURATION" } }, "Outputs": [ { "ContainerSettings": {"Container": "MPD"}, "VideoDescription": { "CodecSettings": { "Codec": "H_264", "H264Settings": { "MaxBitrate": 20000000, "RateControlMode": "QVBR", "SceneChangeDetect": "TRANSITION_DETECTION", "QvbrSettings": { "QvbrQualityLevel": 7 } } } }, "NameModifier": "_dash_video" }, { "ContainerSettings": {"Container": "MPD"}, "AudioDescriptions": [ { "CodecSettings": { "Codec": "AAC", "AacSettings": { "Bitrate": 96000, "CodingMode": "CODING_MODE_2_0", "SampleRate": 48000 } } } ], "NameModifier": "_dash_audio" } ] }, { "CustomName": "CF-AEMC-GRP-HLS", "Name": "Apple HLS", "OutputGroupSettings": { "Type": "HLS_GROUP_SETTINGS", "HlsGroupSettings": { "Destination": f"s3://{bucket_name}/output/HLS/{object_key}/", "SegmentLength": 6, "MinSegmentLength": 2, "OutputSelection": "MANIFESTS_AND_SEGMENTS", "DirectoryStructure": "SINGLE_DIRECTORY", "ManifestCompression": "NONE", "StreamInfResolution": "INCLUDE" } }, "Outputs": [ { "ContainerSettings": {"Container": "M3U8"}, "VideoDescription": { "CodecSettings": { "Codec": "H_264", "H264Settings": { "MaxBitrate": 20000000, "RateControlMode": "QVBR", "SceneChangeDetect": "TRANSITION_DETECTION", "QvbrSettings": { "QvbrQualityLevel": 7 } } } }, "NameModifier": "_hls_video" }, { "ContainerSettings": {"Container": "M3U8"}, "AudioDescriptions": [ { "AudioSourceName": "Audio Selector 1", "CodecSettings": { "Codec": "AAC", "AacSettings": { "Bitrate": 96000, "CodingMode": "CODING_MODE_2_0", "SampleRate": 48000 } } } ], "NameModifier": "_hls_audio" } ] } ] }, } return job_settings @classmethod def create_job(cls, s3_url, bucket_name, object_key): job_settings = cls.prepare_media_convert_job_settings( s3_url=s3_url, bucket_name=bucket_name, object_key=object_key ) mediaconvert_client = cls.get_client() response = mediaconvert_client.create_job(**job_settings) assert response.get("ResponseMetadata", {}).get("HTTPStatusCode") == 201 # remove extension from object key key = object_key.split(".")[0] dash_url = settings.DASH_FILE_PATH.format( bucket_name=bucket_name, region=cls.aws_region, content_dir=f"DASH/{object_key}", dash_file_name=key, ) hls_url = settings.HLS_FILE_PATH.format( bucket_name=bucket_name, region=cls.aws_region, content_dir=f"HLS/{object_key}", hls_file_name=key, ) return dash_url, hls_url
作业模板JSON
{ "Description": "DASH ISO media convert for videos", "Category": "video", "Name": " Prod AEMC Template", "Settings": { "TimecodeConfig": { "Source": "ZEROBASED" }, "OutputGroups": [ { "CustomName": "CF-AEMC-GRP", "Name": "DASH ISO", "Outputs": [ { "ContainerSettings": { "Container": "MPD" }, "VideoDescription": { "CodecSettings": { "Codec": "H_264", "H264Settings": { "MaxBitrate": 10000000, "RateControlMode": "QVBR", "SceneChangeDetect": "TRANSITION_DETECTION" } } }, "NameModifier": "_dash_video" }, { "ContainerSettings": { "Container": "MPD" }, "AudioDescriptions": [ { "AudioSourceName": "Audio Selector 1", "CodecSettings": { "Codec": "AAC", "AacSettings": { "Bitrate": 96000, "CodingMode": "CODING_MODE_2_0", "SampleRate": 48000 } } } ], "NameModifier": "_dash_audio" } ], "OutputGroupSettings": { "Type": "DASH_ISO_GROUP_SETTINGS", "DashIsoGroupSettings": { "AudioChannelConfigSchemeIdUri": "MPEG_CHANNEL_CONFIGURATION", "SegmentLength": 30, "Destination": "s3://content/output/DASH/", "DestinationSettings": { "S3Settings": { "StorageClass": "STANDARD" } }, "FragmentLength": 2 } } }, { "CustomName": "CF-AEMC-GRP-HLS", "Name": "Apple HLS", "Outputs": [ { "ContainerSettings": { "Container": "M3U8", "M3u8Settings": {} }, "VideoDescription": { "CodecSettings": { "Codec": "H_264", "H264Settings": { "MaxBitrate": 20000000, "RateControlMode": "QVBR", "SceneChangeDetect": "TRANSITION_DETECTION" } } }, "OutputSettings": { "HlsSettings": {} }, "NameModifier": "_hls_video" }, { "ContainerSettings": { "Container": "M3U8", "M3u8Settings": {} }, "AudioDescriptions": [ { "AudioSourceName": "Audio Selector 1", "CodecSettings": { "Codec": "AAC", "AacSettings": { "Bitrate": 96000, "CodingMode": "CODING_MODE_2_0", "SampleRate": 48000 } } } ], "OutputSettings": { "HlsSettings": {} }, "NameModifier": "_hls_audio" } ], "OutputGroupSettings": { "Type": "HLS_GROUP_SETTINGS", "HlsGroupSettings": { "SegmentLength": 10, "Destination": "s3://content/output/HLS/", "DestinationSettings": { "S3Settings": { "StorageClass": "STANDARD" } }, "MinSegmentLength": 0 } } } ], "Inputs": [ { "AudioSelectors": { "Audio Selector 1": { "DefaultSelection": "DEFAULT" } }, "VideoSelector": { "ColorSpace": "FOLLOW" }, "TimecodeSource": "ZEROBASED" } ] }, "AccelerationSettings": { "Mode": "DISABLED" }, "StatusUpdateInterval": "SECONDS_60", "Priority": 0, "HopDestinations": [] }
生成的清单文件
根清单文件
#EXTM3U #EXT-X-VERSION:3 #EXT-X-INDEPENDENT-SEGMENTS #EXT-X-STREAM-INF:BANDWIDTH=1128250,AVERAGE-BANDWIDTH=537898,CODECS="avc1.640029",RESOLUTION=640x360,FRAME-RATE=24.000 Padmaavat_Official_Trailer_Ranveer_Singh_Shahid_Kapoor_Deepika_Padukone_hls_video.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=96510,AVERAGE-BANDWIDTH=96210,CODECS="mp4a.40.2" Padmaavat_Official_Trailer_Ranveer_Singh_Shahid_Kapoor_Deepika_Padukone_hls_audio.m3u8
音频清单文件(截取)
#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:7 #EXT-X-MEDIA-SEQUENCE:1 #EXT-X-PLAYLIST-TYPE:VOD #EXTINF:6, Padmaavat_Official_Trailer_Ranveer_Singh_Shahid_Kapoor_Deepika_Padukone_hls_audio_00001.aac #EXTINF:6, Padmaavat_Official_Trailer_Ranveer_Singh_Shahid_Kapoor_Deepika_Padukone_hls_audio_00002.aac #EXTINF:6, #EXT-X-ENDLIST
问题解答
1. HLS输出配置是否存在缺失项?
是的,核心问题是HLS清单的音频流关联配置缺失:
- 当前根清单把音频作为独立的
#EXT-X-STREAM-INF流存在,但多数HLS播放器不会自动加载独立音频流,需要通过#EXT-X-MEDIA标签声明音频轨,并在视频流的#EXT-X-STREAM-INF中用AUDIO属性关联。 - MediaConvert的HLS音频Output中
HlsSettings为空,未设置音频标识信息(如名称、语言),导致生成的清单没有正确的关联标签。 - 当前配置把音频当成了单独的流轨道,不符合HLS多轨合并的规范,应该将音频配置为音频Rendition而非独立自适应流。
2. 确保HLS流正确合并音视频轨道的步骤
步骤1:修改MediaConvert的HLS输出配置
在HLS OutputGroup的音频Output中添加HlsSettings配置,指定音频标识:
# 音频Output的修改内容 { "ContainerSettings": { "Container": "M3U8", "M3u8Settings": { "AudioRenditionSets": "AUDIO" # 声明为音频轨集合 } }, "AudioDescriptions": [ { "AudioSourceName": "Audio Selector 1", "CodecSettings": { "Codec": "AAC", "AacSettings": { "Bitrate": 96000, "CodingMode": "CODING_MODE_2_0", "SampleRate": 48000 } }, "LanguageCode": "eng", "LanguageDescription": "English" } ], "OutputSettings": { "HlsSettings": { "AudioOnlyContainer": "AUTOMATIC", "Name": "audio_main" # 音频轨命名,用于关联 } }, "NameModifier": "_hls_audio" }
同时在视频Output的HlsSettings中添加关联配置:
# 视频Output的修改内容 { "ContainerSettings": {"Container": "M3U8"}, "VideoDescription": { # 原视频编码配置不变 }, "OutputSettings": { "HlsSettings": { "AudioRenditionSets": "AUDIO" # 关联音频轨集合 } }, "NameModifier": "_hls_video" }
步骤2:调整HlsGroupSettings配置
在HlsGroupSettings中补充以下配置:
"HlsGroupSettings": { "Destination": f"s3://{bucket_name}/output/HLS/{object_key}/", "SegmentLength": 6, "MinSegmentLength": 2, "OutputSelection": "MANIFESTS_AND_SEGMENTS", "DirectoryStructure": "SINGLE_DIRECTORY", "ManifestCompression": "NONE", "StreamInfResolution": "INCLUDE", "ManifestDurationFormat": "FLOATING_POINT", "AudioOnlyStream": "ALLOWED" }
步骤3:验证生成的根清单
修改后生成的根清单应包含#EXT-X-MEDIA标签,并在视频流的STREAM-INF中关联音频:
#EXTM3U #EXT-X-VERSION:4 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="AUDIO",NAME="English",LANGUAGE="eng",DEFAULT=YES,AUTOSELECT=YES,URI="xxx_hls_audio.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=1128250,AVERAGE-BANDWIDTH=537898,CODECS="avc1.640029,mp4a.40.2",RESOLUTION=640x360,FRAME-RATE=24.000,AUDIO="AUDIO" xxx_hls_video.m3u8
这样播放器就能识别视频流关联的音频轨,自动加载播放。
步骤4:测试播放
使用标准HLS播放器(如Safari、hls.js)播放修改后的根清单,确认音视频同步播放。
内容的提问来源于stack exchange,提问作者Abinash Biswal
相关产品推荐
相关产品推荐

