# Outputs

> Where the results go — the output folder, output feeds — and the videos, audio files and subtitle files written there.

`outputs` lists where the results go, its **destinations**, and each destination lists its
**items**: the files to produce there **for every input**.

```json
"outputs": [
  {
    "@type": "S3FolderOutput",
    "items": [
      {
        "@type": "VideoFile", "ext": "mp4", "nameTemplate": "${name}.es.${ext}",
        "useOriginalTracks": true, "dubTracks": [{ "language": "es" }]
      },
      { "@type": "SubtitleFile", "format": "SRT", "language": "es" }
    ]
  }
]
```

> **Note:**
> Every language in `translations` is produced and billed whether or not an output carries it. Give
> each translation subtitles somewhere, and each dub a dub track; a project whose outputs leave
> one out says so in [`meta.messages`](/vod-express/concepts/projects#messages).

## Destinations

| `@type` | Where | How many |
|---|---|---|
| `S3FolderOutput` | The project's output folder, `storage.outputPath`. | At most one. |
| `RssOutput` | A copy of the project's source RSS feed in one language, published at a public URL, its files under `output/feeds/<language>/`. Only in a project whose `sourceMedia` is an `RssSource`. | One per language. |
| `MrssOutput` | The same for a Media RSS feed. Only in a project whose `sourceMedia` is an `MrssSource`. | One per language. |

`GET /enums/destination-types` lists them. Every destination needs at least one item, and a
project at least one destination. Their locations are the API's: a `path` sent on any, or a
`mediaPath` or `mediaUrl` on a feed output, is refused.

### The output folder

```json
{ "@type": "S3FolderOutput", "items": [ … ] }
```

Each item is written at the root of `output/`, named by its `nameTemplate`, in the input's
subfolders. Download from there with `GET /projects/{id}/outputs/download` or the AWS CLI. Every
folder project has one; a feed project may have one too, beside its feeds.

### Output feeds

```json
{
  "@type": "MrssOutput",
  "language": "es",
  "items": [
    {
      "@type": "VideoFile", "ext": "mp4", "nameTemplate": "${name}.${ext}",
      "dubTracks": [{ "language": "es" }]
    }
  ]
}
```

Your source feed published again in `language` (the transcription language or a translation
language), each finished item linking the file it produced, at
`GET /feeds/{projectId}/{language}/feed.xml`, without a token: an `RssOutput` for an `RssSource`,
an `MrssOutput` for an `MrssSource`. Its items must include **exactly one** `VideoFile` or
`AudioFile`, the file each feed item links to; other items are written beside it and not linked
yet. The items are written under `output/feeds/<language>/` and the feed itself to `output/feeds/<language>.xml`,
so they are listed among the project's outputs with those paths. How the feed is made, and the
calls that serve it: [Feeds](/vod-express/concepts/inputs#the-output-feed).

## Items

Each item is one file per input, of one of three kinds:

| `@type` | Produces | Tracks |
|---|---|---|
| `VideoFile` | The input's video with the audio and subtitle tracks you choose | `useOriginalTracks`, `dubTracks`, `subTracks` |
| `AudioFile` | An audio file (MP3, M4A, WAV, …) with one audio track | `useOriginalTracks` or one `dubTracks` entry |
| `SubtitleFile` | A subtitle or transcript file (SRT, VTT, TXT, …) in one language | — |

## Names

Every item has a name template. Variables:

| Variable | Value | In |
|---|---|---|
| `${name}` | The input's name without its extension, subfolders included (`season 2/ep 01`) | all kinds |
| `${ext}` | The item's `ext` (or, for a subtitle file, its format in lower case) | all kinds |
| `${lang}` | The file's language | `SubtitleFile` |

Rules, checked when you save the project:

- a template contains `${name}`, so that inputs do not overwrite each other's outputs;
- it uses only the variables of its kind;
- no two items of one destination render the same name (two destinations may: their files are in
  different folders);
- a template is not blank (a blank `SubtitleFile` template means the default), and neither is `ext`
  or a subtitle file's `format`;
- the name it renders is a relative path under the destination's folder: a subfolder such as
  `dubbed/${name}.${ext}` is fine, but not a leading `/`, a doubled `//`, a `.` or `..` segment, a
  backslash or a control character. `ext` and `format` cannot hold `/` or `\` either.

## VideoFile

```json
{
  "@type": "VideoFile",
  "containerFormat": "mp4",
  "ext": "mp4",
  "nameTemplate": "${name}.dub.${ext}",
  "videoCodec": "copy",
  "useOriginalTracks": true,
  "dubTracks": [
    { "language": "es", "title": "Español" },
    { "language": "de", "title": "Deutsch" }
  ]
}
```

| Field | Default | |
|---|---|---|
| `ext` | required | The extension, `${ext}` in the template. |
| `nameTemplate` | required | See [Names](#names). |
| `containerFormat` | `"mp4"` | The ffmpeg muxer: `mp4`, or another such as `matroska` (with `ext: "mkv"`). |
| `videoCodec` | `"copy"` | `copy` keeps the input's video untouched, the fastest. Another ffmpeg encoder (`libx264`) re-encodes. |
| `useOriginalTracks` | `false` | `true` copies the input file's own audio into the file, as the first audio track. |
| `dubTracks` | none | The dubbed audio tracks, in order, after the input's audio. |
| `subTracks` | none | Subtitle streams muxed into the file. |

Without `useOriginalTracks` and `dubTracks`, the video has no sound.

Every field of every destination and item: [Config reference: `outputs`](/vod-express/configuration/reference#outputs).

### Audio tracks

`useOriginalTracks: true` copies the input file's audio as it is, without re-encoding it, with the
input's own language tag, title and default flag. It always comes first, before any dub track.

Each entry of `dubTracks` adds one dub:

```json
{ "language": "es", "title": "Español", "codec": "copy" }
```

| Field | Default | |
|---|---|---|
| `language` | required | The code of a **dubbed** translation (one with `ttsOptions`), written as in `translations`: `es`, `pt-BR`. |
| `title` | none | The track name players show in their audio menu: written as the track's title (MKV) and handler name (MP4, MOV). |
| `codec` | `"copy"` | `copy` keeps the dub's AAC. Another ffmpeg encoder, such as `libmp3lame`, re-encodes. |

Dub tracks carry no default flag, and a file cannot mark one as the track to play first. With
`useOriginalTracks: true`, a player opens the file on the input's audio, and the dubs are choices in
its audio menu. For a file that plays the dub when it opens, leave `useOriginalTracks` out.

The container's language tag of a dub track is set from `language`, so players label it. The
input's audio keeps the tag the input file carried, which may be missing or wrong: a file tagged
`eng` (a common default) dubbed into English gives two tracks a player labels the same. MP3 files
carry no language tag.

> **Warning:**
> **Known issue on every current build:** the input's audio (`useOriginalTracks`) keeps the input
> file's own language tag (or none), not the transcription language. Dub tracks carry their
> language and `title`. See the [Changelog](/vod-express/changelog#known-issues).

### Subtitle tracks

Selectable subtitles inside the file:

```json
"subTracks": [
  { "language": "en" },
  { "language": "es" }
]
```

| Field | Default | |
|---|---|---|
| `language` | required | The transcription language or a translation language. |
| `subtitleCodec` | `"mov_text"` | `mov_text` for MP4 and MOV; `subrip` or `ass` in Matroska, `webvtt` in WebM. |
| `options` | `{"speaker-label-replacement": ">>"}` | Caption layout options, an object. A track is rendered as SRT before it is muxed, so a `format` inside it can only be `SRT`. |

A subtitle track marks a change of speaker as a subtitle file does ([Speaker changes](#speaker-changes)).

## AudioFile

```json
{
  "@type": "AudioFile",
  "containerFormat": "mp3",
  "ext": "mp3",
  "nameTemplate": "${name}.es.${ext}",
  "dubTracks": [{ "language": "es", "codec": "libmp3lame" }]
}
```

| Field | Default | |
|---|---|---|
| `containerFormat` | required | The ffmpeg muxer: `mp3`, `ipod` (for `.m4a`), … |
| `ext` | required | |
| `nameTemplate` | required | |
| `useOriginalTracks` | `false` | `true` makes the input's audio the file's track. |
| `dubTracks` | none | One dub track, with the fields of a [video's dub track](#audio-tracks). |

An audio file holds exactly one audio track: set `useOriginalTracks: true` or list one dub track.
A file with neither, with both, or with two dubs is refused when you save the project.

The input's audio is copied as it is, AAC in most inputs, which an MP3 or WAV file cannot hold.
For the input's audio, use `ipod` (`.m4a`) or `matroska`.

Common formats:

| Format | `containerFormat` | `ext` | Track |
|---|---|---|---|
| M4A (AAC) | `ipod` | `m4a` | a dub track with `codec: "copy"`, or `useOriginalTracks: true` |
| MP3 | `mp3` | `mp3` | a dub track with `codec: "libmp3lame"` |

## SubtitleFile

```json
{ "@type": "SubtitleFile", "format": "SRT", "language": "es" }
```

| Field | Default | |
|---|---|---|
| `format` | required | `SRT`, `VTT`, `TXT`, … Also the file's extension, in lower case. |
| `language` | required | The transcription language or a translation language. |
| `nameTemplate` | `${name}.${lang}.${ext}` | `episode 01.es.srt` |
| `options` | `{"speaker-label-replacement": ">>"}` | Caption layout options, an object passed to the caption renderer as given. A `format` inside it must be left out or equal the entry's `format`. |

### Speaker changes

Where the speaker changes, a cue starts with `>>`, the broadcast convention; a cue that continues
the same speaker has no mark. The same holds for every transcription engine and for translated
subtitles. Set it in an entry's `options`, of a `SubtitleFile` or of a video's `subTracks` entry:

| `options` | Result |
|---|---|
| left out, or without the two keys below | `>> Good morning and welcome…` |
| `{"speaker-label-replacement": "-"}` | `- Good morning and welcome…`: any text in place of `>>` |
| `{"collapse-speaker-labels": true}` | `Good morning and welcome…`: no speaker marks |

## One input, many outputs

Items are independent. This project writes, for each input, a dubbed video, a Spanish MP3 and a
Spanish M4A into its output folder:

```json
"outputs": [
  {
    "@type": "S3FolderOutput",
    "items": [
      {
        "@type": "VideoFile", "ext": "mp4", "nameTemplate": "${name}.es.${ext}",
        "useOriginalTracks": true, "dubTracks": [{ "language": "es" }]
      },
      {
        "@type": "AudioFile", "containerFormat": "mp3", "ext": "mp3", "nameTemplate": "${name}.es.${ext}",
        "dubTracks": [{ "language": "es", "codec": "libmp3lame" }]
      },
      {
        "@type": "AudioFile", "containerFormat": "ipod", "ext": "m4a", "nameTemplate": "${name}.es.${ext}",
        "dubTracks": [{ "language": "es" }]
      }
    ]
  }
]
```

A feed project can write to the output folder and publish feeds at once. This one dubs into
Spanish and German, keeps an MP4 of each item with its own audio and both dubs in the output
folder, and publishes a Spanish and a German feed:

```json
"outputs": [
  {
    "@type": "S3FolderOutput",
    "items": [
      {
        "@type": "VideoFile", "ext": "mp4", "nameTemplate": "${name}.dub.${ext}",
        "useOriginalTracks": true, "dubTracks": [{ "language": "es" }, { "language": "de" }]
      }
    ]
  },
  {
    "@type": "MrssOutput",
    "language": "es",
    "items": [
      { "@type": "VideoFile", "ext": "mp4", "nameTemplate": "${name}.${ext}", "dubTracks": [{ "language": "es" }] }
    ]
  },
  {
    "@type": "MrssOutput",
    "language": "de",
    "items": [
      { "@type": "VideoFile", "ext": "mp4", "nameTemplate": "${name}.${ext}", "dubTracks": [{ "language": "de" }] }
    ]
  }
]
```

For an item named `4f1c2b9a7d3e.8a2b4c6d.mp4` it writes `4f1c2b9a7d3e.8a2b4c6d.dub.mp4`,
`feeds/es/4f1c2b9a7d3e.8a2b4c6d.mp4` and `feeds/de/4f1c2b9a7d3e.8a2b4c6d.mp4` under `output/`.
