> ## Documentation Index
> Fetch the complete documentation index at: https://docs.livepeer.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Video & Transcoding Pipelines

> How video jobs flow through your gateway - RTMP and HTTP ingest, source segmentation, orchestrator selection via BroadcastSessionsManager, transcoding profiles, on-chain payment per segment, and output delivery as HLS.

export const TableCell = ({children, align = "left", header = false, style = {}, className = "", ...rest}) => {
  const Component = header ? "th" : "td";
  return <Component className={className} style={{
    padding: "0.75rem 1rem",
    textAlign: align,
    border: header ? "none" : "1px solid var(--lp-color-border-default)",
    ...style
  }} {...rest}>
      {children}
    </Component>;
};

export const TableRow = ({children, header = false, hover = false, style = {}, className = "", ...rest}) => {
  const rowId = `table-row-${Math.random().toString(36).substr(2, 9)}`;
  return <>
      {hover && <style>{`
          #${rowId}:hover {
            background-color: var(--lp-color-bg-card);
          }
        `}</style>}
      <tr id={rowId} className={className} style={{
    ...header && ({
      backgroundColor: "var(--lp-color-accent-strong)",
      color: "var(--lp-color-on-accent)",
      fontWeight: "bold"
    }),
    ...style
  }} {...rest}>
        {children}
      </tr>
    </>;
};

export const StyledTable = ({children, variant = "default", style = {}, className = "", ...rest}) => {
  const wrapperVariants = {
    default: {
      border: "1px solid var(--lp-color-border-default)",
      backgroundColor: "var(--lp-color-bg-card)",
      overflow: "hidden"
    },
    bordered: {
      border: "2px solid var(--lp-color-accent)",
      backgroundColor: "var(--lp-color-bg-page)",
      overflow: "hidden"
    },
    minimal: {
      border: "none",
      backgroundColor: "transparent",
      overflow: "visible"
    }
  };
  return <div data-docs-styled-table-shell className={className} style={{
    width: "100%",
    padding: 0,
    margin: 0,
    ...wrapperVariants[variant],
    ...style
  }} {...rest}>
      <table data-docs-styled-table style={{
    width: "100%",
    borderCollapse: "collapse",
    borderSpacing: 0,
    margin: 0,
    backgroundColor: "transparent"
  }}>
        {children}
      </table>
    </div>;
};

