The short video SDK provides video editing and export features. You can import videos, images, and materials, and add effects such as filters, dubbing, and time effects to videos.

Supported editions

Edition Supported
Professional All features are supported.
Standard Features excluding subtitles, animated stickers, and music videos (MVs) are supported.
Basic Not supported.

Related classes

Feature Class Description
Initialization AliyunIEditor A core class that defines video editing.
AliyunEditorFactory The factory class.
Video management AliyunIClipConstructor A class that is used to manage video sources.
AliyunImageClip A class that defines the images that are used in video editing.
AliyunVideoClip A class that defines the video clips that are used in video editing.
Video effect settings EffectBean A model of filters and MVs.
EffectFilter A model of animated filters.
TransitionBase A model of transition effects.
Picture-in-Picture (PiP) settings AliyunIPipManager The PiP manager. You can create, modify, query, and remove a PiP effect.
AliyunIPipController The PiP controller. You can specify the start time and end time of a PiP effect.
AliyunIPipTrack A class that is used to obtain track information.
AliyunILayoutController The layout controller. You can configure settings, such as position, scale, rotation, and alpha, for a PiP effect.
AliyunIAnimationController The animation controller. You can add an animation to a PiP effect.
AliyunIAudioController The audio controller. You can configure audio settings such as volume, noise reduction, sound effects, fade in, and fade out.
AliyunIAugmentationController The augmentation controller. You can configure augmentation settings such as saturation, brightness, and contrast.
Subtitle and animated sticker settings AliyunPasterManager A class that is used to manage subtitles and animated stickers.
AliyunPasterControllerCompoundCaption The subtitle controller.
AliyunPasterController The animated sticker controller.
Draft box AliyunEditorProject A class that defines project configurations.
AliyunDraftManager A class that is used to manage drafts.
AliyunDraft A class that is used to manage draft configurations.
AliyunDraftResourceLoader A class that defines the resource loader.
AliyunDraftResourceUploader A class that defines the resource uploader.
AliyunDraftResourceDownloader A class that defines the resource downloader.
AliyunDraftResTask A class that defines draft tasks.

Video editing process

Configuration Step Description Sample code
Basic configurations 1 Create and initialize an editor. Initialize an editor
2 Crop the video, change video sources, and change the transition time and effects during video editing. The core class of video editing is the AliyunIEditor class. Manage videos
3 Configure the preview. Configure preview
Advanced configurations 4 Configure effects such as filters, transition, and MVs. Configure video effects
5 Configure background music, dubbing, and sound effects. Configure music and sound effects
6 Configure PiP. Configure PiP
7 Configure subtitles, word art, text bubbles, and animated stickers. Configure subtitles and animated stickers
8 Edit videos that are stored in the draft box, or save edited videos to the draft box. Draft box
9 Configure time effects, watermarks, and doodles. Other settings

Initialize an editor

Create and initialize an editor. For more information about the parameters that are used in the code, see Related classes.

// 1. Create an editor.
// configPath is the URL of the imported video, which is the URL of the draft box or the URL that is generated after you call AliyunIImport.generateProjectConfigure().
Uri uri = Uri.parse(configPath); 

AliyunIEditor editor = AliyunEditorFactory.creatAliyunEditor(uri, null);

// 2: Initialize the editor.
// Initialize the editor and configure the preview window.
editor.init(surfaceView, context);


// 3. Call onDestroy() to destroy the instance if you no longer need to use the editor.
editor.onDestroy()

Manage videos

You can manage the videos or images in the video editor by using the AliyunIClipConstructor class. After you call AliyunIClipConstructor to modify the videos or images in the video editor, call AliyunIEditor.applySourceChange() to make the modifications take effect.

For more information about the parameters that are used in the code, see Related classes.

Video source management
// 1. Obtain the video source manager.
AliyunIClipConstructor contructor = AliyunIEditor.getSourcePartManager();


// 2. Add a video or an image. This step is optional.

