通过阅读本文,您可以了解通过服务端SDK调用OpenAPI进行批量混剪的示例。

前提条件

如果您要实现字幕对齐和卡点视频功能,除了开通IMS和OSS服务以外,还需要开通MPS服务。具体操作,请参见开通服务

使用说明

以下示例代码中引入的服务端SDK版本号仅供参考。获取最新的版本,请参见服务端SDK

基础混剪

主要功能

  • 设置一段文字,转为人声音频,再转成字幕合成到视频中,同时设置字体、字号等属性。
  • 进行任意数量的视频拼接。
  • 设置一段音频作为背景音乐。
  • 设置一个图片作为Logo水印。

成片预览

实现代码

Java
/**
Maven引入:

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.5.3</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>ice20201109</artifactId>
    <version>1.1.5</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.68.noneautotype</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>credentials-java</artifactId>
    <version>0.2.12</version>
</dependency>
*/
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.abs.common.util.MD5Util;
import com.aliyun.ice20201109.models.*;
import com.aliyun.teaopenapi.models.Config;
import org.apache.logging.log4j.util.Strings;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Create by oushu
 * Date 2021/12/7 上午9:28
 */
public class BatchProduceVideo_release {

    private String bucket;
    private com.aliyun.ice20201109.Client iceClient;

    public void initClient() throws Exception {
        bucket = "your-bucket";
        iceClient = createIceClient();
    }

    public static void main(String[] args) throws Exception {
        BatchProduceVideo_release batchProduceVideo = new BatchProduceVideo_release();
        batchProduceVideo.initClient();
        batchProduceVideo.batchProduceVideo();
    }

    public void batchProduceVideo() throws Exception {

        // 文字素材
        String text = "测试文案";

        // 视频素材
        List<String> videoUrlList = new ArrayList();
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video1.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video2.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video3.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video4.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video5.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video6.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video7.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video8.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video9.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video10.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video11.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video12.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video13.mp4");
        videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video14.mp4");

        // 背景音乐
        String bgMusic = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-music.mp3";

        // 字幕样式设置
        Integer fontSize = 60;
        String fontName = "WenQuanYi Zen Hei Mono";
        String fontColor = "#FFFFFF";

        // 视频尺寸
        Integer width = 1280;
        Integer height = 720;

        // logo
        String logoUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-logo.png";
        Integer logoX = 20;
        Integer logoY = 20;

        // 输出成片个数
        Integer outputCount = 2;

        // 每个成片包含视频片段数
        Integer videoCount = 8;

        for (int i = 0; i < outputCount; i++) {
            Collections.shuffle(videoUrlList);
            List<String> subUrls = videoUrlList.subList(0, videoCount);
            produceSingleVideo(text, subUrls, bgMusic, fontSize, fontName, fontColor, logoUrl, logoX, logoY, width, height);
        }
    }

    // 提交单个任务
    public void produceSingleVideo(String text, List<String> videoUrls, String bgMusic, int fontSize, String fontName, String fontColor,
                                   String logoUrl, Integer logoX, Integer logoY, int width, int height) throws Exception {
        // 组装字幕轨
        if (fontSize <= 0) {
            fontSize = 32;
        }
        if (Strings.isBlank(fontName)) {
            fontName = "WenQuanYi Zen Hei Mono";
        }
        if (Strings.isBlank(fontColor)) {
            fontColor = "#000000";
        }

        // 组装视频轨
        JSONArray videoTrackClips = new JSONArray();
        for (String url : videoUrls) {
            JSONObject clip = new JSONObject();
            clip.put("MediaURL", url);
            videoTrackClips.add(clip);
        }

        // 组装音频轨
        String audioClip = "{\"AudioTrackClips\":[{\"Type\":\"AI_TTS\",\"Content\":\"" + text + "\",\"Voice\":\"sicheng\",\"Effects\":[{\"Type\":\"AI_ASR\",\"Font\":\"" + fontName + "\",\"Alignment\":\"BottomCenter\",\"Y\":0.1,\"FontSize\":" + fontSize + ",\"FontColor\":\"" + fontColor + "\",\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}},{\"Type\":\"Volume\",\"Gain\":10}]}]}";
        String audioTracks;
        if (Strings.isBlank(bgMusic)) {
            audioTracks = "["+audioClip+"]";
        } else {
            // 两个音频轨,一个人声,一个音乐
            audioTracks = "["+audioClip+",{\"AudioTrackClips\":[{\"MediaURL\":\"" + bgMusic + "\"}]}]";
        }

        // 贴图clips
        String logoClip = "";
        if (Strings.isNotBlank(logoUrl)) {
            logoClip = "{\"ImageURL\":\"" + logoUrl + "\",\"X\":" + logoX + ",\"Y\":" + logoY + "}";
        }

        // 拼时间线
        String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" + videoTrackClips.toJSONString() + "}]," +
                "\"AudioTracks\":" + audioTracks + "," +
                "\"ImageTracks\":[{\"ImageTrackClips\":[" + logoClip + "]}]}";
        System.out.println("timeline : " + timeline);

        // 提交合成任务
        SubmitMediaProducingJobRequest submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest();
        submitMediaProducingJobRequest.setTimeline(timeline);
        String mediaURL = "https://" + bucket + ".oss-shanghai" + ".aliyuncs.com/" + MD5Util.getMd5String(String.valueOf(Math.random())) + ".mp4";
        submitMediaProducingJobRequest.setOutputMediaConfig("{\"MediaURL\":\"" + mediaURL + "\",\"Width\":" + width + ",\"Height\":" + height + "}");
        SubmitMediaProducingJobResponse submitMediaProducingJobResponse = iceClient.submitMediaProducingJob(submitMediaProducingJobRequest);
        System.out.println("job created, jobId : " + submitMediaProducingJobResponse.body.jobId + ", requestId : " + submitMediaProducingJobResponse.body.getRequestId() + ", mediaURL : " + mediaURL);
        // 等待合成任务完成
        while (true) {
            GetMediaProducingJobRequest getMediaProducingJobRequest = new GetMediaProducingJobRequest();
            getMediaProducingJobRequest.setJobId(submitMediaProducingJobResponse.body.jobId);
            GetMediaProducingJobResponse getMediaProducingJobResponse = iceClient.getMediaProducingJob(getMediaProducingJobRequest);
            System.out.println("GetMediaProducingJobResponse : " + JSONObject.toJSONString(getMediaProducingJobResponse.body));
            String status = getMediaProducingJobResponse.getBody().getMediaProducingJob().getStatus();
            if ("Success".equals(status) || "Failed".equals(status)) {
                break;
            }
            Thread.sleep(5000);
        }
        System.out.println("Produce succeed : " + mediaURL);
    }

    public com.aliyun.ice20201109.Client createIceClient() throws Exception {


        // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
        // 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html
        com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
        Config config = new Config();
        config.setCredential(credentialClient);

        // 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
        // config.accessKeyId = <yourAccessKeyId>;
        // config.accessKeySecret = <yourAccessKeySecret>;
        config.endpoint = "ice.cn-shanghai.aliyuncs.com";
        Client client = new Client(config);

        return client;
    }
}
PHP
<?php
/**
composer 引入:
{
    "require": {
        "alibabacloud/ice-20201109": "1.1.6",
        "aliyuncs/oss-sdk-php": "^2.4"
      	"alibabacloud/credentials"
    }
}
*/


