Python m3u8 parser
Project description
.. image:: https://travis-ci.org/globocom/m3u8.svg
:target: https://travis-ci.org/globocom/m3u8
.. image:: https://coveralls.io/repos/globocom/m3u8/badge.png?branch=master
:target: https://coveralls.io/r/globocom/m3u8?branch=master
.. image:: https://gemnasium.com/leandromoreira/m3u8.svg
:target: https://gemnasium.com/leandromoreira/m3u8
.. image:: https://badge.fury.io/py/m3u8.svg
:target: https://badge.fury.io/py/m3u8
m3u8
====
Python `m3u8`_ parser.
Documentation
=============
The basic usage is to create a playlist object from uri, file path or
directly from a string:
::
import m3u8
m3u8_obj = m3u8.load('http://videoserver.com/playlist.m3u8') # this could also be an absolute filename
print m3u8_obj.segments
print m3u8_obj.target_duration
# if you already have the content as string, use
m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ... ')
Supported tags
=============
* #EXT-X-TARGETDURATION
* #EXT-X-MEDIA-SEQUENCE
* #EXT-X-DISCONTINUITY-SEQUENCE
* #EXT-X-PROGRAM-DATE-TIME
* #EXT-X-MEDIA
* #EXT-X-PLAYLIST-TYPE
* #EXT-X-KEY
* #EXT-X-STREAM-INF
* #EXT-X-VERSION
* #EXT-X-ALLOW-CACHE
* #EXT-X-ENDLIST
* #EXTINF
* #EXT-X-I-FRAMES-ONLY
* #EXT-X-BYTERANGE
* #EXT-X-I-FRAME-STREAM-INF
* #EXT-X-DISCONTINUITY
* #EXT-X-CUE-OUT
* #EXT-X-CUE-OUT-CONT
* #EXT-X-INDEPENDENT-SEGMENTS
* #EXT-OATCLS-SCTE35
* #EXT-X-CUE-OUT
* #EXT-X-CUE-IN
* #EXT-X-CUE-SPAN
* #EXT-X-MAP
* #EXT-X-START
Encryption keys
---------------
The segments may be or not encrypted. The ``keys`` attribute list will
be an list with all the different keys as described with `#EXT-X-KEY`_:
Each key has the next properties:
- ``method``: ex.: "AES-128"
- ``uri``: the key uri, ex.: "http://videoserver.com/key.bin"
- ``iv``: the initialization vector, if available. Otherwise ``None``.
If no ``#EXT-X-KEY`` is found, the ``keys`` list will have a unique element ``None``. Multiple keys are supported.
If unencrypted and encrypted segments are mixed in the M3U8 file, then the list will contain a ``None`` element, with one
or more keys afterwards.
To traverse the list of keys available:
::
import m3u8
m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...')
len(m3u8_obj.keys) => returns the number of keys available in the list (normally 1)
for key in m3u8_obj.keys:
if key: # First one could be None
key.uri
key.method
key.iv
Getting segments encrypted with one key
---------------------------------------
There are cases where listing segments for a given key is important. It's possible to
retrieve the list of segments encrypted with one key via ``by_key`` method in the
``segments`` list.
Example of getting the segments with no encryption:
::
import m3u8
m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...')
segmk1 = m3u8_obj.segments.by_key(None)
# Get the list of segments encrypted using last key
segm = m3u8_obj.segments.by_key( m3u8_obj.keys[-1] )
With this method, is now possible also to change the key from some of the segments programatically:
::
import m3u8
m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...')
# Create a new Key and replace it
new_key = m3u8.Key("AES-128", "/encrypted/newkey.bin", None, iv="0xf123ad23f22e441098aa87ee")
for segment in m3u8_obj.segments.by_key( m3u8_obj.keys[-1] ):
segm.key = new_key
# Remember to sync the key from the list as well
m3u8_obj.keys[-1] = new_key
Variant playlists (variable bitrates)
-------------------------------------
A playlist can have a list to other playlist files, this is used to
represent multiple bitrates videos, and it's called `variant streams`_.
See an `example here`_.
::
variant_m3u8 = m3u8.loads('#EXTM3U8 ... contains a variant stream ...')
variant_m3u8.is_variant # in this case will be True
for playlist in variant_m3u8.playlists:
playlist.uri
playlist.stream_info.bandwidth
the playlist object used in the for loop above has a few attributes:
- ``uri``: the url to the stream
- ``stream_info``: a ``StreamInfo`` object (actually a namedtuple) with
all the attributes available to `#EXT-X-STREAM-INF`_
- ``media``: a list of related ``Media`` objects with all the attributes
available to `#EXT-X-MEDIA`_
- ``playlist_type``: the type of the playlist, which can be one of `VOD`_
(video on demand) or `EVENT`_
**NOTE: the following attributes are not implemented yet**, follow
`issue 4`_ for updates
- ``alternative_audios``: its an empty list, unless it's a playlist
with `Alternative audio`_, in this case it's a list with ``Media``
objects with all the attributes available to `#EXT-X-MEDIA`_
- ``alternative_videos``: same as ``alternative_audios``
A variant playlist can also have links to `I-frame playlists`_, which are used
to specify where the I-frames are in a video. See `Apple's documentation`_ on
this for more information. These I-frame playlists can be accessed in a similar
way to regular playlists.
::
variant_m3u8 = m3u8.loads('#EXTM3U ... contains a variant stream ...')
for iframe_playlist in variant_m3u8.iframe_playlists:
iframe_playlist.uri
iframe_playlist.iframe_stream_info.bandwidth
The iframe_playlist object used in the for loop above has a few attributes:
- ``uri``: the url to the I-frame playlist
- ``base_uri``: the base uri of the variant playlist (if given)
- ``iframe_stream_info``: a ``StreamInfo`` object (same as a regular playlist)
Running Tests
=============
::
$ ./runtests
Contributing
============
All contribution is welcome, but we will merge a pull request if, and only if, it
- has tests
- follows the code conventions
If you plan to implement a new feature or something that will take more
than a few minutes, please open an issue to make sure we don't work on
the same thing.
.. _m3u8: https://tools.ietf.org/html/draft-pantos-http-live-streaming-20
.. _#EXT-X-KEY: http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.4
.. _issue 1: https://github.com/globocom/m3u8/issues/1
.. _variant streams: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-6.2.4
.. _example here: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.5
.. _#EXT-X-STREAM-INF: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.2
.. _issue 4: https://github.com/globocom/m3u8/issues/4
.. _I-frame playlists: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.3
.. _Apple's documentation: https://developer.apple.com/library/ios/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-I_FRAME_PLAYLIST
.. _Alternative audio: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.7
.. _#EXT-X-MEDIA: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.1
.. _VOD: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-TNTAG2
.. _EVENT: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-EVENT_PLAYLIST
:target: https://travis-ci.org/globocom/m3u8
.. image:: https://coveralls.io/repos/globocom/m3u8/badge.png?branch=master
:target: https://coveralls.io/r/globocom/m3u8?branch=master
.. image:: https://gemnasium.com/leandromoreira/m3u8.svg
:target: https://gemnasium.com/leandromoreira/m3u8
.. image:: https://badge.fury.io/py/m3u8.svg
:target: https://badge.fury.io/py/m3u8
m3u8
====
Python `m3u8`_ parser.
Documentation
=============
The basic usage is to create a playlist object from uri, file path or
directly from a string:
::
import m3u8
m3u8_obj = m3u8.load('http://videoserver.com/playlist.m3u8') # this could also be an absolute filename
print m3u8_obj.segments
print m3u8_obj.target_duration
# if you already have the content as string, use
m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ... ')
Supported tags
=============
* #EXT-X-TARGETDURATION
* #EXT-X-MEDIA-SEQUENCE
* #EXT-X-DISCONTINUITY-SEQUENCE
* #EXT-X-PROGRAM-DATE-TIME
* #EXT-X-MEDIA
* #EXT-X-PLAYLIST-TYPE
* #EXT-X-KEY
* #EXT-X-STREAM-INF
* #EXT-X-VERSION
* #EXT-X-ALLOW-CACHE
* #EXT-X-ENDLIST
* #EXTINF
* #EXT-X-I-FRAMES-ONLY
* #EXT-X-BYTERANGE
* #EXT-X-I-FRAME-STREAM-INF
* #EXT-X-DISCONTINUITY
* #EXT-X-CUE-OUT
* #EXT-X-CUE-OUT-CONT
* #EXT-X-INDEPENDENT-SEGMENTS
* #EXT-OATCLS-SCTE35
* #EXT-X-CUE-OUT
* #EXT-X-CUE-IN
* #EXT-X-CUE-SPAN
* #EXT-X-MAP
* #EXT-X-START
Encryption keys
---------------
The segments may be or not encrypted. The ``keys`` attribute list will
be an list with all the different keys as described with `#EXT-X-KEY`_:
Each key has the next properties:
- ``method``: ex.: "AES-128"
- ``uri``: the key uri, ex.: "http://videoserver.com/key.bin"
- ``iv``: the initialization vector, if available. Otherwise ``None``.
If no ``#EXT-X-KEY`` is found, the ``keys`` list will have a unique element ``None``. Multiple keys are supported.
If unencrypted and encrypted segments are mixed in the M3U8 file, then the list will contain a ``None`` element, with one
or more keys afterwards.
To traverse the list of keys available:
::
import m3u8
m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...')
len(m3u8_obj.keys) => returns the number of keys available in the list (normally 1)
for key in m3u8_obj.keys:
if key: # First one could be None
key.uri
key.method
key.iv
Getting segments encrypted with one key
---------------------------------------
There are cases where listing segments for a given key is important. It's possible to
retrieve the list of segments encrypted with one key via ``by_key`` method in the
``segments`` list.
Example of getting the segments with no encryption:
::
import m3u8
m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...')
segmk1 = m3u8_obj.segments.by_key(None)
# Get the list of segments encrypted using last key
segm = m3u8_obj.segments.by_key( m3u8_obj.keys[-1] )
With this method, is now possible also to change the key from some of the segments programatically:
::
import m3u8
m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...')
# Create a new Key and replace it
new_key = m3u8.Key("AES-128", "/encrypted/newkey.bin", None, iv="0xf123ad23f22e441098aa87ee")
for segment in m3u8_obj.segments.by_key( m3u8_obj.keys[-1] ):
segm.key = new_key
# Remember to sync the key from the list as well
m3u8_obj.keys[-1] = new_key
Variant playlists (variable bitrates)
-------------------------------------
A playlist can have a list to other playlist files, this is used to
represent multiple bitrates videos, and it's called `variant streams`_.
See an `example here`_.
::
variant_m3u8 = m3u8.loads('#EXTM3U8 ... contains a variant stream ...')
variant_m3u8.is_variant # in this case will be True
for playlist in variant_m3u8.playlists:
playlist.uri
playlist.stream_info.bandwidth
the playlist object used in the for loop above has a few attributes:
- ``uri``: the url to the stream
- ``stream_info``: a ``StreamInfo`` object (actually a namedtuple) with
all the attributes available to `#EXT-X-STREAM-INF`_
- ``media``: a list of related ``Media`` objects with all the attributes
available to `#EXT-X-MEDIA`_
- ``playlist_type``: the type of the playlist, which can be one of `VOD`_
(video on demand) or `EVENT`_
**NOTE: the following attributes are not implemented yet**, follow
`issue 4`_ for updates
- ``alternative_audios``: its an empty list, unless it's a playlist
with `Alternative audio`_, in this case it's a list with ``Media``
objects with all the attributes available to `#EXT-X-MEDIA`_
- ``alternative_videos``: same as ``alternative_audios``
A variant playlist can also have links to `I-frame playlists`_, which are used
to specify where the I-frames are in a video. See `Apple's documentation`_ on
this for more information. These I-frame playlists can be accessed in a similar
way to regular playlists.
::
variant_m3u8 = m3u8.loads('#EXTM3U ... contains a variant stream ...')
for iframe_playlist in variant_m3u8.iframe_playlists:
iframe_playlist.uri
iframe_playlist.iframe_stream_info.bandwidth
The iframe_playlist object used in the for loop above has a few attributes:
- ``uri``: the url to the I-frame playlist
- ``base_uri``: the base uri of the variant playlist (if given)
- ``iframe_stream_info``: a ``StreamInfo`` object (same as a regular playlist)
Running Tests
=============
::
$ ./runtests
Contributing
============
All contribution is welcome, but we will merge a pull request if, and only if, it
- has tests
- follows the code conventions
If you plan to implement a new feature or something that will take more
than a few minutes, please open an issue to make sure we don't work on
the same thing.
.. _m3u8: https://tools.ietf.org/html/draft-pantos-http-live-streaming-20
.. _#EXT-X-KEY: http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.4
.. _issue 1: https://github.com/globocom/m3u8/issues/1
.. _variant streams: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-6.2.4
.. _example here: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.5
.. _#EXT-X-STREAM-INF: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.2
.. _issue 4: https://github.com/globocom/m3u8/issues/4
.. _I-frame playlists: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.3
.. _Apple's documentation: https://developer.apple.com/library/ios/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-I_FRAME_PLAYLIST
.. _Alternative audio: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.7
.. _#EXT-X-MEDIA: https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-4.3.4.1
.. _VOD: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-TNTAG2
.. _EVENT: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-EVENT_PLAYLIST
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
m3u8-0.3.7.tar.gz
(16.4 kB
view details)
File details
Details for the file m3u8-0.3.7.tar.gz
.
File metadata
- Download URL: m3u8-0.3.7.tar.gz
- Upload date:
- Size: 16.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: Python-urllib/2.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f743627e04fb2bd89ad4fe4e6bb1c4bb0ce04a413e403730b6a704243acf38f7 |
|
MD5 | 37e2e243045490e9d663a4e2f6c003bb |
|
BLAKE2b-256 | f3097babf08a743d37b44d2a0cd742252f9e10663f9f5badb51a1dce759eb32b |