export const CustomDivider = ({color = "var(--lp-color-border-default)", middleText = "", spacing = "default", style = {}, className = "", ...rest}) => {
  const spacingPresets = {
    default: {
      margin: "24px 0"
    },
    overlap: {
      margin: "-1rem 0 -1rem 0"
    },
    tight: {
      margin: "0 0 -1rem 0"
    },
    section: {
      margin: "0 0 -2rem 0"
    },
    sectionOverlap: {
      margin: "-1rem 0 -2rem 0"
    },
    deepOverlap: {
      margin: "-1rem 0 -1.5rem 0"
    }
  };
  const spacingStyle = spacingPresets[spacing] || spacingPresets.default;
  return <div role="separator" aria-orientation="horizontal" className={className} style={{
    display: "flex",
    alignItems: "center",
    ...spacingStyle,
    fontSize: style?.fontSize || "16px",
    height: "fit-content",
    ...style
  }} {...rest}>
      <span style={{
    marginRight: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
      </span>
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      {middleText && <>
          <Icon icon="circle" size={2} />
          <span style={{
    margin: "0 8px",
    fontWeight: "bold",
    color: color,
    opacity: 0.7
  }}>
            {middleText}
          </span>
          <Icon icon="circle" size={2} />
        </>}
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      <span style={{
    marginLeft: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <span style={{
    display: "inline-block",
    transform: "scaleX(-1)"
  }}>
          <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
        </span>
      </span>
    </div>;
};

<Note>
  This is a conceptual and tuning guide, not a setup guide. For initial installation and startup, see Setup. For transcoding profile JSON and flag reference, see Pipeline Configuration.
</Note>

<CustomDivider style={{margin: "-1rem 0 -1rem 0"}} />

The video transcoding pipeline moves a stream from ingest to playback-ready [HLS](https://en.wikipedia.org/wiki/HTTP_Live_Streaming) in three stages:

1. The Gateway segments incoming video,
2. Dispatches each segment to a selected Orchestrator with a payment ticket, and
3. Assembles the transcoded renditions for delivery.

What happens at each stage and how to tune it.

<Warning>
  Video transcoding requires **on-chain operational mode** in production. Remote signers (off-chain mode) do not support video because ticket signing must happen in the hot path per segment. Off-chain video with `-network offchain` is available for local development and testing with a local Orchestrator only.
</Warning>

## Architecture

```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#18794E', 'primaryTextColor': '#fff', 'primaryBorderColor': '#3CB540', 'lineColor': '#3CB540', 'mainBkg': '#18794E', 'nodeBorder': '#3CB540', 'clusterBkg': 'transparent', 'clusterBorder': '#3CB540', 'titleColor': '#3CB540', 'edgeLabelBackground': 'transparent', 'textColor': '#3CB540', 'nodeTextColor': '#fff'}}}%%
flowchart TB
    subgraph INPUT["Video Input"]
        direction LR
        RTMP["RTMP Stream\n:1935"]
        HTTP["HTTP Upload\n:8935"]
    end

    GW["Gateway Node\n-gateway mode"]
    INPUT --> GW

    subgraph SESSION["BroadcastSessionsManager"]
        BSM["Select orchestrators\nby price, latency, capability"]
    end

    GW --> BSM

    subgraph PROC["Processing Pipeline"]
        direction TB
        SEG["Segment source video\n(per GOP or fixed interval)"]
        PAY["Generate payment ticket\n(per segment, wei per pixel)"]
        ORCH["Orchestrators\nTranscode each segment"]
        RCV["Receive transcoded segments\nVerify quality"]
    end

    BSM --> SEG --> PAY --> ORCH --> RCV

    subgraph OUT["Output and Delivery"]
        direction LR
        HLS["HLS Manifest\n.m3u8"]
        REND["Renditions\n240p / 360p / 720p / 1080p"]
    end

    RCV --> HLS --> REND

    subgraph STORE["Storage (optional)"]
        OBJ["Object store\nS3 / IPFS"]
    end
    REND -.-> OBJ

    classDef default fill:#1a1a1a,color:#fff,stroke:#2d9a67,stroke-width:2px
    classDef video fill:#1a1a1a,color:#fff,stroke:#3b82f6,stroke-width:2px
    classDef payment fill:#1a1a1a,color:#fff,stroke:#fbbf24,stroke-width:2px
    class RTMP,HTTP,BSM,SEG,ORCH,RCV,HLS,REND video
    class PAY payment
    style INPUT fill:#0d0d0d,stroke:#2d9a67,stroke-width:1px
    style SESSION fill:#0d0d0d,stroke:#3b82f6,stroke-width:1px
    style PROC fill:#0d0d0d,stroke:#3b82f6,stroke-width:1px
    style OUT fill:#0d0d0d,stroke:#3b82f6,stroke-width:1px
    style PAYMENT fill:#0d0d0d,stroke:#fbbf24,stroke-width:1px
    style STORE fill:#0d0d0d,stroke:#2d9a67,stroke-width:1px,stroke-dasharray: 5 5
```

<Card title="Source reference: BroadcastSessionsManager" icon="github" href="https://github.com/livepeer/go-livepeer/blob/master/core/broadcast.go" horizontal arrow>
  go-livepeer/core/broadcast.go
</Card>

## Ingest

The Gateway accepts incoming video through two protocols. Which one you use depends on your publishing client.

<Tabs>
  <Tab title="RTMP (live streaming)" icon="video">
    RTMP is the standard ingest protocol for live streaming. Encoders such as OBS, FFmpeg, and hardware encoders push streams to the Gateway's RTMP server.

    **Default listen address:** `127.0.0.1:1935`

    To accept external connections, bind to all interfaces:

    ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    -rtmpAddr 0.0.0.0:1935
    ```

    The ingest URL format is:

    ```icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    rtmp://<gateway-host>:1935/<stream-key>
    ```

    The Gateway reads the incoming RTMP stream, extracts GOP (Group of Pictures) boundaries, and slices the video into segments for distribution.
  </Tab>

  <Tab title="HTTP (segment push)" icon="upload">
    HTTP ingest accepts video segments pushed directly over HTTP. This is the path used when integrating programmatically, pushing pre-segmented content via the Livepeer SDK, or uploading VOD (video-on-demand) files for transcoding.

    **Default listen address:** `127.0.0.1:8935`

    To accept external connections:

    ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    -httpAddr 0.0.0.0:8935
    ```

    The Gateway processes uploaded segments with the same transcoding logic as RTMP-ingest segments. For VOD uploads, the Gateway transcodes the entire file and produces HLS output.
  </Tab>
</Tabs>

## Orchestrator Selection

Once the stream is ingested, the `BroadcastSessionsManager` selects which Orchestrators will transcode each segment. Selection is not random - the manager evaluates Orchestrators against multiple criteria simultaneously.

<AccordionGroup>
  <Accordion title="Price ceiling" icon="tag">
    The `-maxPricePerUnit` flag sets the maximum number of wei per pixel your Gateway will pay. Orchestrators advertising prices above this ceiling are excluded. Setting this too low will result in no available Orchestrators; setting it too high means you may overpay.

    The unit of measurement is wei per pixel. A common starting value for production is `1000` wei per pixel, though competitive market rates vary. Use the Livepeer Explorer and `livepeer_cli` to see what Orchestrators are currently advertising.
  </Accordion>

  <Accordion title="Latency and performance" icon="gauge">
    The manager tracks round-trip latency and success rate for each Orchestrator per session. Orchestrators with degraded latency or high failure rates are deprioritised. This is entirely automatic - you do not need to configure individual Orchestrator scoring.
  </Accordion>

  <Accordion title="Session continuity" icon="arrows-rotate">
    Transcoding sessions are maintained across segments. If an Orchestrator fails mid-stream (network drop, timeout, GPU OOM), the manager performs a mid-stream swap: it selects the next best Orchestrator and continues from the next segment. The output is seamless to the viewer because the renditions continue - there is no restart.

    The `livepeer_orchestrator_swaps` Prometheus metric tracks swap frequency. A high swap rate indicates Orchestrator instability or an overly aggressive price ceiling.
  </Accordion>

  <Accordion title="Discovery methods" icon="network-wired">
    **On-chain (production):** the Gateway queries the Livepeer on-chain registry (Arbitrum One) for registered Orchestrators that meet your price ceiling. Discovery is automatic; you do not need to list addresses manually.

    **Direct configuration:** specify Orchestrators directly via `-orchAddr` as a comma-separated list. The Gateway connects to exactly those addresses. Most production Gateways with established Orchestrator relationships use this pattern.

    **Webhook:** use `-orchWebhookUrl` for dynamic Orchestrator lists from an external service.

    ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    # On-chain: registry discovery (set network and ETH credentials)
    -network arbitrum-one-mainnet

    # Direct: specific orchestrator addresses
    -orchAddr http://192.168.1.100:8935,http://192.168.1.101:8935
    ```
  </Accordion>
</AccordionGroup>

## Transcoding

Each segment is sent to the selected Orchestrator along with a payment ticket. The Orchestrator transcodes the segment into the renditions your profile specifies and returns them to the Gateway.

The Gateway verifies each returned segment before assembling the output using pixel count and signature verification (`-localVerify=true`, enabled by default for on-chain Gateways). If a segment fails verification (wrong duration, corrupt data, wrong resolution), the manager retries with a different Orchestrator up to `-maxAttempts` times (default: 3).

[//]: # "REVIEW: Confirm whether -localVerify defaults to false for off-chain mode."

### Built-in rendition presets

If you do not specify a custom transcoding profile, the Gateway uses a comma-separated list of named presets:

```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
-transcodingOptions P240p30fps16x9,P360p30fps16x9
```

Available built-in presets follow the pattern `P<height>p<fps>fps<aspect>`. Common values: `P240p30fps16x9`, `P360p30fps16x9`, `P720p30fps16x9`, `P1080p30fps16x9`.

### Custom JSON profiles

For production deployments, a custom `transcodingOptions.json` file gives you precise control over the encoding ladder. The full JSON format and per-platform setup are in the Pipeline Configuration page.

```json icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
  {
    "name": "720p",
    "width": 1280,
    "height": 720,
    "bitrate": 3000000,
    "fps": 0,
    "profile": "h264constrainedhigh",
    "gop": "1"
  },
  {
    "name": "480p",
    "width": 854,
    "height": 480,
    "bitrate": 1600000,
    "fps": 0,
    "profile": "h264constrainedhigh",
    "gop": "1"
  }
]
```

Reference this file at startup:

```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
-transcodingOptions /path/to/transcodingOptions.json
```

## Payment Flow

On-chain video Gateways use Livepeer's [probabilistic micropayment (PM) system](../payments-and-pricing/payment-guide). Every segment sent to an Orchestrator carries a payment ticket. Most tickets are losing lottery draws; winning tickets are redeemed on the Arbitrum One TicketBroker contract against your ETH deposit.

<Warning>
  You must have a non-zero ETH deposit and reserve on the TicketBroker contract before your Gateway can route video jobs on-chain. Orchestrators will reject jobs from a Gateway with an empty deposit. See Fund Your Gateway for the deposit steps.
</Warning>

The per-segment cost depends on two factors:

* **Pixels transcoded:** width × height × number of renditions
* **Price per pixel:** the Orchestrator's advertised rate in wei per pixel

**Example cost estimate:**

A 720p segment (1280 × 720 pixels) transcoded to three renditions (720p, 480p, 240p) at 1000 wei/pixel:

```icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Total pixels per segment = (1280×720) + (854×480) + (426×240)
                         = 921,600 + 409,920 + 102,240
                         = 1,433,760 pixels

Cost per segment = 1,433,760 × 1000 wei = 1.43376 × 10⁹ wei = ~0.0000014 ETH
```

[//]: # "REVIEW: Confirm the default segment duration and whether operators can configure it directly."

For a 1-hour stream with 2-second segments (1800 segments):

```icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
1800 × 1.43376 × 10⁹ wei ≈ 2.58 × 10¹² wei ≈ 0.00258 ETH
```

Monitor your deposit balance via `livepeer_cli → Option 1` or the `livepeer_gateway_deposit` Prometheus metric. Top up before the deposit approaches zero.

## Output

The Gateway assembles transcoded segments into an HLS manifest (`.m3u8`) with one variant stream per rendition. Your application or CDN pulls this manifest to serve adaptive bitrate playback. Low-Latency HLS (LL-HLS) is also supported for reduced end-to-end latency.

**HLS manifest endpoint:** `http://<gateway-host>:8935/<stream-key>.m3u8`

**Current manifest shortcut:** if `-currentManifest` is enabled, the most recently active stream is accessible at `/stream/current.m3u8` - useful for single-stream setups.

For persistent storage, the `-objectStore` flag pushes segments and manifests to an S3-compatible bucket or IPFS, so streams survive a Gateway restart.

[//]: # "REVIEW: Confirm LL-HLS configuration details and whether DASH output is supported."

## Key Metrics

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>Metric</TableCell>
      <TableCell header>What it tells you</TableCell>
      <TableCell header>Action threshold</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>`livepeer_success_rate`</TableCell>
      <TableCell>Transcoded segments / source segments</TableCell>
      <TableCell>Alert when below 0.95</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>`livepeer_transcode_overall_latency_seconds`</TableCell>
      <TableCell>End-to-end transcoding latency</TableCell>
      <TableCell>Alert when p95 exceeds 5s</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>`livepeer_segment_transcode_failed_total`</TableCell>
      <TableCell>Failed transcode count</TableCell>
      <TableCell>Alert on rate increase</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>`livepeer_orchestrator_swaps`</TableCell>
      <TableCell>Mid-stream Orchestrator changes</TableCell>
      <TableCell>Investigate above 1 per 10 minutes</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>`livepeer_gateway_deposit`</TableCell>
      <TableCell>Remaining ETH deposit (wei)</TableCell>
      <TableCell>Alert when below 0.01 ETH</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>`livepeer_ticket_value_sent`</TableCell>
      <TableCell>ETH being spent on tickets</TableCell>
      <TableCell>Budget monitoring</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>`livepeer_fast_verification_done`</TableCell>
      <TableCell>Successful segment verifications</TableCell>
      <TableCell>Compare against failed count</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>`livepeer_fast_verification_failed`</TableCell>
      <TableCell>Failed segment verifications</TableCell>
      <TableCell>Alert on any sustained failures</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

For Prometheus setup and alert YAML, see Monitoring Setup.

## Pipeline Tuning

<AccordionGroup>
  <Accordion title="Increasing orchestrator availability" icon="plus">
    If jobs are failing because no Orchestrators are available under your price ceiling, either raise `-maxPricePerUnit` or use on-chain mode for access to the full Orchestrator pool. Use `livepeer_cli` to see available Orchestrators and their advertised rates.
  </Accordion>

  <Accordion title="Reducing latency" icon="clock">
    Lower GOP size in your transcoding profile reduces segment duration and therefore end-to-end latency. Set `"gop": "1"` for keyframe-aligned segments. Use a lower `-maxAttempts` value if retries on failed Orchestrators are adding unacceptable delay - but ensure you have redundant Orchestrators before reducing retry tolerance.
  </Accordion>

  <Accordion title="Concurrent streams" icon="list">
    The `-maxSessions` flag (default: 10) caps concurrent active streams. Increase it for high-throughput deployments. The Gateway does not enforce per-stream quality independently - all streams share the Orchestrator pool you have connected.
  </Accordion>

  <Accordion title="Ingest authentication" icon="lock">
    Use `-authWebhookUrl` to point to an HTTPS endpoint that validates stream keys before the Gateway begins transcoding. The webhook receives the stream key and returns allow/deny. This prevents unauthorised streams from consuming your Orchestrator budget.
  </Accordion>
</AccordionGroup>

## Related Resources

<CardGroup cols={2}>
  <Card title="Pipelines Guide" icon="compass" href="/v2/gateways/guides/node-pipelines/guide">
    All pipeline types, node types, and Orchestrator discovery patterns.
  </Card>

  <Card title="Pipeline Configuration" icon="sliders" href="/v2/gateways/guides/node-pipelines/pipeline-configuration">
    Full JSON transcoding profile reference, per-platform setup (Docker, Linux, Windows), and AI routing parameters.
  </Card>

  <Card title="Pricing Strategy" icon="tag" href="/v2/gateways/guides/payments-and-pricing/pricing-strategy">
    How to set -maxPricePerUnit, estimate costs, and position competitively against Orchestrator rates.
  </Card>

  <Card title="Monitoring Setup" icon="chart-line" href="/v2/gateways/guides/monitoring-and-tooling/monitoring-setup">
    Prometheus metrics, Grafana dashboards, and alert configuration for video workloads.
  </Card>

  <Card title="AI Inference Pipeline" icon="brain" href="/v2/gateways/guides/node-pipelines/ai-pipelines">
    How AI inference requests are routed - Orchestrator discovery, model matching, pipeline types, and platform limits.
  </Card>

  <Card title="BYOC" icon="cube" href="/v2/developers/build/byoc">
    How to build and implement BYOC Pipelines and Workloads.
  </Card>
</CardGroup>

{/*
PURPOSE:
Journey step: "How do video jobs flow through my gateway?"
Gateway-side video pipeline guide. NOT a setup guide (that's in Setup → Configuration).
This is "understand and tune your video pipeline" - how data flows, what happens at
each stage, how to configure transcoding profiles, and how to optimise.

SECTION HOME: Guides → AI and Job Pipelines

JOURNEY POSITION:
1. Pipeline Overview - "What workloads can my gateway route?"
2. Video Transcoding Pipeline (this page) - "How do video jobs flow?"
3. AI Inference Pipeline - "How do AI jobs flow?"
4. BYOC Pipelines - "Custom containers on the network"
5. Pipeline Configuration - "Configure transcoding profiles and AI routing"

RELATED FILES (draw from):
- all-resources/ctx-new--video-configuration.mdx           - PRIMARY (90%): 745 lines. Comprehensive video config with Mermaid architecture diagram, essential flags, transcoding options JSON, Docker/CLI/binary examples, production considerations.
- all-resources/v1--transcoding-options.mdx                 - PRIMARY (80%): 93 lines. V1 transcoding config guide: JSON template, platform-specific instructions (Docker, Linux, Windows).
- all-resources/v2-setup--transcoding-options.mdx            - PRIMARY (80%): 109 lines. V2 copy of transcoding options with platform-specific config.
- all-resources/ctx-new--video-configuration-view.mdx       - SECONDARY (30%): 193 lines. Tabbed view alternative with Mermaid diagram, quickstart, config flags.
- all-resources/v2-run--video-configuration.mdx              - SECONDARY (40%): Run-a-gateway video configuration (if different from _contextData_ version).
- all-resources/v2-run--transcoding.mdx                      - Placeholder (5%): 38 lines. Reserved page, planned structure only.

CROSS-REFS:
- Setup → Video Configuration - initial setup vs this guide's "how it works and how to tune"
- Payments & Pricing → Pricing Strategy - per-pixel pricing for video transcoding
- Monitoring → Health Checks - video pipeline health verification
- Resources → Configuration Flags - full flag reference for video flags
- Resources → Prometheus Metrics - video-specific metrics (success_rate, transcode_latency)
*/}
