The short video SDK provides video editing features. You can import videos, images, and materials and add effects such as filters, dubs, time effects, and picture-in-picture (PiP) effects to videos. This topic describes how to use the short video SDK for iOS to edit videos.

Supported editions

Edition Description
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 AliyunEditor A core class that defines video editing.
Editing AliyunIClipConstructor A class that is used to manage video sources.
AliyunClip A class that defines media clips.
AEPVideoTrack A class that defines the track of the main stream in the project configuration.
AEPVideoTrackClip A class that defines the clips of the main stream in the project configuration.
Preview control AliyunIPlayer A class that defines the playback protocol.
AliyunIPlayerCallback A class that defines the playback status callback protocol.
Video effect settings AliyunEffectFilter A class that defines the model for filters.
AliyunEffectTimeFilter A class that defines the model for time effects.
AliyunTransitionEffect A base class that defines transitions.
AliyunEffectMV A class that defines the model for MVs.
AliyunFilterManager A class that defines the filter manager, which can be used to manage Lookup Table (LUT) filters and static filters.
AliyunLutFilterController A class that defines the LUT filter controller.
AliyunLutFilter A class that defines the model for LUT filters.
AliyunShaderFilterController A class that defines the static filter controller.
AliyunShaderFilter A class that defines the model for static filters.
Music and sound effect settings AliyunEffectMusic A class that defines music.
AliyunEffectDub A class that defines dubs.
AEPAudioTrack A class that defines the audio track in the project configuration.
AEPAudioTrackClip A class that defines the audio track clips in the project configuration.
PiP settings AliyunPipManager A class that defines the PiP manager.
AliyunPipTrackController A class that defines the PiP track controller.
AliyunPipClipController A class that defines the PiP clip controller.
AliyunPipClip A class that defines the PiP data model.
AEPPipVideoTrackClip A class that defines the PiP clips in the project configuration.
AEPPipVideoTrack A class that defines the PiP track in the project configuration.
AliyunClipAugmentationInfo A class that defines the image supplemental enhancement information (SEI).
AliyunClipAudioInfo A class that defines the audio information.
AliyunPureColorBorderInfo A class that defines the border information.
Subtitle and sticker settings AliyunStickerManager A class that defines the sticker and subtitle manager.
AliyunCaptionStickerController A class that defines the subtitle controller.
AliyunGifStickerController A class that defines the animated GIF controller.
AliyunImageStickerController A class that defines the static image controller.
AliyunCaptionSticker A class that defines the subtitle data model.
AliyunGifSticker A class that defines the animated GIF data model.
AliyunImageSticker A class that defines the static image data model.
AEPGifStickerTrack A class that defines the animated GIF track in the project configuration.
AEPImageStickerTrack A class that defines the static image track in the project configuration.
AEPCaptionTrack A class that defines the subtitle track in the project configuration.
Draft box AliyunEditorProject A class that defines the project configuration.
AliyunDraft A class that defines draft objects.
AliyunDraftManager A class that defines the local draft manager.
AliyunDraftLoadTask A class that defines draft resource loading tasks.
AliyunDraftProjectUploadTask A class that defines draft upload tasks.
AEPSource A class that defines resource objects.
AEPResourceModel A class that defines the specific resource model in a loading task.
Other settings AliyunICanvasView A class that defines the doodle and canvas view.
AliyunIPaint A class that defines the paintbrush.

Video editing process

Configuration Step Description Sample code
Basic configurations 1 Create and initialize an editor. Initialize an editor
2 Crop the video, dynamically change video sources, and dynamically modify the transition time and effects during video editing. Manage videos
3 Configure the preview. Configure preview
Advanced configurations 4 Configure effects such as filters, transitions, and MVs. Configure video effects
5 Configure background music, dubs, and sound effects. Configure music and sound effects
6 Configure PiP. Configure PiP
7 Configure subtitles, word art, bubbles, and 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 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. Task path: A task is generated for each media file that you want to edit. You must provide the task path during editing initialization. The task must be initialized first.
NSString *taskPath = @"xxx"; // taskPath is the URL of the video that you import. In most cases, the video is imported from local sources or the draft box.

