Parser and generator of M3U8-playlists for Apple HLS. Library for Go language. :cinema:

Overview

M3U8

This is the 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 does not offer ways to play HLS or handle playlists over HTTP. So 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 use with DRM systems like Verimatrix etc.
  • Support for non standard Google Widevine tags.

The library covered by BSD 3-clause license. See LICENSE for the full text. Versions 0.8 and below was covered by GPL v3. License was changed from the version 0.9 and upper.

See the list of the library authors at AUTHORS file.

Install

go get github.com/grafov/m3u8

or get releases from https://github.com/grafov/m3u8/releases

Documentation Go Walker GoDoc

Package online documentation (examples included) available at:

Supported by the HLS protocol tags and their library support explained in M3U8 cheatsheet.

Examples

Parse playlist:

	f, err := os.Open("playlist.m3u8")
	if err != nil {
		panic(err)
	}
	p, listType, err := m3u8.DecodeFrom(bufio.NewReader(f), true)
	if err != nil {
		panic(err)
	}
	switch listType {
	case m3u8.MEDIA:
		mediapl := p.(*m3u8.MediaPlaylist)
		fmt.Printf("%+v\n", mediapl)
	case m3u8.MASTER:
		masterpl := p.(*m3u8.MasterPlaylist)
		fmt.Printf("%+v\n", masterpl)
	}

Then you get filled with parsed data structures. For master playlists you get Master struct with slice consists of pointers to Variant structures (which represent playlists to each bitrate). For media playlist parser returns MediaPlaylist structure with slice of Segments. Each segment is of MediaSegment type. See structure.go or full documentation (link below).

You may use API methods to fill structures or create them manually to generate playlists. Example of media playlist generation:

	p, e := m3u8.NewMediaPlaylist(3, 10) // with window of size 3 and capacity 10
	if e != nil {
		panic(fmt.Sprintf("Creating of media playlist failed: %s", e))
	}
	for i := 0; i < 5; i++ {
		e = p.Append(fmt.Sprintf("test%d.ts", i), 6.0, "")
		if e != nil {
			panic(fmt.Sprintf("Add segment #%d to a media playlist failed: %s", i, e))
		}
	}
	fmt.Println(p.Encode().String())

Custom Tags

M3U8 supports parsing and writing of custom tags. You must implement both the CustomTag and CustomDecoder interface for each custom tag that may be encountered in the playlist. Look at the template files in example/template/ for examples on parsing custom playlist and segment tags.

Library structure

Library has compact code and bundled in three files:

  • structure.go — declares all structures related to playlists and their properties
  • reader.go — playlist parser methods
  • writer.go — playlist generator methods

Each file has own test suite placed in *_test.go accordingly.

Related links

Library usage

This library was successfully used in streaming software developed for company where I worked several years ago. It was tested then in generating of VOD and Live streams and parsing of Widevine Live streams. Also the library used in opensource software so you may look at these apps for usage examples:

Project status Go Report Card

Build Status Build Status Coverage Status

DeepSource

Code coverage: https://gocover.io/github.com/grafov/m3u8

Project maintainers:

  • Lei Gao @leikao
  • Bradley Falzon @bradleyfalzon
  • Alexander Grafov @grafov

Roadmap

To version 1.0:

  • Support all M3U8 tags up to latest version of specs.
  • Code coverage by unit tests up to 90%

FYI M3U8 parsing/generation in other languages

