m3u8: github.com/grafov/m3u8 Index | Examples | Files | Directories

package m3u8

import "github.com/grafov/m3u8"

Package M3U8 is parser & generator library for Apple HLS.

This is a most complete opensource library for parsing and generating of M3U8 playlists used in HTTP Live Streaming (Apple HLS) for internet video translations.

M3U8 is simple text format and parsing library for it must be simple too. It did not offer ways to play HLS or handle playlists over HTTP. Library features are:

* Support HLS specs up to version 5 of the protocol.
* Parsing and generation of master-playlists and media-playlists.
* Autodetect input streams as master or media playlists.
* Offer structures for keeping playlists metadata.
* Encryption keys support for usage with DRM systems like Verimatrix (http://verimatrix.com) etc.
* Support for non standard Google Widevine (http://www.widevine.com) tags.

Library coded accordingly with IETF draft http://tools.ietf.org/html/draft-pantos-http-live-streaming

Examples of usage may be found in *_test.go files of a package. Also see below some simple examples.

Create simple media playlist with sliding window of 3 segments and maximum of 50 segments.

p, e := NewMediaPlaylist(3, 50)
if e != nil {
  panic(fmt.Sprintf("Create media playlist failed: %s", e))
}
for i := 0; i < 5; i++ {
  e = p.Add(fmt.Sprintf("test%d.ts", i), 5.0)
  if e != nil {
    panic(fmt.Sprintf("Add segment #%d to a media playlist failed: %s", i, e))
  }
}
fmt.Println(p.Encode(true).String())

We add 5 testX.ts segments to playlist then encode it to M3U8 format and convert to string.

Next example shows parsing of master playlist:

f, err := os.Open("sample-playlists/master.m3u8")
if err != nil {
  fmt.Println(err)
}
p := NewMasterPlaylist()
err = p.DecodeFrom(bufio.NewReader(f), false)
if err != nil {
  fmt.Println(err)
}

fmt.Printf("Playlist object: %+v\n", p)

We are open playlist from the file and parse it as master playlist.

Index

Examples

Package Files

doc.go reader.go structure.go writer.go

Constants

const (
    DATETIME = time.RFC3339Nano // Format for EXT-X-PROGRAM-DATE-TIME defined in section 3.4.5
)

Variables

var (
    ErrPlaylistFull = errors.New("playlist is full")
)
var TimeParse func(value string) (time.Time, error) = FullTimeParse

Allow globally apply and/or override Time Parser function. Available variants:

* FullTimeParse - implements full featured ISO/IEC 8601:2004
* StrictTimeParse - implements only RFC3339 Nanoseconds format

func Decode Uses

func Decode(data bytes.Buffer, strict bool) (Playlist, ListType, error)

Decode detects type of playlist and decodes it. It accepts bytes buffer as input.

func DecodeAttributeList Uses

func DecodeAttributeList(line string) map[string]string

DecodeAttributeList turns an attribute list into a key, value map. You should trim any characters not part of the attribute list, such as the tag and ':'.

func DecodeFrom Uses

func DecodeFrom(reader io.Reader, strict bool) (Playlist, ListType, error)

DecodeFrom detects type of playlist and decodes it. It accepts data conformed with io.Reader.

func DecodeWith Uses

func DecodeWith(input interface{}, strict bool, customDecoders []CustomDecoder) (Playlist, ListType, error)

DecodeWith detects the type of playlist and decodes it. It accepts either bytes.Buffer or io.Reader as input. Any custom decoders provided will be used during decoding.

func FullTimeParse Uses

func FullTimeParse(value string) (time.Time, error)

FullTimeParse implements ISO/IEC 8601:2004.

func StrictTimeParse Uses

func StrictTimeParse(value string) (time.Time, error)

StrictTimeParse implements RFC3339 with Nanoseconds accuracy.

type Alternative Uses

type Alternative struct {
    GroupId         string
    URI             string
    Type            string
    Language        string
    Name            string
    Default         bool
    Autoselect      string
    Forced          string
    Characteristics string
    Subtitles       string
}

This structure represents EXT-X-MEDIA tag in variants.

type CustomDecoder Uses

type CustomDecoder interface {
    // TagName should return the full indentifier including the leading '#' as well as the
    // trailing ':' if the tag also contains a value or attribute list
    TagName() string
    // Decode parses a line from the playlist and returns the CustomTag representation
    Decode(line string) (CustomTag, error)
    // SegmentTag should return true if this CustomDecoder should apply per segment.
    // Should returns false if it a MediaPlaylist header tag.
    // This value is ignored for MasterPlaylists.
    SegmentTag() bool
}

Interface for decoding custom and unsupported tags

type CustomTag Uses

type CustomTag interface {
    // TagName should return the full indentifier including the leading '#' as well as the
    // trailing ':' if the tag also contains a value or attribute list
    TagName() string
    // Encode should return the complete tag string as a *bytes.Buffer. This will
    // be used by Playlist.Decode to write the tag to the m3u8.
    // Return nil to not write anything to the m3u8.
    Encode() *bytes.Buffer
    // String should return the encoded tag as a string.
    String() string
}

Interface for encoding custom and unsupported tags

type Key Uses

type Key struct {
    Method            string
    URI               string
    IV                string
    Keyformat         string
    Keyformatversions string
}

This structure represents information about stream encryption.

Realizes EXT-X-KEY tag.

type ListType Uses

type ListType uint
const (
    // use 0 for not defined type
    MASTER ListType = iota + 1
    MEDIA
)

type Map Uses

type Map struct {
    URI    string
    Limit  int64 // <n> is length in bytes for the file under URI
    Offset int64 // [@o] is offset from the start of the file under URI
}

It applies to every Media Segment that appears after it in the Playlist until the next EXT-X-MAP tag or until the end of the playlist.

Realizes EXT-MAP tag.

type MasterPlaylist Uses

type MasterPlaylist struct {
    Variants      []*Variant
    Args          string // optional arguments placed after URI (URI?Args)
    CypherVersion string // non-standard tag for Widevine (see also WV struct)

    Custom map[string]CustomTag
    // contains filtered or unexported fields
}

This structure represents a master playlist which combines media playlists for multiple bitrates. URI lines in the playlist identify media playlists. Sample of Master Playlist file:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1280000
http://example.com/low.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2560000
http://example.com/mid.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7680000
http://example.com/hi.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS="mp4a.40.5"
http://example.com/audio-only.m3u8

func NewMasterPlaylist Uses

func NewMasterPlaylist() *MasterPlaylist

Create new empty master playlist. Master playlist consists of variants.

func (*MasterPlaylist) Append Uses

func (p *MasterPlaylist) Append(uri string, chunklist *MediaPlaylist, params VariantParams)

Append variant to master playlist. This operation does reset playlist cache.

func (*MasterPlaylist) Decode Uses

func (p *MasterPlaylist) Decode(data bytes.Buffer, strict bool) error

Decode parses a master playlist passed from the buffer. If `strict` parameter is true then it returns first syntax error.

func (*MasterPlaylist) DecodeFrom Uses

func (p *MasterPlaylist) DecodeFrom(reader io.Reader, strict bool) error

DecodeFrom parses a master playlist passed from the io.Reader stream. If `strict` parameter is true then it returns first syntax error.

func (*MasterPlaylist) Encode Uses

func (p *MasterPlaylist) Encode() *bytes.Buffer

Generate output in M3U8 format.

func (*MasterPlaylist) IndependentSegments Uses

func (p *MasterPlaylist) IndependentSegments() bool

IndependentSegments returns true if all media samples in a segment can be decoded without information from other segments.

func (*MasterPlaylist) ResetCache Uses

func (p *MasterPlaylist) ResetCache()

func (*MasterPlaylist) SetCustomTag Uses

func (p *MasterPlaylist) SetCustomTag(tag CustomTag)

SetCustomTag sets the provided tag on the master playlist for its TagName

func (*MasterPlaylist) SetIndependentSegments Uses

func (p *MasterPlaylist) SetIndependentSegments(b bool)

SetIndependentSegments sets whether all media samples in a segment can be decoded without information from other segments.

func (*MasterPlaylist) SetVersion Uses

func (p *MasterPlaylist) SetVersion(ver uint8)

SetVersion sets the playlist version number, note the version maybe changed automatically by other Set methods.

func (*MasterPlaylist) String Uses

func (p *MasterPlaylist) String() string

For compatibility with Stringer interface For example fmt.Printf("%s", sampleMediaList) will encode playist and print its string representation.

Create new master playlist Add media playlist Encode structures to HLS

Code:

m := NewMasterPlaylist()
p, _ := NewMediaPlaylist(3, 5)
for i := 0; i < 5; i++ {
    p.Append(fmt.Sprintf("test%d.ts", i), 5.0, "")
}
m.Append("chunklist1.m3u8", p, VariantParams{ProgramId: 123, Bandwidth: 1500000, AverageBandwidth: 1500000, Resolution: "576x480", FrameRate: 25.000})
m.Append("chunklist2.m3u8", p, VariantParams{ProgramId: 123, Bandwidth: 1500000, AverageBandwidth: 1500000, Resolution: "576x480", FrameRate: 25.000})
fmt.Printf("%s", m)

Output:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:PROGRAM-ID=123,BANDWIDTH=1500000,AVERAGE-BANDWIDTH=1500000,RESOLUTION=576x480,FRAME-RATE=25.000
chunklist1.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=123,BANDWIDTH=1500000,AVERAGE-BANDWIDTH=1500000,RESOLUTION=576x480,FRAME-RATE=25.000
chunklist2.m3u8

func (*MasterPlaylist) Version Uses

func (p *MasterPlaylist) Version() uint8

Version returns the current playlist version number

func (*MasterPlaylist) WithCustomDecoders Uses

func (p *MasterPlaylist) WithCustomDecoders(customDecoders []CustomDecoder) Playlist

WithCustomDecoders adds custom tag decoders to the master playlist for decoding

type MediaPlaylist Uses

type MediaPlaylist struct {
    TargetDuration   float64
    SeqNo            uint64 // EXT-X-MEDIA-SEQUENCE
    Segments         []*MediaSegment
    Args             string // optional arguments placed after URIs (URI?Args)
    Iframe           bool   // EXT-X-I-FRAMES-ONLY
    Closed           bool   // is this VOD (closed) or Live (sliding) playlist?
    MediaType        MediaType
    DiscontinuitySeq uint64 // EXT-X-DISCONTINUITY-SEQUENCE
    StartTime        float64
    StartTimePrecise bool

    Key    *Key // EXT-X-KEY is optional encryption key displayed before any segments (default key for the playlist)
    Map    *Map // EXT-X-MAP is optional tag specifies how to obtain the Media Initialization Section (default map for the playlist)
    WV     *WV  // Widevine related tags outside of M3U8 specs
    Custom map[string]CustomTag
    // contains filtered or unexported fields
}

This structure represents a single bitrate playlist aka media playlist. It related to both a simple media playlists and a sliding window media playlists. URI lines in the Playlist point to media segments.

Simple Media Playlist file sample:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5220
#EXTINF:5219.2,
http://media.example.com/entire.ts
#EXT-X-ENDLIST

Sample of Sliding Window Media Playlist, using HTTPS:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:2680

#EXTINF:7.975,
https://priv.example.com/fileSequence2680.ts
#EXTINF:7.941,
https://priv.example.com/fileSequence2681.ts
#EXTINF:7.975,
https://priv.example.com/fileSequence2682.ts

func NewMediaPlaylist Uses

func NewMediaPlaylist(winsize uint, capacity uint) (*MediaPlaylist, error)

Creates new media playlist structure. Winsize defines how much items will displayed on playlist generation. Capacity is total size of a playlist.

func (*MediaPlaylist) Append Uses

func (p *MediaPlaylist) Append(uri string, duration float64, title string) error

Append general chunk to the tail of chunk slice for a media playlist. This operation does reset playlist cache.

func (*MediaPlaylist) AppendSegment Uses

func (p *MediaPlaylist) AppendSegment(seg *MediaSegment) error

AppendSegment appends a MediaSegment to the tail of chunk slice for a media playlist. This operation does reset playlist cache.

func (*MediaPlaylist) Close Uses

func (p *MediaPlaylist) Close()

Close sliding playlist and make them fixed.

func (*MediaPlaylist) Count Uses

func (p *MediaPlaylist) Count() uint

Count tells us the number of items that are currently in the media playlist

func (*MediaPlaylist) Decode Uses

func (p *MediaPlaylist) Decode(data bytes.Buffer, strict bool) error

Decode parses a media playlist passed from the buffer. If `strict` parameter is true then return first syntax error.

func (*MediaPlaylist) DecodeFrom Uses

func (p *MediaPlaylist) DecodeFrom(reader io.Reader, strict bool) error

DecodeFrom parses a media playlist passed from the io.Reader stream. If `strict` parameter is true then it returns first syntax error.

func (*MediaPlaylist) DurationAsInt Uses

func (p *MediaPlaylist) DurationAsInt(yes bool)

TargetDuration will be int on Encode

Example of parsing a playlist with EXT-X-DISCONTINIUTY tag and output it with integer segment durations.

Code:

f, _ := os.Open("sample-playlists/media-playlist-with-discontinuity.m3u8")
p, _, _ := DecodeFrom(bufio.NewReader(f), true)
pp := p.(*MediaPlaylist)
pp.DurationAsInt(true)
fmt.Printf("%s", pp)

Output:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:10
#EXTINF:10,
ad0.ts
#EXTINF:8,
ad1.ts
#EXT-X-DISCONTINUITY
#EXTINF:10,
movieA.ts
#EXTINF:10,
movieB.ts

func (*MediaPlaylist) Encode Uses

func (p *MediaPlaylist) Encode() *bytes.Buffer

Generate output in M3U8 format. Marshal `winsize` elements from bottom of the `segments` queue.

func (*MediaPlaylist) Remove Uses

func (p *MediaPlaylist) Remove() (err error)

Remove current segment from the head of chunk slice form a media playlist. Useful for sliding playlists. This operation does reset playlist cache.

func (*MediaPlaylist) ResetCache Uses

func (p *MediaPlaylist) ResetCache()

Reset playlist cache. Next called Encode() will regenerate playlist from the chunk slice.

func (*MediaPlaylist) SetCustomSegmentTag Uses

func (p *MediaPlaylist) SetCustomSegmentTag(tag CustomTag) error

SetCustomTag sets the provided tag on the current media segment for its TagName

func (*MediaPlaylist) SetCustomTag Uses

func (p *MediaPlaylist) SetCustomTag(tag CustomTag)

SetCustomTag sets the provided tag on the media playlist for its TagName

func (*MediaPlaylist) SetDefaultKey Uses

func (p *MediaPlaylist) SetDefaultKey(method, uri, iv, keyformat, keyformatversions string) error

Set encryption key appeared once in header of the playlist (pointer to MediaPlaylist.Key). It useful when keys not changed during playback. Set tag for the whole list.

func (*MediaPlaylist) SetDefaultMap Uses

func (p *MediaPlaylist) SetDefaultMap(uri string, limit, offset int64)

Set default Media Initialization Section values for playlist (pointer to MediaPlaylist.Map). Set EXT-X-MAP tag for the whole playlist.

func (*MediaPlaylist) SetDiscontinuity Uses

func (p *MediaPlaylist) SetDiscontinuity() error

Set discontinuity flag for the current media segment. EXT-X-DISCONTINUITY indicates an encoding discontinuity between the media segment that follows it and the one that preceded it (i.e. file format, number and type of tracks, encoding parameters, encoding sequence, timestamp sequence).

func (*MediaPlaylist) SetIframeOnly Uses

func (p *MediaPlaylist) SetIframeOnly()

Mark medialist as consists of only I-frames (Intra frames). Set tag for the whole list.

func (*MediaPlaylist) SetKey Uses

func (p *MediaPlaylist) SetKey(method, uri, iv, keyformat, keyformatversions string) error

Set encryption key for the current segment of media playlist (pointer to Segment.Key)

func (*MediaPlaylist) SetMap Uses

func (p *MediaPlaylist) SetMap(uri string, limit, offset int64) error

Set map for the current segment of media playlist (pointer to Segment.Map)

func (*MediaPlaylist) SetProgramDateTime Uses

func (p *MediaPlaylist) SetProgramDateTime(value time.Time) error

Set program date and time for the current media segment. EXT-X-PROGRAM-DATE-TIME tag associates the first sample of a media segment with an absolute date and/or time. It applies only to the current media segment. Date/time format is YYYY-MM-DDThh:mm:ssZ (ISO8601) and includes time zone.

func (*MediaPlaylist) SetRange Uses

func (p *MediaPlaylist) SetRange(limit, offset int64) error

Set limit and offset for the current media segment (EXT-X-BYTERANGE support for protocol version 4).

func (*MediaPlaylist) SetSCTE Uses

func (p *MediaPlaylist) SetSCTE(cue string, id string, time float64) error

SetSCTE sets the SCTE cue format for the current media segment.

Deprecated: Use SetSCTE35 instead.

func (*MediaPlaylist) SetSCTE35 Uses

func (p *MediaPlaylist) SetSCTE35(scte35 *SCTE) error

SetSCTE35 sets the SCTE cue format for the current media segment

func (*MediaPlaylist) SetVersion Uses

func (p *MediaPlaylist) SetVersion(ver uint8)

SetVersion sets the playlist version number, note the version maybe changed automatically by other Set methods.

func (*MediaPlaylist) SetWinSize Uses

func (p *MediaPlaylist) SetWinSize(winsize uint) error

SetWinSize overwrites the playlist's window size.

func (*MediaPlaylist) Slide Uses

func (p *MediaPlaylist) Slide(uri string, duration float64, title string)

Combines two operations: firstly it removes one chunk from the head of chunk slice and move pointer to next chunk. Secondly it appends one chunk to the tail of chunk slice. Useful for sliding playlists. This operation does reset cache.

func (*MediaPlaylist) String Uses

func (p *MediaPlaylist) String() string

For compatibility with Stringer interface For example fmt.Printf("%s", sampleMediaList) will encode playist and print its string representation.

Create new media playlist Add two segments to media playlist Print it

Code:

p, _ := NewMediaPlaylist(1, 2)
p.Append("test01.ts", 5.0, "")
p.Append("test02.ts", 6.0, "")
fmt.Printf("%s\n", p)

Output:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:6
#EXTINF:5.000,
test01.ts

func (*MediaPlaylist) Version Uses

func (p *MediaPlaylist) Version() uint8

Version returns the current playlist version number

func (*MediaPlaylist) WinSize Uses

func (p *MediaPlaylist) WinSize() uint

WinSize returns the playlist's window size.

func (*MediaPlaylist) WithCustomDecoders Uses

func (p *MediaPlaylist) WithCustomDecoders(customDecoders []CustomDecoder) Playlist

WithCustomDecoders adds custom tag decoders to the media playlist for decoding

type MediaSegment Uses

type MediaSegment struct {
    SeqId           uint64
    Title           string // optional second parameter for EXTINF tag
    URI             string
    Duration        float64   // first parameter for EXTINF tag; duration must be integers if protocol version is less than 3 but we are always keep them float
    Limit           int64     // EXT-X-BYTERANGE <n> is length in bytes for the file under URI
    Offset          int64     // EXT-X-BYTERANGE [@o] is offset from the start of the file under URI
    Key             *Key      // EXT-X-KEY displayed before the segment and means changing of encryption key (in theory each segment may have own key)
    Map             *Map      // EXT-X-MAP displayed before the segment
    Discontinuity   bool      // EXT-X-DISCONTINUITY indicates an encoding discontinuity between the media segment that follows it and the one that preceded it (i.e. file format, number and type of tracks, encoding parameters, encoding sequence, timestamp sequence)
    SCTE            *SCTE     // SCTE-35 used for Ad signaling in HLS
    ProgramDateTime time.Time // EXT-X-PROGRAM-DATE-TIME tag associates the first sample of a media segment with an absolute date and/or time
    Custom          map[string]CustomTag
}

This structure represents a media segment included in a media playlist. Media segment may be encrypted. Widevine supports own tags for encryption metadata.

type MediaType Uses

type MediaType uint

for EXT-X-PLAYLIST-TYPE tag

const (
    // use 0 for not defined type
    EVENT MediaType = iota + 1
    VOD
)

type Playlist Uses

type Playlist interface {
    Encode() *bytes.Buffer
    Decode(bytes.Buffer, bool) error
    DecodeFrom(reader io.Reader, strict bool) error
    WithCustomDecoders([]CustomDecoder) Playlist
    String() string
}

Interface applied to various playlist types.

type SCTE Uses

type SCTE struct {
    Syntax  SCTE35Syntax  // Syntax defines the format of the SCTE-35 cue tag
    CueType SCTE35CueType // CueType defines whether the cue is a start, mid, end (if applicable)
    Cue     string
    ID      string
    Time    float64
    Elapsed float64
}

SCTE holds custom, non EXT-X-DATERANGE, SCTE-35 tags

type SCTE35CueType Uses

type SCTE35CueType uint

SCTE35CueType defines the type of cue point, used by readers and writers to write a different syntax

const (
    SCTE35Cue_Start SCTE35CueType = iota // SCTE35Cue_Start indicates an out cue point
    SCTE35Cue_Mid                        // SCTE35Cue_Mid indicates a segment between start and end cue points
    SCTE35Cue_End                        // SCTE35Cue_End indicates an in cue point
)

type SCTE35Syntax Uses

type SCTE35Syntax uint

SCTE35Syntax defines the format of the SCTE-35 cue points which do not use the draft-pantos-http-live-streaming-19 EXT-X-DATERANGE tag and instead have their own custom tags

const (
    // SCTE35_67_2014 will be the default due to backwards compatibility reasons.
    SCTE35_67_2014 SCTE35Syntax = iota // SCTE35_67_2014 defined in http://www.scte.org/documents/pdf/standards/SCTE%2067%202014.pdf
    SCTE35_OATCLS                      // SCTE35_OATCLS is a non-standard but common format
)

type Variant Uses

type Variant struct {
    URI       string
    Chunklist *MediaPlaylist
    VariantParams
}

This structure represents variants for master playlist. Variants included in a master playlist and point to media playlists.

type VariantParams Uses

type VariantParams struct {
    ProgramId        uint32
    Bandwidth        uint32
    AverageBandwidth uint32 // EXT-X-STREAM-INF only
    Codecs           string
    Resolution       string
    Audio            string // EXT-X-STREAM-INF only
    Video            string
    Subtitles        string // EXT-X-STREAM-INF only
    Captions         string // EXT-X-STREAM-INF only
    Name             string // EXT-X-STREAM-INF only (non standard Wowza/JWPlayer extension to name the variant/quality in UA)
    Iframe           bool   // EXT-X-I-FRAME-STREAM-INF
    VideoRange       string
    HDCPLevel        string
    FrameRate        float64        // EXT-X-STREAM-INF
    Alternatives     []*Alternative // EXT-X-MEDIA
}

This structure represents additional parameters for a variant used in EXT-X-STREAM-INF and EXT-X-I-FRAME-STREAM-INF

type WV Uses

type WV struct {
    AudioChannels          uint
    AudioFormat            uint
    AudioProfileIDC        uint
    AudioSampleSize        uint
    AudioSamplingFrequency uint
    CypherVersion          string
    ECM                    string
    VideoFormat            uint
    VideoFrameRate         uint
    VideoLevelIDC          uint
    VideoProfileIDC        uint
    VideoResolution        string
    VideoSAR               string
}

This structure represents metadata for Google Widevine playlists. This format not described in IETF draft but provied by Widevine Live Packager as additional tags with #WV-prefix.

Directories

PathSynopsis
example
example/template

Package m3u8 imports 9 packages (graph) and is imported by 37 packages. Updated 2019-08-09. Refresh now. Tools for package owners.