// 2. Preview view: After you configure a preview view, each of your operation will be reflected in the preview view in real time during editing.
UIView *preview = xxx;

// 3. Instantiate the editor.
AliyunEditor *editor = [[AliyunEditor alloc] initWithPath:taskPath preview:preview];
            
Note To ensure that what is displayed in the preview view is consistent with that displayed in the output video, we recommend that you set the aspect ratio of the preview view to be the same as that of the output video.

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 editor, you must call [editor startEdit] the next time you use the editor so that the modifications can take effect.

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

// 1. Obtain the video source manager.
id<AliyunIClipConstructor> contructor = [editor getClipConstructor];

// 2. Add video clips.
// 2.1 Stop editing.
[editor stopEdit]; 
// 2.2 Create a video clip.
AliyunClip *clip = [[AliyunClip alloc] initWithVideoPath:videoPath startTime:2 duration:6 animDuration:0];
// 2.3.1 Append the video clip to the end.
[contructor addMediaClip:clip];
// 2.3.2 Alternatively, add the video clip to a specified position.
[contructor addMediaClip:clip atIndex:1];
// 2.4 Start editing.
[editor startEdit]; 

// 3. Update or replace video clips.
[contructor updateMediaClip:clip atIndex:1];

// 4. Delete video clips.
// 4.1 Delete the last video clip.
[contructor deleteLastMediaClip];
// 4.2 Delete a specified video clip.
[contructor deleteMediaClipAtIndex:1];
// 4.3 Delete all video clips.
[contructor deleteAllMediaClips];

// 5. Obtain all video clips.
NSArray<AliyunClip *> *mediaClips = contructor.mediaClips;

Configure preview

During video editing, you can perform various operations on the video. For example, you can play the video, pause the video, or obtain the duration of the playback timeline. For more information about the parameters that are used in the code, see Related classes.

Playback control

// Obtain the preview player.
id<AliyunIPlayer> player = [editor getPlayer];

// Start playback.    
[player play];

// Resume playback.
[player resume];

// Pause playback.
[player pause];

// Skip to a specified position.
[player seek:timeInSecond];

// Mute the video.
[editor setMute:YES];

// Configure the volume.
[editor setVolume:50];

// Obtain the current position of the stream, which is not affected by time effects.
double currentTime = [player getCurrentStreamTime];

// Obtain the current position on the playback timeline, which is not affected by time effects.
double currentTime = [player getCurrentTime];

// Obtain the duration of the stream, which is not affected by time effects.
double duration = [player getStreamDuration];

// Obtain the total playback duration, which is affected by time effects.
double duration = [player getDuration];

Playback callbacks

// Listen to the playback status.
editor.playerCallback = self;

// The protocol.
- (void)playerDidEnd {
    // The callback that is returned when playback ends.
}

- (void)playProgress:(double)playSec streamProgress:(double)streamSec {
    // The callback for playback progress.
}

- (void)playError:(int)errorCode {
    // The callback that is returned when an error occurs during playback.
}
            

Configure video effects

You can configure video effects such as filters, transitions, MVs, and time effects. For more information about the parameters that are used in the code, see Related classes.

Filters
  • Filters include LUT filters, static filters, and animated filters.
    • LUT filters: uses Lookup Table to replace pixels.
    • Static filters: calculates pixels by writing in a shading language. Animated effects are not supported.
    • Animated filters: calculates pixels by writing in a shading language. Animated effects are used.
  • You can create custom filters. For more information, see Filters and transitions.
LUT filters
// 1. Add a LUT filter.
AliyunLutFilterController *controller = [[editor getFilterManager] applyLutFilterWithPath:path intensity:intensity];
if (!controller) {
    // Failed to add a LUT filter.
}

// 2. Update the intensity.
controller.model.intensity = 0.5;

// 3. Remove a LUT filter.
[[editor getFilterManager] removeFilter:controller];
Static filters
// 1. Add a static filter.
AliyunShaderFilterController *controller = [[editor getFilterManager] applyShadeFilterWithPath:path];
if (!controller) {
    // Failed to add a static filter.
}

