All Products
Search
Document Center

Intelligent Media Services:Preparations

Last Updated:Dec 09, 2024

This topic describes how to use the Intelligent Media Services (IMS) SDK to call the SubmitMediaProducingJob operation to edit audio and video materials together.

Feature description

Batch editing

Batch editing allows you to produce different video clips from given audio and video materials.

Scenarios

In the 5G era, more sellers market their products and services by using short-form videos. For example, sellers may cooperate with key opinion leaders (KOLs) on short-form video platforms to connect to more potential customers. To prevent video content theft, mainstream short-form video platforms apply video content deduplication mechanisms that block videos with the same content and structure from being posted to different accounts on the same platform. Batch editing helps create differentiating video content from similar input information. You can change the Timeline parameter settings in the SubmitMediaProducingJob operation based on your batch editing requirements.

Pricing

When you submit an editing and composition job, you might be charged for multiple items. For more information, see Intelligent production.

Usage notes

  • You can produce a video from one or more videos, audio files, images, and subtitle materials by configuring Timeline parameters and calling the SubmitMediaProducingJob operation.

  • A timeline is created when you add materials and configure effects to create a video. A timeline consists of tracks, materials, and effects.

  • Intelligent production supports editing and compositing, effect rendering, and template-based production for live streams, VOD files, and materials from Object Storage Service (OSS). For more information, see Intelligent production.

Prerequisites

Step 1: Create an OSS bucket

Log on to the OSS console. In the left-side navigation pane, click Buckets. On the Buckets page, click Create Bucket. In the Create Bucket panel, specify a bucket name, select China (Shanghai) for Region, and click Create. The bucket will be used to store the output videos later.

image