require_once '../vendor/autoload.php';

use AlibabaCloud\Credentials\Credential;
use AlibabaCloud\SDK\ICE\V20201109\ICE;
use AlibabaCloud\SDK\ICE\V20201109\Models;
use AlibabaCloud\SDK\ICE\V20201109\Models\SubmitMediaProducingJobRequest;
use AlibabaCloud\SDK\ICE\V20201109\Models\GetMediaProducingJobRequest;

use Darabonba\OpenApi\Models\Config;

class BatchProduceVideo {
    var $iceClient;
    var $bucket;
    var $region;

    function createClient() {
        $this->bucket = "your-bucket";
        $this->region = "cn-shanghai";

        // ice
        $iceConfig = new Config();
      	//本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。
        $iceConfig->credential = $credential;
        //如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
      	//$iceConfig->accessKeyId = "accessKeyId";
        //$iceConfig->accessKeySecret = "accessKeySecret";
        $iceConfig->regionId = "cn-shanghai";
        $iceConfig->endpoint = "ice.cn-shanghai.aliyuncs.com";
        $this->iceClient = new ICE($iceConfig);
    }

    function run() {
        echo "start!!!\n";
        // 初始化client
        $this->createClient();

        // 文字素材
        $text = "测试文案";

        // 视频素材
        $videoUrls = array();
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video1.mp4";
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video2.mp4";
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video3.mp4";
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video4.mp4";
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video5.mp4";
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video6.mp4";
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video7.mp4";
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video8.mp4";
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video9.mp4";
        $videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video10.mp4";

        // 背景音乐
        $bgMusic = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/test_media/your-music.mp3";

        // 字幕样式设置
        $fontSize = 60;
        $fontName = "WenQuanYi Zen Hei Mono";
        $fontColor = "#FFFFFF";

        // logo
        $logoUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-logo.png";
        $logoX = 20;
        $logoY = 20;

        // 视频尺寸
        $width = 1920;
        $height = 1080;

        // 输出成片个数
        $outputCount = 2;

        // 每个成片包含视频片段数
        $videoCount = 8;

        for ($i = 0; $i < $outputCount; $i++) {
            shuffle($videoUrls);
            $subUrls = array_slice($videoUrls, 0, $videoCount);
            $this->produceSingleVideo($text, $subUrls, $bgMusic, $fontSize, $fontName, $fontColor, $logoUrl, $logoX, $logoY, $width, $height);
        }
    }

    // 提交单个任务
    function produceSingleVideo($text, $videoUrls, $bgMusic, $fontSize, $fontName, $fontColor, $logoUrl, $logoX, $logoY, $width, $height) {
        $bucket = $this->bucket;
        $region = $this->region;

        // 组装字幕轨
        if ($fontSize <= 0) {
            $fontSize = 32;
        }
        if ($fontName == "") {
            $fontName = "WenQuanYi Zen Hei Mono";
        }
        if ($fontColor == "") {
            $fontColor = "#000000";
        }

        // 组装视频轨
        $videoTrackClips = array();
        foreach ($videoUrls as $url) {
            $videoTrackClips[] = array('MediaURL' => $url);
        }
        var_dump(json_encode($videoTrackClips));

        // 组装音频轨
        $audioClip = "{\"AudioTrackClips\":[{\"Type\":\"AI_TTS\",\"Content\":\"" . $text . "\",\"Voice\":\"sicheng\",\"Effects\":[{\"Type\":\"AI_ASR\",\"Font\":\"" . $fontName . "\",\"Alignment\":\"BottomCenter\",\"Y\":0.1,\"FontSize\":" . $fontSize . ",\"FontColor\":\"" . $fontColor . "\",\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}},{\"Type\":\"Volume\",\"Gain\":10}]}]}";
        $audioTracks;
        if ($bgMusic == "") {
            $audioTracks = "[" . $audioClip . "]";
        } else {
            // 两个音频轨,一个人声,一个音乐
            $audioTracks = "[" . $audioClip . ",{\"AudioTrackClips\":[{\"MediaURL\":\"" . $bgMusic . "\"}]}]";
        }
        var_dump($audioTracks);

        // 贴图clips
        $logoClip = "";
        if ($logoUrl != "") {
            $logoClip = "{\"ImageURL\":\"" . $logoUrl . "\",\"X\":" . $logoX . ",\"Y\":" . $logoY . "}";
        }
        var_dump($logoClip);

        // 拼时间线
        $timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" . json_encode($videoTrackClips) . "}]," .
                "\"AudioTracks\":" . $audioTracks . "," .
                "\"ImageTracks\":[{\"ImageTrackClips\":[" . $logoClip . "]}]}";
        echo $timeline."\n";

        // 提交合成任务
        $submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest();
        $submitMediaProducingJobRequest->timeline = $timeline;

        $mediaURL = "https://" . $bucket . ".oss-" . $region . ".aliyuncs.com/" . md5(rand()) . ".mp4";
        $submitMediaProducingJobRequest->outputMediaConfig = "{\"MediaURL\":\"" . $mediaURL . "\",\"Width\":" . $width . ",\"Height\":" . $height . "}";
        $submitMediaProducingJobResponse = $this->iceClient->submitMediaProducingJob($submitMediaProducingJobRequest);
        $jobId = $submitMediaProducingJobResponse->body->jobId;
        $resuestId = $submitMediaProducingJobResponse->body->requestId;
        echo "jobId : ". $jobId . ", resuestId : " . $resuestId . ", mediaURL : " . $mediaURL . "\n";

        // 等待合成任务完成
        while (true) {
            $getMediaProducingJobRequest = new GetMediaProducingJobRequest();
            $getMediaProducingJobRequest->jobId = $jobId;
            $getMediaProducingJobResponse = $this->iceClient->getMediaProducingJob($getMediaProducingJobRequest);
            $status = $getMediaProducingJobResponse->body->mediaProducingJob->status;
            echo "job Status : " . $status . "\n";
            if ("Success" == $status) {
                break;
            }
            sleep(5);
        }
        echo "job finished !";
    }
}