// 2. Remove a static filter.
[[editor getFilterManager] removeFilter:controller];
Animated filters
// 1. Add an animated filter.
AliyunEffectFilter *animationFilter = [[AliyunEffectFilter alloc] initWithFile:filterFolder];
animationFilter.startTime = 2;
animationFilter.endTime = 10;
// ... For information about other parameters, see the API documentation.
[editor applyAnimationFilter:animationFilter];

// 2. Modify an animated filter.
animationFilter.startTime = 4;
animationFilter.endTime = 12;
// ... For information about other parameters, see the API documentation.
[editor updateAnimationFilter:animationFilter];

// 3. Remove an animated filter.
[editor removeAnimationFilter:animationFilter];
Transitions
  • You can create custom transitions. For more information, see Filters and transitions.
  • The short video SDK provides the following transitions: AliyunTransitionEffectTypeCircle (circle), AliyunTransitionEffectTypeFade (fade-in and fade-out), AliyunTransitionEffectTypePolygon (polygon), AliyunTransitionEffectTypeShuffer (blinds), and AliyunTransitionEffectTypeTranslate (translate). For more information about operation parameters, see AliyunTransitionEffectType.

Position of transitions

You can apply a transition only between two video clips. If only one video clip exists, transitions are not supported. A transition starts from the 0-second position. See the following example.

[----Video clip A----] [----Video clip B----] [----Video clip C----]...[----Video clip N----]
                ^                ^                 ^
 Position:           0                1                N-1 -->

Configure transitions

// Add a transition.
// Note: Before you call the following operation, you must first call [editor stopEdit]. After you call the following operation, call [editor startEdit]. 
AliyunTransitionEffect *transition = [[AliyunTransitionEffect alloc] initWithPath:transitionFolder];
[editor applyTransition:transition atIndex:0];

// Update a transition.
// Note: The duration of a transition cannot be longer than the duration of either video before and after the transition.
transition.overlapDuration = 1;
// ... For information about other parameters, see the API documentation.
[editor updateTransition:transition atIndex:0];

// Remove a transition.
[editor removeTransitionAtIndex:0];

MVs

You can create custom MVs. For more information, see MVs.

// Add an MV.
AliyunEffectMV *mv = [[AliyunEffectMV alloc] initWithFile:mvFolder];
[editor applyMV:mv];

// Mute an MV.
[editor removeMVMusic];

// Remove an MV.
[editor removeMV];

Time effects

The short video SDK provides the following time effects: TimeFilterTypeSpeed (speed ramping), TimeFilterTypeRepeat (looping), and TimeFilterTypeInvert (reverse playback). For more information about operation parameters, see TimeFilterType.

Note When you configure reverse playback for a video, if the group of pictures (GOP) size of the video is greater than 35, you must transcode the video before you can use the reverse playback effect. You can obtain the GOP size by calling AliyunNativeParser. You can transcode the video by using the video cropping feature.
// 1. Add a time effect.
// 1.1 Configure speed ramping.
AliyunEffectTimeFilter *timeFilter = [[AliyunEffectTimeFilter alloc] init];
timeFilter.type = TimeFilterTypeSpeed;
timeFilter.param = 0.67;
timeFilter.startTime = 2;
timeFilter.endTime = 10;
// ... For information about other parameters, see the API documentation.
[editor applyTimeFilter:timeFilter];

// 1.2 Configure looping.
AliyunEffectTimeFilter *timeFilter = [[AliyunEffectTimeFilter alloc] init];
timeFilter.type = TimeFilterTypeRepeat;
timeFilter.param = 3; // For example, configure the video to loop three times.
timeFilter.startTime = 2;
timeFilter.endTime = 10;
// ... For information about other parameters, see the API documentation.
[editor applyTimeFilter:timeFilter];

// 1.3 Configure reverse playback.
AliyunEffectTimeFilter *timeFilter = [[AliyunEffectTimeFilter alloc] init];
timeFilter.type = TimeFilterTypeInvert;
// ... For information about other parameters, see the API documentation.
[editor applyTimeFilter:timeFilter];


// 2. Remove a time effect.
[editor removeTimeFilter:timeFilter];

Configure music and sound effects