Issues
  • Time Parsing fix for #EXT-X-PROGRAM-DATE-TIME

    Time Parsing fix for #EXT-X-PROGRAM-DATE-TIME

    While HLS Draft in section 3.4.5 require that time should comply with RFC3339, during my work i noticed that many Encoders use ISO8601 where Timezone representation is less strict than RFC3339. ISO8601 allow to expose TZ in several ways:

    DateTime/Zone
    <time>Z
    <time>±hh:mm (by RFC3339)
    <time>±hhmm
    <time>±hh
    

    Example of manifest where we getting Parser error:

    #EXTM3U
    #EXT-X-TARGETDURATION:8
    #EXT-X-PROGRAM-DATE-TIME:2017-01-30T17:26:04+0100
    #EXT-X-MEDIA-SEQUENCE:855733
    #EXTINF:8,
    1478947334-fast-1920-1080-2750000-855733.ts
    #EXTINF:8,
    1478947334-fast-1920-1080-2750000-855734.ts
    #EXTINF:8,
    1478947334-fast-1920-1080-2750000-855735.ts
    

    Error itself: parsing time "2017-01-30T17:26:04+0100" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "+0100" as "Z07:00"

    But while RFC3339 newer then ISO8601, lot of software still use it, so my proposal is to create Format validation for incoming tag #EXT-X-PROGRAM-DATE-TIME in reader.go and using switch{case} test incoming string against precompiled regexp rules, and route string to time.Parse() with proper layout(format).

    I implemented only RFC3339 with Nano seconds, this should be enough and in case we need add other formats this will be easy to add to switch{case} chain.

    enhancement 
    opened by md2k 32
  • Add CLOSED-CAPTIONS= to writer for (STREAM-INF)

    Add CLOSED-CAPTIONS= to writer for (STREAM-INF)

    enhancement 
    opened by mbowBC 16
  • Parsing SCTE35 tag from playlist

    Parsing SCTE35 tag from playlist

    Adding feature as per SCTE standards Ref : http://www.scte.org/documents/pdf/standards/SCTE%2067%202014.pdf 12.1.6.1 HLS Cue Tags

    enhancement 
    opened by vishal24tuniki 13
  • Increase efficiency for large playlist

    Increase efficiency for large playlist

    Increase efficiency for large playlist.

    before

    BenchmarkDecodeMediaPlaylist-8        50          23445112 ns/op        12282139 B/op     160240 allocs/op
    BenchmarkEncodeMediaPlaylist-8       100          14378131 ns/op         1749294 B/op      81643 allocs/op
    

    after

    BenchmarkDecodeMediaPlaylist-8       100          16781361 ns/op        11001559 B/op     120172 allocs/op
    BenchmarkEncodeMediaPlaylist-8       100          13064495 ns/op         1744527 B/op      81247 allocs/op
    
    enhancement 
    opened by hori-ryota 12
  • Export winsize

    Export winsize

    When decoding a playlist with a window size bigger than 8 then an encode will result in a truncated playlist. This due to this line here.

    media, err = NewMediaPlaylist(8, 1024) // TODO make it autoextendable
    

    Would it be possible to update the winsize afterwards through Count() internally?

    opened by konradreiche 12
  • Custom Tag Support

    Custom Tag Support

    Hello, thanks for an awesome m3u8 project. We came across the need to read and write custom tags to m3u8 so I've implemented it through an interface in my fork, but would love to get this upstream so we don't have to use a fork. I've implemented this in a way that should allow for the parsing of any format as the user will have to implement the interface. This way we do not have to pollute the source code with parsing/writing for non-standard tags that only a few users have need for or that cant be made open source. I've also included example template files for how to implement your own custom tag readers and writers.

    I noticed there is an issue as well that this will help resolve #82

    opened by mjneil 10
  • Add values to VariantParams

    Add values to VariantParams

    Sorry, I am a Golang newbie and my use case is to introduce a new key into the variant called 'rendition-id' to help clients create a rendition switcher.

    package main
    
    import (
    	"fmt"
    
    	"github.com/grafov/m3u8"
    )
    
    // https://godoc.org/github.com/grafov/m3u8#VariantParams
    
    type myVariantParams struct {
    	*m3u8.VariantParams
    	RenditionId string
    }
    
    func main() {
    
    	masterPlaylist := m3u8.NewMasterPlaylist()
    
    	pp, _ := m3u8.NewMediaPlaylist(3, 5)
    	for i := 0; i < 5; i++ {
    		pp.Append(fmt.Sprintf("test%d.ts", i), 5.0, "")
    	}
    
    	// WORKS
    	masterPlaylist.Append("chunklist2.m3u8", pp, m3u8.VariantParams{ProgramId: 123, Bandwidth: 1500000, Resolution: "576x480"})
    
    	// Trying to extend VariantParams doesn't !
    	// masterPlaylist.Append("chunklist2.m3u8", pp, myVariantParams{VariantParams: &m3u8.VariantParams{ProgramId: 123, Bandwidth: 1500000, Resolution: "576x480"}, RenditionId: "foo"})
    
    	fmt.Println(len(masterPlaylist.Variants))
    	masterPlaylist.ResetCache()
    
    	fmt.Println(masterPlaylist.Encode().String())
    
    }
    

    Perhaps this is the same as #82. Anyway, just thought I'd convey my use case. My tact now is to fork and add the missing values.

    question 
    opened by kaihendry 9
  • Add support for multiple SCTE-35 tag syntax

    Add support for multiple SCTE-35 tag syntax

    There appear to be various non-standard implementations of SCTE-35 integration with HLS.

    The recent draft of HLS now has an official method to support SCTE-35 tags as well as the cue points. See: https://www.ietf.org/rfcdiff?url1=draft-pantos-http-live-streaming-18&url2=draft-pantos-http-live-streaming-19

    I'd like this library to support the new standard, but #40 and #41 introduced support for a different standard. There's also at least two other formats I've seen.

    I think we need a method to read multiple standards, store and manipulate them consistently and write multiple standards. With the focus being on the HLS RFC's method, and the existing format already supported by this library - but this may require some breaking changes.

    This issue is open to discuss this.

    Other support that could be added later: http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/primetime/pdfs/PrimetimeDigitalProgramInsertionSignalingSpecification1_1.pdf

    enhancement 
    opened by bradleyfalzon 8
  • Change license to a more permissive

    Change license to a more permissive

    This library uses the GPL license which makes it actually impossible for us to use as it would require us to use the GPL license as well as disclose our source code. Working on a commercial product it would mean that we need to move away from this library and roll our own implementation.

    How deliberate is the choice of GPL. Would other, more permissive licenses, like MIT or Apache be a feasible alternative?

    opened by konradreiche 8
  • encode Segment.Map attribute

    encode Segment.Map attribute

    Hi @grafov have added encoding for Segment.Map to address https://github.com/grafov/m3u8/issues/93

    opened by andyborn 8
  • I  have a  SCTE-35 parser......

    I have a SCTE-35 parser......

    https://github.com/futzu/threefive/tree/master/go

    I think we could help each other.

    Adrian

    opened by futzu 0
  • EXT-X-MEDIA CHANNELS

    EXT-X-MEDIA CHANNELS

    CHANNELS attribute example in

    curl -k "https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8"
    
    opened by vany-egorov 3
  • Declare errors to make easier for callers to detect

    Declare errors to make easier for callers to detect

    We've found a few places where it would be nice to be able to handle specific errors without resorting to string processing.

    opened by eric 2
  • m3u8.DecodeFrom panics in case of blank lines in playlist

    m3u8.DecodeFrom panics in case of blank lines in playlist

    package main
    
    import (
    	"bytes"
    
    	"github.com/grafov/m3u8"
    )
    
    func main() {
    	raw := []byte(`#EXTM3U
    #EXT-X-VERSION:2
    #EXT-X-ALLOW-CACHE:NO
    #EXT-X-TARGETDURATION:7
    #EXT-X-MEDIA-SEQUENCE:2718
    
    #EXT-X-KEY:METHOD=NONE
    
    #EXTINF:6,
    stream300k2020_9_22_12_41_58-2718.ts
    #EXTINF:7,
    stream300k2020_9_22_12_42_5-2719.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_11-2720.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_18-2721.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_24-2722.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_30-2723.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_37-2724.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_43-2725.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_50-2726.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_56-2727.ts`)
    
    	buf := bytes.NewBuffer(raw)
    
    	m3u8.DecodeFrom(buf, false)
    }
    
    go run ./m3u8-with-new-lines.go
    panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4e2357]
    
    goroutine 1 [running]:
    github.com/grafov/m3u8.decodeLineOfMediaPlaylist(0xc0000d6000, 0xc0000d4000, 0xc000093e00, 0x5cc4f0, 0x1, 0x0, 0x0, 0x0)
            gopath/pkg/mod/github.com/grafov/[email protected]/reader.go:539 +0x3537
    github.com/grafov/m3u8.decode(0xc000093ef8, 0x53ce00, 0x0, 0x0, 0x0, 0x0, 0x4fdb80, 0xc000096250, 0xc000093f18, 0xc000093f20)
            gopath/pkg/mod/github.com/grafov/[email protected]/reader.go:227 +0x30a
    github.com/grafov/m3u8.DecodeFrom(0x53cec0, 0xc000098240, 0x406000, 0xc000094058, 0x0, 0x0, 0x0, 0x4f5ca0)
            gopath/pkg/mod/github.com/grafov/[email protected]/reader.go:161 +0xca
    main.main()
            m3u8-with-new-lines.go:41 +0xc5
    exit status 2
    
    $ go version
    go version go1.15.1 linux/amd64
    

    Very fast hack/work-around:

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"regexp"
    
    	"github.com/grafov/m3u8"
    )
    
    var reBlankLines = regexp.MustCompile(`[\t\r\n]+`)
    
    func removeBlankLinesFromBuffer(buf *bytes.Buffer) {
    	data := buf.Bytes()
    	if reBlankLines.Match(data) {
    		data = reBlankLines.ReplaceAll(
    			bytes.TrimSpace(buf.Bytes()),
    			[]byte("\n"),
    		)
    		buf.Reset()
    		buf.Write(data)
    	}
    }
    
    func main() {
    	raw := []byte(`#EXTM3U
    #EXT-X-VERSION:2
    #EXT-X-ALLOW-CACHE:NO
    #EXT-X-TARGETDURATION:7
    #EXT-X-MEDIA-SEQUENCE:2718
    
    #EXT-X-KEY:METHOD=NONE
    
    #EXTINF:6,
    stream300k2020_9_22_12_41_58-2718.ts
    #EXTINF:7,
    stream300k2020_9_22_12_42_5-2719.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_11-2720.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_18-2721.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_24-2722.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_30-2723.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_37-2724.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_43-2725.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_50-2726.ts
    #EXTINF:6,
    stream300k2020_9_22_12_42_56-2727.ts`)
    
    	buf := bytes.NewBuffer(raw)
    
    	removeBlankLinesFromBuffer(buf)
    
    	p, t, err := m3u8.DecodeFrom(buf, false)
    	fmt.Println(p, t, err)
    }
    
    opened by vany-egorov 0
  • [update] Project addition

    [update] Project addition

    Just a fun tool I built using this amazing library :)

    opened by imthaghost 1
  • MediaPlaylist decode custom tag panic

    MediaPlaylist decode custom tag panic

    func (p *MediaPlaylist) decode(buf *bytes.Buffer, strict bool) error { var eof bool var line string var err error

    state := new(decodingState)
    wv := new(WV)
    
    for !eof {
    	if line, err = buf.ReadString('\n'); err == io.EOF {
    		eof = true
    	} else if err != nil {
    		break
    	}
    
    	err = decodeLineOfMediaPlaylist(p, wv, state, line, strict)
    	if strict && err != nil {
    		return err
    	}
    
    }
    if state.tagWV {
    	p.WV = wv
    }
    if strict && !state.m3u {
    	return errors.New("#EXTM3U absent")
    }
    return nil
    

    }


    if p has customDecoder, directly decode, but state not initalized, when call decodeLineOfMediaPlaylist will panic

    opened by panda1986 0
  • Update URL

    Update URL

    We have changed our url😀

    opened by wolfcon 1
  • .

    .

    opened by zackmark29 2
  • EXT-X-MEDIA audio missing from VariantParams.Alternatives for master playlist decode

    EXT-X-MEDIA audio missing from VariantParams.Alternatives for master playlist decode

    For the master playlist below, the MasterPlaylist object (after decoding) is missing the audio stream with GROUP-ID="audio-aacl-128". That is, MasterPlaylist.Variants[9].VariantParams.Alternatives is nil.

    Also, only the first variant's Alternatives is populated, which I believe is this ticket: https://github.com/grafov/m3u8/issues/96. However, I can't work around this by accessing the audio-aacl-128 stream using the first variant, because it specifies AUDIO="audio-aacl-64".

    #EXTM3U
    #EXT-X-VERSION:5
    ## Created with Unified Streaming Platform(version=1.9.5)
    
    # AUDIO groups
    #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-aacl-64",NAME="English",LANGUAGE="en",AUTOSELECT=YES,DEFAULT=YES,CHANNELS="2",URI="avc_decrypted_global-stream_audio_eng_64000=64000.m3u8"
    
    # variants
    #EXT-X-STREAM-INF:BANDWIDTH=202000,AVERAGE-BANDWIDTH=184000,CODECS="mp4a.40.2,avc1.42C01E",RESOLUTION=192x108,FRAME-RATE=25,AUDIO="audio-aacl-64",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=112000.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=407000,AVERAGE-BANDWIDTH=370000,CODECS="mp4a.40.2,avc1.4D401F",RESOLUTION=480x270,FRAME-RATE=25,AUDIO="audio-aacl-64",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=288000.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=631000,AVERAGE-BANDWIDTH=574000,CODECS="mp4a.40.2,avc1.4D401F",RESOLUTION=640x360,FRAME-RATE=25,AUDIO="audio-aacl-64",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=480000.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=1051000,AVERAGE-BANDWIDTH=956000,CODECS="mp4a.40.2,avc1.4D401F",RESOLUTION=960x540,FRAME-RATE=25,AUDIO="audio-aacl-64",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=840000.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=1821000,AVERAGE-BANDWIDTH=1655000,CODECS="mp4a.40.2,avc1.4D401F",RESOLUTION=960x540,FRAME-RATE=25,AUDIO="audio-aacl-64",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=1499968.m3u8
    
    # AUDIO groups
    #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-aacl-128",NAME="English",LANGUAGE="en",AUTOSELECT=YES,DEFAULT=YES,CHANNELS="2",URI="avc_decrypted_global-stream_audio_eng_128000=128000.m3u8"
    
    # variants
    #EXT-X-STREAM-INF:BANDWIDTH=2824000,AVERAGE-BANDWIDTH=2568000,CODECS="mp4a.40.2,avc1.4D401F",RESOLUTION=1280x720,FRAME-RATE=25,AUDIO="audio-aacl-128",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=2299968.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=3641000,AVERAGE-BANDWIDTH=3310000,CODECS="mp4a.40.2,avc1.4D401F",RESOLUTION=1280x720,FRAME-RATE=25,AUDIO="audio-aacl-128",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=3000000.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=5273000,AVERAGE-BANDWIDTH=4794000,CODECS="mp4a.40.2,avc1.640020",RESOLUTION=1280x720,FRAME-RATE=50,AUDIO="audio-aacl-128",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=4400000.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=7722000,AVERAGE-BANDWIDTH=7020000,CODECS="mp4a.40.2,avc1.640020",RESOLUTION=1280x720,FRAME-RATE=50,AUDIO="audio-aacl-128",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=6499968.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=9471000,AVERAGE-BANDWIDTH=8610000,CODECS="mp4a.40.2,avc1.640020",RESOLUTION=1280x720,FRAME-RATE=50,AUDIO="audio-aacl-128",CLOSED-CAPTIONS=NONE
    avc_decrypted_global-video=8000000.m3u8
    
    # keyframes
    #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=17000,CODECS="avc1.42C01E",RESOLUTION=192x108,URI="keyframes/avc_decrypted_global-video=112000.m3u8"
    #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=42000,CODECS="avc1.4D401F",RESOLUTION=480x270,URI="keyframes/avc_decrypted_global-video=288000.m3u8"
    #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=70000,CODECS="avc1.4D401F",RESOLUTION=640x360,URI="keyframes/avc_decrypted_global-video=480000.m3u8"
    #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=123000,CODECS="avc1.4D401F",RESOLUTION=960x540,URI="keyframes/avc_decrypted_global-video=840000.m3u8"
    #EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=336000,CODECS="avc1.4D401F",RESOLUTION=1280x720,URI="keyframes/avc_decrypted_global-video=2299968.m3u8"
    
    opened by elv-peter 1
  • EXT-X-MAP BYTERANGE should be quoted

    EXT-X-MAP BYTERANGE should be quoted

    According to RFC 8216, section 4.3.2.5, the EXT-X-MAP tag attribute BYTERANGE is a quoted-string.

    Apple's mediastreamvalidator complains about this:

    Error: #EXT-X-MAP BYTERANGE: missing quotes

    opened by ronhopper 0
