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

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

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
Comments
  • 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.

  • 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
    
  • 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?

  • 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

  • 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.

  • 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?

  • 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

  • Add reader support for EXT-OATCLS-SCTE35 and EXT-X-CUE-OUT

    Add reader support for EXT-OATCLS-SCTE35 and EXT-X-CUE-OUT

    Deprecation: MediaPlaylist.SetSCTE() has been deprecated, use MediaPlaylist.SetSCTE35() instead

    SCTE has 3 new fields, .Syntax defines the format of the SCTE data, .CueType defines whether the cue point was start/mind/end, .Elapsed can be used for formats that track the elapsed time.

    SCTE now supports another SCTE-35 syntax we've nicknamed OATCLS (due to the presence of this string in the tag), see sample-playlists/media-playlist-with-oatcls-scte35.m3u8 for an example. Both reads and writes are supported.

  • Looking for a new project maintainer

    Looking for a new project maintainer

    The stats show that the library still in use by many people and the code still actual. Thanks a lot to all the contributors! Of course, this lib is the small piece of code but it added some value to the applicability of Go for writing the video casting applications. Unfortunately, working with video is out of the scope of my current interests. I coding mostly on Go since 2012 and think this language was the right choice for me. But the areas where I apply my programming skills shifted a lot from the time when I started the M3U8 library. So in future, I could add minor changes like code style and readme updates but I have no resources to review the major changes that require the actual knowledge in modern M3U8 standard and in the areas of the video casting.

    Now the project has two maintainers — me and @bradleyfalzon. Bradley helped a lot with reviewing and contributing. But it seems we need more people who currently working in the area of video casting and interested in support of this lib. There are a lot of issues that could be reviewed and merged.

    I could still keep my rights of the project owner for the project safety. And keep the main purpose of the library — be simple and allow basic features for parsing and generating M3U8 playlists.

    Drop a comment if you would ready to become the maintainer of the project.

  • MediaSegment@SeqId should be the media sequence of an individual segment?

    MediaSegment@SeqId should be the media sequence of an individual segment?

    Each sub manifest has its initial (media) sequence number and I was under the impression that the attribute SeqId from the MediaSegment was the individual media sequence for that segment, am I right?

    Also, I was browsing through the docs and also the source code and I couldn't find where the attribute SeqId is filled.

  • Add InsertSegment to account for when segments arrive out-of-order

    Add InsertSegment to account for when segments arrive out-of-order

    Hi @grafov, I added an InsertSegment method to account for when segments arrive out-of-order during a live-streaming scenario. It was useful for me in a p2p context.

    Just want to merge back in case this is useful for you as well :)

  • safari play fail bug

    safari play fail bug

    #EXTM3U #EXT-X-VERSION:7 #EXT-X-MAP:URI="EPICGAMING_S01E01_MARIOKART8_1080p.m4s",BYTERANGE=1361@0 #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-TARGETDURATION:2 #EXT-X-BYTERANGE:724886@1361 #EXTINF:2.000, EPICGAMING_S01E01_MARIOKART8_1080p.m4s #EXT-X-BYTERANGE:1054644@726247 #EXTINF:2.000, EPICGAMING_S01E01_MARIOKART8_1080p.m4s

    in attributes of EXT-X-MAP, value of BYTERANGE is a quoted-string。but the lib is not a quoted-string。then play failed in safari。

  • program panic when i get the url of media segments

    program panic when i get the url of media segments

    retry this

    
    import (
    	"bytes"
    	"fmt"
    
    	"github.com/grafov/m3u8"
    )
    
    func main() {
    	body := `#EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-MEDIA-SEQUENCE:0
    #EXT-X-PROGRAM-DATE-TIME:2022-03-01T20:15:19.786+08:00
    #EXT-X-TARGETDURATION:4
    #EXTINF:4.000,
    test
    #EXTINF:4.000,
    test
    #EXTINF:4.000,
    test
    #EXTINF:4.000,
    test
    #EXTINF:4.000,
    test
    #EXTINF:4.000,
    test
    #EXT-X-ENDLIST
    `
    	p, listType, err := m3u8.DecodeFrom(bytes.NewReader([]byte(body)), true)
    	if err != nil {
    		panic(err)
    	}
    	switch listType {
    	case m3u8.MEDIA:
    		mediapl := p.(*m3u8.MediaPlaylist)
    		for _, segment := range mediapl.Segments {
    			println(segment.URI)
    		}
    	case m3u8.MASTER:
    		masterpl := p.(*m3u8.MasterPlaylist)
    		fmt.Printf("%+v\n", masterpl)
    	}
    }
    

    Expected Behavior

    print the url of segments

    Actual Behavior

    program panic

    Solve

    https://github.com/grafov/m3u8/pull/186

  • Support for channels

    Support for channels

    Add support for attribute CHANNELS. https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-10#section-4.4.6.1

    https://github.com/grafov/m3u8/issues/181

  • tag: #EXT-X-MEDIA attribute: CHANNELS is not recognized

    tag: #EXT-X-MEDIA attribute: CHANNELS is not recognized

    CHANNELS should be recognized according to the RFC

    All audio EXT-X-MEDIA tags SHOULD have a CHANNELS attribute.

    Yes, I am aware of func SetCustomTag() but this is an existing tag and even if I could use that to bend the existing tag handler to include the CHANNELS attribute it would be nice if m3u8 can follow the standard.

    There is an old and incomplete (lacks reader, lacks tests) PR for this in https://github.com/grafov/m3u8/pull/168

    Maybe, maybe, we (my team), can finish that job.