// Add a video or an image at the end of the timeline. You can call AliyunVideoClip to add a video or call AliyunImageClip to add an image.
contructor.addMediaClip(AliyunClip clip);

// Add a video or an image at the specified position. You can call AliyunVideoClip to add a video or call AliyunImageClip to add an image.
contructor.addMediaClip(int index, AliyunClip clip);

// 3. Delete a video or an image. This step is optional.

// Delete the last video or image.
contructor.deleteMediaClip();

// Delete the specified video or image.
contructor.deleteMediaClip(int index);

// 4. Replace a video or an image. This step is optional.
// Replace the video or image at the specified position.
contructor.updateMediaClip(int index, AliyunClip clip);

// Replace all videos or images.
contructor.updateAllClips(List<AliyunClip> clips);


// 5. Apply updates. After the media file configurations are complete, call the following operation to make the modifications take effect.
AliyunIEditor.applySourceChange();
Other operations
// Adjust the positions of media files.    
contructor.swap(int pos1, int pos2);

// Obtain the number of media files.    
contructor.getMediaPartCount();

// Obtain the list of media files.    
contructor.getAllClips();

Configure preview

During video editing, you can perform operations, such as playback, pause, and obtaining the duration of the playback timeline, on the video. For more information about the parameters that are used in the code, see Related classes.

// Start playback.    
AliyunIEditor.play();

// Resume playback.
AliyunIEditor.resume();

// Pause playback.
AliyunIEditor.pause();

// Skip to the specified position.
AliyunIEditor.seek(long time);

// Specify whether to mute the audio.
AliyunIEditor.setAudioSilence(boolean silence);

// Configure the volume.    
AliyunIEditor.setVolume(int volume);

// Configure the display mode of the video.    
AliyunIEditor.setDisplayMode(VideoDisplayMode mode);

// Configure the background color in scaling mode.
AliyunIEditor.setFillBackgroundColor(int color);

// Obtain the current position of the stream, which is not affected by time effects.
AliyunIEditor.getCurrentStreamPosition();

// Obtain the current position on the playback timeline, which is not affected by time effects.
AliyunIEditor.getCurrentPlayPosition();

// Obtain the duration of the stream, which is not affected by time effects.
AliyunIEditor.getStreamDuration();

// Obtain the total playback duration, which is affected by time effects.
AliyunIEditor.getDuration();

Configure video effects

You can configure and create custom video effects such as filters, transition effects, and MVs. For more information, see Filters and transitions and MVs. For more information about the parameters that are used in the code, see Related classes.
  • Filters include Lookup Table (LUT) filters, static filters, and animated filters.
    • LUT filters: uses Lookup Table to replace pixels.
    • Static filters: calculates pixels by writing a shading language. Animated effects are not supported. The bean of the static filter is EffectBean. For more information about operation parameters, see EffectBean.
    • Animated filters: calculates pixels by writing a shading language. Animated effects are supported. The bean of the animated filter is EffectFilter. For more information about operation parameters, see EffectFilter.
  • The short video SDK provides the following transition effects: TransitionCircle (iris round), TransitionFade (fade in and fade out), TransitionFiveStar (star), TransitionShutter (blinds), and TransitionTranslate (slide).
LUT filters
LUTEffectBean bean = new LUTEffectBean();
bean.setPath("image_01.png");
bean.setIntensity(1.f);

// Add a LUT filter.
mAliyunIEditor.applyLutFilter(bean);
// Remove a LUT filter.
mAliyunIEditor.applyLutFilter(null);
Static filters
EffectBean effect = new EffectBean();
effect.setId(id)
effect.setSource(new Souce(filePath));

// Add a filter.
AliyunIEditor.applyFilter(effect);
// Remove a filter.
AliyunIEditor.applyFilter(new EffectBean());
Animated filters
EffectFilter effectFilter = new EffectFilter(new Souce(filePath));
effectFilter.setStartTime(startTime);
effectFilter.setDuration(duration);

// Add an animated filter.
AliyunIEditor.addAnimationFilter(effectFilter);

