Documentation
¶
Overview ¶
Package transcode wraps Ether's bundled ffmpeg: discovery, hardware encoder detection, probing, the direct play / remux / transcode decision and HLS and MPEG-DASH sessions. Manager implements core.Transcoder.
Index ¶
- Constants
- Variables
- func Decide(info core.MediaInfo, caps core.ClientCaps, opts core.DecideOptions, pol Policy) core.Decision
- func DownloadCopyable(info core.MediaInfo, audioStream int, caps core.ClientCaps) (video, audio *core.StreamInfo, ok bool)
- func H264HighLevel(width, height int, fps float64, peakKbps, dpbFrames int) int
- func H264HighLevelLimits(level int) (int, int, bool)
- func HLSContainer(caps core.ClientCaps, videoCodec, audioCodec string) string
- func HLSVariantAttributes(info core.MediaInfo, d core.Decision) string
- func HasQuirk(product, platform, device, model, version, name string) bool
- func IsImageSubtitle(codec string) bool
- func IsJPEG(b []byte) bool
- func IsTextSubtitle(codec string) bool
- func LookPath() string
- func MarshalBIF(frames []BIFFrame) ([]byte, error)
- func NormalizeCodec(c string) string
- func NormalizeContainer(formatName string) string
- func OutputGeometry(width, height, maxHeight int) (int, int)
- func ParseProbe(b []byte) (*core.MediaInfo, error)
- func ParseSegmentName(name string) (int, bool)
- func PlexDASHURLs(sessionID string) (string, string)
- func PolicyStamp(product, platform, device, model, version string, ...) (dv []int, subs []string, dvChanged, subsChanged bool)
- func ProbeSource(ctx context.Context, src io.ReaderAt, size int64) (*core.MediaInfo, error)
- func ProbeTrailer(ctx context.Context, src io.ReaderAt, size int64, m *core.MediaInfo) bool
- func ProfileVideoKbps(height int) int
- func SRTToVTT(dst io.Writer, src io.Reader) error
- func SegmentName(n int, container string) string
- func SupportsDVProfile(c core.ClientCaps, profile int) bool
- func VTTToSRT(dst io.Writer, src io.Reader) error
- func WithSubtitleSource(ctx context.Context, source string) context.Context
- func WriteBIF(w io.Writer, frames []BIFFrame) error
- func WriteSRT(dst io.Writer, cues []Cue) error
- func WriteVTT(dst io.Writer, cues []Cue) error
- type BIF
- type BIFFrame
- type Capability
- type ClientPolicy
- type Command
- type Cue
- type DASHURLs
- type DownloadRemuxer
- type ExecRunner
- type GraphError
- type Manager
- func (m *Manager) Capability() Capability
- func (m *Manager) Close() error
- func (m *Manager) Decide(info core.MediaInfo, caps core.ClientCaps, opts core.DecideOptions) core.Decision
- func (m *Manager) EnhancementStatus() core.VideoEnhancementSupport
- func (m *Manager) ExtractSubtitle(ctx context.Context, inputURL string, streamIndex int, codec string, ...) error
- func (m *Manager) FFmpegPath() string
- func (m *Manager) FFprobePath() string
- func (m *Manager) HWAccel() core.HWAccel
- func (m *Manager) NewDownloadRemuxer(cfg config.Downloads) (*DownloadRemuxer, error)
- func (m *Manager) Policy() Policy
- func (m *Manager) Probe(ctx context.Context, inputURL string) (*core.MediaInfo, error)
- func (m *Manager) ProbeLive(ctx context.Context, inputURL string) (*core.MediaInfo, error)
- func (m *Manager) ProbeLiveWithHeaders(ctx context.Context, input string, headers map[string]string) (*core.MediaInfo, error)
- func (m *Manager) Session(id string) (core.HLSSession, bool)
- func (m *Manager) Sessions() []*Session
- func (m *Manager) StartHLS(ctx context.Context, req core.HLSRequest) (core.HLSSession, error)
- func (m *Manager) StartHLSOwned(ctx context.Context, req core.HLSRequest) (core.HLSSession, core.EncoderRetirement, error)
- func (m *Manager) Stop(id string)
- func (m *Manager) UpdateConfig(cfg config.Transcode)
- func (m *Manager) Version() string
- type Option
- func WithAudioMatchBudget(d time.Duration) Option
- func WithBuffering(restartAhead, maxAhead, keepBehind time.Duration) Option
- func WithDASHURLs(f DASHURLs) Option
- func WithEncoderObserver(f func(sessionID string, started bool, excerpt string)) Option
- func WithFailureHandler(f func(sessionID string, at time.Duration, err error)) Option
- func WithIdleTimeout(d time.Duration) Option
- func WithInputFailureHandler(f func(sessionID, inputURL string, at time.Duration, err error)) Option
- func WithManifestWait(d time.Duration) Option
- func WithRunStartHandler(f func(inputURL string, from, to time.Duration)) Option
- func WithRunner(r Runner) Option
- func WithRuntimeDir(dir string) Option
- func WithSegmentTimeout(d time.Duration) Option
- func WithSegmentURI(f func(n int, container string) string) Option
- func WithTracePlayback(on bool) Option
- func WithoutHWDetection() Option
- type PlaybackDefaults
- type Policy
- type Process
- type Progress
- type RTXRunner
- type Runner
- type SegMode
- type SegmentPlan
- type Session
- func (s *Session) CheckSwap(info core.MediaInfo) error
- func (s *Session) Close() error
- func (s *Session) Container() string
- func (s *Session) Decision() core.Decision
- func (s *Session) EncoderRetirement() core.EncoderRetirement
- func (s *Session) GoodputKbps() int
- func (s *Session) HWAccelerated() bool
- func (s *Session) ID() string
- func (s *Session) IndependentSegments() bool
- func (s *Session) Info() core.MediaInfo
- func (s *Session) LastAccess() time.Time
- func (s *Session) PlaybackState(state string)
- func (s *Session) PrepareSwap(ctx context.Context, input string, info core.MediaInfo, at time.Duration) error
- func (s *Session) Progress() Progress
- func (s *Session) Protocol() string
- func (s *Session) RecoveryBuffer() core.RecoveryBuffer
- func (s *Session) RequestedPosition() time.Duration
- func (s *Session) RetireEncoder() error
- func (s *Session) Rungs() []core.HLSRung
- func (s *Session) SegmentDuration() time.Duration
- func (s *Session) ServeInit(w http.ResponseWriter, r *http.Request, rep int)
- func (s *Session) ServeManifest(w http.ResponseWriter, r *http.Request)
- func (s *Session) ServeMedia(w http.ResponseWriter, r *http.Request, rep, n int)
- func (s *Session) ServePlaylist(w http.ResponseWriter, r *http.Request)
- func (s *Session) ServeRungPlaylist(w http.ResponseWriter, r *http.Request, rungID string)
- func (s *Session) ServeRungSegment(w http.ResponseWriter, r *http.Request, rungID string, n int)
- func (s *Session) ServeSegment(w http.ResponseWriter, r *http.Request, n int)
- func (s *Session) SwapInput(ctx context.Context, inputURL string, info core.MediaInfo, at time.Duration) error
- func (s *Session) SwapInputBuffered(ctx context.Context, inputURL string, info core.MediaInfo, at time.Duration) error
- func (s *Session) Touch()
- type ThumbOptions
- type Thumbnails
- func (t *Thumbnails) CancelTrickplay(releaseID string)
- func (t *Thumbnails) Close() error
- func (t *Thumbnails) EnsureTrickplay(_ context.Context, src core.TrickplaySource)
- func (t *Thumbnails) PreviewInterval() time.Duration
- func (t *Thumbnails) PreviewWidth() int
- func (t *Thumbnails) SetTrickplayFallback(releaseID string, jpeg []byte)
- func (t *Thumbnails) TrickplayAvailable(releaseID string) bool
- func (t *Thumbnails) TrickplayBIF(releaseID string) ([]byte, bool)
- func (t *Thumbnails) TrickplayFrame(releaseID string, at time.Duration) ([]byte, bool)
- type Timeline
- func (tl *Timeline) ClampKbps(n int) int
- func (tl *Timeline) Dur(n int) time.Duration
- func (tl *Timeline) IndexAt(rel time.Duration) int
- func (tl *Timeline) Keyframed() bool
- func (tl *Timeline) ModeAt(n int) SegMode
- func (tl *Timeline) NextChange(n int) int
- func (tl *Timeline) Plan(n int) SegmentPlan
- func (tl *Timeline) SetClamp(n, kbps int)
- func (tl *Timeline) Start(n int) time.Duration
- func (tl *Timeline) TargetDuration() time.Duration
- func (tl *Timeline) Total() int
Constants ¶
const ( ContainerMPEGTS = "mpegts" ContainerFMP4 = "fmp4" ContainerMatroska = "mkv" )
HLS segment containers reported in core.Decision.Container.
const ( AccelNone = "none" AccelVideoToolbox = "videotoolbox" AccelNVENC = "nvenc" AccelQSV = "qsv" AccelVAAPI = "vaapi" )
Hardware accelerator names, as used in config.Transcode.HWAccel and core.HWAccel.Name.
const DefaultDASHSegmentDuration = 5 * time.Second
DefaultDASHSegmentDuration is the DASH segment length when a request leaves it unset; PMS uses 5 s.
const DefaultSegmentDuration = 4 * time.Second
DefaultSegmentDuration is the HLS segment length when a request leaves it unset.
const DefaultVAAPIDevice = "/dev/dri/renderD128"
DefaultVAAPIDevice is the render node used when none is configured.
const InitSegment = -1
InitSegment is the segment number ServeSegment uses for the fMP4 initialization segment (init.mp4).
const InitSegmentName = "init.mp4"
InitSegmentName is the init segment's URI in media playlists.
const MatroskaHeaderName = "header"
MatroskaHeaderName matches Plex's segmented-Matroska initialization URI.
Variables ¶
var ErrEncoderCapacity = errors.New("transcode: encoder retirement capacity exhausted")
var ErrFFmpegNotFound = errors.New("transcode: ffmpeg not found")
ErrFFmpegNotFound means no usable ffmpeg/ffprobe executable was found in the configured path, the bundled locations or PATH.
var ErrImageSubtitle = errors.New("transcode: bitmap subtitles cannot be converted to text")
ErrImageSubtitle is returned when a bitmap subtitle is asked for as text.
var ErrIncompatibleSwap = errors.New("transcode: replacement cannot match the delivered video")
ErrIncompatibleSwap reports a replacement source whose video cannot be delivered in the session's fixed output contract.
var ErrNoCues = errors.New("transcode: no subtitle cues found")
ErrNoCues means the input held no parsable subtitle cues.
var ErrPauseUnsupported = errors.New("transcode: pausing processes is not supported on this platform")
ErrPauseUnsupported is returned by Process.Pause on platforms that cannot suspend a process.
var ErrProbeIncomplete = errors.New("transcode: native probe incomplete")
ErrProbeIncomplete means native probing cannot vouch for the stream parameters; ffprobe must run.
var ErrTooManyTranscodes = errors.New("transcode: too many concurrent transcodes")
ErrTooManyTranscodes is returned by StartHLS when config MaxTranscodes video transcodes are already running. Remuxes are not counted.
Functions ¶
func Decide ¶
func Decide(info core.MediaInfo, caps core.ClientCaps, opts core.DecideOptions, pol Policy) core.Decision
func DownloadCopyable ¶
func DownloadCopyable(info core.MediaInfo, audioStream int, caps core.ClientCaps) (video, audio *core.StreamInfo, ok bool)
DownloadCopyable reports whether info's video (and chosen audio) can be stream-copied to MP4, returning the streams a remux would keep.
func H264HighLevel ¶ added in v0.3.0
H264HighLevel returns the smallest supported High-profile level for a known encode geometry, rate, peak bitrate and decoded-picture budget. Zero means the facts are unknown or exceed this encoder contract.
func H264HighLevelLimits ¶ added in v0.3.0
H264HighLevelLimits returns peak bitrate and decoded-picture limits for a level selected by H264HighLevel.
func HLSContainer ¶
func HLSContainer(caps core.ClientCaps, videoCodec, audioCodec string) string
HLSContainer preserves explicit client targets separately from the formats its direct-play decoder accepts. Plex's enhanced player requests segmented Matroska; AVPlayer and browser HLS keep the standard TS/fMP4 path.
func HLSVariantAttributes ¶
HLSVariantAttributes describes the output selected by the media decision. Apple HLS requires CODECS; HDR and Dolby Vision also need explicit signaling. https://developer.apple.com/streaming/hls-authoring-specification-for-apple-devices.html
func IsImageSubtitle ¶
IsImageSubtitle reports whether a subtitle codec is bitmap-based and so must be burned in to be shown in HLS.
func IsTextSubtitle ¶
IsTextSubtitle reports whether a subtitle codec can be converted to WebVTT.
func LookPath ¶ added in v0.3.0
func LookPath() string
LookPath finds bundled or PATH ffmpeg the same way Manager does.
func MarshalBIF ¶
MarshalBIF encodes frames as a BIF file. Frames are sorted by time (stable, on a copy) and duplicate timestamps keep the first frame, so the output is deterministic for a given input order. At least one frame with image data is required.
func NormalizeCodec ¶
NormalizeCodec maps ffprobe codec names to Ether/Plex codec names.
func NormalizeContainer ¶
NormalizeContainer maps an ffprobe format_name to Ether's container name.
func OutputGeometry ¶ added in v0.3.0
OutputGeometry uses the same geometry as the encoder's scale plan.
func ParseProbe ¶
ParseProbe maps ffprobe -print_format json -show_format -show_streams output to MediaInfo.
func ParseSegmentName ¶
ParseSegmentName parses a segment URI produced by SegmentName (or InitSegmentName) back to its number; init.mp4 yields InitSegment.
func PlexDASHURLs ¶
PlexDASHURLs is the URL layout real PMS uses (captured from a PMS start.mpd): segments live next to start.mpd under session/{id}/.
func PolicyStamp ¶ added in v0.3.0
func PolicyStamp(product, platform, device, model, version string, overrides []core.ClientCapabilityOverride) (dv []int, subs []string, dvChanged, subsChanged bool)
PolicyStamp returns Dolby Vision profiles and subtitle codecs when an owner override changed them. Unchanged defaults stay unset so a Plex client cap matches the historical shape.
func ProbeSource ¶ added in v0.2.4
ProbeSource probes a media source natively: Matroska/WebM and MP4/MOV/M4V. Other containers return ErrProbeIncomplete.
func ProbeTrailer ¶ added in v0.2.4
ProbeTrailer reads metadata Matroska keeps after the media (tail Chapters, mkvmerge statistics tags). It fills only facts that are not already known and never changes stream identity or codec parameters, so it can run after playback has started.
func ProfileVideoKbps ¶ added in v0.3.0
bitrateCeiling is the bitrate past which a height gains little. ProfileVideoKbps is the H.264 video target Decide uses for a quality profile height. Silo publishes the same number on that rung.
func SRTToVTT ¶
SRTToVTT converts SubRip to WebVTT (OpenSubtitles sidecars to HLS/Plex web clients).
func SegmentName ¶
SegmentName is the default playlist URI of segment n: "00042.ts" or "00042.m4s" or "00042.mkv" (relative to index.m3u8).
func SupportsDVProfile ¶
func SupportsDVProfile(c core.ClientCaps, profile int) bool
SupportsDVProfile requires both the generic DV flag and a compatible profile. With no model evidence an unspecified profile is accepted only if the client explicitly advertised DV; known unsupported profiles use their base layer.
func VTTToSRT ¶
VTTToSRT converts WebVTT to SubRip. Cue settings and WebVTT-only markup (voice, class, timestamp tags) are dropped; <i>, <b>, <u> are kept.
func WithSubtitleSource ¶ added in v0.3.0
WithSubtitleSource names the source an extraction reads, the same for every session of that source (its release). ExtractSubtitle caches the track's WebVTT under it; an empty name extracts uncached.
Types ¶
type BIF ¶
type BIF struct {
Version uint32
Multiplier uint32 // ms per timestamp unit
// contains filtered or unexported fields
}
BIF is a parsed BIF file.
type Capability ¶ added in v0.3.0
type Capability struct {
Notice string `json:"notice,omitempty"`
PlaybackError string `json:"playbackError,omitempty"`
FiltersProbed bool `json:"filtersProbed"`
ToneMap []string `json:"toneMap,omitempty"`
Colour []string `json:"colour,omitempty"`
}
Capability is the owner-visible transcoder health card: which colour and tone-map paths were probed, plus the latest graph failure.
type ClientPolicy ¶
type ClientPolicy struct {
Family string `json:"family"`
DolbyVisionProfiles []int `json:"dolbyVisionProfiles"`
SubtitleCodecs []string `json:"subtitleCodecs"`
Notes string `json:"notes"`
}
ClientPolicy records the registry's family defaults for one client. Headers and profile declarations remain authoritative; a model name alone does not certify a display or an audio chain.
func ClientPolicies ¶
func ClientPolicies() []ClientPolicy
ClientPolicies is the owner-facing supplemental quirk matrix. It describes defaults only; a real request's profile and hardware declarations refine it.
func ClientPolicyFor ¶
func ClientPolicyFor(c core.ClientCaps) ClientPolicy
ClientPolicyFor resolves the embedded registry with no owner overrides.
func ResolvePolicy ¶ added in v0.3.0
func ResolvePolicy(c core.ClientCaps, overrides []core.ClientCapabilityOverride) ClientPolicy
ResolvePolicy layers owner overrides on the registry, then lets a runtime declaration replace Dolby Vision profiles and subtitle codecs.
type Cue ¶
type Cue struct {
Start, End time.Duration
// Settings are WebVTT cue settings ("line:0 align:start"); dropped in SRT.
Settings string
Text string // lines joined with \n
}
Cue is one timed subtitle.
type DASHURLs ¶
DASHURLs returns the initialization and media SegmentTemplate URLs of a session, relative to the MPD, with $RepresentationID$ and $Number$.
type DownloadRemuxer ¶
type DownloadRemuxer struct {
// contains filtered or unexported fields
}
DownloadRemuxer remuxes resolved sources to temporary MP4s. It implements core.DownloadRemuxer.
func (*DownloadRemuxer) ReleaseDownload ¶
func (d *DownloadRemuxer) ReleaseDownload(path string)
ReleaseDownload implements core.DownloadRemuxer.
func (*DownloadRemuxer) RemuxDownload ¶
func (d *DownloadRemuxer) RemuxDownload(ctx context.Context, req core.DownloadRemuxRequest, progress func(float64)) (string, int64, error)
RemuxDownload implements core.DownloadRemuxer.
func (*DownloadRemuxer) UsedBytes ¶
func (d *DownloadRemuxer) UsedBytes() int64
UsedBytes is the budget currently held by finished and in-flight downloads (tests and diagnostics).
type ExecRunner ¶
type ExecRunner struct{}
ExecRunner runs real executables with os/exec.
func (ExecRunner) Run ¶
func (ExecRunner) Run(ctx context.Context, c Command) error
Run implements Runner.
type GraphError ¶ added in v0.3.0
type GraphError struct{ Message string }
GraphError is a transcode this ffmpeg cannot build. The message is owner-visible (Activity and the transcoder health card). It is not an ffmpeg stderr tail, and it is not retried as the same filter graph.
func (*GraphError) Error ¶ added in v0.3.0
func (e *GraphError) Error() string
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager runs ffmpeg for Ether. It implements core.Transcoder.
func New ¶
New finds ffmpeg/ffprobe, detects hardware encoders and starts the idle session reaper. It fails with ErrFFmpegNotFound when no ffmpeg exists.
func (*Manager) Capability ¶ added in v0.3.0
func (m *Manager) Capability() Capability
Capability reports probed filters and any owner-visible limitation.
func (*Manager) Decide ¶
func (m *Manager) Decide(info core.MediaInfo, caps core.ClientCaps, opts core.DecideOptions) core.Decision
Decide implements core.Transcoder.
func (*Manager) EnhancementStatus ¶ added in v0.2.4
func (m *Manager) EnhancementStatus() core.VideoEnhancementSupport
EnhancementStatus is suitable for an owner status API. Available means detection passed; it deliberately does not mean a VSR run has succeeded.
func (*Manager) ExtractSubtitle ¶
func (m *Manager) ExtractSubtitle(ctx context.Context, inputURL string, streamIndex int, codec string, w io.Writer) error
ExtractSubtitle writes an embedded text subtitle stream as WebVTT. It reads the whole input (subtitle packets are interleaved through it).
func (*Manager) FFmpegPath ¶
FFmpegPath is the ffmpeg executable in use.
func (*Manager) FFprobePath ¶
FFprobePath is the ffprobe executable in use.
func (*Manager) NewDownloadRemuxer ¶
func (m *Manager) NewDownloadRemuxer(cfg config.Downloads) (*DownloadRemuxer, error)
NewDownloadRemuxer prepares the download temp dir under the transcode temp dir. Boot cleanup follows the single stale-download policy (see staleDownloadAge in manager.go for who deletes what): stale dl-* orphans are removed by cleanStaleDownloads, while fresh dl-* orphans it keeps are ADOPTED by the new remuxer — registered in files/used at their real size, with their real mtime, so they count against the disk budget from the start and expire at runtime via expireStaleAdopted once they cross staleDownloadAge.
func (*Manager) ProbeLive ¶
ProbeLive accepts complete audio/video parameters without a finite duration. Requiring a duration on an endless feed always forces the expensive retry. This optional capability leaves ordinary file probing unchanged.
func (*Manager) ProbeLiveWithHeaders ¶
func (m *Manager) ProbeLiveWithHeaders(ctx context.Context, input string, headers map[string]string) (*core.MediaInfo, error)
ProbeLiveWithHeaders is the authenticated variant of the optional live probe.
func (*Manager) Session ¶
func (m *Manager) Session(id string) (core.HLSSession, bool)
Session implements core.Transcoder.
func (*Manager) StartHLS ¶
func (m *Manager) StartHLS(ctx context.Context, req core.HLSRequest) (core.HLSSession, error)
StartHLS implements core.Transcoder. A replacement cannot begin until the prior exact session has completed its process and directory cleanup.
func (*Manager) StartHLSOwned ¶ added in v0.3.0
func (m *Manager) StartHLSOwned(ctx context.Context, req core.HLSRequest) (core.HLSSession, core.EncoderRetirement, error)
func (*Manager) UpdateConfig ¶
UpdateConfig applies changed limits (MaxTranscodes, RemoteMaxBitrateKbps) and schedules optional RTX runtime setup. FFmpeg paths and the ordinary hardware encoder choice still need a restart.
type Option ¶
type Option func(*options)
Option tunes a Manager.
func WithAudioMatchBudget ¶ added in v0.2.20
WithAudioMatchBudget bounds the best-effort loudness analysis run before a source swap (default 1.5s). Integration tests on slow or race-instrumented machines raise it; production keeps the short budget so a swap never waits.
func WithBuffering ¶
WithBuffering tunes seeking and disk use: a request more than restartAhead past the encoder restarts ffmpeg there (default 24s); ffmpeg is suspended when maxAhead in front of the player (default 2m, 0 = never); segments more than keepBehind behind the player are deleted (default 3m, 0 = never).
func WithDASHURLs ¶
WithDASHURLs sets the segment URL templates written into DASH MPDs. The default is PlexDASHURLs, the layout of real PMS.
func WithEncoderObserver ¶ added in v0.2.49
WithEncoderObserver is told when ffmpeg starts or fails to start. excerpt is already redacted argument text and must not be required for playback.
func WithFailureHandler ¶
WithFailureHandler is called (in its own goroutine) when ffmpeg fails mid-session, e.g. because the source lost articles; at is the media time playback had reached. Playback typically answers with SwapInput.
func WithIdleTimeout ¶
WithIdleTimeout sets how long an unrequested session lives (default 2m).
func WithInputFailureHandler ¶ added in v0.2.4
func WithInputFailureHandler(f func(sessionID, inputURL string, at time.Duration, err error)) Option
WithInputFailureHandler includes the failed input generation, so delayed encoder exits cannot fail over a healthy replacement that is already playing.
func WithManifestWait ¶
WithManifestWait bounds how long a DASH session's first MPD request waits for ffmpeg's init segments to learn the exact codecs (default 15s); after that the MPD is served with codecs estimated from the probe.
func WithRunStartHandler ¶ added in v0.2.4
WithRunStartHandler is told, before ffmpeg is spawned, which part of the input a new run will read first, so the source can fetch it in parallel while the encoder starts and locates it.
func WithRuntimeDir ¶ added in v0.2.10
WithRuntimeDir enables managed optional tool installation in this node-local directory. No downloads occur while RTX Video is off. Embedded/test managers that omit this option never install software.
func WithSegmentTimeout ¶
WithSegmentTimeout bounds how long ServeSegment waits for ffmpeg (default 45s).
func WithSegmentURI ¶
WithSegmentURI sets the segment URIs written into media playlists. The default is SegmentName ("00042.ts", relative to index.m3u8).
func WithTracePlayback ¶ added in v0.3.0
WithTracePlayback logs Plex HLS playhead decisions and ffmpeg run start/stop reasons. It does not change encoding or delivery.
func WithoutHWDetection ¶
func WithoutHWDetection() Option
WithoutHWDetection skips the startup hardware probe and encodes on CPU.
type PlaybackDefaults ¶ added in v0.3.0
type PlaybackDefaults struct {
ID string
Video, Audio, Containers []string
MaxHeight int
HDR10, DolbyVision, HeightLocked bool
}
PlaybackDefaults is the registry baseline for a client that sent no profile. ID is the matched playback record. "generic" means nothing more specific matched.
func PlaybackDefaultsFor ¶ added in v0.3.0
func PlaybackDefaultsFor(product, platform, device, model, version string, overrides []core.ClientCapabilityOverride) PlaybackDefaults
PlaybackDefaultsFor evaluates the registry, including owner overrides. Model is separate from ClientCaps because Plex carries it on the request.
type Policy ¶
type Policy struct {
// RemoteMaxBitrateKbps caps streams to clients outside the LAN; 0 = none.
RemoteMaxBitrateKbps int
// HEVCEncoder is true when HEVC can be encoded in real time (Manager
// sets it only for hardware encoders). It is required to keep HDR in a
// transcode; without it HDR is tone-mapped to SDR H.264.
HEVCEncoder bool
// HEVCHardware is true when HEVC encoding is hardware accelerated, which
// makes HEVC a good target for 4K transcodes.
HEVCHardware bool
}
Policy is the server-side input to Decide that is not per request.
type Process ¶
type Process interface {
// Done is closed when the process has exited.
Done() <-chan struct{}
// Err is the exit error; valid once Done is closed.
Err() error
// Stop kills the process and blocks until it is gone. It is safe to
// call more than once and after exit.
Stop()
// Pause suspends the process (throttling); ErrPauseUnsupported where
// the platform cannot.
Pause() error
// Resume continues a paused process.
Resume() error
}
Process is a started long-running command (an ffmpeg HLS run).
type Progress ¶
type Progress struct {
Frame int64 `json:"frame"`
FPS float64 `json:"fps"`
Speed float64 `json:"speed"` // x realtime
OutTime time.Duration `json:"outTime"` // media time reached
Bitrate string `json:"bitrate,omitempty"`
Ended bool `json:"ended"`
Updated time.Time `json:"updated"`
}
Progress is the latest `-progress` report of a session's ffmpeg run.
type Runner ¶
type Runner interface {
// Start launches a long-running command.
Start(cmd Command) (Process, error)
// Run executes a command to completion, killing it when ctx ends.
Run(ctx context.Context, cmd Command) error
}
Runner starts processes. The default runs real executables; tests inject fakes.
type SegmentPlan ¶
type SegmentPlan struct {
Index int
Start time.Duration // playlist-relative
Duration time.Duration
Mode SegMode
DiscontinuityBefore bool
}
SegmentPlan is one planned segment, for tests and admin reporting.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session is one HLS or DASH remux or transcode. It implements core.HLSSession, and core.DASHSession for DASH sessions.
Segment n always covers media time base+n*segDur (base is the request's StartOffset for HLS and 0 for DASH, whose MPD always spans the whole title). ffmpeg runs are started at a segment boundary with -ss and -copyts, so restarting at any segment (a seek far ahead or behind, a failover to another release) keeps numbering and timestamps continuous.
An HLS session has one track of muxed segments. A DASH session has one track per representation (video, audio); ffmpeg's dash muxer writes short chunks that the session regroups into numbered segments by timestamp.
func (*Session) CheckSwap ¶ added in v0.2.4
CheckSwap reports whether SwapInput can deliver info's video in the format the client already opened. Playback calls it before committing a replacement so an incompatible candidate is skipped, not spliced.
func (*Session) EncoderRetirement ¶ added in v0.3.0
func (s *Session) EncoderRetirement() core.EncoderRetirement
func (*Session) GoodputKbps ¶
GoodputKbps is the session's measured client delivery goodput.
func (*Session) HWAccelerated ¶
HWAccelerated reports whether the current run encodes on hardware.
func (*Session) IndependentSegments ¶ added in v0.3.0
IndependentSegments implements core.HLSIndependentSegments. It reports a proven all-renditions guarantee, not the legacy playlist convention.
func (*Session) LastAccess ¶
LastAccess implements core.HLSSession.
func (*Session) PlaybackState ¶ added in v0.2.9
func (*Session) PrepareSwap ¶ added in v0.2.9
func (s *Session) PrepareSwap(ctx context.Context, input string, info core.MediaInfo, at time.Duration) error
PrepareSwap checks real replacement pixels while the old generation still owns playback. Failed reads reject only this candidate, never the title.
func (*Session) RecoveryBuffer ¶ added in v0.2.8
func (s *Session) RecoveryBuffer() core.RecoveryBuffer
func (*Session) RequestedPosition ¶ added in v0.2.4
RequestedPosition is the title position of the player's latest segment request. Source reads can be far ahead or at the container's tail index.
func (*Session) RetireEncoder ¶ added in v0.3.0
func (*Session) SegmentDuration ¶
SegmentDuration is the session's segment length.
func (*Session) ServeInit ¶
ServeInit implements core.DASHSession: representation rep's initialization segment.
func (*Session) ServeManifest ¶
func (s *Session) ServeManifest(w http.ResponseWriter, r *http.Request)
ServeManifest implements core.DASHSession: the static, full-length MPD. The first request waits (bounded) for ffmpeg's init segments so the MPD carries exact codecs strings; until then they are estimated.
func (*Session) ServeMedia ¶
ServeMedia implements core.DASHSession: media segment n of representation rep. Each segment starts with its run's init segment, so segments from different ffmpeg runs (seeks, failovers) play back to back.
func (*Session) ServePlaylist ¶
func (s *Session) ServePlaylist(w http.ResponseWriter, r *http.Request)
ServePlaylist implements core.HLSSession: the full-length VOD playlist (the MPD for DASH sessions).
func (*Session) ServeRungPlaylist ¶
ServeRungPlaylist implements core.HLSLadderSession.
func (*Session) ServeRungSegment ¶
ServeRungSegment implements core.HLSLadderSession.
func (*Session) ServeSegment ¶
ServeSegment implements core.HLSSession. n == InitSegment serves the fMP4 init segment. For DASH sessions it serves the first representation.
func (*Session) SwapInput ¶
func (s *Session) SwapInput(ctx context.Context, inputURL string, info core.MediaInfo, at time.Duration) error
SwapInput implements core.HLSSession: restart on a new input at `at` (mid-stream failover). Segments from `at` on are discarded and produced again from the new input; numbering stays continuous.
func (*Session) SwapInputBuffered ¶ added in v0.2.8
type ThumbOptions ¶
type ThumbOptions struct {
Runner Runner
FFmpeg string
Logger *slog.Logger
Interval time.Duration // frame spacing (default 10s)
Width int // thumbnail width px (default 320, Plex "sd")
Quality int // ffmpeg -q:v (default 7)
FrameTimeout time.Duration // per-frame extraction cap (default 25s)
BatchFrames int // frames per batch before a pause (default 12)
BatchPause time.Duration // pause between batches (default 4s)
MaxConcurrent int // global extraction jobs (default 2)
MaxBytes int64 // total stored JPEG bytes, LRU-evicted (default 256MiB)
MaxReleases int // releases kept, LRU-evicted (default 32)
RetryBackoff time.Duration // pause before retrying a failed release (default 2m)
}
ThumbOptions tunes a Thumbnails store. Runner and FFmpeg are required; zero limits take the defaults documented on each field.
type Thumbnails ¶
type Thumbnails struct {
// contains filtered or unexported fields
}
Thumbnails builds sparse BIF preview indexes for releases while they stream. Extraction only ever reads a source handed to EnsureTrickplay (the loopback input of an active playback or warmup session): one fast-seek ffmpeg run per frame decodes a single (key)frame, so bytes are read around the requested frame only — never the whole file ahead of playback. Jobs run at most one per release under a small global cap, fill in bounded batches with pauses, and stop when the source stops answering (the session ended) or Close is called.
It implements core.TrickplayProvider.
func NewThumbnails ¶
func NewThumbnails(o ThumbOptions) *Thumbnails
NewThumbnails builds an empty thumbnail store. Call Close on shutdown.
func (*Thumbnails) CancelTrickplay ¶
func (t *Thumbnails) CancelTrickplay(releaseID string)
CancelTrickplay stops the active extraction for a release. Playback calls this after the last viewer session for that release ends.
func (*Thumbnails) Close ¶
func (t *Thumbnails) Close() error
Close stops all generation and waits for jobs to finish.
func (*Thumbnails) EnsureTrickplay ¶
func (t *Thumbnails) EnsureTrickplay(_ context.Context, src core.TrickplaySource)
EnsureTrickplay implements core.TrickplayProvider.
func (*Thumbnails) PreviewInterval ¶ added in v0.3.0
func (t *Thumbnails) PreviewInterval() time.Duration
PreviewInterval and PreviewWidth describe the grid the shared provider generates. Callers compose sheets from these values instead of assuming a second thumbnail cache.
func (*Thumbnails) PreviewWidth ¶ added in v0.3.0
func (t *Thumbnails) PreviewWidth() int
func (*Thumbnails) SetTrickplayFallback ¶
func (t *Thumbnails) SetTrickplayFallback(releaseID string, jpeg []byte)
SetTrickplayFallback implements core.TrickplayProvider.
func (*Thumbnails) TrickplayAvailable ¶
func (t *Thumbnails) TrickplayAvailable(releaseID string) bool
TrickplayAvailable implements core.TrickplayProvider.
func (*Thumbnails) TrickplayBIF ¶
func (t *Thumbnails) TrickplayBIF(releaseID string) ([]byte, bool)
TrickplayBIF implements core.TrickplayProvider.
func (*Thumbnails) TrickplayFrame ¶
TrickplayFrame implements core.TrickplayProvider.
type Timeline ¶
type Timeline struct {
// SwitchSeg is the first steady segment after the fast-start ramp
// (== len(durs) when the whole title is ramp, 0 when there is none).
SwitchSeg int
// contains filtered or unexported fields
}
Timeline is a session's segment plan. Starts are relative to the session's playlist position zero (the HLS StartOffset); callers add base for absolute media time.
func (*Timeline) Keyframed ¶ added in v0.2.4
Keyframed reports whether the boundaries come from a keyframe index.
func (*Timeline) NextChange ¶
NextChange is the first segment after n produced in a different mode than n (the exclusive end of a run starting at n), or -1 when the mode runs to the end of what is known.
func (*Timeline) Plan ¶
func (tl *Timeline) Plan(n int) SegmentPlan
Plan returns segment n's plan. discont reports discontinuities for the primary encode; rung playlists pass their own via playlist rendering.
func (*Timeline) TargetDuration ¶
TargetDuration is the HLS #EXT-X-TARGETDURATION: the ceiling of the longest segment duration.
Source Files
¶
- args.go
- audio_match.go
- bif.go
- bif_thumbs.go
- bitstream.go
- capabilities.go
- capability_assertions.go
- chunks.go
- clientpolicy.go
- colour.go
- contract.go
- dash.go
- dash_session.go
- decide.go
- discover.go
- download.go
- encoder_input.go
- encoder_linux.go
- encoder_retirement.go
- encoder_unix.go
- failover_audio.go
- fmp4.go
- fmp4_edit.go
- goodput.go
- gpu_pipeline.go
- guardian.go
- h264_level.go
- hls_attributes.go
- http_session.go
- hwaccel.go
- input_failure.go
- input_headers.go
- input_safety.go
- ladder.go
- live_timestamps.go
- manager.go
- mkv_hls.go
- mux_output.go
- mux_output_other.go
- nativeprobe.go
- nativeprobe_mp4.go
- picture_crop.go
- playlist.go
- probe.go
- probe_live.go
- proc_unix.go
- process_memory_unix.go
- progress.go
- recovery_buffer.go
- remove.go
- rtx_args.go
- rtx_install.go
- rtx_process_other.go
- rtx_session.go
- rtx_setup.go
- rtx_video.go
- runner.go
- segment_files.go
- segment_plan.go
- session.go
- session_delivery.go
- session_encoder.go
- session_monitor.go
- session_playlist.go
- session_swap.go
- software_threads.go
- subtitle_cache.go
- subtitles.go
- vbv.go
- videotoolbox_compat.go