try {
    $batchProduceVideo = new BatchProduceVideo();
    $batchProduceVideo->run();
} catch (Error $e) {
    var_dump($e);
}

相关接口

字幕对齐

主要功能

  • 输入一段文字,转为人声音频,或直接输入一段人声音频,再转成字幕合成到视频中,同时设置字体、字号等属性。
  • 进行任意数量的视频拼接,随机排序,将视频按照每段人声的长度进行截取并拼接。
  • 为视频素材添加背景模糊效果、随机氛围类特效,并静音。
  • 设置一段音频作为背景音乐。
  • 设置一个图片作为Logo水印。

成片预览

实现代码

  • 输入为文字
    Java
    /**
     Maven引入:
    
     <dependency>
         <groupId>com.aliyun</groupId>
         <artifactId>aliyun-java-sdk-core</artifactId>
         <version>4.5.3</version>
     </dependency>
     <dependency>
         <groupId>com.aliyun</groupId>
         <artifactId>ice20201109</artifactId>
         <version>1.2.0</version>
     </dependency>
     <dependency>
         <groupId>com.aliyun</groupId>
         <artifactId>mts20140618</artifactId>
         <version>3.3.33</version>
     </dependency>
     <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
        <version>3.10.2</version>
    </dependency>
     <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>fastjson</artifactId>
     </dependency>
     <dependency>
         <groupId>com.aliyun</groupId>
         <artifactId>credentials-java</artifactId>
         <version>0.2.12</version>
     </dependency>
     */
    import com.alibaba.common.lang.io.ByteArrayInputStream;
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import com.aliyun.abs.common.util.MD5Util;
    import com.aliyun.ice20201109.models.GetMediaProducingJobRequest;
    import com.aliyun.ice20201109.models.GetMediaProducingJobResponse;
    import com.aliyun.ice20201109.models.SubmitMediaProducingJobRequest;
    import com.aliyun.ice20201109.models.SubmitMediaProducingJobResponse;
    import com.aliyun.mts20140618.models.QueryIProductionJobRequest;
    import com.aliyun.mts20140618.models.QueryIProductionJobResponse;
    import com.aliyun.mts20140618.models.SubmitIProductionJobRequest;
    import com.aliyun.mts20140618.models.SubmitIProductionJobResponse;
    
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    
    import com.aliyun.oss.model.OSSObject;
    import com.aliyun.oss.model.PutObjectRequest;
    import com.aliyun.teaopenapi.models.Config;
    import com.google.common.io.CharStreams;
    
    import org.apache.commons.io.Charsets;
    import org.apache.logging.log4j.util.Strings;
    
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.*;
    
    /**
     * Create by oushu
     * Date 2021/12/7 上午9:28
     */
    public class BatchProduceTTSSubtitleRelease {
    
        private String bucket;
        private String output;
        private String regionId;
        private OSS ossClient;
        private com.aliyun.mts20140618.Client mpsClient;
        private com.aliyun.ice20201109.Client iceClient;
    
        public void initClient() throws Exception {
            bucket = "your-bucket";
            output = "output-path";
            regionId = "cn-shanghai";
            ossClient = createOssClient();
            mpsClient = createMpsClient();
            iceClient = createIceClient();
        }
    
        public static void main(String[] args) throws Exception {
            BatchProduceTTSSubtitleRelease batchProduceVideo = new BatchProduceTTSSubtitleRelease();
            batchProduceVideo.initClient();
            batchProduceVideo.batchProduceVideo();
        }
    
        public void batchProduceVideo() throws Exception {
            // 文字素材
            String text = "人们懂得用五味杂陈形容人生,因为懂得味道是每个人心中固守的情怀。在这个时代,每一个人都经历了太多的苦痛和喜悦,人们总会将苦涩藏在心里,而把幸福变成食物,呈现在四季的餐桌之上";
    
            // 视频素材
            List<String> videoUrlList = new ArrayList();
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_1.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_2.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_3.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_4.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_5.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_6.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_7.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_8.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_9.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_10.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_11.mp4");
            videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_12.mp4");
    
            // 背景音乐
            String bgMusic = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/iproduction/demo/music/generated_6_good.wav";
    
            // 字幕样式设置
            Integer fontSize = 45;
            String fontName = "WenQuanYi Zen Hei Mono";
            String fontColor = "#FFFFFF";
    
            // 视频尺寸
            Integer width = 720;
            Integer height = 1280;
    
            // logo
            String logoUrl = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your-logo.png";
            Integer logoX = 20;
            Integer logoY = 20;
    
            String title = "这里是标题";
            String subTitle = "这里是副标题";
    
            // 成片数量
            int targetCount = 2;
            // 每次提交一个任务,业务方根据需要更换不同参数提交多次
            produceSingleVideo(text, videoUrlList, title, subTitle, bgMusic, fontSize, fontName, fontColor, logoUrl, logoX, logoY, width, height, targetCount);
        }
    
        // 提交单个任务
        public void produceSingleVideo(String text, List<String> videoUrls, String title, String subtitle, String bgMusic, int fontSize, String fontName, String fontColor,
                                       String logoUrl, Integer logoX, Integer logoY, int width, int height, int targetCount) throws Exception {
            // 提交MPS任务,文字生成语音和字幕
            String voice = "zhichu";
            String jobParams = "{\"voice\":\"" + voice + "\",\"format\":\"mp3\",\"sample_rate\":16000}";
            String textObject = "iproduction/20211214/" + MD5Util.getMd5String(text) + ".txt";
            text = text.replaceAll(",", "。"); // AsyncTextToSpeech任务用句号进行断句
            putObjectContent(textObject, text);
            String input = "oss://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + textObject;
            System.out.println("input : " + input);
    
            SubmitIProductionJobRequest submitIProductionJobRequest = new SubmitIProductionJobRequest();
            submitIProductionJobRequest.setFunctionName("AsyncTextToSpeech");
            submitIProductionJobRequest.setInput(input);
            submitIProductionJobRequest.setOutput("oss://" + bucket + ".oss-" + regionId + ".aliyuncs.com/iproduction/20220617/{source}-{sequenceId}.{resultType}");
    
            submitIProductionJobRequest.setJobParams(jobParams);
            SubmitIProductionJobResponse submitIProductionJobResponse = mpsClient.submitIProductionJob(submitIProductionJobRequest);
            System.out.println("submit mps response : " + JSONObject.toJSONString(submitIProductionJobResponse.body));
    
            // 等待任务完成
            String jobId = submitIProductionJobResponse.body.jobId;
            String result;
            while (true) {
                QueryIProductionJobRequest queryIProductionJobRequest = new QueryIProductionJobRequest();
                queryIProductionJobRequest.setJobId(jobId);
                QueryIProductionJobResponse queryIProductionJobResponse = mpsClient.queryIProductionJob(queryIProductionJobRequest);
                System.out.println("job info : " + JSONObject.toJSONString(queryIProductionJobResponse.body));
                if ("Success".equals(queryIProductionJobResponse.body.state)) {
                    result = queryIProductionJobResponse.body.result;
                    break;
                }
                Thread.sleep(5000);
            }
    
            // 获取生成的音频和字幕
            JSONObject resultObj = JSONObject.parseObject(result);
            String dataString = resultObj.getString("Data");
            System.out.println("data : " + dataString);
    
            String audioObject = null;
            String subtitleObject = null;
            JSONObject dataObject = JSONObject.parseObject(dataString);
            JSONArray array = dataObject.getJSONArray("result");
            for (Object obj : array) {
                JSONObject jsonObject = (JSONObject)obj;
                String object = jsonObject.getString("file");
                if (object.endsWith("mp3")) {
                    audioObject = object;
                } else if (object.endsWith("txt")) {
                    subtitleObject = object;
                }
            }
            System.out.println("audioObject : " + audioObject);
            System.out.println("subtitleObject : " + subtitleObject);
    
            // 获取字幕内容
            String subtitleContent = getObjectContent(subtitleObject);
            System.out.println("subtitleContent : " + subtitleContent);
    
            // 组装字幕轨
            if (fontSize <= 0) {
                fontSize = 32;
            }
            if (Strings.isBlank(fontName)) {
                fontName = "WenQuanYi Zen Hei Mono";
            }
            if (Strings.isBlank(fontColor)) {
                fontColor = "#000000";
            }
    
            for (int j = 0; j < targetCount; j++) {
                // 每次循环将视频素材随机,并提交合成任务
                Collections.shuffle(videoUrls);
    
                JSONArray subtitleTrackClips = new JSONArray();
                JSONArray mpsSubtitles = JSONArray.parseArray(subtitleContent);
                JSONArray videoTrackClips = new JSONArray();
    
                // 字幕距离底部距离
                float subtitleBottom = 0.25f;
                // 随机特效,更多特效见:https://help.aliyun.com/document_detail/207059.html
                List<String> vfxs = Arrays.asList("heartfireworks", "colorfulradial", "meteorshower", "starry", "colorfulstarry", "moons_and_stars", "flyfire", "starexplosion", "spotfall", "sparklestarfield");
                // 随机转场,更多转场见:https://help.aliyun.com/document_detail/204853.html
                List<String> transitions = Arrays.asList("windowslice", "displacement", "bowTieVertical", "linearblur", "waterdrop", "polka", "wiperight", "gridflip", "hexagonalize", "windowblinds", "风车");
                float transDuration = 0.3f;
                Collections.shuffle(vfxs);
                for (int i = 0; i < mpsSubtitles.size(); i++) {
                    JSONObject mpsSubtitle = mpsSubtitles.getJSONObject(i);
                    String content = mpsSubtitle.getString("text");
                    content = content.replaceAll("。", "");
                    Float timelineIn = mpsSubtitle.getFloat("begin_time") / 1000;
                    Float timelineOut = mpsSubtitle.getFloat("end_time") / 1000;
                    String subtitleClip = "{\"Content\":\"" + content + "\",\"TimelineIn\":" + timelineIn + ",\"TimelineOut\":" + timelineOut +
                            ",\"Type\":\"Text\",\"X\":0.0,\"Y\":" + subtitleBottom + ",\"Font\":\"" + fontName + "\",\"Alignment\":\"BottomCenter\",\"FontSize\":" + fontSize +
                            ",\"FontColor\":\"" + fontColor + "\",\"OutlineColour\":\"#000000\",\"FontColor\":\"#ffffff\",}";
                    subtitleTrackClips.add(JSONObject.parseObject(subtitleClip));
    
                    // 根据字幕轨,截取视频轨片段
                    float out = timelineOut - timelineIn;
                    // 随机特效
                    String vfx = vfxs.get(i % vfxs.size());
                    String transition = transitions.get(i % transitions.size());
                    String url = videoUrls.get(i % videoUrls.size());
                    JSONObject clip = new JSONObject();
                    clip.put("MediaURL", url);
                    if (url.endsWith(".jpg")) {
                        clip.put("Duration", out + transDuration);
                        clip.put("Type", "Image");
                    } else {
                        clip.put("Out", out + transDuration);
                    }
                    JSONArray effects = new JSONArray();
                    // 添加背景模糊
                    effects.add(JSONObject.parseObject("{\"Type\":\"Background\",\"SubType\":\"Blur\",\"Radius\":0.1}"));
                    // 添加氛围类特效
                    effects.add(JSONObject.parseObject("{\"Type\":\"VFX\",\"SubType\":\"" + vfx + "\"}"));
                    // 视频静音
                    effects.add(JSONObject.parseObject("{\"Type\":\"Volume\",\"Gain\":0}"));
                    // 添加转场
                    effects.add(JSONObject.parseObject("{\"Type\":\"Transition\",\"SubType\":\"" + transition + "\",\"Duration\":"+transDuration+"}"));
    
                    clip.put("Effects", effects);
                    videoTrackClips.add(clip);
                }
    
                if (title != null && title.length() > 0) {
                    float titleY = 280;
                    int titleFontSize = 70;
                    String titleFont = "AlibabaPuHuiTi";
                    String titleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + titleY + ",\"Font\":\"" + titleFont + "\",\"Content\":\"" + title + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + titleFontSize + ",\"FontColor\":\"#FFD700\",\"Outline\":4,\"OutlineColour\":\"#000000\",\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}}";
                    subtitleTrackClips.add(JSONObject.parse(titleClip));
                }
                if (subtitle != null && subtitle.length() > 0) {
                    float subtitleY = 200;
                    int subtitleFontSize = 60;
                    String subtitleFont = "AlibabaPuHuiTi";
                    String subtitleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + subtitleY + ",\"Font\":\"" + subtitleFont + "\",\"Content\":\"" + subtitle + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + subtitleFontSize + ",\"FontColorOpacity\":1,\"FontColor\":\"#ffffff\",\"Outline\":2,\"OutlineColour\":\"#000000\",\"FontFace\":{\"Bold\":false,\"Italic\":false,\"Underline\":false}}";
                    subtitleTrackClips.add(JSONObject.parse(subtitleClip));
                }
    
                // 组装音频轨
                String audioUrl = "http://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + audioObject;
                String audioTrackClips = "";
                if (Strings.isBlank(bgMusic)) {
                    audioTrackClips = "[{\"MediaURL\":\"" + audioUrl + "\"}]";
                } else {
                    // 两个音频轨,一个人声,一个音乐
                    audioTrackClips = "[{\"MediaURL\":\"" + audioUrl + "\"}]},{\"AudioTrackClips\":[{\"MediaURL\":\"" + bgMusic + "\"}]";
                }
    
                // 图片轨,用于展示logo
                String logoClip = "";
                int logoWidth = 200;
                int logoHeight = 60;
                if (Strings.isNotBlank(logoUrl)) {
                    logoClip = "{\"ImageURL\":\"" + logoUrl + "\",\"X\":" + logoX + ",\"Y\":"
                            + logoY + ",\"Width\":\"" + logoWidth + "\",\"Height\":\"" + logoHeight + "\"}";
                }
    
                // 拼时间线
                String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" + videoTrackClips.toJSONString() + "}]," +
                        "\"SubtitleTracks\":[{\"SubtitleTrackClips\":" + subtitleTrackClips.toJSONString() + "}]," +
                        "\"AudioTracks\":[{\"AudioTrackClips\":" + audioTrackClips + "}]," +
                        "\"ImageTracks\":[{\"ImageTrackClips\":[" + logoClip + "]}]}";
                System.out.println("timeline : " + timeline);
    
                // 提交合成任务
                SubmitMediaProducingJobRequest submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest();
                submitMediaProducingJobRequest.setTimeline(timeline);
    
                String outputPath = output + "/" + UUID.randomUUID().toString().replaceAll("-","");
                String mediaURL = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + outputPath + ".mp4";
                submitMediaProducingJobRequest.setOutputMediaConfig("{\"MediaURL\":\"" + mediaURL + "\",\"Width\":" + width + ",\"Height\":" + height + "}");
                SubmitMediaProducingJobResponse submitMediaProducingJobResponse = iceClient.submitMediaProducingJob(submitMediaProducingJobRequest);
                System.out.println("job created, jobId : " + submitMediaProducingJobResponse.body.jobId + ", requestId : " + submitMediaProducingJobResponse.body.getRequestId() + ", mediaURL : " + mediaURL);
    
                // 等待合成任务完成
                while (true) {
                    GetMediaProducingJobRequest getMediaProducingJobRequest = new GetMediaProducingJobRequest();
                    getMediaProducingJobRequest.setJobId(submitMediaProducingJobResponse.body.jobId);
                    GetMediaProducingJobResponse getMediaProducingJobResponse = iceClient.getMediaProducingJob(getMediaProducingJobRequest);
                    System.out.println("GetMediaProducingJobResponse : " + JSONObject.toJSONString(getMediaProducingJobResponse.body));
                    String status = getMediaProducingJobResponse.getBody().getMediaProducingJob().getStatus();
                    if ("Success".equals(status)) {
                        break;
                    }
                    Thread.sleep(5000);
                }
                System.out.println("Produce succeed : " + mediaURL);
            }
    
        }
    
        public String getObjectContent(String object) throws Exception {
            OSSObject obj = ossClient.getObject(bucket, object);
            InputStream stream = obj.getObjectContent();
            String result = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
            return result;
        }
    
        public void putObjectContent(String object, String content) throws Exception {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, object, new ByteArrayInputStream(content.getBytes()));
            ossClient.putObject(putObjectRequest);
        }
    
        public com.aliyun.mts20140618.Client createMpsClient() throws Exception {
            // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
            // 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html
            com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
            Config config = new Config();
            config.setCredential(credentialClient);
    
            // 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
            // config.accessKeyId = <yourAccessKeyId>;
            // config.accessKeySecret = <yourAccessKeySecret>;
            config.endpoint = "mts." + regionId + ".aliyuncs.com";
            com.aliyun.mts20140618.Client mtsClient = new com.aliyun.mts20140618.Client(config);
    
            return mtsClient;
        }
    
        public OSS createOssClient() throws Exception {
            String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
            String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
            String endpoint = "http://oss-" + regionId + ".aliyuncs.com";
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            return ossClient;
        }
    
        public com.aliyun.ice20201109.Client createIceClient() throws Exception {
            // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
            // 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html
            com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
            Config config = new Config();
            config.setCredential(credentialClient);
    
            // 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
            // config.accessKeyId = <yourAccessKeyId>;
            // config.accessKeySecret = <yourAccessKeySecret>;
            config.endpoint = "ice." + regionId + ".aliyuncs.com";
            com.aliyun.ice20201109.Client iceClient = new com.aliyun.ice20201109.Client(config);
    
            return iceClient;
        }
    
    }
  • 输入为人声音频
    Java
    /**
     Maven引入:
    
     <dependency>
        <groupId>com.aliyun</groupId>
         <artifactId>aliyun-java-sdk-core</artifactId>
         <version>4.5.3</version>
     </dependency>
     <dependency>
     <groupId>com.aliyun</groupId>
         <artifactId>ice20201109</artifactId>
         <version>1.2.0</version>
     </dependency>
     <dependency>
        <groupId>com.alibaba</groupId>
         <artifactId>fastjson</artifactId>
         <version>2.0.8.graal</version>
     </dependency>
     <dependency>
     <groupId>com.aliyun</groupId>
         <artifactId>credentials-java</artifactId>
         <version>0.2.12</version>
     </dependency>
     */
    
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import com.aliyun.ice20201109.Client;
    import com.aliyun.teaopenapi.models.Config;
    import com.aliyun.ice20201109.models.*;
    import org.apache.logging.log4j.util.Strings;
    
    import java.util.*;
    
    /**
     * Create by oushu
     * Date 2021/12/7 上午9:28
     */
    public class BatchProduceASRSubtitleRelease {
    
        private String bucket;
        private String output;
        private String regionId;
        private Client iceClient;
    
        public void initClient() throws Exception {
            bucket = "your-bucket";
            output = "output-path";
            regionId = "cn-shanghai";
            iceClient = createIceClient();
        }
    
        public static void main(String[] args) throws Exception {
            BatchProduceASRSubtitleRelease batchProduceVideo = new BatchProduceASRSubtitleRelease();
            batchProduceVideo.initClient();
            batchProduceVideo.batchProduceVideo();
        }
    
        public void batchProduceVideo() throws Exception {
            // 人声素材
            String voiceUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-voice.mp3";
    
            // 视频素材
            List<String> videoUrlList = new ArrayList();
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video1.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video2.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video3.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video4.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video5.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video6.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video7.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video8.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video9.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video10.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video11.mp4");
            videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video12.mp4");
    
            // 背景音乐
            String bgMusic = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-music.wav";
    
            // 字幕样式设置
            Integer fontSize = 45;
            String fontName = "WenQuanYi Zen Hei Mono";
            String fontColor = "#FFFFFF";
    
            // 成片尺寸
            Integer width = 720;
            Integer height = 1280;
    
            // logo
            String logoUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-logo.png";
            Integer logoX = 20;
            Integer logoY = 20;
    
            String title = "这里是标题";
            String subTitle = "这里是副标题";
    
            int targetCount = 2;
            // 每次提交一个任务,业务方根据需要更换不同参数提交多次
            for (int i = 0; i < targetCount; i++) {
                Collections.shuffle(videoUrlList);
                produceSingleVideo(voiceUrl, videoUrlList, title, subTitle, bgMusic, fontSize, fontName, fontColor, logoUrl, logoX, logoY, width, height);
            }
        }
    
        // 提交单个任务
        public void produceSingleVideo(String voiceUrl, List<String> videoUrls, String title, String subtitle, String bgMusic, int fontSize, String fontName, String fontColor,
                                       String logoUrl, Integer logoX, Integer logoY, int width, int height) throws Exception {
    
            String inputFile = voiceUrl.replaceAll("https://", "oss://");
            inputFile = inputFile.replaceAll("http://", "oss://");
            SubmitASRJobRequest submitASRJobRequest = new SubmitASRJobRequest();
            submitASRJobRequest.setInputFile(inputFile);
            SubmitASRJobResponse submitASRJobResponse = iceClient.submitASRJob(submitASRJobRequest);
            String smartJobId = submitASRJobResponse.getBody().getJobId();
    
            String subtitleContent = "";
            while (true) {
                GetSmartHandleJobRequest getSmartHandleJobRequest = new GetSmartHandleJobRequest();
                getSmartHandleJobRequest.setJobId(smartJobId);
                GetSmartHandleJobResponse getSmartHandleJobResponse = iceClient.getSmartHandleJob(getSmartHandleJobRequest);
                System.out.println("asr response : " + JSONObject.toJSONString(getSmartHandleJobResponse.getBody()));
                String status = getSmartHandleJobResponse.getBody().getState();
                if ("Failed".equalsIgnoreCase(status) || "Finished".equalsIgnoreCase(status)) {
                    subtitleContent = getSmartHandleJobResponse.getBody().getOutput();
                    break;
                }
                Thread.sleep(5000);
            }
            System.out.println("subtitleContent : " + subtitleContent);
    
            // 组装字幕轨
            if (fontSize <= 0) {
                fontSize = 32;
            }
            if (Strings.isBlank(fontName)) {
                fontName = "WenQuanYi Zen Hei Mono";
            }
            if (Strings.isBlank(fontColor)) {
                fontColor = "#000000";
            }
    
            JSONArray subtitleTrackClips = new JSONArray();
            JSONArray mpsSubtitles = JSONArray.parseArray(subtitleContent);
            JSONArray videoTrackClips = new JSONArray();
    
            // 字幕距离底部距离
            float subtitleBottom = 0.25f;
            // 随机特效
            List<String> vfxs = Arrays.asList("heartfireworks", "colorfulradial", "meteorshower", "starry", "colorfulstarry", "moons_and_stars", "flyfire", "starexplosion", "spotfall", "sparklestarfield");
            Collections.shuffle(vfxs);
            for (int i = 0; i < mpsSubtitles.size(); i++) {
                JSONObject mpsSubtitle = mpsSubtitles.getJSONObject(i);
                String content = mpsSubtitle.getString("content");
                content = content.replaceAll("。", "");
                Float timelineIn = mpsSubtitle.getFloat("from") ;
                Float timelineOut = mpsSubtitle.getFloat("to") ;
                String subtitleClip = "{\"Content\":\"" + content + "\",\"TimelineIn\":" + timelineIn + ",\"TimelineOut\":" + timelineOut +
                        ",\"Type\":\"Text\",\"X\":0.0,\"Y\":" + subtitleBottom + ",\"Font\":\"" + fontName + "\",\"Alignment\":\"BottomCenter\",\"FontSize\":" + fontSize +
                        ",\"FontColor\":\"" + fontColor + "\",\"Outline\":2,\"OutlineColour\":\"#000000\",\"FontColor\":\"#ffffff\",}";
                subtitleTrackClips.add(JSONObject.parseObject(subtitleClip));
    
                // 根据字幕轨,截取视频轨片段
                float out = timelineOut - timelineIn;
                // 随机特效
                String vfx = vfxs.get(i % vfxs.size());
                String url = videoUrls.get(i % videoUrls.size());
                JSONObject clip = new JSONObject();
                clip.put("MediaURL", url);
                if (url.endsWith(".jpg")) {
                    clip.put("Duration", out);
                    clip.put("Type", "Image");
                } else {
                    clip.put("Out", out);
                }
                JSONArray effects = new JSONArray();
                // 添加背景模糊
                effects.add(JSONObject.parseObject("{\"Type\":\"Background\",\"SubType\":\"Blur\",\"Radius\":0.1}"));
                // 添加氛围类特效
                effects.add(JSONObject.parseObject("{\"Type\":\"VFX\",\"SubType\":\"" + vfx + "\"}"));
                // 视频静音
                effects.add(JSONObject.parseObject("{\"Type\":\"Volume\",\"Gain\":0}"));
                clip.put("Effects", effects);
                videoTrackClips.add(clip);
            }
    
            if (title != null && title.length() > 0) {
                float titleY = 280;
                int titleFontSize = 70;
                String titleFont = "AlibabaPuHuiTi";
                String titleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + titleY + ",\"Font\":\"" + titleFont + "\",\"Content\":\"" + title + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + titleFontSize + ",\"FontColor\":\"#FFD700\",\"Outline\":4,\"OutlineColour\":\"#000000\",\"TimelineIn\":0,\"TimelineOut\":5,\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}}";
                subtitleTrackClips.add(JSONObject.parse(titleClip));
            }
            if (subtitle != null && subtitle.length() > 0) {
                float subtitleY = 200;
                int subtitleFontSize = 60;
                String subtitleFont = "AlibabaPuHuiTi";
                String subtitleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + subtitleY + ",\"Font\":\"" + subtitleFont + "\",\"Content\":\"" + subtitle + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + subtitleFontSize + ",\"FontColorOpacity\":1,\"FontColor\":\"#ffffff\",\"Outline\":2,\"OutlineColour\":\"#000000\",\"FontFace\":{\"Bold\":false,\"Italic\":false,\"Underline\":false}}";
                subtitleTrackClips.add(JSONObject.parse(subtitleClip));
            }
    
            // 组装音频轨
            String audioTrackClips = "";
            if (Strings.isBlank(bgMusic)) {
                audioTrackClips = "[{\"MediaURL\":\"" + voiceUrl + "\"}]";
            } else {
                // 两个音频轨,一个人声,一个音乐
                audioTrackClips = "[{\"MediaURL\":\"" + voiceUrl + "\"}]},{\"AudioTrackClips\":[{\"MediaURL\":\"" + bgMusic + "\"}]";
            }
    
            // 图片轨,用于展示logo
            String logoClip = "";
            int logoWidth = 200;
            int logoHeight = 60;
            if (Strings.isNotBlank(logoUrl)) {
                logoClip = "{\"ImageURL\":\"" + logoUrl + "\",\"X\":" + logoX + ",\"Y\":"
                        + logoY + ",\"Width\":\"" + logoWidth + "\",\"Height\":\"" + logoHeight + "\"}";
            }
    
            // 拼时间线
            String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" + videoTrackClips.toJSONString() + "}]," +
                    "\"SubtitleTracks\":[{\"SubtitleTrackClips\":" + subtitleTrackClips.toJSONString() + "}]," +
                    "\"AudioTracks\":[{\"AudioTrackClips\":" + audioTrackClips + "}]," +
                    "\"ImageTracks\":[{\"ImageTrackClips\":[" + logoClip + "]}]}";
            System.out.println("timeline : " + timeline);
    
            // 提交合成任务
            SubmitMediaProducingJobRequest submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest();
            submitMediaProducingJobRequest.setTimeline(timeline);
            String outputPath = output + "/" + UUID.randomUUID().toString().replaceAll("-","");
            String mediaURL = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + outputPath + ".mp4";
            submitMediaProducingJobRequest.setOutputMediaConfig("{\"MediaURL\":\"" + mediaURL + "\",\"Width\":" + width + ",\"Height\":" + height + "}");
            SubmitMediaProducingJobResponse submitMediaProducingJobResponse = iceClient.submitMediaProducingJob(submitMediaProducingJobRequest);
            System.out.println("job created, jobId : " + submitMediaProducingJobResponse.body.jobId + ", requestId : " + submitMediaProducingJobResponse.body.getRequestId() + ", mediaURL : " + mediaURL);
    
            // 等待合成任务完成
            while (true) {
                GetMediaProducingJobRequest getMediaProducingJobRequest = new GetMediaProducingJobRequest();
                getMediaProducingJobRequest.setJobId(submitMediaProducingJobResponse.body.jobId);
                GetMediaProducingJobResponse getMediaProducingJobResponse = iceClient.getMediaProducingJob(getMediaProducingJobRequest);
                System.out.println("GetMediaProducingJobResponse : " + JSONObject.toJSONString(getMediaProducingJobResponse.body));
                String status = getMediaProducingJobResponse.getBody().getMediaProducingJob().getStatus();
                if ("Success".equals(status)) {
                    break;
                }
                Thread.sleep(5000);
            }
            System.out.println("Produce succeed : " + mediaURL);
        }
    
        public Client createIceClient() throws Exception {
            // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
            // 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html
            com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
            Config config = new Config();
            config.setCredential(credentialClient);
    
            // 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
            // config.accessKeyId = <yourAccessKeyId>;
            // config.accessKeySecret = <yourAccessKeySecret>;
    
            config.endpoint = "ice." + regionId + ".aliyuncs.com";
            Client client = new Client(config);
            return client;
        }
    }