Releases(v0.11.1)
  • v0.11.1(Aug 9, 2019)

  • v0.11.0(Jul 24, 2019)

    This is a major release version after v0.10 since 2017, added lots of features and bugfix.

    Features:

    1. Add reader support for EXT-OATCLS-SCTE35 and EXT-X-CUE-OUT (#81)
    2. Make comma optional in #EXTINF when strict mode is false (#85, #84)
    3. Encode Segment.Map attribute (#94)
    4. Add support for AVERAGE-BANDWIDTH, FRAME-RATE and HDCP-LEVEL attributes of EXT-X-STREAM-INF tag (#112, #132)
    5. Add support for EXT-X-DISCONTINUITY-SEQUENCE tag (#112)
    6. Add writer support of the SeqId attribute of MediaSegment (#124)
    7. Add support for EXT-X-INDEPENDENT-SEGMENTS tag (#128, #103)
    8. Add support for EXT-X-START tag (#131)

    Bugfix:

    1. Omit URI for Key method NONE (#95, #68)
    2. Increase sequence number in Slide() method automatically (#113, #72)
    3. Decode got error while #EXT-X-PROGRAM-DATE-TIME exists in media playlist (#121, #120)
    4. Add new line after EXT-X-DISCONTINUITY-SEQUENCE (#129)

    Thanks to @bradleyfalzon @andyborn @0xApe @soldiermoth @mlafeldt @eric @soldiermoth @mihail812 @agparadiso @leikao for contributing.

    Source code(tar.gz)
    Source code(zip)
  • v0.10(Mar 19, 2017)

    The release introduces two features:

    • Add closed captions to writer. Refs #79, #80 Thanks to @mbowBC for this contribution.

    • Customizable TimeParse() function allows broad support for time formats beside RFC3339. It allows parse playlists for devices that not strictly conform dates and times standards. By default it uses FullTimeParse() that implemented parsing that follows date representations from ISO/IEC 8601:2004. Refs #78 Thanks to @md2k for this contribution.

    • Comments slightly polished.

    Source code(tar.gz)
    Source code(zip)
  • v0.9(Nov 13, 2016)

    This release has no new features or bugfixes. It just moved license of the project from GNU GPL to BSD. See the new LICENSE in the root of the repo. Previous release v0.8 and the versions below available under GNU GPL v.3.

    More explanations in the issue #71 and in the release notes of the previous release. If you have complains please create an issue or drop me a mail.

    Source code(tar.gz)
    Source code(zip)
  • v0.8(Nov 12, 2016)

    There are a lot of bugfixes and optimizations.

    This is the last release under GNU GPL license. As decided by the maintainers of the project the code from the next release will be covered by BSD 3-clause license (#71). It will allow usage of m3u8 package in any kind of projects include the projects under proprietary licenses. It is no problem for GPL projects as conditions of GPL license allows include the code under BSD-licenses.

    So the next release v0.9 will be with the same code but include the new license. The code of the version 0.8 and below can be used under GNU GPL.

    There are a lot of contributions was made since the project started. As initial author of the project I very glad that this piece of the code was useful and attracted other people for participating. I am very grateful for all the participants for their contribution to the project! So if the conditions of BSD license totally inappropriate for a contributor and he don't want to see his name among authors of the code under non-GPL license then he can create the issue with a complain or just drop me a mail. Then I will remove the patches from this contributor and replace them with a new code under my authorship. I not sure how it is correct from the view of law but m3u8 is amateur project for me so I don't want spend many time for license questions. It is the code only matters.

    Source code(tar.gz)
    Source code(zip)
  • v0.7(Apr 24, 2016)

    Features:

    #42, #41, #40 SCTE35 tag support #39, #37 Starting serNo from 0 not from 1.

    Bugfixes:

    #43 Fix #36 Media Playlist Set* methods modifying wrong segment #38 Fixed bug of writing vod playlist

    Source code(tar.gz)
    Source code(zip)
  • v0.6.1(Jan 9, 2016)

  • v0.6(Oct 17, 2015)

    Minor feature added:

    • Support Name attribute in #EXT-X-STREAM-INF tag #30

    Bugfix:

    • Append Args if playlist already has query params #31

    No changes in API.

    Source code(tar.gz)
    Source code(zip)
  • v0.5.2(Oct 4, 2015)

    Minor features added:

    • Added encoding for KEYFORMATVERSIONS for AES encrypted playlists (refs #28)
    • Added copyright for library authors referenced to AUTHORS file.

    No API changes.

    Source code(tar.gz)
    Source code(zip)
  • v0.5.1(Aug 22, 2015)

  • v0.5(Aug 15, 2015)

  • v0.4.2(May 16, 2015)

  • v0.4.1(May 16, 2015)

  • v0.4(Apr 5, 2015)

    Patches by @dennwc #16, @zshenker #17 and @Mistobaan #18 with fixes:

    • Fix handling of multiple codecs in params string
    • Fixed Audio group name being incorrectly set to the Video group name
    • When using Alternatives (which writes an EXT-X-MEDIA-TAG, master manifest version should be 4 (not let at the default of 3)
    • RESOLUTION should not be in quotes (mediastreamvalidator will complain about this, and some players will have issues)
    • LANGUAGE was not being included in the EXT-X-MEDIA tag
    • TYPE & AUTOSELECT should not be quoted, they are considered enums
    • Add check for parameter existence in EXTINF parsing.

    No API changes.

    Source code(tar.gz)
    Source code(zip)
  • v0.3.2(Feb 2, 2015)

    API changes:

    • Added Count of mediaplaylist segments to public API (#4). It was planned to merge for 0.3.0 but was missed.

    Features was introduced in a major v0.3 release:

    • Support all tags up to version 5 of the protocol
    • Added support of tags EXT-X-I-FRAME-STREAM-INF, EXT-X-I-FRAMES-ONLY, EXT-X-MAP

    New tags support was not well tested yet, please see #15.

    Source code(tar.gz)
    Source code(zip)
  • v0.3.1(Feb 1, 2015)

    Fixes:

    • Fixed bug #7 reported by THE108
    • Fixed bug with inverted DurationAsInt() logic

    API changes:

    • DurationAsInt(true) now set duration values to integers as expected from a function declaration.

    Features was introduced in a major v0.3 release:

    • Support all tags up to version 5 of the protocol
    • Added support of tags EXT-X-I-FRAME-STREAM-INF, EXT-X-I-FRAMES-ONLY, EXT-X-MAP

    New tags support was not well tested yet, please see #15.

    Source code(tar.gz)
    Source code(zip)
  • v0.3(Feb 1, 2015)

    Features support of all tags up to version 5 of the protocol and minor fixes:

    • Support of tags EXT-X-I-FRAME-STREAM-INF, EXT-X-I-FRAMES-ONLY, EXT-X-MAP
    • Merged with URI-quotes patch made by Jamie Stackhouse #10

    New tags support was not well tested yet, please see #15.

    Source code(tar.gz)
    Source code(zip)
  • v0.2.2(Jan 10, 2015)

    Changes:

    • Merged with branch 'allow-cache-no' from https://github.com/jamie-stackhouse/m3u8, fixes #8
    • M3U8.md updated to version 7 of the HLS protocol (draft 14).
    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Nov 9, 2014)

    Fixed bugs with parsing media-playlists:

    • #EXT-X-PLAYLIST-TYPE parsing broken #12 (fixed with #13)
    • Fixing typos in media alternatives parsing #9

    No new functions. Update from 0.2 recommended.

    Source code(tar.gz)
    Source code(zip)
  • v0.2-rc(Jul 1, 2014)

  • v0.2(Jul 1, 2014)

  • v0.1(Jan 3, 2014)

Owner
Alexander I.Grafov
I am high skilled master of useless code with a specialization on the architecture of perpetuum mobile engines and cloud castles.
Alexander I.Grafov
Parse and generate m3u8 playlists for Apple HTTP Live Streaming (HLS) in Golang (ported from gem https://github.com/sethdeckard/m3u8)

go-m3u8 Golang package for m3u8 (ported m3u8 gem https://github.com/sethdeckard/m3u8) go-m3u8 provides easy generation and parsing of m3u8 playlists d

Tan Quang Ngo 75 Jun 2, 2021
live video streaming server in golang

中文 Simple and efficient live broadcast server: Very simple to install and use; Pure Golang, high performance, and cross-platform; Supports commonly us

浩麟 6.8k Jul 19, 2021
Live on-demand transcoding in go using ffmpeg. Also with NVIDIA GPU hardware acceleration.

Go live HTTP on-demand transcoding Transcoding is expensive and resource consuming operation on CPU and GPU. For big companies with thousands of custo

Miroslav Šedivý 42 Jul 22, 2021
🔥 Golang live stream lib/client/server. support RTMP/RTSP/HLS/HTTP[S]-FLV/HTTP-TS, H264/H265/AAC, relay, cluster, record, HTTP API/Notify, GOP cache. 官方文档见 https://pengrl.com/lal

lal是一个开源GoLang直播流媒体网络传输项目,包含三个主要组成部分: lalserver:流媒体转发服务器。类似于nginx-rtmp-module等应用,但支持更多的协议,提供更丰富的功能。lalserver简介 demo:一些小应用,比如推、拉流客户端,压测工具,流分析工具,调度示例程序等

yoko 598 Jul 19, 2021
Plays videos using Prometheus and Grafana, e.g. Bad Apple.

prometheus_video_renderer Plays videos using Prometheus and Grafana, e.g. Bad Apple. Modes Currently 3 different modes are supported. Bitmap The bitma

Jacob Colvin 44 Jul 11, 2021
falco is VCL parser and linter optimized for Fastly.

falco falco is VCL parser and linter optimized for Fastly. Disclaimer This is a VCL parser, but dedicated to Fastly's VCL (version 2.x), so we don't c

Yoshiaki Sugimoto 20 Jul 15, 2021
👾 Annie is a fast, simple and clean video downloader built with Go.

?? Annie is a fast, simple and clean video downloader built with Go. Installation Prerequisites Install via go get Homebrew (macOS only) Arch Linux Vo

Xinzhao Xu 15.1k Jul 24, 2021
Take control over your live stream video by running it yourself. Streaming + chat out of the box.

Take control over your content and stream it yourself. Explore the docs » View Demo · Use Our Server for Testing · FAQ · Report Bug Table of Contents

Owncast 4.9k Jul 20, 2021
Parse and demux MPEG Transport Streams (.ts) natively in GO

This is a Golang library to natively parse and demux MPEG Transport Streams (ts) in GO. WARNING: this library is not yet production ready. Use at your

Quentin Renard 370 Jul 16, 2021
RTSP 1.0 client and server library for the Go programming language

RTSP 1.0 client and server library for the Go programming language

Alessandro Ros 97 Jul 14, 2021
Golang bindings for FFmpeg

goav Golang binding for FFmpeg A comprehensive binding to the ffmpeg video/audio manipulation library. Usage import "github.com/giorgisio/goav/avforma

H. Giorgis 1.7k Jul 24, 2021
Manipulate subtitles in GO (.srt, .ssa/.ass, .stl, .ttml, .vtt (webvtt), teletext, etc.)

This is a Golang library to manipulate subtitles. It allows you to manipulate srt, stl, ttml, ssa/ass, webvtt and teletext files for now. Available op

Quentin Renard 323 Jul 15, 2021
golang library to read and write various subtitle formats

libgosubs Golang library to read and write subtitles in the following formats Advanced SubStation Alpha v4 SRT TTML v1.0 - This is based on the spec p

Wargarblgarbl 14 May 20, 2021
Go bindings for libVLC and high-level media player interface

Go bindings for libVLC 2.X/3.X/4.X and high-level media player interface. The package can be useful for adding multimedia capabilities to applications

Adrian-George Bostan 224 Jul 20, 2021