Desktop application to download videos and playlists from youtube by simply copying its url.
Desktop application to download videos and playlists from youtube by simply copying its url.

tubemp3 Desktop application to download videos and playlists from youtube by simply copying its url. You just need to run tubemp3 and copy (CTRL + C)

Oct 25, 2022
🔥 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
🔥 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:一些小应用,比如推、拉流客户端,压测工具,流分析工具,调度示例程序等

Jan 1, 2023
hls converter.

hlsconv hls converter. 外部依赖 ffmpeg: 4.2.1 使用方式 linix/macos # 转换单个文件 bin/hlsconv -i video/in.mp4 -o outvideo/ # 批量转换文件 bin/hlsconv -i video/ -o outvide

Jan 15, 2022
Plays videos using Prometheus and Grafana, e.g. Bad Apple.
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

Nov 30, 2022
falco is VCL parser and linter optimized for Fastly.
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

Dec 7, 2022
RTSP 1.0 client and server library for the Go programming language

RTSP 1.0 client and server library for the Go programming language

Jan 3, 2023
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

Sep 27, 2022
A simple library to extract video and audio frames from media containers (based on libav).
A simple library to extract video and audio frames from media containers (based on libav).

Reisen A simple library to extract video and audio frames from media containers (based on libav, i.e. ffmpeg). Dependencies The library requires libav

Jan 2, 2023
golang library for mux and demux file containers such as mpeg-ts,mpeg-ps,flv

gomedia mpeg-ts,mpeg-ps,flv muxer/demuxer mpeg-ts muxer mpeg-ts demuxer mpeg-ps muxer mpeg-ps demuxer flv muxer flv demuxer mpeg-ps will be done in th

Jan 4, 2023
lmmp3 is a little golang library that download a video from youtube, and convert it to a mp3 file using ffmpeg

lmmp3 lmmp3 is a function that download a video from youtube, and convert it to a mp3 file using ffmpeg You need to have installed ffmpeg in your syst

Aug 12, 2022
Go4vl is Go library for working with the Video for Linux API (V4L2) natively, without any C bindings.

go4vl A Go library for working with the Video for Linux user API (V4L2). Gov4l hides all the complexities of working with V4L2 and exposes idiomatic G

Dec 23, 2022
Package implement reading and writing popular playlist formats: PLS, ASX, M3U, XSPF and others.

go-playlist ⚠️ WARNING The API is not stable yet and can change. Package playlist implement reading and writing popular playlist formats: PLS, ASX, M3

Oct 14, 2021
ffcommander - An easy frontend to FFmpeg and Imagemagick to automatically process video and manipulate subtitles.

% FFCOMMANDER(1) ffcommander 2.39 % Mikael Hartzell (C) 2018 % 2021 Name ffcommander - An easy frontend to FFmpeg and Imagemagick to automatically pro

May 9, 2022
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

Jan 9, 2023
Go bindings for libVLC and high-level media player interface
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

Dec 31, 2022
Project to get Youtube video descriptions and search those videos as required

FamPayProject Project to get Youtube video descriptions and search those videos as required Prerequisities Postgres DB for persisting data Youtube Dat

Nov 5, 2021
Synthetic media is a realistic transformation of audio and video using artificial intelligence.

Synthetic media is a realistic transformation of audio and video using artificial intelligence.

Nov 20, 2021
golang function that download a video from youtube, and convert it to a mp3 file using ffmpeg

echedwnmp3 echedwnmp3 is a function that download a video from youtube, and convert it to a mp3 file using ffmpeg example package main import(echedwn

Dec 7, 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.

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

Jun 1, 2022