亚马逊AWS官方博客

Amazon Interactive Video Service (Amazon IVS) 直播过程中生成多个点播文件的合并

随着互联网和多媒体技术的不断发展,其在教育,社交,电商等行业的应用越来越广泛,比如电商行业的通过直播的方式销售商品已经非常流行,但是对于一个企业或者商家来讲,如果要搭建一套直播平台是非常复杂和成本高昂的事情。
Amazon Interactive Video Service (Amazon IVS) 是一种托管的直播流式处理解决方案,快速且易于设置,非常适合创建交互式视频体验。使用流式传输软件和服务将您的直播流发送到 Amazon IVS,然后该服务将执行向世界各地的观众提供低延迟视频直播所需的一切工作,让您专注于伴随着视频直播构建交互式体验。您可以通过 Amazon IVS 播放器 SDK 和定时元数据 API 轻松自定义并增强观众体验,从而使您可以在自己的网站和应用程序上与观众建立更具价值的关系。
在通过使用Amazon IVS构建自己的直播频道后,同时大多数客户也会有点播的需求用于提供给客户回放,因此Amazon IVS也提供了自动生成点播文件到Amazon S3的功能,这样客户后续可以通过Cloudfront针对存储在S3中的点播文件进行分发从而实现快速高效的点播能力。本文的重点会介绍一下在点播场景下遇到的一个问题,以及解决方案。

 

问题背景

在Amazon IVS直播场景中往往会因为推流端网络不稳定导致直播效果不佳,同时在生成点播文件的时候可能会生成多个点播文件,也就是说因为网络的不稳定推流端会主动发起生成点播文件的指令,从而在一场直播中可能会生成多个点播文件数据。多个点播文件给后续的点播带来问题,当需要点播这场直播的时候需要针对多个点播的文件进行处理才能实现无缝衔接并观看。下面会介绍通过AWS Elemental MediaConvert服务如何来实现自动合并多个点播文件,从而简化客户端点播功能的实现。

 

解决方案

  1. 主播通过推流App端开启直播,此时推流App端通过Amazon IVS的推流地址将直播流推送到Amazon IVS,客户端通过Amazon IVS提供的播放地址开始观看直播
  2. IVS录播功能启动的情况下,当主播端的网络不稳定导致IVS输入断流一段时间(如60秒)又重新恢复时,IVS录播会生成新的点播文件目录存储到S3中
  3. 当主播端终止直播后,发出请求给后端服务,后端服务首先会发出指令给Amazon IVS直播已停止,然后删除当前channel(可选操作,根据业务需要可以不删除)
  4. 后端服务然后判断当前如果生成了多个点播文件则发出请求给AWS Elemental MediaConvert
  5. AWS Elemental Mediaconvert 启动job进行合并,并将合并后的文件输出到S3中
  6. 客户端通过播放器播放S3中由AWS Elemental MediaConvert 生成的文件,一般会同时与Cloudfront结合来实现点播加速

下面针对如上方案进行详细介绍。

 

MediaConvert配置