You can add music and dubs, or add sound effects such as fade-in, fade-out, and voice change to audio. For more information about the parameters that are used in the code, see Related classes.

Music

Music includes background music and dubs. Background music is not affected by time effects such as speed ramping, looping, and reverse playback. Dubs are affected by time effects.

Background music
// 1. Add background music.
AliyunEffectMusic *music =[[AliyunEffectMusic alloc] initWithFile:musicFilePath];
music.duration = 3;
music.audioMixWeight = 50; // Indicates the weighted volume of background music.
// ... For information about other parameters, see the API documentation.
[editor applyMusic:music];

// 2. Remove background music.
[editor removeMusic:music];
Dubs
// 1. Add a dub.
AliyunEffectDub *dub =[[AliyunEffectDub alloc] initWithFile:dubFilePath];
dub.startTime = 2;
dub.audioMixWeight = 50; // Indicates the weighted volume of the dub.
dub.audioDenoiseWeight = 50; // Indicates the degree of noise reduction.
// ... For information about other parameters, see the API documentation.
[editor applyDub:dub];

// 2. Remove a dub.
[editor removeDub:dub];
Sound effects
  • Fade-in and fade-out: AliyunAudioFadeShapeLinear (linear curve) and AliyunAudioFadeShapeSin (sinusoidal curve) are supported. For more information about operation parameters, see AliyunAudioFadeShape.
  • The following voice change effects are supported. For more information about operation parameters, see AliyunAudioEffectType.
    • AliyunAudioEffectLolita (lively female voice)
    • AliyunAudioEffectUncle (husky male voice)
    • AliyunAudioEffectReverb (reverberation)
    • AliyunAudioEffectEcho (echo)
    • AliyunAudioEffectRobot (robot voice)
    • AliyunAudioEffectBigDevil (sinister voice)
    • AliyunAudioEffectMinions (minion voice)
    • AliyunAudioEffectDialect (dialect)
Fade-in and fade-out
// 1. Configure the fade-in effect before you add audio. The operations for configuring the fade-out effect are similar, with the fadeIn parameter replaced with the fadeOut parameter.
AliyunAudioFade *fadeIn = [[AliyunAudioFade alloc] init];
fadeIn.shape = AliyunAudioFadeShapeLinear;
fadeIn.duration = 2;
music.fadeIn = fadeIn; // The procedure for configuring dubs is similar.

// 2. Modify the fade-in effect after you add audio. The operation for modifying the fade-out effect is similar, with the functions changed to setAudioFadeOutShape:, duration:, and streamId:.
[editor setAudioFadeInShape:AliyunAudioFadeShapeLinear duration:2 streamId:music.effectVid];

// 3. Remove the fade-in effect after you add audio. The operation for removing the fade-out effect is similar, with the function changed to removeAudioFadeOutWithStreamId:.
[editor removeAudioFadeInWithStreamId:music.effectVid]; // The procedure for removing dubs is similar.
Voice change
// 1. Configure voice change before you add audio.
AliyunAudioEffect *audioEffect = [[AliyunAudioEffect alloc] init];
audioEffect.type = AliyunAudioEffectLolita;
audioEffect.weight = 50;
[dub.audioEffects addObject:audioEffect]; // Note: Only one voice change effect can be configured.

// 2. Configure voice change after you add audio.
[editor setAudioEffect:AliyunAudioEffectLolita weight:50 streamId:dub.effectVid];

// 3. Remove the voice change effect after you add audio.
[editor removeAudioEffect:AliyunAudioEffectLolita streamId:dub.effectVid];

Configure PiP

The PiP feature allows you to add one or more PiP effects to an 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 the 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 among different PiP tracks.

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

// Obtain the PiP manager. You can use the PiP manager to add, remove, modify, and check PiP effects.
AliyunPipManager * pipManager = [editor getPipManager];


// Add a PiP effect.
// 1. Add a PiP track to the top layer and add a PiP clip to the track.
// 1.1 Add a video clip.
NSError *error = nil;
AliyunPipClipController *pipClipController = [pipManager addClipWithType:AliyunPipClipTypeVideo path:xxVideoPath error:&error];
// 1.2 Add an image.
NSError *error = nil;
AliyunPipClipController *pipClipController = [pipManager addClipWithType:AliyunPipClipTypeImage path:xxImagePath error:&error];