// Remove an animated filter.
AliyunIEditor.removeAnimationFilter(effectFilter);
// Remove all animated filters.
AliyunIEditor.clearAllAnimationFilter();
Transition effects
// 1. Configure a transition effect.
// Configure a transition effect. index specifies the position on the playback timeline when the transition starts. If the index is set to 0, the transition starts at the end of the first video. If you want to cancel the transition, set the parameter to null.
AliyunEditor.setTransition(int index, TransitionBase transition); 

// Configure transition effects in batch. If you want to cancel the transition, set the parameter to null.
AliyunEditor.setTransition(Map<Integer, TransitionBase> transitions); // Configure multiple transition effects.


// 2. Update a transition effect.
// Update a transition effect by using another transition effect. The parameter cannot be set to null.
AliyunEditor.updateTransition(int index, TransitionBase transition); 

MV

You can create a custom MV. For more information, see MVs.
// Add an MV.
AliyunIEditor.applyMV(EffectBean effect);

// Remove an MV.
AliyunIEditor.applyMV(null);

Configure music and sound effects

Music

Music includes background music and dubbing voice. Background music is not affected by time effects such as speed ramping, repeat, and reverse playback. Dubbing is affected by time effects. For more information about the parameters that are used in the code, see Related classes.

EffectBean musicBean = new EffectBean();
musicBean.setId(effectInfo.id);
musicBean.setSource(effectInfo.getSource());

                    
// After you change the music, you must call the seek operation and set the value to 0 to clear the music cache to prevent the music from stopping immediately after the music starts.
musicBean.setStartTime(startTime);
musicBean.setDuration(Integer.MAX_VALUE);// Set the duration to the maximum value.
musicBean.setStreamStartTime(streamStartTime);
musicBean.setStreamDuration(streamDuration);

int audioSteamId;
// 1. Add background music or dubbing voice.
audioSteamId = AliyunIEditor.applyMusic (musicBean);// Add background music.
AliyunIEditor.applyDub(EffectBean effect);// Add dubbing voice.

// 2. Remove background music or dubbing voice.
AliyunIEditor.removeMusic(EffectBean effect);// Remove background music.
AliyunIEditor.removeDub(EffectBean effect);// Remove dubbing voice.

// 3. Adjust the weight of the background music or dubbing when the background music or dubbing is mixed with the original audio.
AliyunIEditor.applyMusicMixWeight(int audioSteamId, int weight);

// 4. Adjust the volume of the specified audio stream.
// For more information about the background music, dubbing voice, and original audio, see API references.
AliyunIEditor.applyMusicWeight(int audioSteamId, int weight);

// 5. Perform noise reduction on the specified audio stream.
AliyunIEditor.denoise(int audioSteamId, boolean needDenoise);

Sound effects

The short video SDK provides the following sound effects and allows you to add sound effects to audio streams:
  • AudioEffectType.EFFECT_TYPE_LOLITA (Lively female voice)
  • AudioEffectType.EFFECT_TYPE_REVERB (Reverberation)
  • AudioEffectType.EFFECT_TYPE_UNCLE (Husky male voice)
  • AudioEffectType.EFFECT_TYPE_ECHO (Echo)
  • AudioEffectType.EFFECT_TYPE_ROBOT (Robot)
  • AudioEffectType.EFFECT_TYPE_BIG_DEVIL (Sinister)
  • AudioEffectType.EFFECT_TYPE_MINIONS (Minion)
  • AudioEffectType.EFFECT_TYPE_DIALECT (Chinese dialects)
// 1. Configure a sound effect.
// For more information about AudioEffectType, see API references.
int audioEffect(int audioSteamId, AudioEffectType type, int weight);

// 2. Remove a sound effect.
// Sound effects can overlap each other. Before you use a new sound effect, remove the existing sound effect. 
int removeAudioEffect(int audioSteamId, AudioEffectType type);

Configure PiP

