> ## 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.

# LPMS

> Livepeer Media Server (LPMS): the embeddable Go library for RTMP ingest, HLS output, and GPU-accelerated transcoding.

export const CenteredContainer = ({children, maxWidth = "800px", padding = "0", preset = "default", width = "", minWidth = "", marginRight = "", marginBottom = "", textAlign = "", style = {}, className = "", ...rest}) => {
  const presets = {
    default: {},
    fitContent: {
      width: "fit-content",
      minWidth: "fit-content"
    },
    readable70: {
      width: "70%",
      minWidth: "fit-content"
    },
    readable80: {
      width: "80%",
      minWidth: "fit-content"
    },
    readable90: {
      width: "90%"
    },
    wide900: {
      maxWidth: "900px"
    }
  };
  const presetStyle = presets[preset] || presets.default;
  return <div className={className} style={{
    maxWidth: presetStyle.maxWidth || maxWidth,
    margin: "0 auto",
    padding: padding,
    ...presetStyle.width ? {
      width: presetStyle.width
    } : {},
    ...presetStyle.minWidth ? {
      minWidth: presetStyle.minWidth
    } : {},
    ...width ? {
      width
    } : {},
    ...minWidth ? {
      minWidth
    } : {},
    ...marginRight ? {
      marginRight
    } : {},
    ...marginBottom ? {
      marginBottom
    } : {},
    ...textAlign ? {
      textAlign
    } : {},
    ...style
  }} {...rest}>
      {children}
    </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>;
};

export const LinkArrow = ({href, label, description, newline = true, borderColor, className = '', style = {}, ...rest}) => {
  const linkArrowStyle = {
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: "var(--lp-spacing-1)",
    width: 'fit-content',
    ...borderColor && ({
      borderColor
    })
  };
  return <span className={className} style={style} {...rest}>
      {newline && <br />}
      <span style={linkArrowStyle}>
        <a href={href} target="_blank" rel="noopener noreferrer">
          {label}
        </a>
        <Icon icon="arrow-up-right" size={14} color="var(--lp-color-accent)" />
      </span>
      {description && description}
      {description && <div style={{
    height: "var(--lp-spacing-3)"
  }} />}
    </span>;
};

<CenteredContainer preset="readable90">
  <Tip>LPMS is the media server component embedded in go-livepeer. Use it in your own Go applications when you need RTMP-in, HLS-out transcoding without running the full protocol node.</Tip>
</CenteredContainer>

***

LPMS (`livepeer/lpms`) is a Go library providing RTMP ingest, HLS output, and FFmpeg-backed transcoding. It is the core media handling layer inside go-livepeer's broadcaster node and is available independently for Go applications that need media server functionality.

LPMS can run as a standalone binary for testing or be imported as a library into a larger Go application.

<CustomDivider />

## Building LPMS

LPMS requires libavcodec (FFmpeg) and related libraries. The `install_ffmpeg.sh` script installs all dependencies to `~/compiled`:

```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
git clone https://github.com/livepeer/lpms.git
cd lpms
bash install_ffmpeg.sh
export PKG_CONFIG_PATH=~/compiled/lib/pkgconfig:$PKG_CONFIG_PATH
go build ./...
```

For NVIDIA GPU support, a Pascal or later GPU and the NVIDIA CUDA toolkit are required. The build system detects GPU capability automatically when CUDA is on the path.

<CustomDivider />

## Default Endpoints

The test LPMS server exposes:

| Endpoint                                           | Purpose                         |
| -------------------------------------------------- | ------------------------------- |
| `rtmp://localhost:1935/stream/<id>`                | RTMP ingest: push a stream here |
| `http://localhost:7935/stream/<id>.m3u8`           | HLS playback                    |
| `http://localhost:7935/stream/<id>/<profile>.m3u8` | Specific rendition              |

Run the test server:

```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
go build cmd/main.go
./main
```

Push a test stream with FFmpeg:

```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
ffmpeg -f avfoundation -framerate 30 -i "0:0" \
  -c:v libx264 -tune zerolatency -b:v 900k \
  -x264-params keyint=60:min-keyint=60 \
  -c:a aac -ac 2 -ar 44100 \
  -f flv rtmp://localhost:1935/stream/test
```

Play back from the HLS endpoint:

```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
ffplay http://localhost:7935/stream/test.m3u8
```

<CustomDivider />

## Embedding LPMS

Import LPMS and configure `LPMSOpts`:

```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main

import (
    "github.com/livepeer/lpms/lpms"
    "net/url"
)

func main() {
    opts := lpms.LPMSOpts{
        RtmpAddr: "127.0.0.1:1935",
        HttpAddr: "127.0.0.1:7935",
        WorkDir:  "/tmp/lpms",
    }

    server := lpms.New(&opts)

    server.HandleRTMPPublish(
        // getStreamID: extract stream ID from the ingest URL
        func(url *url.URL) (string, error) {
            return getStreamIDFromPath(url.Path), nil
        },
        // onPublish: called when RTMP stream begins
        func(url *url.URL, rtmpStrm interface{}) error {
            return nil
        },
        // onFinish: called when RTMP stream ends
        func(url *url.URL, rtmpStrm interface{}) error {
            return nil
        },
    )

    server.HandleRTMPPlay(
        func(ctx context.Context, reqPath string, dst interface{}) error {
            streamID := getStreamIDFromPath(reqPath)
            return server.GetRTMPStream(streamID, dst)
        },
    )

    server.Start(context.Background())
}
```

See `core/lpms.go` for the full `LPMSOpts` fields including segment duration, manifest window size, and GOP configuration.

<CustomDivider />

## GPU Transcoding

LPMS exposes a GPU transcoding API using NVENC (encoding) and NVDEC (decoding) via FFmpeg's hardware acceleration path. Select the processing mode and GPU device at runtime:

```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Software transcoding
err := transcoder.Transcode(
    &TranscodeOptionsIn{Fname: "input.ts"},
    []TranscodeOptions{{Oname: "output_720p.ts", Profile: P720p30fps16x9}},
)

// NVIDIA GPU device 0
err := transcoder.Transcode(
    &TranscodeOptionsIn{Fname: "input.ts", Accel: Nvidia, Device: "0"},
    []TranscodeOptions{{Oname: "output_720p.ts", Profile: P720p30fps16x9}},
)
```

The `cmd/transcoding/transcoding.go` sample program demonstrates GPU selection via CLI flags and is the reference implementation for testing NVIDIA processing in an LPMS environment.

<Note>
  LPMS is the media layer embedded in go-livepeer. For the full Livepeer Protocol with Orchestrator discovery, Probabilistic Micropayments, and network routing, run go-livepeer in broadcaster mode instead of using LPMS directly.
</Note>

<CustomDivider />

## Related Pages

<CardGroup cols={2}>
  <Card title="Transcoding" icon="cpu" href="/v2/developers/build/video/transcoding-direct-quickstart" arrow horizontal>
    Segment submission API and transcoding profile configuration for the broadcaster Gateway.
  </Card>

  <Card title="Video Overview" icon="grid" href="/v2/developers/build/video/overview" arrow horizontal>
    Comparison of LPMS, broadcaster Gateway, and managed SDK access paths.
  </Card>
</CardGroup>
