Remove Watermark / Remove Subtitles
Remove watermarks, logos, hard subtitles, and other overlays from a video. You can process a video in one request, or detect candidate regions first and process them after the user reviews them. Both ffmpeg (region blur) and raft (content inpainting) algorithms are supported.
Before / After
subtitle Mode
Before
After
full_screen Mode
Before
After
Choose a Usage Path
The same endpoint, POST /task/video_purify, supports two usage paths. Whether the request includes phase determines which one you are using:
| Usage path | How to call | When to use | What you get |
|---|---|---|---|
| Option 1: One-shot processing | 1 request, omit phase | You already know you want to remove subtitles, remove text across the full frame, or remove known regions | A processed video |
| Option 2: Detect and review | 2 requests: phase=detect first, then phase=purify after the user reviews in your client | The user wants to see what the system finds, then remove false positives, adjust regions, or add new ones | Request 1 returns a candidate-region JSON file; request 2 returns a processed video |
Each path has its own request parameters. Once you choose a path, refer only to the matching parameter table under "Create Task". The two requests in Option 2 create separate tasks, and each is billed by video duration.
Detect-and-Review Flow
- Detect: Your client sends a
phase=detectrequest that scans the full frame, the subtitle area, or one custom area. The system returns a JSON file of candidate text regions and does not generate a video. A video can produce thousands of candidates. Detection currently finds text only; graphical logos and translucent patterns must be added manually by the user. - Review: Your client displays the candidates and lets the user build a final list:
- Remove a false positive: leave it out of the list. If it overlaps another retained region, also add a protection region for it; otherwise the overlapping part is still processed.
- Adjust position, size, or time: change the region's coordinates, width and height, or
start/end. - Add a region: draw a box manually (
source=manual). Everything inside it is removed during the specified time range. - Protect content: add anything that must not be changed to the protection list,
protect_regions.
- Process: Your client submits the final list with
phase=purify. The server processes only the regions in that list. It does not detect again and does not restore candidates that the user removed.
ℹ️ Note: "Client" here means a GUI that the caller develops and maintains (a web app, desktop client, or mobile app). Gitruck Cloud does not provide it. The caller implements video preview, candidate display, region editing, time adjustment, and final submission; the Gitruck Cloud API only performs detection and processing.
Create Task
Basic Information
| Item | Value |
|---|---|
| Request Method | POST |
| Request Path | /task/video_purify |
| Content-Type | application/json |
| Authentication | Raw API key in the Authorization header |
Three kinds of requests share this endpoint, each with a different request body:
| Request | phase | Purpose |
|---|---|---|
| One-shot processing | Omitted | Option 1: generate a processed video directly |
| Detection | detect | Option 2, step 1: return candidate regions only |
| Final-list processing | purify | Option 2, step 2: generate a processed video from the final list; can also be called directly, without detection, when the coordinates are already known |
💡 Tip: Each request reads only the fields in its own parameter table. Other fields are ignored and do not change how the video is processed. For example, if
phaseis omitted andpurify_scope=subtitle, only subtitles are removed even ifregionsis also supplied.
Input Video Requirements
The input video is checked before the task is created. If a requirement is not met, the request returns an error code; no task is created and nothing is charged:
| Item | Requirement | Error code if not met |
|---|---|---|
| Duration | No longer than 2 hours; no longer than 20 minutes with the raft algorithm | 6019; 6016 when a raft video is longer than 20 minutes |
| Resolution | Width and height are both 4000 px or less. Common 3840×2160 video is accepted; 4096×2160 exceeds the limit. With the raft algorithm, the shorter side must be at least 128 px | 6022; 6035 when the shorter side is too small for raft |
| Frame rate | 120 fps or less | 6023 |
| File integrity | The file can be parsed and decoded | 6017 / 6021 |
The two raft limits are checked only when the video is actually processed. Detection requests and empty-list processing are not affected.
One-Shot Processing
Omit phase. purify_scope selects the processing mode.
Request Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
file_id | string | Yes | - | Uploaded video file ID |
purify_scope | string | No | full_screen | Processing mode: full_screen / subtitle / custom / region; see the table below |
rois | array | Yes when purify_scope=custom | - | One or more recognition areas. See "Region Object" for the item structure; id and source are not needed here, and start / end may be omitted. Text is recognized and removed only inside these areas; the rest of the frame is left untouched |
regions | array | Yes when purify_scope=region | - | Regions to remove directly. See "Region Object" for the item structure; id and source are not needed here, and start / end may be omitted |
purify_func_type | string | No | ffmpeg | Processing algorithm: ffmpeg blurs the region and is faster; raft inpaints the content, supports videos up to 20 minutes, and cannot guarantee recovery of the original scene |
Processing Modes
purify_scope | Behavior | Required parameter |
|---|---|---|
full_screen | Recognizes and removes text across the full frame | - |
subtitle | Recognizes and removes text in the subtitle area only | - |
custom | Recognizes and removes text only inside the one or more areas in rois, each optionally limited to a time range; everything else inside the areas and the rest of the frame stay as is | rois |
region | No recognition: everything inside each regions box is processed, including the main subject, optionally within a time range. Use it for graphic logos, translucent patterns, or stylized lettering that cannot be recognized, and for badges that appear only during part of the video | regions |
💡 Tip: In
regionmode, smaller boxes that fit the element tightly give better results. Box edges get a soft transition of a few pixels.
💡 Tip: In
custommode, multiple areas are detected in one pass and billed once by video duration. When text crosses an area's edge, only the part inside the area is processed. Areas that fit the text closely give better results.
Request Examples
subtitle mode (remove subtitles):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"purify_scope": "subtitle",
"purify_func_type": "raft"
}'
custom mode (remove text in the bottom 20% of the frame for the whole video, and the title in the top-left corner for the first 10 seconds only):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"purify_scope": "custom",
"rois": [
{"x": 0.0, "y": 0.78, "w": 1.0, "h": 0.2},
{"x": 0.02, "y": 0.02, "w": 0.3, "h": 0.1, "start": 0, "end": 10}
]
}'
region mode (remove the top-right badge for the first 5 seconds, and a bottom area from 120 seconds to the end):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"purify_scope": "region",
"purify_func_type": "raft",
"regions": [
{"x": 0.8, "y": 0.02, "w": 0.18, "h": 0.08, "start": 0, "end": 5},
{"x": 0.3, "y": 0.85, "w": 0.4, "h": 0.1, "start": 120}
]
}'
Detection
Option 2, step 1. Returns candidate regions only and does not generate a video. Billed by video duration.
Request Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
file_id | string | Yes | - | Uploaded video file ID |
phase | string | Yes | - | Must be detect |
detect_scope | string | No | full_screen | Detection scope: full_screen (full frame) / subtitle (subtitle area) / custom (area set by detect_roi) |
detect_roi | object | Yes when detect_scope=custom | - | Detection area {"x","y","w","h"}, with the same value rules as x, y, w, h in "Region Object" |
Detection requests do not need purify_func_type; choose the algorithm in step 2.
Request Examples
Full-frame detection:
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"phase": "detect",
"detect_scope": "full_screen"
}'
Detect only in the bottom 25% of the frame:
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"phase": "detect",
"detect_scope": "custom",
"detect_roi": {"x": 0.0, "y": 0.75, "w": 1.0, "h": 0.25}
}'
When the task completes, get the detection file's download path from "Query Task Result". See "Detection Result File" for its structure.
Final-List Processing
Option 2, step 2. Submits the user-approved final list and generates a processed video. When you already know the coordinates and need protection regions, you can also call it directly without detection.
Request Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
file_id | string | Yes | - | Uploaded video file ID |
phase | string | Yes | - | Must be purify |
regions | array | Yes | - | Final removal list. See "Region Object" for the item structure; every field is required. May be an empty array, meaning nothing is processed |
protect_regions | array | No | [] | Protection list with the same structure as regions; protection wins where it overlaps a removal region |
source_file_id | string | No | - | source.file_id from the detection file. When provided, it must equal file_id; this prevents submitting one video's detection result for another video |
purify_func_type | string | No | ffmpeg | Processing algorithm; same as in "One-Shot Processing" |
Processing Rules
- The effective treatment area is the union of all removal regions minus the union of all protection regions. Removing one candidate does not cancel other removal regions that overlap it; add a protection region for content that must stay.
- The server processes only the submitted list. It does not detect again and does not restore candidates that the user removed.
- If
regionsis an empty array, the server copies the source file without transcoding or running repair. The task is still billed by video duration, and the query result hasunchangedset totrue. - Thousands of regions can be submitted. A task that exceeds server resource limits such as video duration, resolution, or request size returns
6016. - Protection regions, exact-bound processing, and empty-list copies require server protocol version 2. Confirm it first with "Check Protocol Capabilities".
Request Examples
Submit the reviewed list (keep one detected region and add one manual region):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"source_file_id": "537489015178246",
"phase": "purify",
"purify_func_type": "raft",
"regions": [
{"id": "det-000001", "source": "detected", "x": 0.70, "y": 0.04, "w": 0.22, "h": 0.09, "start": 0.0, "end": 5.2},
{"id": "manual-000001", "source": "manual", "x": 0.05, "y": 0.05, "w": 0.25, "h": 0.20, "start": 2.0, "end": 8.0}
]
}'
Skip detection: remove a known corner badge and protect overlapping text (adjust the example coordinates for the actual video):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"phase": "purify",
"purify_func_type": "ffmpeg",
"regions": [
{"id": "corner-1", "source": "manual", "x": 0.8, "y": 0.02, "w": 0.18, "h": 0.08, "start": 0, "end": 5}
],
"protect_regions": [
{"id": "keep-1", "source": "manual", "x": 0.8, "y": 0.08, "w": 0.08, "h": 0.02, "start": 2, "end": 5}
]
}'
Region Object
Each item in regions, rois, and protect_regions is a region object. One-shot processing and final-list processing require different fields:
| Field | Type | One-shot (region / custom mode) | Final-list processing | Description |
|---|---|---|---|---|
id | string | Not used | Required | Unique region ID within one list. Detected regions come with IDs such as det-000001; generate your own for regions added in the client |
source | string | Not used | Required | detected (from detection) or manual (added by the user) |
x, y | number | Required | Required | Top-left corner in normalized frame coordinates (0-1) |
w, h | number | Required | Required | Width and height in normalized frame coordinates (0-1); must be greater than 0, with x+w≤1 and y+h≤1 |
start | number | Optional, default 0 | Required | Start time in seconds from the beginning of the video; must be ≥0 and less than the video duration |
end | number | Optional, default end of video | Required | End time in seconds; must be greater than start. Values past the video duration are treated as the end of the video |
- Coordinates are relative to the displayed, rotation-corrected frame, as seen in a player.
- Time ranges are half-open:
[start, end). - Regions may overlap. The server merges masks internally but does not modify the submitted list.
- In final-list processing, changes are written only inside the regions, and soft edge transitions do not enter protection regions. Lossy video encoding may still slightly change nearby pixels, so pixel-exact output is not guaranteed. Variable-frame-rate (VFR) sources are output at a constant frame rate (CFR).
Detection Result File
When a detection task completes, download the file from output_result.regions_download_url. It has this structure:
{
"version": 1,
"source": {"file_id": "537489015178246"},
"video": {
"width": 1920,
"height": 1080,
"duration": 120.0,
"fps": 30,
"fps_exact": "30/1"
},
"regions": [
{"id": "det-000001", "source": "detected", "x": 0.7, "y": 0.04, "w": 0.22, "h": 0.09, "start": 0.0, "end": 5.2, "score": 0.9132}
]
}
| Field | Description |
|---|---|
version | File format version, currently 1 |
source.file_id | File ID of the detected video; use it as source_file_id in final-list processing |
video | Video width, height, duration (seconds), and frame rate; fps_exact is the exact rational frame rate, such as 30000/1001 |
regions | Candidate regions, possibly thousands. Each item already contains every field required for final-list processing and can be submitted as regions after editing. Each item also has score (0-1): how confident the detector is that the area is text; higher means more text-like |
Use score to filter out false detections, for example by showing only candidates whose score is at or above a threshold you choose per video. Real text such as subtitles and titles also scores high, so score tells you how text-like an area is; deciding which text to remove is still up to the user. In rare cases no confidence is available and a candidate has no score; treat it as unscored. Detection results do not include recognized text.
Success Example
{
"code": 200,
"msg": "success",
"data": {
"task_id": "537489015178247",
"task_type": "video_purify",
"status": "queued"
}
}
Query Task Result
Basic Information
| Item | Value |
|---|---|
| Request Method | GET |
| Request Path | /task/video_purify/{task_id} |
| Authentication | Raw API key in the Authorization header |
Output Result (output_result)
Detection tasks and processing tasks return different fields:
| Parameter | Type | Description |
|---|---|---|
phase | string | detect or purify for tasks created with phase; not returned for one-shot tasks |
file_id | string | Processing tasks: processed video file ID |
download_url | string | Processing tasks: download path for the processed video |
unchanged | boolean | true when final-list processing received an empty regions array, meaning the output is a copy of the source |
regions_file_id | string | Detection tasks: JSON file ID for the detection results |
regions_download_url | string | Detection tasks: download path for the detection results |
region_count | number | Detection tasks: number of candidate regions, which may be in the thousands |
video | object | Detection tasks: video metadata, including width, height, duration, fps, and fps_exact |
Success Examples
Processing task completed:
{
"code": 200,
"msg": "success",
"data": {
"task_id": "537489015178247",
"status": "completed",
"progress": 100,
"output_result": {
"file_id": "537489015178248",
"download_url": "/download/a1/output.mp4"
},
"create_time": "2026-04-05T08:00:00Z",
"update_time": "2026-04-05T08:01:00Z"
}
}
Detection task completed:
{
"code": 200,
"msg": "success",
"data": {
"task_id": "537489015178250",
"status": "completed",
"progress": 100,
"output_result": {
"phase": "detect",
"regions_file_id": "537489015178249",
"regions_download_url": "/download/a1/regions.json",
"region_count": 2387,
"video": {
"width": 1920,
"height": 1080,
"duration": 120.0,
"fps": 30,
"fps_exact": "30/1"
}
},
"create_time": "2026-04-05T08:00:00Z",
"update_time": "2026-04-05T08:00:40Z"
}
}
Check Protocol Capabilities
Protection regions, exact-bound processing, and empty-list copies require server protocol version 2. Before using them, call this endpoint and confirm that data.review_protocol is 2. This authenticated request creates no task and incurs no charge.
curl https://api.ai-mcn.tv:10000/task/video_purify/capabilities \
-H "Authorization: YOUR_API_KEY"
{
"code": 200,
"msg": "success",
"data": {
"review_protocol": 2
}
}
Use the gtrk CLI
Agents can run the same flow with gtrk purify commands:
| Command | Purpose |
|---|---|
gtrk purify detect video.mp4 --json | Detect and get the complete region file with a summary |
gtrk purify edit regions.json --delete-id det-000001 --out final.json | Edit the region list |
gtrk purify apply final.json --json | Process the final list |
gtrk purify run video.mp4 --detect-scope subtitle --json | Complete everything in one step when the target scope is already clear |
gtrk purify resume journal.json --json | Reuse tasks that were already submitted |
- Before submitting a processing request, the CLI checks that the server supports the required protocol capabilities.
- If the final list is empty, the CLI returns the local source file without creating a processing task.
- If a submission response is lost, the CLI stops and asks you to reconcile with the cloud task instead of resubmitting automatically.
Error Codes
| Error Code | HTTP Status | Description | Resolution |
|---|---|---|---|
6013 | 400 | Missing file_id | Pass the file_id field |
6016 | 400 | Invalid parameters or regions: a parameter required by the current request is missing, coordinates are out of range, end is not greater than start, region data or request size exceeds server resource limits, or the video is longer than 20 minutes in raft mode | Check the parameters against the table for the request you are sending and against "Region Object"; split or narrow a task that exceeds server resource limits; keep raft mode videos within 20 minutes |
6014 | 400 | File type does not match the task | Upload a video file |
6004 | 404 | File not found | Verify the file_id |
6017 | 400 | Video file cannot be parsed: the file is corrupted, malformed, or has conflicting metadata such as frame rates | Re-export the video with an editing or transcoding tool and upload it again |
6019 | 400 | Video duration is 0 or longer than 2 hours | Trim the video and upload it again |
6021 | 400 | Video integrity check failed: some positions cannot be decoded, or the end of the file is incomplete | Use another source file, or re-export a complete video and upload it again |
6022 | 400 | Video resolution exceeds the limit: width or height is greater than 4000 px | Scale the video so that width and height are both 4000 px or less, then upload it again |
6023 | 400 | Video frame rate exceeds 120 fps | Convert the video to 120 fps or less (such as 60 fps) and upload it again |
6035 | 400 | Video frame too small: raft mode requires the shorter side to be at least 128 px (the error message states the current size) | Switch to purify_func_type: ffmpeg, or provide a larger source video |
6502 | 401 | Authentication failed | Check the Authorization header |
6202 | 402 | Insufficient balance | Recharge in the Dashboard |