The PiP feature allows you to add one or more PiP effects to the existing main track.
  • Main track: the default track on the editing page. Only one main track is allowed. A main track can contain multiple video streams.
  • PiP: You can add multiple PiP effects and configure settings for PiP effects, such as position, scaling, and rotation. By default, a PiP track is automatically created when you create a PiP effect. A PiP effect can be moved in different PiP tracks.
Note The short video SDK does not limit the number of PiP effects. However, we recommend that you do not add more than three PiP effects at the same time. The maximum number of PiP effects is determined by you.

For more information about the parameters that are used in the code, see Related classes.

// Obtain the PiP manager in AliyunIEditor.
AliyunIPipManager pipManager = mAliyunIEditor.getPipManager();

// Add a PiP effect.
mAliyunIEditor.puase(); // Pause the video.
long current = mAliyunIEditor.getCurrentPlayPosition(); // Obtain the current position on the playback timeline.
AliyunIPipManager pipManager = mAliyunIEditor.getPipManager();
AliyunIPipController pipController = pipManager.createNewPip ("The URL of the stream file");
pipController.setTimelineStartTime(current) // Start from the current time point of the track.
                .setClipStartTime(0) // The start time of the PiP effect in the video.
                .apply(); // Apply the settings.


// Remove a PiP effect.
mAliyunIEditor.puase(); // Pause the video.
AliyunIPipManager pipManager = mAliyunIEditor.getPipManager();
pipManager.removePip(pipController);


// Call AliyunILayoutController to modify the layout.
mAliyunIEditor.puase(); // Pause the video.
AliyunILayoutController layoutController = pipController.getLayoutController(); // Obtain the layout controller.
layoutController.setRotation(3.14) // Specify the rotation radian. Valid values: 0 to 3.14.
                .setScale(0.3) // Specify the scale.
                .setPosition(0.5, 0.5) // Center the layout.
                .apply();

// Obtain the position of the PiP effect in the canvas.
RectF rectf = pipController.getPipRectFInCurrentScreen(); // Obtain the rectangular area where the PiP effect is located.
int width = mSurfaceView.getWidth() * rectf.width(); // The actual width of the PiP effect in the canvas.
int height = mSurfaceView.getWidth() * rectf.height(); // The actual height of the PiP effect in the canvas.


// Call AliyunIAudioController to modify the sound.
mAliyunIEditor.puase(); // Pause the video.
AliyunIAudioController audioController=pipController.getAudioController(); // Obtain the audio controller.
audioController.setVolume(100) // Set the volume to the maximum value.
                .setAudioEffect(AudioEffectType.EFFECT_TYPE_LOLITA) // Set the sound effect to lively female voice.
                .apply(); // Apply.


// Call AliyunIAnimationController to add an animation to the PiP effect.
mAliyunIEditor.puase(); // Pause the video.
AliyunIAnimationController animationController = pipController.getAnimationController();
if (mActionTranslate == null) { // Add a translate animation.
    mActionTranslate = new ActionTranslate();
    mActionTranslate.setFromPointX(-1);
    mActionTranslate.setFromPointY(-1);
    mActionTranslate.setToPointX(1);
    mActionTranslate.setToPointY(1);
    mActionTranslate.setStartTime(pipController.getTimeLineStartTimeInMillis() * 1000);
    mActionTranslate.setDuration(pipController.getClipDurationInMillis() * 1000);
    animationController.addFrameAnimation(mActionTranslate);
} else { // Remove a translate animation.
    animationController.removeFrameAnimation(mActionTranslate);
    mActionTranslate = null;
}


// Call AliyunIAugmentationController to configure augmentation settings.
mAliyunIEditor.puase(); // Pause the video.
AliyunIAugmentationController augmentationController=pipController.getAugmentationController(); // Obtain the augmentation controller.
augmentationController.setVignette(0 to 1) // Specify the vignette.
                        .setSharpness(0 to 1) // Specify the sharpness.
                        .setSaturation(0 to 1) // Specify the saturation.
                        .apply(); // Apply.