// 2. Insert a PiP clip into a specified PiP track.
// 2.1 Create a PiP clip.
AliyunPipClip *pipClip = [[AliyunPipClip alloc] initWithClipType:AliyunPipClipTypeVideo clipPath:xxxVideoPath];
// ... For information about other parameter settings for PiP, see https://alivc-demo-cms.alicdn.com/versionProduct/doc/shortVideo/iOS_cn/Classes/AliyunPipClip.html

// 2.2 Insert the PiP clip into a specified track.
NSError *error = nil;
AliyunPipClipController *pipClipController = [pipManager addClipWithModel:pipClip toTrack:pipManager.trackControllers.firstObject error:&error]; // For example, add the PiP clip to the first track.


// Remove a PiP effect.
NSError *error = nil;
[pipManager removePipClipController:pipClipController error:&error];


// Switch the PIP track.
[pipManager movePipClipController:pipController toTrack:pipManager.trackControllers.firstObject withStartTime:0]; // For example, move the PiP clip to the start position of the first track.


// Modify a PiP clip.
//   For example, change the position of the PiP clip.
pipController.clip.center = CGPointMake(100, 100);

//   For example, change the position, size, and rotation of the PiP clip.
[pipController beginEdit];
pipController.clip.center = CGPointMake(100, 100);
pipController.clip.scale = 0.7;
pipController.clip.rotation = M_PI_2;
[pipController endEdit];

// Perform testing.
// For example, obtain a PiP clip at the top layer of a touch point at the current time.
double currentTime = [[editor getPlayer] getCurrentTime];
AliyunPipClipController *pipClipController = [pipManager hitTest:touchPoint withTime:currentTime];

Configure subtitles and animated stickers

  • You can manage subtitles and stickers by using AliyunStickerManager. In addition, you can manage the status of subtitles and stickers by using AliyunCaptionStickerController and AliyunStickerController, respectively. Both the subtitle controller and the rendering controller derive from AliyunRenderBaseController. Therefore, the logic for modifying subtitles and stickers is the same as that for modifying the attributes of underlying elements.
  • The short video SDK allows you to apply word art and bubbles to subtitles. You can create custom word art effects and bubbles. For more information, see Word art and Animations.
  • Stickers include static stickers and animated stickers. Animated stickers are similar to bubbles but have no text. You can create custom animated stickers. For more information, see Animations.
  • For more information about the parameters that are used in the code, see Related classes.
Manager
  • You can use the manager to add, remove, modify, and check subtitles and stickers. For more information about operation parameters, see AliyunStickerManager.
  • Both subtitles and stickers derive from the rendering model AliyunRenderModel and have the attributes of underlying rendering elements. You can find the subtitle or sticker controller at the position where you click to preview the coordinate of a subtitle or sticker at the top layer at a point in time.
// Obtain the manager.
AliyunStickerManager *stickerManager = [editor getStickerManager];

// Add a subtitle or sticker.
// For example, add a subtitle.
AliyunCaptionStickerController *captionController = [stickerManager addCaptionText:@"Hello" bubblePath:nil startTime:0 duration:5];

// Remove a subtitle or sticker.
[stickerManager remove:gifController];

// Find a subtitle or sticker.
// For example, obtain a subtitle or sticker at the top layer of a touch point at the current time.
double currentTime = [[editor getPlayer] getCurrentTime];
AliyunRenderBaseController *controller = [stickerManager findControllerAtPoint:touchPoint atTime:currentTime];
Subtitles
// Add a subtitle.
AliyunCaptionStickerController *captionController = [stickerManager addCaptionText:@"Hello" bubblePath:nil startTime:0 duration:5];

