Video Remix
Description
Video Remix supports business modes including standard remixing, text-poster videos, finished-video packaging, and narration. Standard remixing and finished-video packaging can either be completed in one call using full, or invoked in stages using script → scene → tts → match → formula → vgn. When a script is already available, processing can start from the scene or tts stage.
Version
1.0
Media Requirements
The input consists of multimedia files and supports formats including wav, m4a, mp4, mp3, and aac. Media requirements vary by stage as follows:
- The
scriptandmatchstages require source videos; thesceneandttsstages can be called without media input. - The
formulastage takes both the video clips produced bymatchand the audio produced bytts, together with their respective durations. Each video clip must also include a group ID. - The
vgnstage uses the formula returned by theformulastage.
API URL
Production environment: https://openapi.meitu.com
Task submission endpoint: https://openapi.meitu.com/api/v1/sdk/sync/push
Task name (task): /v1/video_mashup/482418
Task type (task_type): formulaMethod
POST
Content-Type: application/json
Authentication
Request Parameters
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | params | string | Algorithm parameters as a JSON string |
| Yes | init_images | object[] | Multimedia file list; pass an empty array for stages that do not require media input |
| Yes | task | string | Fixed value: /v1/video_mashup/482418 |
| Yes | task_type | string | Fixed value: formula |
| No | sync_timeout | int | Default: 30; synchronous timeout |
Structure of each multimedia file in init_images:
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | url | string | Multimedia URL or base64 data |
| Yes | profile | object | Attribute metadata |
Structure of profile:
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | media_profiles | object | Media metadata |
| Yes | version | string | Fixed value: v1 |
Structure of media_profiles:
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | media_data_type | string | url indicates a URL; types such as jpg and png indicate base64 data |
| No | media_data_duration | int | Media duration in milliseconds; used by the tts, match, and formula stages |
| No | media_data_group_id | int | Matching group ID; used by the match and formula stages to place assets in the same matching group |
The params inference parameter is a JSON string with the following structure:
| Required | Field | Type | Description |
|---|---|---|---|
| No | rsp_media_type | string | Default: url; jpg indicates base64 data |
| Yes | parameter | object | Core algorithm parameter object |
Details of the algorithm parameters in parameter:
| Required | Parameter | Type | Default | Description |
|---|---|---|---|---|
| No | mode | string | mashup | Business mode: mashup, concat, package, or narration |
| No | task_type | string | full | Algorithm stage: full, script, scene, tts, match, formula, or vgn. This field is inside parameter and differs from the top-level task_type, whose fixed value is formula |
| No | script | string | - | Narration or script text; when omitted in a standard remix full workflow, the script is generated from the video content |
| No | has_caption | bool | true | Whether to display captions |
| No | uid | string | - | User ID; when using a cloned voice, it must be provided together with timbre_id |
| No | timbre_id | string | - | Voice or cloned-voice ID |
| No | voice_speed | float | 1.0 | Voice speed multiplier for the full workflow |
| No | voice_volume | float | 1.0 | Narration volume |
| No | voice_emotion | string | - | Voice emotion |
| No | language | string | chinese | Language type |
| No | canvas_resolution | object | - | Output resolution, for example {"width":1080,"height":1920}; inferred from the source assets when omitted |
| No | target_duration | int | 15 | Target output duration in seconds |
| No | font_size | int | - | To be supported |
| No | video_volume | float | 0.0 | Original video audio volume |
| No | music_url | string | - | External background music URL |
| No | music_id | string | - | Platform music ID |
| No | music_volume | float | 1.0 | Background music volume |
| Conditionally required | script_scenes | string[] | - | Required for the tts and formula stages; list of storyboard script strings |
| No | speed | float | 1.0 | Speech synthesis speed for the tts stage |
| Conditionally required | script_data | object[] | - | Required for the match stage; each item contains the scene text and a duration in milliseconds |
| Conditionally required | formula | string/object | - | Required for the vgn stage; use the formula JSON string or object returned by the formula stage. Long strings should be serialized in code rather than manually escaped and concatenated |
| No | overlay_text | string | - | Caption text for text-poster videos in concat mode |
| No | location_y | string | top | Text-poster position: top, middle, or bottom |
Algorithm stage details:
| parameter.task_type | Purpose | Key Inputs or Outputs |
|---|---|---|
full | Complete the remixing or packaging workflow in one call | Takes source assets; returns the remixed video and cover image |
script | Generate a script from video | Takes video; supports target_duration, language, timbre_id, and uid |
scene | Split a script into storyboard scenes | Requires script; media input can be omitted; returns the language and script_scenes |
tts | Synthesize speech for storyboard scenes | Requires script_scenes and timbre_id; a cloned voice also requires uid; returns audio for each scene |
match | Match storyboard scenes to source assets | Takes script_data and source videos; returns segmented video clips grouped by media_data_group_id |
formula | Generate a formula from video clips and audio | Takes storyboard scenes, matched clips, and speech audio; returns parameters.result.formula, which also appears at data.parameter.result.formula |
vgn | Render a finished video from a formula | Requires formula; returns the finished video and cover image |
The concat mode supports video concatenation and text-poster captions. Using full is recommended, but vgn is also supported.
Request Example
The following example performs a standard remix in one call. When script is omitted, the server generates the script from the video content.
{
"task": "/v1/video_mashup/482418",
"task_type": "formula",
"init_images": [
{
"url": "https://xiuxiu-pro-pre.meitudata.com/test_0520/60b619534ba1164446e95132cd858859.mp4",
"profile": {
"media_profiles": {
"media_data_type": "url"
},
"version": "v1"
}
}
],
"params": "{\"rsp_media_type\":\"url\",\"parameter\":{\"mode\":\"mashup\",\"task_type\":\"full\",\"canvas_resolution\":{\"width\":1080,\"height\":1920},\"has_caption\":true,\"target_duration\":15}}",
"sync_timeout": 30
}For text-poster mode, use the following parameter configuration:
{
"task": "/v1/video_mashup/482418",
"task_type": "formula",
"init_images": [
{
"url": "https://mt-deepnet-models-release.oss-cn-beijing.aliyuncs.com/deepnet/cloud/3d70da04-7f38-11f1-86df-6a248def2af9.mp4",
"profile": {
"media_profiles": {
"media_data_type": "url"
},
"version": "v1"
}
}
],
"params": "{\"rsp_media_type\":\"url\",\"parameter\":{\"mode\":\"concat\",\"task_type\":\"full\",\"overlay_text\":\"广东话真是太神奇了今天又听\",\"location_y\":\"top\",\"canvas_resolution\":{\"width\":1080,\"height\":1920}}}",
"sync_timeout": 30
}Response Fields
Generated results are periodically deleted. Download and save them promptly.| Field | Type | Description |
|---|---|---|
| request_id | string | Request identifier |
| trace_id | string | Trace identifier |
| code | int | Business status code; 0 indicates that the request was accepted successfully |
| error_code | int | Error code; 0 indicates success |
| message | string | Business message |
| tips | any | Additional information; may be null |
| data | object | Task status and algorithm result |
Fields in data:
| Field | Type | Description |
|---|---|---|
| status | int | Status code: -1, task not found; 0, created successfully; 1, running; 2, failed; 9, timed out—use the Query API; 10, succeeded |
| result | object | Algorithm result |
| progress | number | Task progress, for example 0.1, 0.85, or 1 |
| predict_elapsed | int | Estimated processing time in milliseconds |
| create_time | int64 | Creation timestamp in milliseconds |
| task_id | string | Task ID |
| custom_task_id | string | Client-defined task ID |
| trace_id | string | Trace identifier |
| client_info | string | Client information |
| init_images | object[]/null | Echoed input media |
Fields in result:
| Field | Type | Description |
|---|---|---|
| id | string | Task ID; same value as data.task_id |
| urls | string[] | List of media URLs such as the finished video, cover image, audio, or matched clips; present only for applicable successful stages |
| images | string[] | List of URLs such as the finished video and cover image; mirrors urls |
| msg | string | Result message, such as success or an error message |
| msg_id | string | Message ID |
| parameters | object | Stage identifier and stage result. stage can be full, scene, tts, match, formula, or vgn; scene can return result.language and result.script_scenes; formula returns result.formula |
| parameter | object | Detailed stage result; varies by algorithm stage |
| data | object | Result details |
| mtlab_res | object | mtlab result containing ErrorCode, ErrorMsg, error_code, error_msg, media_info_list, msg_id, and parameter |
| media_info_list | object[]/null | Media information list; mirrors result.data.media_info_list |
Fields in result.data:
| Field | Type | Description |
|---|---|---|
| duration | object | Algorithm processing, waiting, and other timing information |
| error_code | int | Algorithm error code; 0 indicates no error |
| error_msg | string | Algorithm error message |
| extra | object | Additional information; typically empty |
| media_info_list | object[] | Media information list; an empty array indicates that no media information is available |
| msg_id | string | Message ID |
| parameter | object | Detailed stage return parameters; for the formula stage, result.formula is the same as result.parameters.result.formula |
Fields in duration:
| Field | Type | Description |
|---|---|---|
| alg_process_time | int | Algorithm processing time in milliseconds |
| created_timestamp | int | Creation timestamp in Unix time |
| pull_timestamp | int | Pull timestamp in Unix time |
| repost_time | int | Retry time in seconds |
| upload_time | int | Upload time in seconds |
| waiting_time | int | Waiting time in seconds |
Fields in each item of media_info_list:
| Field | Type | Description |
|---|---|---|
| media_data | string | Media URL or media data |
| media_extra | object | Additional media information; may contain the original media type, media duration, matching group ID, and storyboard text |
| media_profiles | object | Output media description; when a URL is returned, media_data_type is url |
Response Examples
Successful Response Example
{
"request_id": "",
"trace_id": "",
"code": 0,
"error_code": 0,
"message": "success",
"tips": null,
"data": {
"status": 10,
"result": {
"id": "t_mt1a3i5n7b8918965f-189d-49f8-9272-58ef9a915763",
"urls": [
"https://mt-vgen-public-release.meitudata.com/stash/fomula_video_merge/2026-07-22/hkmazv2zjdapv7iq.mp4",
"https://mt-deepnet-models-release.oss-cn-beijing.aliyuncs.com/deepnet/cloud/f34bb8de-8579-11f1-800c-c6f4cabfa4a7.jpg"
],
"parameters": {
"stage": "full"
},
"data": {
"duration": {
"alg_process_time": 248844,
"created_timestamp": 1784689178,
"pull_timestamp": 1784689178,
"repost_time": 0,
"upload_time": 0,
"waiting_time": 64
},
"error_code": 0,
"error_msg": "success",
"extra": {},
"media_info_list": [
{
"media_data": "https://mt-vgen-public-release.meitudata.com/stash/fomula_video_merge/2026-07-22/hkmazv2zjdapv7iq.mp4",
"media_extra": {
"media_profiles": {
"media_data_type": "MP4"
}
},
"media_profiles": {
"media_data_type": "url"
}
},
{
"media_data": "https://mt-deepnet-models-release.oss-cn-beijing.aliyuncs.com/deepnet/cloud/f34bb8de-8579-11f1-800c-c6f4cabfa4a7.jpg",
"media_extra": {
"media_profiles": {
"media_data_type": "PNG"
}
},
"media_profiles": {
"media_data_type": "url"
}
}
],
"msg_id": "8267aeb5-c5a7-4078-6c4a-r009f30b78dc",
"parameter": {
"stage": "full"
}
},
"msg": "success",
"msg_id": "8267aeb5-c5a7-4078-6c4a-r009f30b78dc",
"images": [
"https://mt-vgen-public-release.meitudata.com/stash/fomula_video_merge/2026-07-22/hkmazv2zjdapv7iq.mp4",
"https://mt-deepnet-models-release.oss-cn-beijing.aliyuncs.com/deepnet/cloud/f34bb8de-8579-11f1-800c-c6f4cabfa4a7.jpg"
],
"mtlab_res": {
"ErrorCode": 0,
"ErrorMsg": "",
"error_code": 0,
"error_msg": "",
"media_info_list": null,
"msg_id": "8267aeb5-c5a7-4078-6c4a-r009f30b78dc",
"parameter": null
},
"media_info_list": [
{
"media_data": "https://mt-vgen-public-release.meitudata.com/stash/fomula_video_merge/2026-07-22/hkmazv2zjdapv7iq.mp4",
"media_extra": {
"media_profiles": {
"media_data_type": "MP4"
}
},
"media_profiles": {
"media_data_type": "url"
}
},
{
"media_data": "https://mt-deepnet-models-release.oss-cn-beijing.aliyuncs.com/deepnet/cloud/f34bb8de-8579-11f1-800c-c6f4cabfa4a7.jpg",
"media_extra": {
"media_profiles": {
"media_data_type": "PNG"
}
},
"media_profiles": {
"media_data_type": "url"
}
}
]
},
"progress": 1,
"predict_elapsed": 10000,
"create_time": 1784689177801,
"task_id": "t_mt1a3i5n7b8918965f-189d-49f8-9272-58ef9a915763",
"custom_task_id": "",
"trace_id": "",
"client_info": "",
"init_images": null
}
}Query-Required Response Example
Use the Query API to retrieve the result.
Response Status: 200
content-type: application/json; charset=utf-8
{
"request_id": "",
"trace_id": "",
"code": 0,
"error_code": 0,
"message": "success",
"tips": null,
"data": {
"status": 9,
"result": {
"id": "t_mt1a3i5n7b8918965f-189d-49f8-9272-58ef9a915763"
},
"progress": 0,
"predict_elapsed": 10000,
"create_time": 1784689177801,
"task_id": "t_mt1a3i5n7b8918965f-189d-49f8-9272-58ef9a915763",
"custom_task_id": "",
"trace_id": "3fb7de72-d400-49b3-837b-162836173e5e",
"client_info": "",
"init_images": null
}
}Failed Response Example
Response Status: 400
content-type: application/json; charset=utf-8
{
"request_id": "",
"trace_id": "",
"code": 20001,
"error_code": 20001,
"message": "PROCESS_ERROR",
"tips": null,
"data": {
"status": 2,
"result": {
"id": "t_mt1a3i5n7b8918965f-189d-49f8-9272-58ef9a915763",
"error_code": 20001,
"error_msg": "PROCESS_ERROR",
"msg": "PROCESS_ERROR"
},
"progress": 1,
"predict_elapsed": 10000,
"create_time": 1784689177801,
"task_id": "t_mt1a3i5n7b8918965f-189d-49f8-9272-58ef9a915763",
"custom_task_id": "",
"trace_id": "",
"client_info": "",
"init_images": null
}
}Common Error Codes and Messages
API-specific error: 20001 (PROCESS_ERROR), indicating a processing error.
For details, see API Error Codes.
SDK Examples
All four language examples use the same one-call standard remix request: mode=mashup, algorithm stage task_type=full, a target duration of 15 seconds, and captions enabled.
Python
import json
import requests
from sign_sdk import sign
def api_call_example():
key = "your_api_key"
secret = "your_api_secret"
url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
method = "POST"
headers = {
"Content-Type": "application/json",
sign.HeaderHost: "openapi.meitu.com",
}
inner_params = {
"rsp_media_type": "url",
"parameter": {
"mode": "mashup",
"task_type": "full",
"target_duration": 15,
"has_caption": True,
},
}
payload = {
"task": "/v1/video_mashup/482418",
"task_type": "formula",
"init_images": [
{
"url": "https://xiuxiu-pro-pre.meitudata.com/test_0520/60b619534ba1164446e95132cd858859.mp4",
"profile": {
"media_profiles": {"media_data_type": "url"},
"version": "v1",
},
}
],
"params": json.dumps(inner_params, ensure_ascii=False),
"sync_timeout": 30,
}
body = json.dumps(payload, ensure_ascii=False)
signer = sign.Signer(key, secret)
signed_request = signer.sign(url, method, headers, body)
response = requests.Session().send(signed_request)
print(f"Status: {response.status_code}")
print(f"Response: {response.text}")
if __name__ == "__main__":
api_call_example()Go
package main
import (
"fmt"
"io"
"net/http"
"github.com/mtlab/api/signer"
)
func main() {
key := "your_api_key"
secret := "your_api_secret"
signObj := signer.NewSigner(key, secret)
url := "https://openapi.meitu.com/api/v1/sdk/sync/push"
method := http.MethodPost
headers := make(http.Header)
headers.Set(signer.HeaderHost, "openapi.meitu.com")
headers.Set("Content-Type", "application/json")
body := `{
"task": "/v1/video_mashup/482418",
"task_type": "formula",
"init_images": [{
"url": "https://xiuxiu-pro-pre.meitudata.com/test_0520/60b619534ba1164446e95132cd858859.mp4",
"profile": {
"media_profiles": {"media_data_type": "url"},
"version": "v1"
}
}],
"params": "{\"rsp_media_type\":\"url\",\"parameter\":{\"mode\":\"mashup\",\"task_type\":\"full\",\"target_duration\":15,\"has_caption\":true}}",
"sync_timeout": 30
}`
req, err := signObj.Sign(url, method, headers, body)
if err != nil {
fmt.Println("Failed to sign request:", err)
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println("Failed to send request:", err)
return
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Read response failed:", err)
return
}
fmt.Println("Response:", resp.StatusCode, string(responseBody))
}PHP
<?php
require 'signer.php';
$key = 'your_api_key';
$secret = 'your_api_secret';
$signer = new Signer($key, $secret);
$url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
$method = 'POST';
$headers = ['Content-Type' => 'application/json'];
$innerParams = json_encode([
'rsp_media_type' => 'url',
'parameter' => [
'mode' => 'mashup',
'task_type' => 'full',
'target_duration' => 15,
'has_caption' => true,
],
]);
$body = json_encode([
'task' => '/v1/video_mashup/482418',
'task_type' => 'formula',
'init_images' => [
[
'url' => 'https://xiuxiu-pro-pre.meitudata.com/test_0520/60b619534ba1164446e95132cd858859.mp4',
'profile' => [
'media_profiles' => ['media_data_type' => 'url'],
'version' => 'v1',
],
],
],
'params' => $innerParams,
'sync_timeout' => 30,
]);
$curl = $signer->sign($url, $method, $headers, $body);
$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status === 0) {
echo 'Error: ' . curl_error($curl);
} else {
echo "Status: {$status}\n";
echo "Response: {$response}\n";
}
curl_close($curl);
?>Java
package com.meitu.openai.common;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
Signer signer = new Signer("your_api_key", "your_api_secret");
String url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
String method = "POST";
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put(Signer.HeaderHost, "openapi.meitu.com");
String body = "{\n" +
" \"task\": \"/v1/video_mashup/482418\",\n" +
" \"task_type\": \"formula\",\n" +
" \"init_images\": [{\n" +
" \"url\": \"https://xiuxiu-pro-pre.meitudata.com/test_0520/60b619534ba1164446e95132cd858859.mp4\",\n" +
" \"profile\": {\n" +
" \"media_profiles\": {\"media_data_type\": \"url\"},\n" +
" \"version\": \"v1\"\n" +
" }\n" +
" }],\n" +
" \"params\": \"{\\\"rsp_media_type\\\":\\\"url\\\",\\\"parameter\\\":{\\\"mode\\\":\\\"mashup\\\",\\\"task_type\\\":\\\"full\\\",\\\"target_duration\\\":15,\\\"has_caption\\\":true}}\",\n" +
" \"sync_timeout\": 30\n" +
"}";
Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod(method);
for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
connection.setDoOutput(true);
connection.getOutputStream().write(body.getBytes(StandardCharsets.UTF_8));
int status = connection.getResponseCode();
InputStream stream = status >= 400
? connection.getErrorStream()
: connection.getInputStream();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
System.out.println("Response: " + status + " " + response);
}
}
}