Giter Club home page Giter Club logo

m3u8's Introduction

Gem Version Build Status Coverage Status Code Climate Dependency Status security

m3u8

m3u8 provides easy generation and parsing of m3u8 playlists defined in the HTTP Live Streaming (HLS) Internet Draft published by Apple.

  • The library completely implements version 20 of the HLS Internet Draft.
  • Provides parsing of an m3u8 playlist into an object model from any File, StringIO, or string.
  • Provides ability to write playlist to a File or StringIO or expose as string via to_s.
  • Distinction between a master and media playlist is handled automatically (single Playlist class).
  • Optionally, the library can automatically generate the audio/video codecs string used in the CODEC attribute based on specified H.264, AAC, or MP3 options (such as Profile/Level).

Installation

Add this line to your application's Gemfile:

gem 'm3u8'

And then execute:

$ bundle

Or install it yourself as:

$ gem install m3u8

Usage (creating playlists)

Create a master playlist and add child playlists for adaptive bitrate streaming:

require 'm3u8'
playlist = M3u8::Playlist.new

Create a new playlist item with options:

options = { width: 1920, height: 1080, profile: 'high', level: 4.1,
            audio_codec: 'aac-lc', bandwidth: 540, uri: 'test.url' }
item = M3u8::PlaylistItem.new(options)
playlist.items << item

Add alternate audio, camera angles, closed captions and subtitles by creating MediaItem instances and adding them to the Playlist:

hash = { type: 'AUDIO', group_id: 'audio-lo', language: 'fre',
         assoc_language: 'spoken', name: 'Francais', autoselect: true,
         default: false, forced: true, uri: 'frelo/prog_index.m3u8' }
item = M3u8::MediaItem.new(hash)
playlist.items << item

Create a standard playlist and add MPEG-TS segments via SegmentItem. You can also specify options for this type of playlist, however these options are ignored if playlist becomes a master playlist (anything but segments added):

options = { version: 1, cache: false, target: 12, sequence: 1 }
playlist = M3u8::Playlist.new(options)

item = M3u8::SegmentItem.new(duration: 11, segment: 'test.ts')
playlist.items << item

You can pass an IO object to the write method:

require 'tempfile'
file = Tempfile.new('test')
playlist.write(file)

You can also access the playlist as a string:

playlist.to_s

M3u8::Writer is the class that handles generating the playlist output.

Alternatively you can set codecs rather than having it generated automatically:

options = { width: 1920, height: 1080, codecs: 'avc1.66.30,mp4a.40.2',
            bandwidth: 540, uri: 'test.url' }
item = M3u8::PlaylistItem.new(options)

Usage (parsing playlists)

file = File.open 'spec/fixtures/master.m3u8'
playlist = M3u8::Playlist.read(file)
playlist.master?
# => true

Access items in playlist:

playlist.items.first
#  => #<M3u8::PlaylistItem:0x007fa569bc7698 @program_id="1", @resolution="1920x1080", 
#  @codecs="avc1.640028,mp4a.40.2", @bandwidth="5042000", 
#  @playlist="hls/1080-7mbps/1080-7mbps.m3u8">

Create a new playlist item with options:

options = { width: 1920, height: 1080, profile: 'high', level: 4.1,
            audio_codec: 'aac-lc', bandwidth: 540, uri: 'test.url' }
item = M3u8::PlaylistItem.new(options)
#add it to the top of the playlist
playlist.items.unshift(item)

M3u8::Reader is the class handles parsing if you want more control over the process.

Usage (misc)

Generate the codec string based on audio and video codec options without dealing a playlist instance:

options = { profile: 'baseline', level: 3.0, audio_codec: 'aac-lc' }
codecs = M3u8::Playlist.codecs(options)
# => "avc1.66.30,mp4a.40.2"
  • Values for audio_codec (codec name): aac-lc, he-aac, mp3
  • Values for profile (H.264 Profile): baseline, main, high.
  • Values for level (H.264 Level): 3.0, 3.1, 4.0, 4.1.

Not all Levels and Profiles can be combined and validation is not currently implemented, consult H.264 documentation for further details.

Roadmap

  • Implement validation of all tags, attributes, and values per HLS I-D.
  • Perhaps support for different versions of HLS I-D, defaulting to latest.