// Modify a subtitle.
[captionController beginEdit];
captionController.model.text = xxx;
captionController.model.outlineWidth = 3;
captionController.model.outlineColor = UIColor.redColor;
// ... For information about other parameters, see the page about AliyunCaptionSticker in the API documentation.
[captionController endEdit];
Word art
// Apply a word art effect.
captionController.model.fontEffectTemplatePath = fontEffectFolder; // Indicates the word art resource package folder.
// Remove a word art effect.
captionController.model.fontEffectTemplatePath = nil;
Bubbles
// Apply a bubble.
captionController.model.resourePath=bubbleEffectFolder; // Indicates the bubble resource package folder.
// Remove a bubble.
captionController.model.resourePath = nil;
Animated stickers
// Add an animated sticker.
AliyunGifStickerController *gifController = [stickerManager addGif:gifFilePath startTime:0 duration:5];


// Modify an animated sticker.
[gifController beginEdit];
gifController.gif.center = xxx;
// ... For information about other parameters, see the page about AliyunGifSticker in the API documentation.
[gifController endEdit];
Static stickers
// Add a static sticker.
AliyunImageStickerController *imageController = [stickerManager addImage:imageFilePath startTime:0 duration:5];

// Modify a static sticker.
[imageController beginEdit];
imageController.image.center = xxx;
// ... For information about other parameters, see the page about AliyunImageSticker in the API documentation.
[imageController endEdit];

Draft box

For each edit, an editing task is generated and recorded as a change of the project configuration. If you do not want to export the editing results immediately, you can save the edit as a draft. The next time you load the draft, you can restore the previous edit and continue editing. For more information about the parameters that are used in the code, see Related classes.

Project configuration

Edits are characterized as draft objects and described in a timeline structure. Each editing action is reflected by changes of the project configuration. We recommend that you associate the project configuration with your editing interface. When you load a draft, the project configuration is used to restore the editing interface that matches the corresponding edit.
// Obtain the project configuration during editing.
AliyunEditorProject *project = [editor getEditorProject];

Draft objects

An edit can be saved as a draft object, named AliyunDraft. You can save an edit by using the following methods.

// 0. Before you save an edit as a draft, you must specify where to store the draft. The short video SDK provides a draft management object that can be used as the draft container.
AliyunDraftManager *draftManager; // For more information about draft management, see the following section in this topic.

// 1. Specify the draft title and save the draft. You must also specify where to store the draft. The draft object is returned.
AliyunDraft *draft = [editor saveToDraft:draftManager withTitle:@"your draft title"];

// 2.1 You do not specify the draft title. In this case, the last draft title is used.
AliyunDraft *draft = [editor saveToDraft:draftManager];

// 2.2 Modify the draft title after you obtain the draft object.
[draft renameTitle:@"your draft title"];
To better identify drafts and help users develop on-premises or cloud draft businesses, the short video SDK reserves IDs for users. You can call the following API operation to set an ID for your business.
[draft changeProjectId:@"your custom project id"];

Draft thumbnails

During an edit, a thumbnail is automatically generated. In most cases, the first frame of the video is used as the thumbnail. You can also use a custom thumbnail by calling the following API operation.

[editor updateCover:yourCoverImage];

// If you leave the parameter blank, the default generated thumbnail is used.
[editor updateCover:nil];

You can change the thumbnail after you obtain the draft object.

[draft updateCover:yourCoverImage];
Note If you want to use a custom thumbnail, we recommend that you configure the custom thumbnail as soon as possible. After a custom thumbnail is used for a draft, the draft will no longer update its thumbnail. This way, you can improve your editing efficiency.

Draft management

Notice The draft management object parses all managed draft objects during initialization. Therefore, a certain performance loss is caused. We recommend that you use the draft management object as a global object, instead of creating and destroying the object frequently.
// Initialize the draft management object.
// For better isolation among users, we recommend that you use your ID for your draft management object.
NSString *draftManagerId; 
// Instantiate the draft management object.
AliyunDraftManager *draftManager = [[AliyunDraftManager alloc] initWithId:draftManagerId];


// Manage the draft list.

// Obtain the draft list.
NSArray<AliyunDraft *> *draftList = draftManager.draftList;
// You can listen to changes of the draft list.
draftManager.delegate = yourListener;
// To listen to changes of the draft list, implement the AliyunDraftManagerDelegate protocol.
// - (void) onAliyunDraftManager:(AliyunDraftManager *)mgr listDidChange:(NSArray<AliyunDraft *> *)list;


