# Transcode, resize, or watermark videos

Robot: `/video/encode`

🤖/video/encode encodes, resizes, applies watermarks to videos and animated GIFs.

The /video/encode Robot is a versatile tool for video processing that handles transcoding, resizing, and watermarking. It supports various formats including modern standards like HEVC (H.265), and provides features such as presets for common devices, custom FFmpeg parameters for powerusers, watermark positioning, and more.

## Adding text overlays with FFmpeg

You can add text overlays to videos using FFmpeg's `drawtext` filter through this <dfn>Robot</dfn>'s `ffmpeg` parameter. Here are two examples — one with the default font and one with a custom font family name:

```json
{
  "steps": {
    ":original": {
      "robot": "/upload/handle"
    },
    "text_overlay_default": {
      "use": ":original",
      "robot": "/video/encode",
      "preset": "empty",
      "ffmpeg_stack": "{{stacks.ffmpeg.recommended_version}}",
      "ffmpeg": {
        "codec:a": "copy",
        "vf": "drawtext=text='My text overlay':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2"
      },
      "result": true
    },
    "text_overlay_custom": {
      "use": ":original",
      "robot": "/video/encode",
      "preset": "empty",
      "ffmpeg_stack": "{{stacks.ffmpeg.recommended_version}}",
      "ffmpeg": {
        "codec:a": "copy",
        "vf": "drawtext=font='Times New Roman':text='My text overlay':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2"
      },
      "result": true
    }
  }
}
```

**Notes:**

* Use the `font` attribute to reference a font by family name with FFmpeg's `drawtext`
* FFmpeg font family names typically do not contain dashes (e.g. `Times New Roman`), while
  ImageMagick uses dashed names (e.g. `Times-New-Roman`).
* File-loading `drawtext` options such as `textfile` and `fontfile` are not supported. Use
  inline `text` and a font family name instead.
* Preserve the source audio by setting `"codec:a": "copy"`.
* Position text with the `x` and `y` expressions. The example above centers the text.

See the [live text overlay demo](/demos/video-encoding/add-text-overlay.md).

Stage: ga

## Usage example