Contributing

  1. Fork it ( https://github.com/sethdeckard/m3u8/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Run the specs, make sure they pass and that new features are covered. Code coverage should be 100%.
  4. Commit your changes (git commit -am 'Add some feature')
  5. Push to the branch (git push origin my-new-feature)
  6. Create a new Pull Request

License

MIT License - See LICENSE.txt for details.

m3u8's People

Contributors

dakaz avatar elsurudo avatar jviney avatar raphi avatar rmberg avatar sethdeckard avatar takashisite avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

m3u8's Issues

get segment from TimeItem

Hello,
I've tried parsing my file

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:1582061
#EXTINF:10, no desc
#EXT-X-PROGRAM-DATE-TIME:2016-01-01T18:22:09Z
20160321T150304_2_5560256_1582061.ts
#EXTINF:10, no desc
#EXT-X-PROGRAM-DATE-TIME:2016-01-01T18:22:19Z
20160321T150304_2_5560256_1582062.ts

I get a list of TimeItem which makes sens, but how can I get the filename (.ts) ? Does this lib support this format?
thanks

Request/bug: Support iTunes' m3u8 files

Such as the files that iTunes outputs when exporting playlists.

It's understandable (and clearly necessary) to have a library that handles HLS m3u8 files, it would just also be nice to import these other standard files.

M3u8::Playlist.read("path/to/file") fails silently

Had a few minutes of head scratching when I tried calling M3u8::Playlist.read with a path before I realized I needed an IO object. Calling read with a path doesn't throw an error and returns a playlist regardless

irb(main):002:0> M3u8::Playlist.read("~/Desktop/long_hls")
=> #<M3u8::Playlist:0x007fb77388de20 @version=nil, @sequence=0, @cache=nil, @target=10, @type=nil, @iframes_only=false, @independent_segments=false, @items=[]>

#EXT-X-PROGRAM-DATE-TIME missing?

date = "#{program_date_time}\n" unless program_date_time.nil?

It looks like when this gets rendered it's missing the #EXT-X-PROGRAM-DATE-TIME, only rendering the time. I'm not sure if this was an intentional design decision or a bug? It looks like it's been in there for 5 years if it is a bug, so wanted to make sure before working on a PR.

Details:

...
playlist.items << M3u8::SegmentItem.new(program_date_time: Time.now, duration: 10, segment: 'http://example.com/segment-1.aac')
....

Expected:

#EXTINF:9.770667,
#EXT-X-PROGRAM-DATE-TIME: 2020-11-25 14:27:00 -0600
http://example.com/segment-1.aac

Actual:

#EXTINF:9.770667,
2020-11-25 14:27:00 -0600
http://example.com/segment-1.aac

the latter seems to cause players to try and request "2020-11-25 14:27:00 -0600" as a fragment url.

I worked around the issue for the timebeing by passing the "#EXT-X-PROGRAM-DATE-TIME: #{Time.now}", as the program_date_time attribute, which feels a little clunky unless I'm missing the reasoning for it being this way. Thoughts?

Elegant way to find items by criteria

Thanks for making this library!

Is there a built-in search feature, ie. find the item with the best video resolution? Or at least a less clunky way than:

item = m3u8.items.max_by { |e| (e.respond_to?(:height) && e.height) || 0 }

Wouldn't it be simpler and better if the object returned was a symbol hash rather than an object with methods?

Feature request: Type conversion from M3u8::Playlist to M3u8::PlaylistItem

Recently I had a use case where I was looking to convert a M3u8::Playlist to M3u8::PlaylistItem. I was a bit surprised it's not supported by this gem, and that PlaylistItem instances need to be built from an options hash. This doesn't seem like a rare use case, especially when working with a master playlists, parsing media playlists they contain, working with them, and building a new master playlist as a result.

Here's a short example use case I'm imagining:

my_file = File.open('spec/fixtures/media_playlist-664.m3u8')
media_playlist = M3u8::Playlist.read(my_file)
playlist_item = M3u8::PlaylistItem.new(media_playlist)

My temporary workaround for this is to dump all of a Playlist's instance variables into a hash (excluding items, etc.) and building a new PlaylistItem from that. If there's a more intuitive way to do this that I'm missing, please let me know.

A secondary solution could be to implement a Playlist#to_options method that returns an options hash that allows for easy creation of a PlaylistItem:

my_file = File.open('spec/fixtures/media_playlist-664.m3u8')
media_playlist = M3u8::Playlist.read(my_file)
playlist_item = M3u8::PlaylistItem.new(media_playlist.to_options)

If you are on board with the feature request, I'll be happy to write the specs and open a PR.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.