AWS Elemental MediaConvert 是一款具有广播级功能的基于文件的视频转码服务。借助该服务,您能够轻松创建视频点播 (VOD) 内容,实现大规模的广播和多屏幕传输。该服务将高级视频和音频功能与简单的 Web 服务界面相结合,并采用按需付费的定价模式。借助 AWS Elemental MediaConvert,您可以专注于提供引人注目的媒体体验,而无需执行复杂的视频处理基础设施构建和运营操作。
下面我们重点介绍一下如何使用MediaConvert实现将IVS输出的多个HLS点播文件自动合并为一个HLS文件的方法,针对MediaConvert的其它功能可以参考[AWS Elemental MediaConver](https://aws.amazon.com/cn/mediaconvert/)。AWS Elemental MediaConvert 实现合并的思路是通过配置多路的HLS输入,然后配置一路HLS的输出的方式来实现视频的转码(当当需要输出多种格式时也可以配置多路输出如同时转码为mp4),下面介绍一下具体的配置方法。

创建转码任务

输入配置

已ivs生成的点播文件作为输入,同时设置hls文件s3地址
针对多个输入,后续通过代码根据生成的点播文件数量来动态生成输入数量(测试阶段可以配置两个或者多个固定输入)。

输出配置

输出配置指定输出的格式为HLS以及对应的转码配置比如分辨率,如果需要多种分辨率输出可以在输出配置中增加多个分辨率的输出配置。

启动任务

通过控制台启动任务后,会根据输入的文件大小以及转码的配置操作信息执行时间有所不同,本示例大概需要3分钟左右会执行完成,通过控制台查看任务执行情况如下图:

从上图可以看到如下信息:

  1. 任务的处理时间状态等
  2. 可以看到输入3路hls文件
  3. 可以看到合并后文件的多个分辨率的输出

点击输出部分的 Apple HLS master链接在S3中查看合并后的文件信息.

通过模版配置

测试成功后可以导出当前配置为job.json,然后通过MediaConvert 任务模版管理配置信息,导入job.json生成配置模版同时只保留一个输入配置,后续代码部分将使用该模版自动生成转码任务的多个输入。

 

自动合并代码实现

上面架构图中提到当主播停止直播后会触发后端服务(这里用java实现),后端服务判断当前是否有多个点播文件生成,然后通过调用AWS Elemental MediaConvert的API读取配置的模版,并根据生成点播文件数量和点播文件地址生成多个输入,然后构造出最终的模版作为输入来启动转码任务。
下面通过具体代码介绍一下如何用java来实现,测试类是测试的入口类生产中可以将此部分代码集成到后端服务中。MediaConvertService类是转码合并功能实现的实现类。

测试类:

    public void testCreateJob(){
        String input1 = "s3://vod-liuhengtao/ivs/517141035927/RBb8M9xU3DBu/2021-01-26T11-58-28.33Z/CxbvSCiFgcR4/media/hls/master.m3u8";
        String input2 = "s3://vod-liuhengtao/ivs/517141035927/RBb8M9xU3DBu/2021-01-26T11-58-28.33Z/CxbvSCiFgcR4/media/hls/master.m3u8";
        String templateName = "ivs-vod-merge";
        String roleArn = "arn:aws:iam::xxxx:role/test-vod2-MediaConvertRole";
        String jobId = mediaConvertService.createJob(templateName,roleArn,input1,input2);
        String jobStatus = mediaConvertService.queryJobStatus(jobId);
        System.out.println(jobStatus);
    }

实现类初始化MediaConvert

private static AWSMediaConvert mediaConvert = AWSMediaConvertClientBuilder.standard()
            .withRegion(Regions.US_WEST_2)
            .build();

    /**
     * 初始化MediaConvert客户端
     * */
    static {
        DescribeEndpointsRequest describeEndpointsRequest =new DescribeEndpointsRequest();
        DescribeEndpointsResult endpoint =  mediaConvert.describeEndpoints(describeEndpointsRequest);
        String endpointUrl = endpoint.getEndpoints().get(0).getUrl();

        AwsClientBuilder.EndpointConfiguration endpointConfiguration
                =new AwsClientBuilder.EndpointConfiguration(endpointUrl,Regions.US_WEST_2.getName());

        mediaConvert = AWSMediaConvertClientBuilder.standard()
                .withEndpointConfiguration(endpointConfiguration)
                .build();
    }


    public void MediaConvertService(){
    }

实现类读取模版并启动任务

测试类调用的MediaConvertService启动转码任务代码,下面代码使用两个输入作为测试,实际生产中根据多个输入动态生成输入

测试类调用的MediaConvertService启动转码任务代码,下面代码使用两个输入作为测试,实际生产中根据多个输入动态生成输入

 /**
     *
     * @param templateName
     * @param roleArn
     * @param  req1 用于合并的m3u8 文件
     * @param  req2 用于合并的m3u8 文件
     * @return 返回jobId
     *
     * */
    public String createJob(String templateName, String roleArn, String req1, String req2) {
        CreateJobRequest createJobRequest =new CreateJobRequest();
        createJobRequest.setRole(roleArn);
        Map<String, String> userMetadata = new HashMap<>();
        userMetadata.put("assetID", UUID.randomUUID()+"");
        createJobRequest.setUserMetadata(userMetadata);

        GetJobTemplateRequest getJobTemplateRequest = new GetJobTemplateRequest();
        getJobTemplateRequest.setName(templateName);
        GetJobTemplateResult getJobTemplateResult =  mediaConvert.getJobTemplate(getJobTemplateRequest);
        JobTemplate jobTemplate = getJobTemplateResult.getJobTemplate();

        createJobRequest.setJobTemplate(jobTemplate.getArn());

        JobSettings jobSettings = new JobSettings();
        List<Input> inputs = new ArrayList();
        Input input_1 =new Input();
        input_1.setFileInput(req1);
        inputs.add(input_1);

        Input input_2 =new Input();
        input_2.setFileInput(req2);
        inputs.add(input_2);

        jobSettings.setInputs(inputs);

        createJobRequest.setSettings(jobSettings);
        CreateJobResult createJobResult =  mediaConvert.createJob(createJobRequest);
        return createJobResult.getJob().getId();
    }

实现类异步调用

当转码任务执行完毕后,需要进一步执行一些操作的话,可以通过异步启动任务的方法来实现。比如转换完成后更新点播列表的状态为可观看便于前段播放列表更新,下面是异步调用的代码实现:

测试

public void testAsyncCreateJob(){
        String input1 = "s3://vod-liuhengtao/ivs/517141035927/RBb8M9xU3DBu/2021-01-26T11-58-28.33Z/CxbvSCiFgcR4/media/hls/master.m3u8";
        String input2 = "s3://vod-liuhengtao/ivs/517141035927/RBb8M9xU3DBu/2021-01-26T11-58-28.33Z/CxbvSCiFgcR4/media/hls/master.m3u8";
        String templateName = "ivs-vod-merge";
        String roleArn = "arn:aws:iam::517141035927:role/test-vod2-MediaConvertRole";
        Future<CreateJobResult> jobResultFuture = asyncMediaConvertService.createJAsyncob(templateName,roleArn,input1,input2);
        try {
            while(!jobResultFuture.isDone()) {
                    Thread.sleep(300);
            }
            System.out.println("test "+jobResultFuture.isDone());
            System.out.println();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

建异步任务

/**
     *
     * @param templateName
     * @param roleArn
     * @param  req1 用于合并的m3u8 文件
     * @param  req2 用于合并的m3u8 文件
     * @return 返回jobId
     *
     * */
    public Future<CreateJobResult> createJAsyncob(String templateName, String roleArn, String req1, String req2) {
        CreateJobRequest createJobRequest =new CreateJobRequest();
        createJobRequest.setRole(roleArn);
        Map<String, String> userMetadata = new HashMap<>();
        userMetadata.put("assetID", UUID.randomUUID()+"");
        createJobRequest.setUserMetadata(userMetadata);

        GetJobTemplateRequest getJobTemplateRequest = new GetJobTemplateRequest();
        getJobTemplateRequest.setName(templateName);
        GetJobTemplateResult getJobTemplateResult =  awsMediaConvertAsync.getJobTemplate(getJobTemplateRequest);
        JobTemplate jobTemplate = getJobTemplateResult.getJobTemplate();

        createJobRequest.setJobTemplate(jobTemplate.getArn());

        JobSettings jobSettings = new JobSettings();
        List<Input> inputs = new ArrayList();
        Input input_1 =new Input();
        input_1.setFileInput(req1);
        inputs.add(input_1);

        Input input_2 =new Input();
        input_2.setFileInput(req2);
        inputs.add(input_2);

        jobSettings.setInputs(inputs);

        createJobRequest.setSettings(jobSettings);
        Future<CreateJobResult> createJobResultFuture = awsMediaConvertAsync.createJobAsync(createJobRequest,new JobHandler());
        return createJobResultFuture;
    }

通过控制台查看任务

此时可以通过控制台看到任务已经执行完毕,执行效果与通过console上测试是同样的效果。

 

总结

通过本文可以了解到以下信息:

  • Amazon IVS服务可以快速的构建直播能力,同时可以自动生成点播数据用于后续回看[如何使用IVS](https://docs.aws.amazon.com/ivs/)
  • AWS Elemental MediaConvert 服务可以实现基于文件的转码,以及具体如何使用它来实现多个HLS文件的转码合并[如何使用MediaConver](https://aws.amazon.com/cn/mediaconvert/)
  • 如何利用AWS Elemental MediaConvert AWS SDK实现基于配置的模版动态构建新的模版并启动转码任务,以及如何实现异步的任务启动。

 

 

本篇作者

刘恒涛

AWS 解决方案架构师,负责基于AWS的云计算方案架构咨询和设计。同时致力于AWS云服务在国内的应用和推广,当前重点关注机器学习以及Serverless领域。

高源

AWS Elemental中国区Specialist,视频领域专家