# `FFix.Command.Output`
[🔗](https://github.com/akash-akya/ffix/blob/v0.2.0/lib/ffix/command/output.ex#L1)

Choose the streams, encoding, and destination for one output.

Create outputs with `FFix.output/3`, `new/3`, or a `FFix.Muxer` helper. Pass
them to `FFix.command/2` to assemble the invocation.

    source = FFix.input("interview.mp4")

    output =
      FFix.output(
        [FFix.video(source, 0), FFix.audio(source, 0)],
        "excerpt.mp4",
        t: 30
      )

The source list determines mapping order. Bare streams use FFmpeg's default
encoders; `FFix.Encoder` and `FFix.stream_copy/1` choose encoding explicitly.
General output options, such as `t`, apply to this destination. See
`FFix.Command.Mapping` for encoding several tracks and `FFix.Muxer` for
container options.

## Named mappings and callbacks

Some FFmpeg options refer to output-stream positions. Give mappings names
and use an option callback to build those references from the final order.
This is useful for an HLS master playlist with two video renditions sharing
one audio rendition:

    alias FFix.{Encoder, Filter, Muxer}
    source = FFix.input("interview.mp4")
    [high, low] = source |> FFix.video(0) |> Filter.fps(fps: 24) |> Filter.split(outputs: 2)

    high = high |> Filter.scale(w: -2, h: 720) |> Encoder.libx264(b: "1800k", g: 48)
    low = low |> Filter.scale(w: -2, h: 360) |> Encoder.libx264(b: "600k", g: 48)
    sound = Encoder.aac(FFix.audio(source, 0), b: "128k")

    output =
      Muxer.hls([high: high, low: low, sound: sound], "hls/%v.m3u8",
        hls_time: 4,
        master_pl_name: "master.m3u8",
        var_stream_map: fn streams ->
          Enum.join([
            "#{streams.high.specifier},agroup:audio,name:720p",
            "#{streams.low.specifier},agroup:audio,name:360p",
            "#{streams.sound.specifier},agroup:audio,name:audio,default:yes"
          ], " ")
        end
      )

    FFix.command(output)

Create the `hls` directory before executing. The callback receives:

    %{
      high: %{index: 0, specifier: "v:0"},
      low: %{index: 1, specifier: "v:1"},
      sound: %{index: 2, specifier: "a:0"}
    }

`index` counts every output stream. `specifier` counts within its media type.
Reordering the mappings updates these values automatically. Counts restart
for each output, and names must be unique atoms within that output. Unnamed
mappings count toward positions but have no entry in the callback map.

Callbacks are accepted as encoder, muxer, and general output option values.
Every mapping in that output must identify one required stream of known media
so the positions can be calculated. Use indexed media selections or filter
outputs rather than `:all`, optional selections, or raw queries.

> #### Keep callbacks repeatable {: .tip}
> Each option callback runs once per serialization. Inspecting a command and
> then executing it calls the callbacks twice. Keep them free of side effects.

Callback results undergo normal option-value checks. They must be values,
rather than another callback. Missing names raise `KeyError`; exceptions from
your callback propagate to the caller. Construction and `FFix.validate!/1`
check the layout while leaving callbacks unevaluated.

See the [HLS muxer reference](https://ffmpeg.org/ffmpeg-formats.html#hls-2)
for playlist and rendition options.

# `option`

```elixir
@type option() :: {atom() | String.t(), term()}
```

# `t`

```elixir
@type t() :: %FFix.Command.Output{
  mappings: [FFix.Command.Mapping.t()],
  muxer: FFix.Muxer.t() | nil,
  options: [option()],
  target: target()
}
```

# `target`

```elixir
@type target() ::
  String.t() | :stdout | {:pipe, non_neg_integer()} | {:url, String.t()}
```

# `new`

```elixir
@spec new(FFix.Command.binding() | [FFix.Command.binding()], target(), [option()]) ::
  t()
```

Declares an output from a source or ordered source list, a target, and options.

    FFix.Command.Output.new([main: video, sound: audio], "interview.mp4", t: 30)

Sources may be stream references, selections, or configured mappings. For
explicit low-level commands, graph export handles are also accepted; see
`FFix.Command.new/1`.

Targets can be path/URL strings, `{:url, url}`, `:stdout`, or `{:pipe, descriptor}`.
The `muxer:` option accepts a `FFix.Muxer` configuration. Remaining options are
general FFmpeg output controls; see `FFix.Command` for option syntax.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
