mediamtx/internal/hls/client.go
Alessandro Ros c778c049ce
switch to gortsplib v2 (#1301)
Fixes #1103

gortsplib/v2 supports multiple formats inside a single track (media). This allows to apply the resizing algorithm to single formats inside medias.

For instance, if a media contains a a proprietary format and an H264 format, and the latter has oversized packets, they can now be resized.
2022-12-13 20:54:17 +01:00

122 lines
2.3 KiB
Go

package hls
import (
"context"
"fmt"
"net/url"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
"github.com/aler9/rtsp-simple-server/internal/logger"
)
const (
clientMPEGTSEntryQueueSize = 100
clientFMP4MaxPartTracksPerSegment = 200
clientLiveStartingInvPosition = 3
clientLiveMaxInvPosition = 5
clientMaxDTSRTCDiff = 10 * time.Second
)
func clientAbsoluteURL(base *url.URL, relative string) (*url.URL, error) {
u, err := url.Parse(relative)
if err != nil {
return nil, err
}
return base.ResolveReference(u), nil
}
// ClientLogger allows to receive log lines.
type ClientLogger interface {
Log(level logger.Level, format string, args ...interface{})
}
// Client is a HLS client.
type Client struct {
fingerprint string
onTracks func(*format.H264, *format.MPEG4Audio) error
onVideoData func(time.Duration, [][]byte)
onAudioData func(time.Duration, []byte)
logger ClientLogger
ctx context.Context
ctxCancel func()
playlistURL *url.URL
// out
outErr chan error
}
// NewClient allocates a Client.
func NewClient(
playlistURLStr string,
fingerprint string,
onTracks func(*format.H264, *format.MPEG4Audio) error,
onVideoData func(time.Duration, [][]byte),
onAudioData func(time.Duration, []byte),
logger ClientLogger,
) (*Client, error) {
playlistURL, err := url.Parse(playlistURLStr)
if err != nil {
return nil, err
}
ctx, ctxCancel := context.WithCancel(context.Background())
c := &Client{
fingerprint: fingerprint,
onTracks: onTracks,
onVideoData: onVideoData,
onAudioData: onAudioData,
logger: logger,
ctx: ctx,
ctxCancel: ctxCancel,
playlistURL: playlistURL,
outErr: make(chan error, 1),
}
go c.run()
return c, nil
}
// Close closes all the Client resources.
func (c *Client) Close() {
c.ctxCancel()
}
// Wait waits for any error of the Client.
func (c *Client) Wait() chan error {
return c.outErr
}
func (c *Client) run() {
c.outErr <- c.runInner()
}
func (c *Client) runInner() error {
rp := newClientRoutinePool()
dl := newClientDownloaderPrimary(
c.playlistURL,
c.fingerprint,
c.logger,
rp,
c.onTracks,
c.onVideoData,
c.onAudioData,
)
rp.add(dl)
select {
case err := <-rp.errorChan():
rp.close()
return err
case <-c.ctx.Done():
rp.close()
return fmt.Errorf("terminated")
}
}