多码率自适应即指将指定的音视频文件流统一打包生成一个自适应码流文件,该自适应码流文件包含不同音视频文件流的码率、分辨率等信息,播放器则根据网络带宽环境自动选择最适合当前带宽环境的码流播放。
目前使用比较广的多码率自适应输出格式为HLS和DASH,视频点播目前仅支持HLS多码率自适应生成。更多信息,请参见多码率自适应。
简介
视频点播服务目前支持视频打包模板和字幕打包模板,用于生成可切换不同分辨率和不同语言字幕的多码率自适应文件。支持通过控制台和API的方式创建多码率自适应模板。
相比较传统的单码率播放,自适应码率文件能够让播放器可根据终端网络带宽环境,选择最适合当前带宽环境和终端设备的码流播放,从而提升播放体验。视频打包模板和普通转码模板的区别,如下表所示:
区别项 | 视频打包模板 | 普通转码模板 |
参数配置 | 需要配置打包参数(打包类型、宽带阈值)。 | 无此参数配置。 |
字幕添加 | 可设置压制字幕及外挂字幕。 | 只能通过API的方式设置压制字幕。 |
播放效果 | 可根据客户当前宽带环境自动选择码率进行播放。 | 只能播放指定的码流。 |
注意事项
视频打包模板不支持使用标准加密,如果要使用标准加密,请使用普通转码模板。
字幕文件必须和视频源文件存储在同一个区域,同一个OSS Bucket中。
字幕打包模板不能单独创建使用,必须与视频打包模板一同使用。
字幕打包模板中,字幕文件仅只支持VTT格式。通过API方式配置时需注意,字幕参数覆盖时,Language参数仅用于检索需要替换的字幕文件,而Language本身不会被替换,不存在的字幕语言不能替换。
转码服务均为收费项,具体请参见收费标准。
控制台方式配置
创建多码率自适应的转码模板组。
说明如果只需要使用多码率打包模板,则不需要创建普通转码模板,或删除所有普通转码模板,以免产生多余的转码费用。
发起多码率转码。
在视频点播控制台,选择
。在音/视频页面,单击目标视频的媒体处理。
处理类型选择用转码模板组处理,转码模板组选择第一步所创建的转码模板组,单击确定,发起媒体处理。
效果展示。
多码率打包后码流展示:(2路转码流,1路自适应流)
在点播控制台,选择
,单击目标视频(上一步经过媒体处理的视频)的管理,选择视频地址页签。播放效果展示:(使用上图中自适应的地址播放)
在Aliplayer播放器的基础配置页,输入播放地址(使用上图中视频地址页中自适应的地址),在播放预览页查看播放效果。
操作步骤
创建用于多码率自适应的转码模板组。
本示例代码中列举了普通转码模板配置、多码率打包模板配置、字幕打包模板配置,可根据实际情况使用。
说明如果只需要使用多码率打包模板,则不需要创建普通转码模板,或删除所有普通转码模板,以免产生多余的转码费用。
/** * 以下为调用示例 */ public static void main(String[] args) throws ClientException { // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。 // 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。 // 本示例通过从环境变量中读取AccessKey,来实现API访问的身份验证。运行代码示例前,请配置环境变量ALIBABA_CLOUD_ACCESS_KEY_ID和ALIBABA_CLOUD_ACCESS_KEY_SECRET。 DefaultAcsClient client = initVodClient(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"), System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); AddTranscodeTemplateGroupResponse response = new AddTranscodeTemplateGroupResponse(); try { response = addTranscodeTemplateGroup(client); System.out.println("TranscodeTemplateGroupId = " + response.getTranscodeTemplateGroupId()); } catch (Exception e) { System.out.println("ErrorMessage = " + e.getLocalizedMessage()); } System.out.println("RequestId = " + response.getRequestId()); } /** * 添加转码模板组配置 */ public static AddTranscodeTemplateGroupResponse addTranscodeTemplateGroup(DefaultAcsClient client) throws Exception { AddTranscodeTemplateGroupRequest request = new AddTranscodeTemplateGroupRequest(); request.setName("grouptest2"); JSONArray transcodeTemplateList = new JSONArray(); //普通转码模板配置 transcodeTemplateList.add(buildNormalTranscodeConfig()); //多码率打包转码模板配置 transcodeTemplateList.add(buildVideoPackageConfig()); //字幕打包配置 transcodeTemplateList.add(buildSubtitlePackageConfig()); request.setTranscodeTemplateList(transcodeTemplateList.toJSONString()); System.out.println("request = " + JSONObject.toJSONString(request)); return client.getAcsResponse(request); } /** * 构建需要添加的转码模板配置数据 * * @return */ public static JSONObject buildNormalTranscodeConfig() { JSONObject transcodeTemplate = new JSONObject(); //模板类型< Normal: 普通转码模板;VideoPackage:视频流打包模板;SubtitlePackage:字幕打包模板> transcodeTemplate.put("Type","Normal"); //模板名称 transcodeTemplate.put("TemplateName", "普通转码模板mp4"); //清晰度 transcodeTemplate.put("Definition", "HD"); //视频流转码配置 JSONObject video = new JSONObject(); video.put("Width", 1280); //video.put("Height", 720); video.put("Bitrate", 1500); video.put("Fps", 25); //video.put("Remove", false); video.put("Codec", "H.264"); video.put("Gop", "250"); video.put("LongShortMode", false); transcodeTemplate.put("Video", video); //音频流转码配置 JSONObject audio = new JSONObject(); audio.put("Codec", "AAC"); audio.put("Bitrate", "64"); audio.put("Channels", "2"); audio.put("Samplerate", "32000"); transcodeTemplate.put("Audio", audio); //封装容器 JSONObject container = new JSONObject(); container.put("Format", "mp4"); transcodeTemplate.put("Container", container); //字幕替换设置 JSONObject subtitleSetting = new JSONObject(); JSONArray subtitleList = new JSONArray(); JSONObject subtitle = new JSONObject(); //字幕文件的OSS地址(不支持https地址) subtitle.put("SubtitleUrl", "http://outin-8db8d2****3e1c9256.oss-cn-shanghai.aliyuncs.com/subtitle/3215879C9F724A43BC84C63BE2AA19AF****.srt"); //字幕内容的编码格式,取值:auto(自动检测)、UTF-8、GBK、BIG5 subtitle.put("CharEncode", "UTF-8"); subtitleList.add(subtitle); transcodeTemplate.put("SubtitleList", subtitleList); return transcodeTemplate; } /** * 视频打包配置 * * @return */ private static JSONObject buildVideoPackageConfig() { JSONObject transcodeTemplate = new JSONObject(); //模板类型< Normal: 普通转码模板;VideoPackage:视频流打包模板;SubtitlePackage:字幕打包模板> transcodeTemplate.put("Type","VideoPackage"); //模板名称 transcodeTemplate.put("TemplateName", "HLS流畅打包"); //清晰度 transcodeTemplate.put("Definition", "LD"); //视频流转码配置 JSONObject video = new JSONObject(); video.put("Width", 1280); //video.put("Height", 720); video.put("Bitrate", 1500); video.put("Fps", 25); //video.put("Remove", false); video.put("Codec", "H.264"); video.put("Gop", "250"); video.put("LongShortMode", false); transcodeTemplate.put("Video", video); //音频流转码配置 JSONObject audio = new JSONObject(); audio.put("Codec", "AAC"); audio.put("Bitrate", "64"); audio.put("Channels", "2"); audio.put("Samplerate", "32000"); transcodeTemplate.put("Audio", audio); //封装容器 JSONObject container = new JSONObject(); container.put("Format", "m3u8"); transcodeTemplate.put("Container", container); //封装容器设置为m3u8,必须设置MuxConfig JSONObject muxConfig = new JSONObject(); JSONObject segment = new JSONObject(); segment.put("Duration", "10");//单位是秒 muxConfig.put("Segment", segment); transcodeTemplate.put("MuxConfig",muxConfig); //打包配置 JSONObject packageSetting = new JSONObject(); //打包类型:取值:HLSPackage (HLS自适应码率打包) packageSetting.put("PackageType","HLSPackage"); JSONObject packageConfig = new JSONObject(); packageConfig.put("BandWidth","500000"); packageSetting.put("PackageConfig",packageConfig); transcodeTemplate.put("PackageSetting",packageSetting); return transcodeTemplate; } /** * 字幕打包配置 * * @return */ private static JSONObject buildSubtitlePackageConfig() { JSONObject transcodeTemplate = new JSONObject(); //模板类型< Normal: 普通转码模板;VideoPackage:视频流打包模板;SubtitlePackage:字幕打包模板> transcodeTemplate.put("Type","SubtitlePackage"); //模板名称 transcodeTemplate.put("TemplateName", "多字幕打包"); //清晰度 transcodeTemplate.put("Definition", "HD"); //视频流转码配置 JSONObject video = new JSONObject(); video.put("Width", 1280); //video.put("Height", 720); video.put("Bitrate", 1500); video.put("Fps", 25); //video.put("Remove", false); video.put("Codec", "H.264"); video.put("Gop", "250"); video.put("LongShortMode", false); transcodeTemplate.put("Video", video); //音频流转码配置 JSONObject audio = new JSONObject(); audio.put("Codec", "AAC"); audio.put("Bitrate", "64"); audio.put("Channels", "2"); audio.put("Samplerate", "32000"); transcodeTemplate.put("Audio", audio); //封装容器 JSONObject container = new JSONObject(); container.put("Format", "m3u8"); transcodeTemplate.put("Container", container); //封装容器设置为m3u8,必须设置MuxConfig JSONObject muxConfig = new JSONObject(); JSONObject segment = new JSONObject(); segment.put("Duration", "10");//单位是秒 muxConfig.put("Segment", segment); transcodeTemplate.put("MuxConfig",muxConfig); /* 字幕文件OSS地址(不支持https地址、不支持纯CDN域名加速地址) 说明:字幕文件必须和视频源文件在同一个区域(例如:cn-shanghai),并且在同一个Bucket当中 */ //字幕打包模板 JSONObject subtitlePackageConfig = new JSONObject(); subtitlePackageConfig.put("Type","SubtitlePackage"); //字幕打包配置 JSONObject subtitlePackageSetting = new JSONObject(); //打包类型:取值:HLSPackage (HLS自适应码率打包) subtitlePackageSetting.put("PackageType","HLSPackage"); JSONArray subtitleExtractConfigs = new JSONArray(); //字幕1 JSONObject subtitleExtractConfig = new JSONObject(); JSONArray subtitleUrlList = new JSONArray(); subtitleUrlList.add("http://outin-bfefbb9****e1c7426.oss-cn-shanghai.aliyuncs.com/subtitle/260447BA31D24F9E9E7752BF73F1319B****.vtt"); subtitleExtractConfig.put("SubtitleUrlList",subtitleUrlList); subtitleExtractConfig.put("Language","cn"); subtitleExtractConfig.put("Format","vtt"); subtitleExtractConfig.put("Name","中文-test"); //字幕2 JSONObject subtitleExtractConfig2 = new JSONObject(); JSONArray subtitleUrlList2 = new JSONArray(); subtitleUrlList2.add("http://outin-bfefbb9****3e1c7426.oss-cn-shanghai.aliyuncs.com/subtitle/661C67325E0543F0BB8CA7AAB756E6D8****.vtt"); subtitleExtractConfig2.put("SubtitleUrlList",subtitleUrlList2); subtitleExtractConfig2.put("Language","en-US"); subtitleExtractConfig2.put("Format","vtt"); subtitleExtractConfig2.put("Name","英文-test"); subtitleExtractConfigs.add(subtitleExtractConfig); subtitleExtractConfigs.add(subtitleExtractConfig2); subtitlePackageSetting.put("SubtitleExtractConfigList",subtitleExtractConfigs); transcodeTemplate.put("PackageSetting",subtitlePackageSetting); return transcodeTemplate; } public static DefaultAcsClient initVodClient(String accessKeyId, String accessKeySecret) throws ClientException { // 点播服务接入区域 String regionId = "cn-shanghai"; DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret); DefaultAcsClient client = new DefaultAcsClient(profile); return client; }
发起多码率转码。
public static void main(String[] args) { //regionId根据服务接入地址填写,例:接入服务在上海,则填cn-shanghai String regionId = "cn-shanghai"; // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。 // 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。 // 本示例通过从环境变量中读取AccessKey,来实现API访问的身份验证。运行代码示例前,请配置环境变量ALIBABA_CLOUD_ACCESS_KEY_ID和ALIBABA_CLOUD_ACCESS_KEY_SECRET。 DefaultProfile profile = DefaultProfile.getProfile(regionId, System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"), System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); IAcsClient client = new DefaultAcsClient(profile); String videoId = "76913816d****8e57e8c2952"; String templateId = "4733b3a5****ae36ac22d34"; try { SubmitTranscodeJobsResponse response = submitTranscodeJobs(client,videoId,templateId); } catch (ServerException e) { e.printStackTrace(); } catch (ClientException e) { System.out.println("ErrCode:" + e.getErrCode()); System.out.println("ErrMsg:" + e.getErrMsg()); System.out.println("RequestId:" + e.getRequestId()); } } /** * 提起转码作业 * 传入视频ID和模板组ID * * @param client * @param videoId * @param templateGroupId * @return * @throws Exception */ public static SubmitTranscodeJobsResponse submitTranscodeJobs(DefaultAcsClient client, String videoId, String templateGroupId) throws Exception { SubmitTranscodeJobsRequest request = new SubmitTranscodeJobsRequest(); //需要转码的视频ID request.setVideoId(videoId); //转码模板组ID request.setTemplateGroupId(templateGroupId); //设置转码优先级(默认级别为6,数字越大,级别越高),范围是[1-10] request.setPriority("8"); JSONObject overrideParams = buildOverrideParams(); //覆盖参数 request.setOverrideParams(overrideParams.toJSONString()); return client.getAcsResponse(request); } //以下为打包字幕替换参数构建示例 public static JSONObject buildOverrideParams() { JSONObject overrideParams = new JSONObject(); //打包字幕替换设置 JSONObject packageSubtitleSetting = new JSONObject(); JSONArray packageSubtitleList = new JSONArray(); JSONObject packageSubtitle = new JSONObject(); //需要替换的打包模板组中字幕模板的ID packageSubtitle.put("SubtitlePackageTemplateId", "69fa6ee58****e8492c76168****"); //Language参数仅用于检索需要替换的字幕文件,而Language本身不会被替换,不存在的字幕语言不能替换。 packageSubtitle.put("Language", "cn"); //字幕文件的OSS地址(不支持https地址),字幕文件需要与视频在同一个存储区域。 packageSubtitle.put("SubtitleUrl", "http://outin-bfefbb9****3e1c7426.oss-cn-shanghai.aliyuncs.com/subtitle/043956117D0C475EAB0CE8C4F7294221****.vtt"); packageSubtitleList.add(packageSubtitle); packageSubtitleSetting.put("PackageSubtitleList", packageSubtitleList); overrideParams.put("PackageSubtitleSetting", packageSubtitleSetting); return overrideParams; }
效果展示。
多码率打包后码流展示:(2路转码流,1路自适应流)
在点播控制台,选择
,单击目标视频(上一步经过媒体处理的视频)的管理,选择视频地址页签。播放效果展示:(使用上图中自适应的地址播放)
在Aliplayer播放器的基础配置页,输入播放地址(使用上图中视频地址页中自适应的地址),在播放预览页查看播放效果。