相关接口

卡点视频

主要功能

  • 输入一段音频,自动识别音频卡点。
  • 输入任意数量视频或图片素材,随机排序,并根据音乐卡点生成Timeline。
  • 添加转场和背景模糊效果。

成片预览

实现代码

Java
package com.alibaba.bltest;

/**
 Maven引入:

 <dependency>
     <groupId>com.aliyun</groupId>
     <artifactId>aliyun-java-sdk-core</artifactId>
     <version>4.5.3</version>
 </dependency>
 <dependency>
     <groupId>com.aliyun</groupId>
     <artifactId>ice20201109</artifactId>
     <version>1.2.0</version>
 </dependency>
 <dependency>
 <groupId>com.aliyun</groupId>
     <artifactId>mts20140618</artifactId>
     <version>3.3.33</version>
 </dependency>
 <dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.10.2</version>
</dependency>
 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
 </dependency>
 <dependency>
     <groupId>com.aliyun</groupId>
     <artifactId>credentials-java</artifactId>
     <version>0.2.12</version>
 </dependency>
 */
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.ice20201109.models.GetMediaProducingJobRequest;
import com.aliyun.ice20201109.models.GetMediaProducingJobResponse;
import com.aliyun.ice20201109.models.SubmitMediaProducingJobRequest;
import com.aliyun.ice20201109.models.SubmitMediaProducingJobResponse;
import com.aliyun.mts20140618.models.QueryIProductionJobRequest;
import com.aliyun.mts20140618.models.QueryIProductionJobResponse;
import com.aliyun.mts20140618.models.SubmitIProductionJobRequest;
import com.aliyun.mts20140618.models.SubmitIProductionJobResponse;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;