// Call AliyunIPipTrack to obtain information about the track.
// Method 1: Obtain all tracks from the management class.
AliyunIPipManager pipManager = mAliyunIEditor.getPipManager();
List<AliyunIPipTrack> pipTrackList=pipManager.getPipTracks(); // Obtain all PIP tracks.

// Method 2: Obtain the track in which the current controller is located.
AliyunIPipTrack pipTrack = pipController.getOwnerTrack();
List<AliyunIPipController> pipControllers=pipTrack.getPipClips(); // Obtain the controller of all PiP effects on the current track.

Configure subtitles and animated stickers

You can manage subtitles and animated stickers by using AliyunPasterManager. You can use AliyunIPasterController in AliyunPasterManager to perform operations on subtitles and animated stickers. For more information about the parameters that are used in the code, see Related classes.

The short video SDK provides word art and bubble effects for subtitles. For more information about how to make word art, bubbles, and animated stickers, see Word art and Animated stickers.

Subtitles

Add or remove a subtitle
Source fontSouce = null;
long startTime = 0L;
long duration = 20000L;

// 1. Add a subtitle.
AliyunPasterControllerCompoundCaption captionController=pasterManager.addCaptionWithStartTime ('Text', null, fontSouce, startTime,duration);

// 2. Remove a subtitle.
controller.remove()

Modify subtitle properties

AliyunPasterControllerCompoundCaption can be used to call all operations related to subtitles. For more information, see API references. Each time you modify subtitle properties, you must call AliyunPasterControllerCompoundCaption.apply() to make the modifications take effect.
// Specify the background color.
captionController.setColor(AliyunColor color);
// Specify the font.
captionController.setFontPath(ISouce fontPath);
// Apply the above modifications.
captionController.apply();

Word art

Source fontEffectSource(fontEffectFolder);

// 1. Apply the word art.
captionController.setFontEffectTemplate(fontEffectSource)

// 2. Remove the word art.
captionController.setFontEffectTemplate(null)

Bubbles

Source bubbleEffectSource(bubbleEffectFolder);
// 1. Apply bubbles.
captionController.setBubbleEffectTemplate(bubbleEffectSource)

// 2. Remove bubbles.
captionController.setBubbleEffectTemplate(null)

Animated stickers

Add an animated sticker

AliyunPasterController pasterController = pasterManager.addPasterWithStartTime(Source path, long startTime, long duration);

Configure the properties of the animated sticker

Animated stickers are animation effects that are displayed on the Android UI. You need to call AliyunPasterBaseView to define properties such as the size, width and height, and rotation angle to display stickers on the Android UI. The animated stickers that you configure for the Android UI are also displayed at the platform layer. You can display or hide the stickers at the rendering layer to prevent the overlap of the stickers.

// You must call the following operation.
pasterController.setPasterView(AliyunPasterBaseView pasterView);

// Display stickers.
pasterController.editCompleted();

// Hide stickers.
pasterController.editStart();

Preview stickers

// Configure the preview.
pasterController.createPasterPlayer(TextureView view);

// Start the playback or stop the preview.
protected void playPasterEffect() {
        TextureView pv = new TextureView(mPasterView.getContext());
        animPlayerView = mController.createPasterPlayer(pv);
        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        ViewGroup vg = (ViewGroup) mPasterView.getContentView();
        vg.addView(pv, 0, lp);

    }

    
    protected void stopPasterEffect() {
        ViewGroup vg = (ViewGroup) mPasterView.getContentView();
        vg.removeViewAt(0);
        animPlayerView = null;
    }

Remove an animated sticker

pasterController.removePaster();

Draft box

For more information about the parameters that are used in the code, see Related classes.

Obtain project configurations
// Perform initialization.
AliyunIEditor.init(SurfaceView surfaceView, Context context);
// Obtain project configurations.
AliyunEditorProject project = AliyunIEditor.getEditorProject();
Initialize the draft manager
AliyunDraftManager draftManager = AliyunDraftManager.getInstance(context);
Obtain the draft list
// Obtain the draft list in an asynchronous manner.
AliyunDraftManager.getInstance(getContext())
                          .getDraftListByAsync(new AliyunDraftListCallback() {
                              @Override
                              public void onFailure(final String msg) {
                                  // Failed to obtain the draft list.
                              }

                              @Override
                              public void onSuccess(final List<AliyunDraft> draftList) {
                                  // Succeeded in obtaining the draft list.
                              }
                          });
