Documentation
¶
Overview ¶
Package mediaprobe observes live media streams and reports codec and timestamp properties without exposing protocol-specific parser types.
Index ¶
Examples ¶
Constants ¶
const ( // DefaultObservationDuration is the media timeline covered by a probe when // no observation-duration option is provided. DefaultObservationDuration = 15 * time.Second // DefaultSampleLimit is the maximum number of sample records retained by a // probe when no sample-limit option is provided. DefaultSampleLimit = 100_000 )
const ReportSchemaVersion = "0.1"
ReportSchemaVersion is the version of the JSON representation produced for Report values.
Variables ¶
var ( ErrNoTracks = errors.New("mediaprobe: stream has no tracks") ErrInvalidTrack = errors.New("mediaprobe: invalid track") ErrInvalidSample = errors.New("mediaprobe: invalid sample") ErrUnknownTrack = errors.New("mediaprobe: sample references unknown track") ErrObservationIncomplete = errors.New("mediaprobe: observation incomplete") ErrInvalidObservationDuration = errors.New("mediaprobe: invalid observation duration") ErrInvalidSampleLimit = errors.New("mediaprobe: invalid sample limit") ErrSampleLimitExceeded = errors.New("mediaprobe: sample limit exceeded") ErrInvalidURL = errors.New("mediaprobe: invalid URL") ErrUnsupportedScheme = errors.New("mediaprobe: unsupported URL scheme") )
Functions ¶
This section is empty.
Types ¶
type Codec ¶
type Codec string
Codec identifies a media codec. It is intentionally open-ended so adapters can report codecs added by their underlying media libraries.
const ( CodecAC3 Codec = "ac3" CodecAAC Codec = "aac" CodecAV1 Codec = "av1" CodecEAC3 Codec = "eac3" CodecFLAC Codec = "flac" CodecG711 Codec = "g711" CodecH264 Codec = "h264" CodecH265 Codec = "h265" CodecJPEG Codec = "jpeg" CodecKLV Codec = "klv" CodecLPCM Codec = "lpcm" CodecMPEG1Audio Codec = "mpeg1audio" CodecMPEG1Video Codec = "mpeg1video" CodecMPEG4Audio Codec = "mpeg4audio" CodecMPEG4Video Codec = "mpeg4video" CodecOpus Codec = "opus" CodecVP8 Codec = "vp8" CodecVP9 Codec = "vp9" )
type H264DTSError ¶
type H264DTSError struct {
At time.Duration `json:"at"`
Code H264DTSErrorCode `json:"code"`
Message string `json:"message"`
}
H264DTSError describes the first DTS derivation failure observed for a track. At is elapsed media time from the first received access unit.
type H264DTSErrorCode ¶
type H264DTSErrorCode string
H264DTSErrorCode identifies a DTS derivation failure without requiring callers to parse the implementation-specific error message.
const ( H264DTSErrorTooManyReorderedFrames H264DTSErrorCode = "too_many_reordered_frames" H264DTSErrorNonMonotonic H264DTSErrorCode = "non_monotonic_dts" H264DTSErrorAfterPTS H264DTSErrorCode = "dts_after_pts" H264DTSErrorUnsupportedPOC H264DTSErrorCode = "unsupported_picture_order" H264DTSErrorMissingSPS H264DTSErrorCode = "missing_sps" H264DTSErrorInvalidSPS H264DTSErrorCode = "invalid_sps" H264DTSErrorOther H264DTSErrorCode = "other" )
type H264DTSReport ¶
type H264DTSReport struct {
// Samples is the number of access units examined. Examination stops after
// the first error.
Samples int `json:"samples"`
Error *H264DTSError `json:"error,omitempty"`
}
H264DTSReport describes attempts to derive DTS from H.264 picture order and PTS, as required by muxers that do not retain source-provided DTS.
type H264Report ¶
type H264Report struct {
DTS H264DTSReport `json:"dts"`
}
H264Report contains diagnostics that require access to H.264 access units.
type Option ¶
type Option func(*probeOptions)
Option configures ProbeStream and ProbeURL.
func WithHTTPClient ¶
WithHTTPClient sets the client used for HTTP-based streams. ProbeURL does not mutate the client. A nil client uses default HTTP settings.
func WithHTTPHeaders ¶
WithHTTPHeaders adds headers to every request made for HTTP-based streams, including cross-origin resources referenced by a playlist. The values are copied when this option is created and whenever it is applied.
func WithObservationDuration ¶
WithObservationDuration overrides DefaultObservationDuration. The duration must be greater than zero.
func WithSampleLimit ¶
WithSampleLimit sets the maximum number of sample records retained across all tracks. The limit must be greater than zero.
type Rate ¶
Rate is an exact rational rate, such as 30000/1001 frames per second.
type Report ¶
type Report struct {
Tracks []TrackReport `json:"tracks"`
ObservationDuration time.Duration `json:"observation_duration"`
IsComplete bool `json:"complete"`
}
Report contains measurements from one stream incarnation.
func ProbeStream ¶
ProbeStream observes a stream until it covers the configured duration of media time. Callers should create a new Stream for each upstream incarnation or reconnect. On failure, the returned report contains any measurements collected so far.
Example ¶
package main
import (
"context"
"fmt"
"io"
"time"
"github.com/zbiljic/mediaprobe"
)
func main() {
stream := &exampleStream{
samples: []mediaprobe.Sample{
{TrackID: 1, PTS: 0, DTS: 0, Size: 1_000},
{TrackID: 1, PTS: time.Second, DTS: time.Second, Size: 1_000},
{TrackID: 1, PTS: 2 * time.Second, DTS: 2 * time.Second, Size: 1_000},
},
}
report, err := mediaprobe.ProbeStream(
context.Background(),
stream,
mediaprobe.WithObservationDuration(2*time.Second),
)
if err != nil {
fmt.Println("error:", err)
return
}
track := report.Tracks[0]
normalizeInCaller := track.IsVariableFrameRate ||
track.NonMonotonicDTS > 0 ||
track.TimestampDiscontinuities > 0 ||
(track.H264 != nil && track.H264.DTS.Error != nil)
fmt.Println("complete:", report.IsComplete)
fmt.Println("samples:", track.SampleCount)
fmt.Printf("observed frame rate: %.1f\n", track.ObservedFrameRate)
fmt.Println("normalize in caller:", normalizeInCaller)
}
var _ mediaprobe.Stream = (*exampleStream)(nil)
type exampleStream struct {
samples []mediaprobe.Sample
next int
}
func (*exampleStream) Tracks(context.Context) ([]mediaprobe.Track, error) {
return []mediaprobe.Track{{
ID: 1,
MediaType: mediaprobe.MediaTypeVideo,
Codec: mediaprobe.CodecH264,
DeclaredFrameRate: mediaprobe.Rate{Numerator: 1, Denominator: 1},
}}, nil
}
func (s *exampleStream) ReadSample(context.Context) (mediaprobe.Sample, error) {
if s.next == len(s.samples) {
return mediaprobe.Sample{}, io.EOF
}
sample := s.samples[s.next]
s.next++
return sample, nil
}
Output: complete: true samples: 3 observed frame rate: 1.0 normalize in caller: false
func ProbeURL ¶
ProbeURL connects to a live media URL and observes it for the configured duration of media time. HTTP(S) HLS, RTSP(S), RTMP(S), SRT, and raw MPEG-TS over TCP or UDP are currently supported. Callers should provide a context with an appropriate wall-clock deadline.
func (Report) MarshalJSON ¶
MarshalJSON returns the stable JSON representation of a probe report. The Go model remains flat for convenient caller access, while the wire model groups declared media metadata separately from measurements made during probing.
type Sample ¶
type Sample struct {
TrackID int
PTS time.Duration
DTS time.Duration
Duration time.Duration
IsKeyFrame bool
Size int
// contains filtered or unexported fields
}
Sample describes the timing of one compressed media sample. When a transport does not distinguish PTS and DTS, its adapter should set both to the same value.
type Stream ¶
type Stream interface {
Tracks(context.Context) ([]Track, error)
ReadSample(context.Context) (Sample, error)
}
Stream is the transport-neutral input consumed by ProbeStream. Implementations can wrap HLS, RTSP, RTMP, SRT, MPEG-TS, or another live demuxer. The caller retains ownership of the stream and is responsible for closing it when necessary.
type Track ¶
type Track struct {
ID int `json:"id"`
MediaType MediaType `json:"type"`
Codec Codec `json:"codec"`
ClockRate int `json:"clock_rate,omitempty"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
SampleRate int `json:"sample_rate,omitempty"`
Channels int `json:"channels,omitempty"`
DeclaredFrameRate Rate `json:"declared_frame_rate,omitzero"`
}
Track describes a logical media track. Protocol-specific codec data remains owned by the source implementation.
type TrackReport ¶
type TrackReport struct {
Track
SampleCount int `json:"sample_count"`
ObservedPTSSpan time.Duration `json:"observed_pts_span"`
ObservedDTSSpan time.Duration `json:"observed_dts_span"`
Bitrate uint64 `json:"bitrate,omitempty"`
ObservedFrameRate float64 `json:"fps,omitempty"`
NominalFrameDuration time.Duration `json:"nominal_frame_duration,omitempty"`
MaxFrameDurationDeviation time.Duration `json:"max_frame_duration_deviation,omitempty"`
IrregularFrameIntervals int `json:"irregular_frame_intervals,omitempty"`
NonMonotonicDTS int `json:"non_monotonic_dts,omitempty"`
TimestampDiscontinuities int `json:"timestamp_discontinuities,omitempty"`
IsVariableFrameRate bool `json:"variable_frame_rate,omitempty"`
H264 *H264Report `json:"h264,omitempty"`
}
TrackReport contains measurements for one track.