// Delete a draft.
[draftManager deleteDraft:targetDraft];


// Copy a draft.
[draftManager copyDraft:fromDraft toPath:newDraftTaskPath withTitle:@"your new draft title"];

Draft loading

A variety of resources may be used during editing. In order to improve performance and save storage space, the used resources are not all copied to the task directory. Before an edit is restored from a draft, you must process some resource loading tasks to make sure that all the resources for the edit are ready. We recommend that you pay special attention to the following types of resources:
  • Media resources in the album: Make sure that you have the read permission on these resources before you start editing.
  • Dynamically customized font resources: Make sure that the corresponding font is registered in the system or at least in the current application session before you start editing.
[draft load:^(NSArray<AliyunDraftLoadTask *> *tasks) {
    for (AliyunDraftLoadTask *task in tasks) {
        // Process resource loading tasks.
        // 1. Obtain the resource model of a task.
        AEPResourceModel *resource = task.resource;

        // 2. Process the task.
        // For information about how to process tasks of other resource types, see AliyunDraftLoader.m in the demo.

        // 3. Mark the processing result.
        // 3.1.1 Success: Ignore the result.
        [task onIgnore];
        // 3.1.2 Success: You need to modify the attributes of the resource model.
        AEPSource *resultSoruce = [resource.source createWithPath:@"result path"]; // For example, if the resource path is changed after loading.
        [task onSuccess:resultSoruce];

        // 3.2.1 Failure: Delete the corresponding node and continue loading.
        [task onFailToRemove]; // For example, if the font of a subtitle cannot be loaded, delete the subtitle and continue loading.
        // 3.2.2 Failure: Mark the overall loading failure. The following error message is displayed.
        NSError *error = xxxx; // You need to specify the reason for load failure.
        [task onFailToStopWithError:error]; // If this failure occurs, we recommend that you stop other loading tasks.
    }
} completion:^(NSString *taskPath, AliyunEditorBaseProject *project, NSError *error) {
    if (!taskPath  !project  error) {
        // Process loading failures.
        // In most cases, error.localizedDescription includes the detailed reason for failure.
        return;
    }

    // The load is successful.
    // You can create an editor by using the taskPath parameter and then restore the edit. See the "Initialize an editor" section of this topic.
}];

Draft upload

An edit mainly consists of project configuration and resources. A cloud draft is generated when the project configuration and resources are synchronized to the cloud. For more information about operation parameters, see AliyunDraftProjectUploadTask.

In order to improve performance and save storage space, resources used for editing are not all copied by default. However, a draft records descriptions of all the used resources. To better index resources, you can use AEPSource.path (local path) and AEPSource.sourceId (resource ID) to describe a resource. For more information, see AEPSource. In the process of loading, uploading, and downloading draft resources, resource descriptions are transmitted. In addition, information such as the node object to which the currently loaded resources belong and the module to which the timeline belongs is also transmitted. For more information, see AEPResourceModel.

Two steps are required for a draft upload.
  1. Upload all the resources used for editing. During this process, the resource descriptions in the project configuration are modified.
  2. Upload the project configuration file with the modified resource descriptions.