Delete a draft based on the draft ID
// Delete a draft. A draft is an item in the draft list. You can obtain the draft list by calling the related API operation.
AliyunDraftManager.getInstance(v.getContext()).deleteDraft(draft.getId());
Rename a draft
// Rename a draft. A draft is an item in the draft list. You can obtain the draft list by calling the related API operation.
AliyunDraftManager.getInstance(v.getContext()).rename(draft.getId(), newName);
Copy a draft
// After you copy a draft, a new draft is generated. A draft is an item in the draft list. You can obtain the draft list by calling the related API operation.
AliyunDraft newDraft = AliyunDraftManager.getInstance(v.getContext()).copy(draft.getId());
Load a draft
// A draft is an item in the draft list. You can obtain the draft list by calling the related API operation.
AliyunDraftManager.getInstance(v.getContext()).preLoadDraft(draft, new AliyunDraftResourceLoader() {

                @Override
                public void onHandleResourceTasks(final List<AliyunDraftResTask> tasks) {
                    // The resource task that you want to process is returned due to the lack of relevant resources. You can repair, ignore, or remove the task.
                    HashMap<String, List<AliyunDraftResTask>> map = new HashMap<>();
                    for (AliyunDraftResTask task : tasks) {
                        if (task.getSource() != null && !StringUtils.isEmpty(task.getSource().getURL())) {
                            if (map.containsKey(task.getSource().getURL())) {
                                map.get(task.getSource().getURL()).add(task);
                            } else {
                                List<AliyunDraftResTask> list = new ArrayList<>();
                                list.add(task);
                                map.put(task.getSource().getURL(), list);
                            }
                        } else {
                            // You can repair, ignore, or remove the task.
                            if (task.getResModuleType() == AliyunResModuleType.MAIN_VIDEO) {
                                task.getSource().setPath(EditorCommon.SD_DIR + "svideo_res/image/aliyun_svideo_failed.jpg");
                                task.onHandleCallback(task.getSource());
                            } else if(task.getResModuleType() == AliyunResModuleType.TRANSITION) {
                                // Remove the task.
                                task.onRemove();
                            } else {
                                // Ignore the task.
                                task.onIgnore();
                            }
                        }
                        for (final Map.Entry<String, List<AliyunDraftResTask>> entry : map.entrySet()) {
                            // The value of Key is the URL of resources. The value of Value is the task that you want to process by using the URL of resources.
                            final List<AliyunDraftResTask> list = entry.getValue();
                            try {
                                final String url = entry.getKey();
                                // Check whether the resources are platform resources.
                                if (url.startsWith(AlivcResUtil.SCHEME)) {
                                    // The callback for loading platform resources.
                                    AlivcResUtil.LoadCallback callback = new AlivcResUtil.LoadCallback() {
                                        @Override
                                        public void onSuccess(String path) {
                                            for (AliyunDraftResTask task : list) {
                                                Source source = task.getSource();
                                                source.setPath(path);
                                                task.onHandleCallback(source);
                                            }
                                        }

                                        @Override
                                        public void onFailure(String type, String msg) {
                                            Log.d("CloudDraft", "loadRes>Failure>type>" + type + ">msg>" + msg);
                                            for (AliyunDraftResTask task : list) {
                                                task.onIgnore();
                                            }
                                        }
                                    };
                                    // Load platform resources. For the complete sample code, see the demo.
                                    AlivcResUtil.loadRes(context, url, callback);
                                } else {
                                    // Download user resources. For the complete sample code, see the demo.
                                    downloadRes(url, new File(item.getEditorProjectUri()).getParent(), list);
                                }
                            } catch (Exception e) {
                                // An error occurred.
                                for (AliyunDraftResTask item : list) {
                                    item.onIgnore();
                                }
                            }
                        }
                    }
                }

                @Override
                public void onFailure(final String msg) {
                    // The preload failed.
                    Toast.makeText(v.getContext(), "The preload failed", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onSuccess() {
                    // After the preload is complete, you can go to the editing page. A draft is an item in the draft list. You can obtain the draft list by calling the related API operation. You can use draft.getEditorProjectUri() to load the draft.
                    EditorActivity.startEdit(v.getContext(), draft);
                }
            });

Upload a draft

To upload a draft, use the draft server. Click the sample code to download the sample code of the server.
// A draft is an item in the draft list. You can obtain the draft list by calling the related API operation.
AliyunDraftManager.getInstance(context)
                          .uploadDraft(draft, new AliyunDraftResourceUploader() {
                              @Override
                              public void onHandleResourceTasks(final List<AliyunDraftResTask> tasks) {
                                  // The resource upload task that you need to process.
                                  HashMap<String, List<AliyunDraftResTask>> map = new HashMap<>();
                                  // Filter duplicate resources.
                                  for (AliyunDraftResTask task : tasks) {
                                      if (task.getSource() == null) {
                                          task.onIgnore();
                                          continue;
                                      }
                                      // If the URL is empty or the URL does not start with alivc_resource, you need to process the URL.
                                      String url = task.getSource().getURL();
                                      if (StringUtils.isEmpty(url) || !url.startsWith("alivc_resource")) {
                                          if (map.containsKey(task.getSource().getPath())) {
                                              map.get(task.getSource().getPath()).add(task);
                                          } else {
                                              List<AliyunDraftResTask> list = new ArrayList<>();
                                              list.add(task);
                                              map.put(task.getSource().getPath(), list);
                                          }
                                      } else {
                                          // Ignore the error.
                                          task.onIgnore();
                                      }
                                  }
                                  for (Map.Entry<String, List<AliyunDraftResTask>> entry : map.entrySet()) {
                                      try {
                                          for (AliyunDraftResTask task : tasks) {
                                              Source source = task.getSource();
                                              // Configure the callback URL after the upload is complete.
                                              source.setURL();
                                              task.onHandleCallback(source);
                                          }
                                      } catch (Exception e) {
                                          // Ignore the error.
                                          List<AliyunDraftResTask> list = entry.getValue();
                                          for (AliyunDraftResTask item:list){
                                              item.onIgnore();
                                          }
                                      }
                                  }
                              }

                              @Override
                              public void onSuccess(final String projectPath, String coverUrl) {
                                  // After all resources are uploaded, the URL of the project configurations and the URL of the thumbnail are returned.
                                  // You can upload the resources to the cloud. Other users can restore the draft to the editing state by using the URL of the project configurations.
                              }

                              @Override
                              public void onFailure(final String msg) {
                                  Toast.makeText(context,"Backup failed",Toast.LENGTH_SHORT).show();
                              }
                          });

Download a draft

To download a draft, use the draft server. Click the sample code to download the sample code of the server.
// Download draft related resources based on the project configurations of the draft. file is a project configuration file that you can download from the server after you back up the draft.
AliyunDraftManager.getInstance(context).downloadDraft(file, new AliyunDraftResourceDownloader() {
            @Override
            public void onHandleResourceTasks(final String projectDir, final List<AliyunDraftResTask> tasks) {
                // The draft resource task that you need to process. You must download the resources in the draft.
                HashMap<String, List<AliyunDraftResTask>> map = new HashMap<>();
                // Filter duplicate resources.
                for (AliyunDraftResTask task : tasks) {
                    if (task.getSource() == null || StringUtils.isEmpty(task.getSource().getURL())) {
                        task.onIgnore();
                    } else if (map.containsKey(task.getSource().getURL())) {
                        map.get(task.getSource().getURL()).add(task);
                    } else {
                        List<AliyunDraftResTask> list = new ArrayList<>();
                        list.add(task);
                        map.put(task.getSource().getURL(), list);
                    }
                }
                for (final Map.Entry<String, List<AliyunDraftResTask>> entry : map.entrySet()) {
                    final List<AliyunDraftResTask> list = entry.getValue();
                    try {
                        final String url = entry.getKey();
                        // Download the draft resource by using the URL.
                        for (AliyunDraftResTask task : list) {
                            Source source = task.getSource();
                            // Specify the local URL of the resource after the download is complete.
                            source.setPath(path);
                            // If the resource is an MV, obtain the ID and specify the ID as the value of Source to display the MV.
                            if (task.getResModuleType() == AliyunResModuleType.MV) {
                                try {
                                    source.setId(Uri.parse(url).getQueryParameter("gid"));
                                }catch (Exception ignored){
                                }
                            }
                            task.onHandleCallback(source);
                        }
                    } catch (Exception e) {
                        // An error occurred.
                        for (AliyunDraftResTask item : list) {
                            item.onIgnore();
                        }
                    }
                }

            }

            @Override
            public void onSuccess(final AliyunDraft draft) {
                // After you download all resources, configure the ProjectID parameter of the server. You can use ProjectID to associate the local draft with the cloud draft.
                AliyunDraftManager.getInstance(context).setProjectId(draft.getId(), projectId);
                Toast.makeText(context,"The draft is restored to the local PC",Toast.LENGTH_SHORT).show();
                // After you restore the draft to the local PC, you can view the draft in the local draft list.
            }

            @Override
            public void onFailure(final String msg) {
                Toast.makeText(context,"Failed to restore the draft to the local PC",Toast.LENGTH_SHORT).show();
            }
        });

Other settings

For more information about the parameters that are used in the code, see Related classes.

Time effects
// 1. Configure speed ramping.
// From SDK V3.7.0, you can apply speed ramping to multiple videos or images.
int effectId;
effectId = AliyunIEditor.rate(float rate, long startTime, long duration, boolean needOriginDuration);

// 2. Configure the repeat setting.
effectId = AliyunIEditor.repeat(int times, long startTime, long duration, boolean needOriginDuration);

//3. Configure reverse playback.
// Note: Transcode videos whose group of pictures (GOP) size is greater than 5 before you perform reverse playback. You can call NativeParser.getMaxGopSize() to view the GOP size of a video. Before you perform transcoding, call CropParam.setGop(1) to set the GOP size to 1.
effectId = AliyunIEditor.invert();


// Remove time effects.
AliyunIEditor.deleteTimeEffect(effectId);

Watermarks

Watermarks include general watermarks and end watermarks. A general watermark is displayed during the entire duration of the video stream. An end watermark is displayed at the end of the video stream.
// Configure a general watermark.
AliyunIEditor.applyWaterMark(String imgPath, float sizeX, float sizeY, float posX, float posY);

// Configure an end watermark.
AliyunIEditor.addTailWaterMark(String imagePath, float sizeX, float sizeY, float posX, float posY, long durationUs);

Doodles

The short video SDK provides a set of doodle operations, including operations for configuring the canvas and paintbrush. You can use AliyunICanvasController to manage doodle configurations.
  • Canvas: a UI interaction view that is provided for doodling. You can add the UI interaction view to the UI interaction view group.
  • Paintbrush: an android.graphics.Paint object. You can configure a custom paintbrush or use the default paintbrush.
// Obtain the doodle controller.
int width = 600;
int height = 800
AliyunICanvasController controller = AliyunIEditor.obtainCanvasController( context, width, height);


// Obtain a doodle canvas.
View canvasView = controller.getCanvas();

// Start doodling.

// Apply doodles.
controller.applyPaintCanvas();

// Release resources.
controller.release();

//*******
// Perform other operations.
//*******

// Undo the previous stroke.
controller.undo();

// Clear the canvas.
controller.clear();

// Remove doodles.

controller.removeCanvas();

// Check whether doodles exist on the canvas.
controller.hasCanvasPath();