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

Canonical representation of a full ffmpeg command.

A command stores global options, ordered inputs, an optional filtergraph, and
ordered outputs. It is still just data until `FFix.to_argv/1`, `FFix.run/1`, or
another boundary function serializes it.

Prefer `FFix.command/3` for the function-based API. Use this module directly
when you want to construct or transform `%FFix.Command{}` values in smaller
steps.

## Examples

    input = FFix.Command.input("input.mp4", ss: "00:00:03", stream_loop: -1)
    video = input[:video]

    command =
      FFix.Command.new(
        global: [y: true],
        inputs: [input],
        outputs: [FFix.Command.output("out.mp4", video, vcodec: :copy)]
      )

    FFix.to_argv(command)
    #=> [
    #=>   "ffmpeg",
    #=>   "-y",
    #=>   "-ss",
    #=>   "00:00:03",
    #=>   "-stream_loop",
    #=>   "-1",
    #=>   "-i",
    #=>   "input.mp4",
    #=>   "-map",
    #=>   "0:v",
    #=>   "-vcodec",
    #=>   "copy",
    #=>   "out.mp4"
    #=> ]

Output option keys are rendered as ffmpeg CLI option names. For options with
stream specifiers, use an atom or string key that already contains the
specifier, for example `:"c:v"` or `"metadata:s:a:0"`.

# `global`

```elixir
@spec global(
  t(),
  keyword()
) :: t()
```

Appends global ffmpeg options to a command.

Global options are rendered before inputs:

    FFix.Command.new()
    |> FFix.Command.global(y: true, loglevel: :error)

# `new`

```elixir
@spec new() :: t()
```

Returns an empty command.

This is useful when building a command step by step with `global/2`,
`input/3`, `graph/2`, and `output/4`.

# `new`

```elixir
@spec new(keyword()) :: t()
```

Builds a command from already-normalized command data.

This lower-level constructor expects ordered input and output structs. For the
function callback API, use `FFix.command/3`.

    src = FFix.Command.input("input.mp4")

    FFix.Command.new(
      inputs: [src],
      outputs: [FFix.Command.output("out.mp4", src[:video], "c:v": :copy)]
    )

# `input`

```elixir
@spec input(FFix.Command.Input.source()) :: FFix.Command.Input.t()
```

Builds an input declaration.

Input options are rendered before `-i`:

    src = FFix.Command.input("input.mp4", ss: "00:00:03")
    src[:video]
    src[:audio]

Prefer shaping inputs in `FFix.command/3` rather than storing labels on the
input itself.

# `input`

```elixir
@spec input(
  FFix.Command.Input.source(),
  keyword()
) :: FFix.Command.Input.t()
@spec input(t(), FFix.Command.Input.source()) :: t()
```

Builds an input with options, or appends an input to a command.

Called as `input(source, options)`, it returns an `%FFix.Command.Input{}`:

    src = FFix.Command.input("input.mp4", ss: "00:00:03")

Called as `input(command, source)`, it appends an input without options and
returns the updated command:

    FFix.Command.new()
    |> FFix.Command.input("input.mp4")

# `input`

```elixir
@spec input(t(), FFix.Command.Input.source(), keyword()) :: t()
```

Appends an input declaration with options to a command.

    FFix.Command.new()
    |> FFix.Command.input("input.mp4", ss: "00:00:03")

# `graph`

```elixir
@spec graph(t(), FFix.Graph.t()) :: t()
```

Sets the filtergraph for a command.

# `output`

```elixir
@spec output(FFix.Command.Output.target(), source() | [source()]) ::
  FFix.Command.Output.t()
```

Builds an output declaration from explicit sources.

This is lower-level than `FFix.output/2`: pass graph exports, graph export names,
graph export indexes, or direct input streams explicitly.

    src = FFix.Command.input("input.mp4")
    FFix.Command.output("copy.mp4", [src[:video], src[:audio]], c: :copy)

Output options are rendered after `-map` entries and before the target.

# `output`

```elixir
@spec output(FFix.Command.Output.target(), source() | [source()], keyword()) ::
  FFix.Command.Output.t()
@spec output(t(), FFix.Command.Output.target(), source() | [source()]) :: t()
```

Builds an output with options, or appends an output to a command.

Called as `output(target, sources, options)`, it returns an
`%FFix.Command.Output{}`:

    FFix.Command.output("copy.mp4", [src[:video], src[:audio]], c: :copy)

Called as `output(command, target, sources)`, it appends an output without
options and returns the updated command.

# `output`

```elixir
@spec output(t(), FFix.Command.Output.target(), source() | [source()], keyword()) ::
  t()
```

Appends an output declaration with options to a command.

    FFix.Command.new()
    |> FFix.Command.input("input.mp4")
    |> FFix.Command.output("copy.mp4", 0, c: :copy)

# `validate!`

```elixir
@spec validate!(t()) :: t()
```

Validates command structure.

This checks declared inputs, graph references, output sources, and filtered
graph export mappings. It does not run ffmpeg or inspect media files.

# `to_argv`

```elixir
@spec to_argv(t()) :: [String.t()]
```

Serializes a command to ffmpeg argv.

The returned list is the canonical boundary for executing a command. Prefer it
over shell strings when passing argv to another process.

# `to_shell_string`

```elixir
@spec to_shell_string(t()) :: String.t()
```

Serializes a command as a shell-escaped string for logs and debugging.

# `option`

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

# `source`

```elixir
@type source() :: FFix.Graph.Export.t() | FFix.Stream.t() | atom() | non_neg_integer()
```

# `t`

```elixir
@type t() :: %FFix.Command{
  global_options: [option()],
  graph: FFix.Graph.t() | nil,
  inputs: [FFix.Command.Input.t()],
  outputs: [FFix.Command.Output.t()]
}
```

---

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