[draft uploadWithResourceUploader:^(NSArray<AliyunDraftLoadTask *> *tasks) {
    for (AliyunDraftLoadTask *task in tasks) {
        // Process upload tasks.
        // 1. Obtain the resource model of a task.
        AEPResourceModel *resource = task.resource;

        // 2. Process the task.
        // For information about how to process tasks of other resource types, see AliyunDraftLoader.m in the demo.

        // 3. Mark the processing result.
        // 3.1.1 Success: Ignore the result.
        [task onIgnore]; // For example, you do not need to upload built-in resources.
        // 3.1.2 Success: You need to modify the attributes of the resource model.
        AEPSource *resultSoruce = [resource.source createWithURL:@"resource URL"]; // For example, if you obtain a network connection after you upload the resources.
        [task onSuccess:resultSoruce];

        // 3.2.1 Failure: Delete the corresponding node and continue uploading.
        [task onFailToRemove]; // For example, if the font of a subtitle failed to be uploaded, delete the subtitle and continue uploading.
        // 3.2.2 Failure: Mark the overall loading failure. The following error message is displayed.
        NSError *error = xxx; // You need to specify the reason for upload failure.
        [task onFailToStopWithError:error]; // If this failure occurs, we recommend that you stop other upload tasks.
    }
} projectUploader:^(AliyunDraftProjectUploadTask *projTask) {
    // Add a cloud draft for processing.
    // 1.1 Obtain the path of the project configuration file of a draft.
    NSString *projectFilePath = projTask.projectFilePath;
    // 1.2 Process the project configuration file.
    NSString *projectUrl = [yourUploader upload:projectFilePath]; // For example, the network path is returned after you upload the configuration file.

    // 2.1 Synchronize the draft.
    NSString *projectId = [yourApi addCloudDraft:projectUrl]; // For example, the ID is returned after you call your service.
    // 2.2 Update the project ID of the draft.
    [projTask.draft changeProjectId:projectId];
    
    // 3. Mark the processing result.
    // 3.1 Success.
    [projTask onSuccess];
    // 3.2 Failure.
    NSError *error = xxx; // You need to specify the reason for failure.
    [projTask onFailWithError:error];
} completion:^(NSError *error) {
    if (error) {
        // Process upload failures.
        return;
    }
        
    // Process upload success.
}];

Draft download

The project configuration of a draft records descriptions of all the used resources. Therefore, a project configuration file can enumerate all the resources. A draft is downloaded when the resources are synchronized to the local system.

You need to specify where to store a draft when you download the draft. Therefore, the draft download API operation is defined in AliyunDraftManager.

// 0. Obtain the project configuration file and project ID corresponding to a cloud draft based on your business.
NSString *projectFilePath = xxx;
NSString *projectId = xxx;

// 1. Download the draft.
[draftManager downloadDraftWithProjectFile:projectFilePath  resourceDownloader:^(NSArray<AliyunDraftLoadTask *> *tasks) {
    for (AliyunDraftLoadTask *task in tasks) {
        // Process download tasks.
        // 1. Obtain the resources.
        AEPResourceModel *resource = task.resource;

        // 2. Process the task.
        NSString *localPath = [yourDownloader download:resource.source.URL]; // For example, when you perform network download.

        // 3. Mark the processing result.
        AEPSource *localSource = [resource.source createWithPath:localPath]; // For example, when the resources are downloaded to the local system.
        [task onSuccess:localSource];
        // For information about marking other results, see the "Draft loading" section.
    }
} completion:^(AliyunDraft *draft, NSError *error) {
    if (error  !draft) {
        // Process download failures.
        return;
    }

    // Process download success.
    [draft changeProjectId:projectId]; // We recommend that you check the ID in the cloud.
    // Complete the rest of processing.
}];

Other settings

Doodles

The short video SDK provides a set of doodle operations, including operations for configuring the canvas and paintbrush. You can use AliyunICanvasView to manage doodle configurations. For more information about the parameters that are used in the code, see Related classes.

// 1. Create a paintbrush.
AliyunIPaint *paint = [[AliyunIPaint alloc]initWithLineWidth:5.0 lineColor:UIColor.whiteColor];
// 2. Add a doodle view.
AliyunICanvasView *paintView = [[AliyunICanvasView alloc]initWithFrame:CGRectMake(0, 0, 100, 100) paint:paint];
[yourView addSubview:paintView];

// 3. Doodle.
// Touch the view to doodle.

// 4. Perform other operations.
// 4.1 Undo an action.
[paintView undo];
// 4.2 Redo an action.
[paintView redo];
// 4.3 Undo all doodle operations.
[paintView undoAllChanges];
// 4.4 Clear all lines. This operation cannot be undone.
[paintView remove];

// 5. Complete doodles.
UIImage *image = [paintView complete];
NSString *paintPath = xxx;
[UIImagePNGRepresentation(image) writeToFile:paintPath atomically:YES];

// 6. Add to an edit.
AliyunEffectImage *paintImage = [[AliyunEffectImage alloc] initWithFile:paintPath];
[editor applyPaint:paintImage linesData:paintView.lines];

// 7. Remove doodles.
[editor removePaint:paintImage];