Step 2: Run batch editing code

  1. Prepare your development environment:

    • Use Windows 8.1 or later, macOS, or Linux.

    • Download and install IntelliJ IDEA 2020.1 or later.

    • Use Java Development Kit (JDK) 1.8 or later.

  2. Create a Maven project and run the code.

  3. Import third-party dependencies.

    Note

    The version number of the server SDK introduced in the following sample code is for reference only. To obtain the latest version, visit the SDK page.

    <dependencies>
      <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>ice20201109</artifactId>
        <version>2.3.0</version>
      </dependency>
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.9</version>
      </dependency>
    </dependencies>

    image.png

  4. Include the AccessKey ID and AccessKey secret in the configuration file. For more information, see Manage access credentials.Manage access credentials

    Note

    For information about how to manage access credentials, see Manage access credentials.

  5. Create a Java class and copy and paste the following sample code.

    Expand

    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import com.aliyun.ice20201109.Client;
    import com.aliyun.ice20201109.models.*;
    import com.aliyun.teaopenapi.models.Config;
    
    import java.util.*;
    
    // The output video is hosted at the following URL:
    // http://oushu-test-shanghai.oss-cn-shanghai.aliyuncs.com/ice_output/46b29eb5775f4f758846171ab79bfca7.mp4
    
    /**
     *  Add the following dependencies:
     *   <dependency>
     *      <groupId>com.aliyun</groupId>
     *      <artifactId>ice20201109</artifactId>
     *      <version>2.1.0</version>
     *  </dependency>
     *  <dependency>
     *      <groupId>com.alibaba</groupId>
     *      <artifactId>fastjson</artifactId>
     *      <version>1.2.9</version>
     *  </dependency>
     */
    public class BatchProduceAlignment {
    
        static final String regionId = "cn-shanghai";
        static final String bucket = "Bucket created in Step 3";
        private Client iceClient;
        
        public static void main(String[] args) {
            try {
                BatchProduceAlignment batchProduce = new BatchProduceAlignment();
                batchProduce.initClient();
                batchProduce.run();
            } catch (Exception e) {
                System.out.println("Produce failed. Exception: " + e.toString());
            }
        }
    
        public void initClient() throws Exception {
    
            // The AccessKey pair of an Alibaba Cloud account has access permissions on all API operations. We recommend that you use the AccessKey pair of a RAM user to call API operations or perform routine O&M. 
            // In this example, the AccessKey ID and AccessKey secret are obtained from the environment variables. For information about how to configure environment variables to store the AccessKey ID and AccessKey secret, visit https://www.alibabacloud.com/help/en/sdk/developer-reference/v2-manage-access-credentials.
            com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
            Config config = new Config();
            config.setCredential(credentialClient);
    
            // To hard-code your AccessKey ID and AccessKey secret, use the following lines. However, we recommend that you do not hard-code your AccessKey ID and AccessKey secret for security concerns. 
            // config.accessKeyId = <AccessKey ID>;
            // config.accessKeySecret = <AccessKey secret>;
            config.endpoint = "ice." + regionId + ".aliyuncs.com";
            config.regionId = regionId;
            iceClient = new Client(config);
        }
    
        public void run() throws Exception {
            // Text material
            String text = "People may describe life as a mixture of five flavors, for flavors are associated with feelings and tastes of life deep in their hearts. This era sees lots of bitterness and sweetness in each individual. Many people leave bitter feelings silent inside and let yummy foods on tables speak for their sweet feelings throughout passing seasons.";
            // Video material
            String[] videoArray = new String[]{
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f1.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f2.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f3.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f4.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f5.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f6.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f7.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f8.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f9.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f10.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f11.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f12.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f13.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f14.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f15.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f16.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f17.mp4",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f18.mp4"
            };
            // Background music
            String[] bgMusicArray = new String[]{
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/music/m1.wav",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/music/m2.wav",
                    "https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/music/m3.wav"
            };
            // Video title
            String title = "Tasty Bites";
            // Specify the number of videos to produce.
            int produceCount = 3;
    
            // Submit tasks.
            List<String> jobIds = new ArrayList<String>();
            for (int i = 0; i < produceCount; i++) {
                String jobId = produceSingleVideo(title, text, videoArray, bgMusicArray);
                jobIds.add(jobId);
            }
            // Iterate over tasks until all the tasks are complete.
            System.out.println("waiting job finished...");
            while (true) {
                Thread.sleep(3000);
                boolean allFinished = true;
                for (int i = 0; i < jobIds.size(); i++) {
                    String jobId = jobIds.get(i);
                    GetMediaProducingJobRequest req = new GetMediaProducingJobRequest();
                    req.setJobId(jobId);
                    GetMediaProducingJobResponse response = iceClient.getMediaProducingJob(req);
                    GetMediaProducingJobResponseBody.GetMediaProducingJobResponseBodyMediaProducingJob mediaProducingJob = response.getBody().getMediaProducingJob();
                    String status = mediaProducingJob.getStatus();
                    System.out.println("jobId: " + mediaProducingJob.getJobId() + ", status:" + status);
                    if ("Failed".equalsIgnoreCase(status)) {
                        System.out.println("jobfailed. jobInfo: " + JSONObject.toJSONString(mediaProducingJob));
                        throw new Exception("Produce failed. jobid: " + mediaProducingJob.getJobId());
                    }
                    if (!"Success".equalsIgnoreCase(status)) {
                        allFinished = false;
                        break;
                    }
                }
                if (allFinished) {
                    System.out.println("all job finished.");
                    break;
                }
            }
        }
    
        public String produceSingleVideo(String title, String text, String[] videoArray, String[] bgMusicArray) throws Exception {
            text = text.replace(",", ".");
            text = text.replace("\n", ".");
            String[] sentenceArray = text. Split(".");
    
            JSONArray videoClipArray = new JSONArray();
            JSONArray audioClipArray = new JSONArray();
    
            List<String> videoList = Arrays.asList(videoArray);
            Collections.shuffle(videoList);
    
            for (int i = 0; i < sentenceArray.length; i++) {
                String sentence = sentenceArray[i];
                String clipId = "clip" + i;
                String videoUrl = videoList.get(i);
                String videoClip = "{\"MediaURL\":\""+videoUrl+"\",\"ReferenceClipId\":\""+clipId+"\",\"Effects\":[{\"Type\":\"Background\",\"SubType\":\"Blur\",\"Radius\":0.1}]}";
                videoClipArray.add(JSONObject.parseObject(videoClip));
                String audioClip = "{\"Type\":\"AI_TTS\",\"Content\":\"" + sentence + "\",\"Voice\":\"zhichu\",\"ClipId\":\""+clipId+"\",\"Effects\":[{\"Type\":\"AI_ASR\",\"Font\":\"Alibaba PuHuiTi\",\"Alignment\":\"TopCenter\",\"Y\":0.75,\"FontSize\":55,\"FontColor\":\"#ffffff\",\"AdaptMode\":\"AutoWrap\",\"TextWidth\":0.8,\"Outline\":2,\"OutlineColour\":\"#000000\"}]}";
                audioClipArray.add(JSONObject.parseObject(audioClip));
            }
    
            String subtitleTrack = "{\"SubtitleTrackClips\":[{\"Type\":\"Text\",\"Font\":\"HappyZcool-2016\",\"Content\":\""+title+"\",\"FontSize\":80,\"FontColor\":\"#ffffff\",\"Y\":0.15,\"Alignment\":\"TopCenter\",\"EffectColorStyle\":\"CS0004-000005\",\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}}]}";
    
            int bgMusicIndex = (int)(Math.random() * bgMusicArray.length);
            String bgMusicUrl = bgMusicArray[bgMusicIndex];
            String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":"+videoClipArray.toJSONString()+"}],\"AudioTracks\":[{\"AudioTrackClips\":"+audioClipArray.toJSONString()+"},{\"AudioTrackClips\":[{\"MediaURL\":\""+bgMusicUrl+"\"}]}],\"SubtitleTracks\":[" + subtitleTrack + "]}";
    
            //
            String targetFileName = UUID.randomUUID().toString().replace("-", "");
            String outputMediaUrl = "http://" + bucket + ".oss-" + regionId + ".aliyuncs.com/ice_output/" + targetFileName + ".mp4";
            int width = 720;
            int height = 1280;
            String outputMediaConfig = "{\"MediaURL\":\"" + outputMediaUrl + "\",\"Width\":"+width+",\"Height\":"+height+"}";
    
            SubmitMediaProducingJobRequest request = new SubmitMediaProducingJobRequest();
            request.setTimeline(timeline);
            request.setOutputMediaConfig(outputMediaConfig);
            SubmitMediaProducingJobResponse response = iceClient.submitMediaProducingJob(request);
            System.out.println("start job. jobid: " + response.getBody().getJobId() + ", outputMediaUrl: " + outputMediaUrl);
            return response.getBody().getJobId();
        }
    
    }
    
  6. Set bucket in the code to the name of the bucket that you created previously.

  7. Run the sample code to produce videos. The sample code implements the following process:

    Timeline creation > Submission of video compositing tasks > Task status polling > Log printingimage.pngimage.png

  8. When the task status is Success, open the file in the returned outputMediaUrl to preview the video. If the access control list (ACL) of the bucket is private, the returned URL of the output video cannot be opened. You need to generate a signed URL of the video in the OSS console and then use the signed URL to access the object.

  9. To change the number of output videos, change the value of the produceCount parameter. You can replace input material provided in the sample code with your actual information. For more information, see Timeline configurations.

References

What to do next