import com.aliyun.oss.model.OSSObject;
import com.aliyun.teaopenapi.models.Config;
import com.google.common.io.CharStreams;

import org.apache.commons.io.Charsets;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

/**
 * Create by oushu
 * Date 2022/07/11 上午11:57
 */
public class BatchProduceASRSubtitleRelease {

    private String bucket;
    private String regionId;
    private String output;
    private OSS ossClient;
    private com.aliyun.mts20140618.Client mpsClient;
    private com.aliyun.ice20201109.Client iceClient;

    public void initClient() throws Exception {
        bucket = "your-bucket";
        output = "output-path";
        regionId = "cn-shanghai";
        ossClient = createOssClient();
        mpsClient = createMpsClient();
        iceClient = createIceClient();
    }

    public static void main(String[] args) throws Exception {
        BatchProduceBeatMusicRelease batchProduceVideo = new BatchProduceBeatMusicRelease();
        batchProduceVideo.initClient();
        batchProduceVideo.batchProduceVideo();
    }

    public void batchProduceVideo() throws Exception {
        String musicUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-music.mp3";

        List<String> mediaUrls = new ArrayList();
        mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-image1.jpg");
        mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-image2.jpg");
        mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-image3.jpg");
        mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-movie1.mp4");
        mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-movie2.mp4");
        mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-movie3.mp4");

        int targetCount = 1;
        for (int i = 0; i < targetCount; i++) {
            Collections.shuffle(mediaUrls);
            List<String> subImageUrls = mediaUrls.subList(0, 15);
            produceSingleVideo(musicUrl, subImageUrls);
        }
    }