Transcode uploaded video to \[HEVC]\(https\://en.wikipedia.org/wiki/High\_Efficiency\_Video\_Coding) (H.265):

```json
{
  "steps": {
    "hevc_encoded": {
      "robot": "/video/encode",
      "use": ":original",
      "preset": "hevc"
    }
  }
}
```

## Parameters

* `interpolate`: Controls whether Assembly Variables are interpolated for individual instruction fields.

  By default, most Robot instruction fields interpolate Assembly Variables. Set this to `false` to treat every instruction field as literal text, or set an individual field path to `false` to treat only that field as literal text. For Robot-specific fields that are literal by default, set this to `true` or set that field path to `true` to opt back into interpolation.

  Use field names such as `path`, or dotted paths such as `ffmpeg.vf` for nested objects.

* `output_meta`: Allows you to specify a set of metadata that is more expensive on CPU power to calculate, and thus is disabled by default to keep your Assemblies processing fast.

  For images, you can add `"has_transparency": true` in this object to extract if the image contains transparent parts and `"dominant_colors": true` to extract an array of hexadecimal color codes from the image.

  For images, you can also add `"blurhash": true` to extract a [BlurHash](https://blurha.sh) string — a compact representation of a placeholder for the image, useful for showing a blurred preview while the full image loads.

  For videos, you can add the `"colorspace": true` parameter to extract the colorspace of the output video.

  For videos, you can also add `"interlaced": true` to detect whether the video is interlaced. This combines the cheap ffprobe `field_order` flag with a bounded `idet` sampling pass over the first frames of the source, exposing `interlaced`, `field_order`, and a diagnostic `interlace_detection` object under `file.meta`. This is computationally expensive and billed accordingly.

  For audio, you can add `"mean_volume": true` to get a single value representing the mean average volume of the audio file.

  You can also set this to `false` to skip metadata extraction and speed up transcoding.

* `result`: Whether the results of this Step should be present in the Assembly Status JSON

* `queue`: Setting the queue to 'batch', manually downgrades the priority of jobs for this step to avoid consuming Priority job slots for jobs that don't need zero queue waiting times

* `force_accept`: Force a Robot to accept a file type it would have ignored.

  By default, Robots ignore files they are not familiar with.
  [🤖/video/encode](/docs/robots/video-encode.md), for
  example, will happily ignore input images.

  With the `force_accept` parameter set to `true`, you can force Robots to accept all files thrown at them.
  This will typically lead to errors and should only be used for debugging or combatting edge cases.

* `ignore_errors`: Ignore errors during specific phases of processing.

  Setting this to `["meta"]` will cause the Robot to ignore errors during metadata extraction.

  Setting this to `["execute"]` will cause the Robot to ignore errors during the main execution phase.

  Setting this to `true` is equivalent to `["meta", "execute"]` and will ignore errors in both phases.

* `use`: Specifies which Step(s) to use as input.

  * You can pick any names for Steps except `":original"` (reserved for user uploads handled by Transloadit)
  * You can provide several Steps as input with arrays:
    ```json
    {
      "use": [
        ":original",
        "encoded",
        "resized"
      ]
    }
    ```
  * You can also tag input Steps with `as` to pass semantic intent to robots:
    ```json
    {
      "use": [
        {
          "name": ":original",
          "as": "image"
        },
        {
          "name": ":original",
          "as": "mask"
        }
      ]
    }
    ```

  > [!Tip]
  > That's likely all you need to know about `use`, but you can view [Advanced use cases](/docs/topics/use-parameter.md).

* `ffmpeg`: A parameter object to be passed to FFmpeg. If a preset is used, the options specified are merged on top of the ones from the preset. For available options, see the [FFmpeg documentation](https://ffmpeg.org/ffmpeg-doc.html). Options specified here take precedence over the preset options.

* `ffmpeg_stack`: Selects the FFmpeg stack version to use for encoding. We currently recommend using "v7". The exact versions "v6.0.0", "v7.0.0", and "v8.0.0" are legacy values that remain accepted for backward compatibility. Deprecated "v5.x" values are also accepted.

* `width`: Width of the new video, in pixels.

  If the value is not specified and the `preset` parameter is available, the `preset`'s [supplied width](/docs/presets/video.md) will be implemented.

* `height`: Height of the new video, in pixels.

  If the value is not specified and the `preset` parameter is available, the `preset`'s [supplied height](/docs/presets/video.md) will be implemented.

* `preset`: Converts a video according to [pre-configured settings](/docs/presets/video.md).

  Starting with `ffmpeg_stack: "v7"`, you can use the value `'empty'` here if you specify your own FFmpeg parameters using the <dfn>Robot</dfn> or do not want Transloadit to set any encoding settings.

* `resize_strategy`: See the [available resize strategies](/docs/topics/resize-strategies.md).

* `zoom`: If this is set to `false`, smaller videos will not be stretched to the desired width and height. For details about the impact of zooming for your preferred resize strategy, see the list of available [resize strategies](/docs/topics/resize-strategies.md).

* `crop`: Specify an object containing coordinates for the top left and bottom right corners of the rectangle to be cropped from the original video(s). Values can be integers for absolute pixel values or strings for percentage based values.

  For example:

  ```json
  {
    "x1": 80,
    "y1": 100,
    "x2": "60%",
    "y2": "80%"
  }
  ```

  This will crop the area from `(80, 100)` to `(600, 800)` from a 1000×1000 pixels video, which is a square whose width is 520px and height is 700px. If `crop` is set, the width and height parameters are ignored, and the `resize_strategy` is set to `crop` automatically.

  You can also use a JSON string of such an object with coordinates in similar fashion:

  ```json
  "{\"x1\": <Integer>, \"y1\": <Integer>, \"x2\": <Integer>, \"y2\": <Integer>}"
  ```

* `background`: The background color of the resulting video in the `"rrggbbaa"` format (red, green, blue, alpha) when used with the `"pad"` resize strategy. The default color is black.

* `rotate`: Forces the video to be rotated by the specified degree integer. Currently, only multiples of `90` are supported. We automatically correct the orientation of many videos when the orientation is provided by the camera. This option is only useful for videos requiring rotation because it was not detected by the camera. If you set `rotate` to `false` no rotation is performed, even if the metadata contains such instructions.

* `hint`: Enables hinting for mp4 files, for RTP/RTSP streaming.

* `turbo`: Splits the video into multiple chunks so that each chunk can be encoded in parallel before all encoded chunks are stitched back together to form the result video. This comes at the expense of extra <dfn>Priority Job Slots</dfn> and may prove to be counter-productive for very small video files.

* `chunk_duration`: Allows you to specify the duration of each chunk when `turbo` is set to `true`. This means you can take advantage of that feature while using fewer <dfn>Priority Job Slots</dfn>. For instance, the longer each chunk is, the fewer <dfn>Encoding Jobs</dfn> will need to be used.

* `watermark_url`: A URL indicating a PNG image to be overlaid above this image. You can also [supply the watermark via another Assembly Step](/docs/topics/use-parameter.md#supplying-the-watermark-via-an-assembly-step).

* `watermark_position`: The position at which the watermark is placed.

  An array of possible values can also be specified, in which case one value will be selected at random, such as `[ "center", "left", "bottom-left", "bottom-right" ]`.

  This setting puts the watermark in the specified corner. To use a specific pixel offset for the watermark, you will need to add the padding to the image itself.

* `watermark_x_offset`: The x-offset in number of pixels at which the watermark will be placed in relation to the position it has due to `watermark_position`.

  Values can be both positive and negative and yield different results depending on the `watermark_position` parameter. Positive values move the watermark closer to the image's center point, whereas negative values move the watermark further away from the image's center point.

* `watermark_y_offset`: The y-offset in number of pixels at which the watermark will be placed in relation to the position it has due to `watermark_position`.

  Values can be both positive and negative and yield different results depending on the `watermark_position` parameter. Positive values move the watermark closer to the image's center point, whereas negative values move the watermark further away from the image's center point.

* `watermark_size`: The size of the watermark, as a percentage, such as `"50%"`. How the watermark is resized greatly depends on the `watermark_resize_strategy`.

* `watermark_resize_strategy`: To explain how the resize strategies work, let's assume our target video size is 800×800 pixels and our watermark image is 400×300 pixels. Let's also assume, the `watermark_size` parameter is set to `"25%"`.

  For the `"fit"` resize strategy, the watermark is scaled so that the longer side of the watermark takes up 25% of the corresponding video side. And the other side is scaled according to the aspect ratio of the watermark image. So with our watermark, the width is the longer side, and 25% of the video size would be 200px. Hence, the watermark would be resized to 200×150 pixels. If the `watermark_size` was set to `"50%"`", it would be resized to 400×300 pixels (so just left at its original size).

  For the `"stretch"` resize strategy, the watermark image is stretched (meaning, it is resized without keeping its aspect ratio in mind) so that both sides take up 25% of the corresponding video side. Since our video is 800×800 pixels, for a watermark size of 25% the watermark would be resized to 200×200 pixels. Its height would appear stretched, because keeping the aspect ratio in mind it would be resized to 200×150 pixels instead.

  For the `"area"` resize strategy, the watermark is resized (keeping its aspect ratio in check) so that it covers `"xx%"` of the video's surface area. The value from `watermark_size` is used for the percentage area size.

* `watermark_start_time`: The delay in seconds from the start of the video for the watermark to appear. By default the watermark is immediately shown.

* `watermark_duration`: The duration in seconds for the watermark to be shown. Can be used together with `watermark_start_time` to create nice effects. The default value is `-1.0`, which means that the watermark is shown for the entire duration of the video.

* `watermark_opacity`: The opacity of the watermark. Valid values are between `0` (invisible) and `1.0` (full visibility).

* `segment`: Splits the file into multiple parts, to be used for Apple's [HTTP Live Streaming](https://developer.apple.com/resources/http-streaming/).

* `segment_duration`: Specifies the length of each HTTP segment. This is optional, and the default value as recommended by Apple is `10`. Do not change this value unless you have a good reason.

* `segment_prefix`: The prefix used for the naming. For example, a prefix of `"segment_"` would produce files named `"segment_0.ts"`, `"segment_1.ts"` and so on. This is optional, and defaults to the base name of the input file. Also see the related `segment_name` parameter.

* `segment_name`: The name used for the final segment. Available variables are `${segment_prefix}`, `${segment_number}` and `${segment_id}` (which is a UUIDv4 without dashes).

* `segment_time_delta`: Delta to apply to segment duration. This is optional and allows fine-tuning of segment boundaries.

* `font_size`

* `font_color`

* `text_background_color`
