Convert a video stored in an OSS bucket into a GIF or WebP animated image using the asynchronous processing API.
How it works

The conversion uses the video/animation action, submitted as an asynchronous job via the x-oss-async-process request header. OSS calls Intelligent Media Management (IMM) to process the video and saves the output to a path you specify. Optionally, IMM sends a completion notification through Message Service (MNS).
Only asynchronous processing is supported. Anonymous access is denied.
Choose an output format
| Format | Browser support | Best for |
|---|---|---|
| GIF | Universal | Maximum compatibility; works in all clients and email |
| WebP | Most modern browsers | Smaller file size than GIF at similar quality |
Use cases
Social media clips: Extract short moments from a video and share them as animated images on social platforms.
Tutorials and demos: Capture step-by-step software operations as looping animated images that readers can follow without playing a video.
Stickers and reactions: Turn video moments into animated stickers for messaging apps.
Event highlights: Clip key moments from live streams, competitions, or presentations and share them instantly.
Prerequisites
Before you begin, ensure that you have:
Created an OSS bucket and uploaded the source video to the bucket
Created and attached an IMM Project via the OSS console or the API; the IMM Project must be in the same region as the bucket
Granted the required permissions to the authorized user
Convert a video to an animated image
Only the Java, Python, and Go SDKs support asynchronous processing for video-to-animated-image conversion.
All examples use the x-oss-async-process header to submit an asynchronous conversion job. The processing string follows this structure:
video/animation,<params>|sys/saveas,b_<base64-bucket>,o_<base64-object>/notify,topic_<base64-topic>The bucket name, output object name, and notification topic must be Base64-encoded (URL-safe, no padding).
Python
Requires Python SDK version 2.18.4 or later.
# -*- coding: utf-8 -*-
import base64
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
def main():
# Read credentials from environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET.
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# Set the endpoint for the region where your bucket is located.
endpoint = 'https://oss-cn-hangzhou.aliyuncs.com'
# Set the region ID that matches the endpoint.
region = 'cn-hangzhou'
bucket = oss2.Bucket(auth, endpoint, 'examplebucket', region=region)
# Set the source video file name and the output file name.
source_key = 'src.mp4'
target_key = 'example.gif'
# Define the conversion parameters: output format GIF, 100x100 px, 1-second frame interval.
animation_style = 'video/animation,f_gif,w_100,h_100,inter_1000'
# Base64-encode the bucket name and output object name (URL-safe, no padding).
bucket_name_encoded = base64.urlsafe_b64encode('examplebucket'.encode()).decode().rstrip('=')
target_key_encoded = base64.urlsafe_b64encode(target_key.encode()).decode().rstrip('=')
# Assemble the full processing string, including save path and MNS notification topic.
process = f"{animation_style}|sys/saveas,b_{bucket_name_encoded},o_{target_key_encoded}/notify,topic_QXVkaW9Db252ZXJ0"
try:
# Submit the asynchronous job.
result = bucket.async_process_object(source_key, process)
print(f"EventId: {result.event_id}")
print(f"RequestId: {result.request_id}")
print(f"TaskId: {result.task_id}")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()Java
Requires Java SDK version 3.17.4 or later.
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.AsyncProcessObjectRequest;
import com.aliyun.oss.model.AsyncProcessObjectResult;
import com.aliyuncs.exceptions.ClientException;
import java.util.Base64;
public class Demo {
public static void main(String[] args) throws ClientException {
// Set the endpoint for the region where your bucket is located.
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// Set the region ID that matches the endpoint.
String region = "cn-hangzhou";
// Read credentials from environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET.
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// Set the bucket name.
String bucketName = "examplebucket";
// Set the name of the source video file.
String sourceKey = "src.mp4";
// Set the output file name.
String targetKey = "dest.gif";
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// Define the conversion parameters: output format GIF, 100x100 px, 1-second frame interval.
String style = "video/animation,f_gif,w_100,h_100,inter_1000";
// Base64-encode the bucket name and output object name (URL-safe, no padding).
String bucketEncoded = Base64.getUrlEncoder().withoutPadding().encodeToString(bucketName.getBytes());
String targetEncoded = Base64.getUrlEncoder().withoutPadding().encodeToString(targetKey.getBytes());
// Assemble the full processing string, including save path and MNS notification topic.
String process = String.format("%s|sys/saveas,b_%s,o_%s/notify,topic_QXVkaW9Db252ZXJ0", style, bucketEncoded, targetEncoded);
// Submit the asynchronous job.
AsyncProcessObjectRequest request = new AsyncProcessObjectRequest(bucketName, sourceKey, process);
AsyncProcessObjectResult response = ossClient.asyncProcessObject(request);
System.out.println("EventId: " + response.getEventId());
System.out.println("RequestId: " + response.getRequestId());
System.out.println("TaskId: " + response.getTaskId());
} finally {
ossClient.shutdown();
}
}
}Go
Requires Go SDK version 3.0.2 or later.
package main
import (
"encoding/base64"
"fmt"
"os"
"log"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// Read credentials from environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET.
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// Create an OSSClient. Set the endpoint and region for the bucket's location.
client, err := oss.New("https://oss-cn-hangzhou.aliyuncs.com", "", "",
oss.SetCredentialsProvider(&provider),
oss.AuthVersion(oss.AuthV4),
oss.Region("cn-hangzhou"))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// Set the bucket name.
bucketName := "examplebucket"
bucket, err := client.Bucket(bucketName)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// Set the source video file name and the output file name.
sourceKey := "src.mp4"
targetKey := "destexample.gif"
// Define the conversion parameters: output format GIF, 100x100 px, 1-second frame interval.
animationStyle := "video/animation,f_gif,w_100,h_100,inter_1000"
// Base64-encode the bucket name and output object name (URL-safe, no padding).
bucketNameEncoded := base64.URLEncoding.EncodeToString([]byte(bucketName))
targetKeyEncoded := base64.URLEncoding.EncodeToString([]byte(targetKey))
// Assemble the full processing string, including save path and MNS notification topic.
process := fmt.Sprintf("%s|sys/saveas,b_%v,o_%v/notify,topic_QXVkaW9Db252ZXJ0", animationStyle, bucketNameEncoded, targetKeyEncoded)
// Submit the asynchronous job.
result, err := bucket.AsyncProcessObject(sourceKey, process)
if err != nil {
log.Fatalf("Failed to async process object: %s", err)
}
fmt.Printf("EventId: %s\n", result.EventId)
fmt.Printf("RequestId: %s\n", result.RequestId)
fmt.Printf("TaskId: %s\n", result.TaskId)
}Parameters
Action: video/animation
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
f | string | Yes | — | Output format. Valid values: gif, webp |
ss | int | No | 0 | Start time in milliseconds. 0 starts from the beginning; any positive value starts from that millisecond. |
num | int | No | No limit | Maximum number of frames to extract. If the video is shorter than expected, fewer frames are extracted. |
inter | int | No | All frames | Frame extraction interval in milliseconds. If set below the source video's frame interval, the source frame interval is used instead. |
fps | float | No | Reciprocal of inter | Playback frame rate of the output animated image. Valid values: [0, 240]. Values above the default speed up playback; values below slow it down. |
w | int | No | Source video width | Output width in pixels. Valid values: [32, 4096] |
h | int | No | Source video height | Output height in pixels. Valid values: [32, 4096] |
scaletype | string | No | stretch | Scaling method. Valid values: crop (scale and crop), stretch (stretch to fill), fill (scale with black borders), fit (scale proportionally, no black borders) |
How `inter`, `fps`, and `num` interact:
intercontrols how often a frame is sampled from the source (in milliseconds).fpscontrols the playback speed of the output. By default it equals1000 / inter, so playback matches the source rate.numsets an upper limit on total frames extracted. Use it to cap output size for long videos.Setting both
interandfpsindependently lets you decouple sampling rate from playback speed. For example, sample every 500 ms (inter_500) but play at 25 fps (fps_25) to produce a time-lapse effect.
Thesys/saveasandnotifyparameters are used in the processing string. For details, see Save as and Message notification.
API examples
GIF, 100x100 px, 1-second interval
Converts example.mkv to a 100x100 px GIF, sampling one frame per second.
POST /example.mkv?x-oss-async-process HTTP/1.1
Host: video-demo.oss-cn-hangzhou.aliyuncs.com
Date: Fri, 28 Oct 2022 06:40:10 GMT
Authorization: OSS4-HMAC-SHA256 Credential=LTAI********************/20250417/cn-hangzhou/oss/aliyun_v4_request,Signature=a7c3554c729d71929e0b84489addee6b2e8d5cb48595adfc51868c299c0c218e
x-oss-async-process=video/animation,f_gif,w_100,h_100,inter_1000|sys/saveas,b_b3V0YnVja2V0,o_b3V0b2JqcHJlZml4LnthdXRvZXh0fQ/notify,topic_QXVkaW9Db252ZXJ0| Parameter | Value | Encoded value |
|---|---|---|
| Output bucket | outbucket | b_b3V0YnVja2V0 |
| Output object | outobjprefix.{autoext} | o_b3V0b2JqcHJlZml4LnthdXRvZXh0fQ |
| Notification topic | AudioConvert | topic_QXVkaW9Db252ZXJ0 |
WebP, quarter size, starting from 5 seconds
Converts example.mkv to WebP starting at the 5-second mark, at 25% of the original dimensions, with a 0.5-second frame interval and 25 fps playback.
POST /example.mkv?x-oss-async-process HTTP/1.1
Host: video-demo.oss-cn-hangzhou.aliyuncs.com
Date: Fri, 28 Oct 2022 06:40:10 GMT
Authorization: OSS4-HMAC-SHA256 Credential=LTAI********************/20250417/cn-hangzhou/oss/aliyun_v4_request,Signature=a7c3554c729d71929e0b84489addee6b2e8d5cb48595adfc51868c299c0c218e
x-oss-async-process=video/animation,ss_5000,f_webp,pw_25,ph_25,fps_25,inter_500|sys/saveas,b_b3V0YnVja2V0,o_b3V0b2JqcHJlZml4LnthdXRvZXh0fQ/notify,topic_QXVkaW9Db252ZXJ0Billing
Converting a video to an animated image triggers billing on both the OSS side and the IMM side.
Starting from 11:00 on July 28, 2025 (UTC+8), the IMM video-to-animated-image conversion service changed from free to paid. The billing item is MediaAnimation, charged based on the number of frames in the output animated image. For details, see the IMM billing adjustment announcement.
OSS billing
For detailed pricing, see OSS pricing.
| API | Billing item | Basis |
|---|---|---|
GetObject | GET requests | Per successful request |
GetObject (public or acceleration endpoint) | Outbound Internet traffic | Data size |
GetObject (Infrequent Access objects) | Infrequent Access data retrieval | Retrieved data size |
GetObject (Archive objects with real-time access enabled) | Archive data retrieval | Retrieved data size |
GetObject (transfer acceleration endpoint) | Transfer acceleration | Data size |
PutObject | PUT requests | Per successful request |
PutObject | Storage fees | Storage class, data size, and storage duration |
HeadObject | GET requests | Per successful request |
IMM billing
For detailed pricing, see IMM billing items.
| API | Billing item | Basis |
|---|---|---|
CreateMediaConvertTask | MediaAnimation | Number of frames in the output animated image |
Usage notes
Video to animated image conversion supports only asynchronous processing (
x-oss-async-process).Anonymous access is denied.