    public void produceSingleVideo(String musicUrl, List<String> imageUrls) throws Exception {
        System.out.println("Start produce!!!!");

        // 提交节奏检测任务
        String input = musicUrl;
        SubmitIProductionJobRequest submitIProductionJobRequest = new SubmitIProductionJobRequest();
        submitIProductionJobRequest.setFunctionName("AudioBeatDetection");
        submitIProductionJobRequest.setInput(input);
        submitIProductionJobRequest.setOutput("oss://" + bucket + ".oss-" + regionId + ".aliyuncs.com/iproduction/{source}-{timestamp}.txt");
        SubmitIProductionJobResponse submitIProductionJobResponse = mpsClient.submitIProductionJob(submitIProductionJobRequest);
        // 等待任务完成
        String jobId = submitIProductionJobResponse.body.jobId;
        String result;
        while (true) {
            QueryIProductionJobRequest queryIProductionJobRequest = new QueryIProductionJobRequest();
            queryIProductionJobRequest.setJobId(jobId);
            QueryIProductionJobResponse queryIProductionJobResponse = mpsClient.queryIProductionJob(queryIProductionJobRequest);
            System.out.println("IProductionJob Info : " + JSONObject.toJSONString(queryIProductionJobResponse.body));
            if ("Success".equals(queryIProductionJobResponse.body.state)) {
                result = queryIProductionJobResponse.body.result;
                break;
            }
            Thread.sleep(5000);
        }

        // 获取节奏检测任务结果
        String file = JSONObject.parseObject(JSONObject.parseObject(result).getString("Data")).getJSONArray("result").getJSONObject(0).getString("file");
        System.out.println("result file : " + file);
        String resultContent = getObjectContent(file);
        System.out.println("result content : " + resultContent);
        JSONArray beatList = JSONObject.parseObject(resultContent).getJSONArray("BeatList");
        // 封装时间线
        JSONArray videoTrackClips = new JSONArray();
        float transitionDur = 0.3f;
        float lastBeat = 0;
        for (int i = 0; i < imageUrls.size(); i++) {
            float beat = Float.parseFloat(beatList.getString(i));
            float beatDuration = beat - lastBeat;

            float duration = beatDuration;
            String url = imageUrls.get(i);
            JSONObject clip = new JSONObject();
            clip.put("MediaURL", url);
            if (beatDuration > transitionDur) {
                clip.put("Effects", JSONArray.parse("[{\"Type\": \"Transition\",\"SubType\": \"linearblur\",\"Duration\": " + transitionDur + "},{\"Type\":\"Background\",\"SubType\":\"Blur\"}]"));
                duration += transitionDur;
            } else {
                clip.put("Effects", JSONArray.parse("[{\"Type\":\"Background\",\"SubType\":\"Blur\"}]"));
            }
            if (url.endsWith(".jpg")) {
                clip.put("Duration", duration);
                clip.put("Type", "Image");
            } else {
                clip.put("Out", duration);
            }
            videoTrackClips.add(clip);
            lastBeat = beat;
        }

        String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" + videoTrackClips.toJSONString() + "}]," +
                "\"AudioTracks\":[{\"AudioTrackClips\":[{\"MediaURL\":\"" + musicUrl + "\"}]}]," +
                "}";
        System.out.println("timeline : " + timeline);

        // 提交合成任务
        SubmitMediaProducingJobRequest submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest();
        submitMediaProducingJobRequest.setTimeline(timeline);
        String outputPath = output + "/" + UUID.randomUUID().toString().replaceAll("-","");
        String mediaURL = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + outputPath + ".mp4";
        submitMediaProducingJobRequest.setOutputMediaConfig("{\"MediaURL\":\"" + mediaURL + "\",\"Width\":720,\"Height\":1280}");
        SubmitMediaProducingJobResponse submitMediaProducingJobResponse = iceClient.submitMediaProducingJob(submitMediaProducingJobRequest);
        System.out.println("job created, jobId : " + submitMediaProducingJobResponse.body.jobId + ", requestId : " + submitMediaProducingJobResponse.body.getRequestId() + ", mediaURL : " + mediaURL);
        // 等待合成任务完成
        while (true) {
            GetMediaProducingJobRequest getMediaProducingJobRequest = new GetMediaProducingJobRequest();
            getMediaProducingJobRequest.setJobId(submitMediaProducingJobResponse.body.jobId);
            GetMediaProducingJobResponse getMediaProducingJobResponse = iceClient.getMediaProducingJob(getMediaProducingJobRequest);
            System.out.println("GetMediaProducingJobResponse : " + JSONObject.toJSONString(getMediaProducingJobResponse.body));
            String status = getMediaProducingJobResponse.getBody().getMediaProducingJob().getStatus();
            if ("Success".equals(status)) {
                break;
            }
            Thread.sleep(5000);
        }
        System.out.println("Produce succeed : " + mediaURL);
    }

    public String getObjectContent(String object) throws Exception {
        OSSObject obj = ossClient.getObject(bucket, object);
        InputStream stream = obj.getObjectContent();
        String result = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
        return result;
    }

    public com.aliyun.mts20140618.Client createMpsClient() throws Exception {
        // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
        // 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html
        com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
        Config config = new Config();
        config.setCredential(credentialClient);

        // 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
        // config.accessKeyId = <yourAccessKeyId>;
        // config.accessKeySecret = <yourAccessKeySecret>;
        config.endpoint = "mts." + regionId + ".aliyuncs.com";
        com.aliyun.mts20140618.Client mtsClient = new com.aliyun.mts20140618.Client(config);

        return mtsClient;
    }

    public OSS createOssClient() throws Exception {
        String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
        String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
        String endpoint = "http://oss-" + regionId + ".aliyuncs.com";
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        return ossClient;
    }

    public com.aliyun.ice20201109.Client createIceClient() throws Exception {
        // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
        // 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html
        com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
        Config config = new Config();
        config.setCredential(credentialClient);

        // 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
        // config.accessKeyId = <yourAccessKeyId>;
        // config.accessKeySecret = <yourAccessKeySecret>;
        config.endpoint = "ice." + regionId + ".aliyuncs.com";
        com.aliyun.ice20201109.Client iceClient = new com.aliyun.ice20201109.Client(config);

        return iceClient;
    }
}

相关接口