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 script and match stages require source videos; the scene and tts stages can be called without media input.
  • The formula stage takes both the video clips produced by match and the audio produced by tts, together with their respective durations. Each video clip must also include a group ID.
  • The vgn stage uses the formula returned by the formula stage.

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): formula

Method

POST

Content-Type: application/json

Authentication

Open Platform API Signature

Request Parameters

RequiredParameterTypeDescription
YesparamsstringAlgorithm parameters as a JSON string
Yesinit_imagesobject[]Multimedia file list; pass an empty array for stages that do not require media input
YestaskstringFixed value: /v1/video_mashup/482418
Yestask_typestringFixed value: formula
Nosync_timeoutintDefault: 30; synchronous timeout

Structure of each multimedia file in init_images:

RequiredParameterTypeDescription
YesurlstringMultimedia URL or base64 data
YesprofileobjectAttribute metadata

Structure of profile:

RequiredParameterTypeDescription
Yesmedia_profilesobjectMedia metadata
YesversionstringFixed value: v1

Structure of media_profiles:

RequiredParameterTypeDescription
Yesmedia_data_typestringurl indicates a URL; types such as jpg and png indicate base64 data
Nomedia_data_durationintMedia duration in milliseconds; used by the tts, match, and formula stages
Nomedia_data_group_idintMatching 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:

RequiredFieldTypeDescription
Norsp_media_typestringDefault: url; jpg indicates base64 data
YesparameterobjectCore algorithm parameter object

Details of the algorithm parameters in parameter:

RequiredParameterTypeDefaultDescription
NomodestringmashupBusiness mode: mashup, concat, package, or narration
Notask_typestringfullAlgorithm 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
Noscriptstring-Narration or script text; when omitted in a standard remix full workflow, the script is generated from the video content
Nohas_captionbooltrueWhether to display captions
Nouidstring-User ID; when using a cloned voice, it must be provided together with timbre_id
Notimbre_idstring-Voice or cloned-voice ID
Novoice_speedfloat1.0Voice speed multiplier for the full workflow
Novoice_volumefloat1.0Narration volume
Novoice_emotionstring-Voice emotion
NolanguagestringchineseLanguage type
Nocanvas_resolutionobject-Output resolution, for example {"width":1080,"height":1920}; inferred from the source assets when omitted
Notarget_durationint15Target output duration in seconds
Nofont_sizeint-To be supported
Novideo_volumefloat0.0Original video audio volume
Nomusic_urlstring-External background music URL
Nomusic_idstring-Platform music ID
Nomusic_volumefloat1.0Background music volume
Conditionally requiredscript_scenesstring[]-Required for the tts and formula stages; list of storyboard script strings
Nospeedfloat1.0Speech synthesis speed for the tts stage
Conditionally requiredscript_dataobject[]-Required for the match stage; each item contains the scene text and a duration in milliseconds
Conditionally requiredformulastring/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
Nooverlay_textstring-Caption text for text-poster videos in concat mode
Nolocation_ystringtopText-poster position: top, middle, or bottom

Algorithm stage details:

parameter.task_typePurposeKey Inputs or Outputs
fullComplete the remixing or packaging workflow in one callTakes source assets; returns the remixed video and cover image
scriptGenerate a script from videoTakes video; supports target_duration, language, timbre_id, and uid
sceneSplit a script into storyboard scenesRequires script; media input can be omitted; returns the language and script_scenes
ttsSynthesize speech for storyboard scenesRequires script_scenes and timbre_id; a cloned voice also requires uid; returns audio for each scene
matchMatch storyboard scenes to source assetsTakes script_data and source videos; returns segmented video clips grouped by media_data_group_id
formulaGenerate a formula from video clips and audioTakes storyboard scenes, matched clips, and speech audio; returns parameters.result.formula, which also appears at data.parameter.result.formula
vgnRender a finished video from a formulaRequires 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.
FieldTypeDescription
request_idstringRequest identifier
trace_idstringTrace identifier
codeintBusiness status code; 0 indicates that the request was accepted successfully
error_codeintError code; 0 indicates success
messagestringBusiness message
tipsanyAdditional information; may be null
dataobjectTask status and algorithm result

Fields in data:

FieldTypeDescription
statusintStatus code: -1, task not found; 0, created successfully; 1, running; 2, failed; 9, timed out—use the Query API; 10, succeeded
resultobjectAlgorithm result
progressnumberTask progress, for example 0.1, 0.85, or 1
predict_elapsedintEstimated processing time in milliseconds
create_timeint64Creation timestamp in milliseconds
task_idstringTask ID
custom_task_idstringClient-defined task ID
trace_idstringTrace identifier
client_infostringClient information
init_imagesobject[]/nullEchoed input media

Fields in result:

FieldTypeDescription
idstringTask ID; same value as data.task_id
urlsstring[]List of media URLs such as the finished video, cover image, audio, or matched clips; present only for applicable successful stages
imagesstring[]List of URLs such as the finished video and cover image; mirrors urls
msgstringResult message, such as success or an error message
msg_idstringMessage ID
parametersobjectStage 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
parameterobjectDetailed stage result; varies by algorithm stage
dataobjectResult details
mtlab_resobjectmtlab result containing ErrorCode, ErrorMsg, error_code, error_msg, media_info_list, msg_id, and parameter
media_info_listobject[]/nullMedia information list; mirrors result.data.media_info_list

Fields in result.data:

FieldTypeDescription
durationobjectAlgorithm processing, waiting, and other timing information
error_codeintAlgorithm error code; 0 indicates no error
error_msgstringAlgorithm error message
extraobjectAdditional information; typically empty
media_info_listobject[]Media information list; an empty array indicates that no media information is available
msg_idstringMessage ID
parameterobjectDetailed stage return parameters; for the formula stage, result.formula is the same as result.parameters.result.formula

Fields in duration:

FieldTypeDescription
alg_process_timeintAlgorithm processing time in milliseconds
created_timestampintCreation timestamp in Unix time
pull_timestampintPull timestamp in Unix time
repost_timeintRetry time in seconds
upload_timeintUpload time in seconds
waiting_timeintWaiting time in seconds

Fields in each item of media_info_list:

FieldTypeDescription
media_datastringMedia URL or media data
media_extraobjectAdditional media information; may contain the original media type, media duration, matching group ID, and storyboard text
media_profilesobjectOutput 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);
        }
    }
}