m3u8
Python m3u8 Parser for HTTP Live Streaming (HLS) Transmissions.
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. OtherwiseNone
.
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 streamstream_info
: aStreamInfo
object (actually a namedtuple) with
all the attributes available to#EXT-X-STREAM-INF
_media
: a list of relatedMedia
objects with all the attributes
available to#EXT-X-MEDIA
_playlist_type
: the type of the playlist, which can be one ofVOD
_
(video on demand) orEVENT
_
NOTE: the following attributes are not implemented yet, follow
issue 4
_ for updates
alternative_audios
: its an empty list, unless it's a playlist
withAlternative audio
, in this case it's a list withMedia
objects with all the attributes available to#EXT-X-MEDIA
alternative_videos
: same asalternative_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 playlistbase_uri
: the base uri of the variant playlist (if given)iframe_stream_info
: aStreamInfo
object (same as a regular playlist)
Running Tests
$ ./runtests