Skip to content

Commit

Permalink
Merge pull request #54 from cristina0botez/average-bandwidth
Browse files Browse the repository at this point in the history
Average bandwidth
  • Loading branch information
leandromoreira committed Aug 7, 2015
2 parents d577a2b + 4690c20 commit 707d212
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 14 deletions.
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ the same thing.
.. _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: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-3.4.10
.. _#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: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-3.4.12
.. _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: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-3.4.9
.. _#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
24 changes: 17 additions & 7 deletions m3u8/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from collections import namedtuple
import os
import posixpath
import errno
import math

Expand Down Expand Up @@ -457,7 +456,8 @@ class Playlist(BasePathMixin):
Attributes:
`stream_info` is a named tuple containing the attributes: `program_id`,
`bandwidth`,`resolution`, `codecs` and `resolution` which is a a tuple (w, h) of integers
`bandwidth`, `average_bandwidth`, `resolution`, `codecs` and `resolution`
which is a a tuple (w, h) of integers
`media` is a list of related Media entries.
Expand All @@ -474,10 +474,13 @@ def __init__(self, uri, stream_info, media, base_uri):
else:
resolution_pair = None

self.stream_info = StreamInfo(bandwidth=stream_info['bandwidth'],
program_id=stream_info.get('program_id'),
resolution=resolution_pair,
codecs=stream_info.get('codecs'))
self.stream_info = StreamInfo(
bandwidth=stream_info['bandwidth'],
average_bandwidth=stream_info.get('average_bandwidth'),
program_id=stream_info.get('program_id'),
resolution=resolution_pair,
codecs=stream_info.get('codecs')
)
self.media = []
for media_type in ('audio', 'video', 'subtitles'):
group_id = stream_info.get(media_type)
Expand All @@ -492,6 +495,9 @@ def __str__(self):
stream_inf.append('PROGRAM-ID=%d' % self.stream_info.program_id)
if self.stream_info.bandwidth:
stream_inf.append('BANDWIDTH=%d' % self.stream_info.bandwidth)
if self.stream_info.average_bandwidth:
stream_inf.append('AVERAGE-BANDWIDTH=%d' %
self.stream_info.average_bandwidth)
if self.stream_info.resolution:
res = str(self.stream_info.resolution[0]) + 'x' + str(self.stream_info.resolution[1])
stream_inf.append('RESOLUTION=' + res)
Expand Down Expand Up @@ -530,6 +536,7 @@ def __init__(self, base_uri, uri, iframe_stream_info):

self.iframe_stream_info = StreamInfo(
bandwidth=iframe_stream_info.get('bandwidth'),
average_bandwidth=None,
program_id=iframe_stream_info.get('program_id'),
resolution=resolution_pair,
codecs=iframe_stream_info.get('codecs')
Expand All @@ -555,7 +562,10 @@ def __str__(self):

return '#EXT-X-I-FRAME-STREAM-INF:' + ','.join(iframe_stream_inf)

StreamInfo = namedtuple('StreamInfo', ['bandwidth', 'program_id', 'resolution', 'codecs'])
StreamInfo = namedtuple(
'StreamInfo',
['bandwidth', 'average_bandwidth', 'program_id', 'resolution', 'codecs']
)

class Media(BasePathMixin):
'''
Expand Down
1 change: 1 addition & 0 deletions m3u8/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ def _parse_stream_inf(line, data, state):
atribute_parser = remove_quotes_parser('codecs', 'audio', 'video', 'subtitles')
atribute_parser["program_id"] = int
atribute_parser["bandwidth"] = int
atribute_parser["average_bandwidth"] = int
state['stream_info'] = _parse_attribute_list(protocol.ext_x_stream_inf, line, atribute_parser)

def _parse_i_frame_stream_inf(line, data):
Expand Down
14 changes: 12 additions & 2 deletions tests/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@
http://example.com/audio-only.m3u8
'''

VARIANT_PLAYLIST_WITH_AVERAGE_BANDWIDTH = '''
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1252345
http://example.com/low.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2560000,AVERAGE-BANDWIDTH=2466570
http://example.com/mid.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7680000,AVERAGE-BANDWIDTH=7560423
http://example.com/hi.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,AVERAGE-BANDWIDTH=63005,CODECS="mp4a.40.5,avc1.42801e"
http://example.com/audio-only.m3u8
'''

VARIANT_PLAYLIST_WITH_IFRAME_PLAYLISTS = '''
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=800000,RESOLUTION=624x352,CODECS="avc1.4d001f, mp4a.40.5"
Expand Down Expand Up @@ -105,7 +117,6 @@

IFRAME_PLAYLIST = '''
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-VERSION:4
#EXT-X-TARGETDURATION:10
#EXT-X-PLAYLIST-TYPE:VOD
Expand Down Expand Up @@ -143,7 +154,6 @@

PLAYLIST_USING_BYTERANGES = '''
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-VERSION:4
#EXT-X-TARGETDURATION:11
#EXTINF:10,
Expand Down
5 changes: 3 additions & 2 deletions tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ def test_segment_discontinuity_attribute():
def test_segment_cue_out_attribute():
obj = m3u8.M3U8(playlists.CUE_OUT_PLAYLIST)
segments = obj.segments
print segments[0].__dict__

assert segments[0].cue_out == True
assert segments[1].cue_out == True
assert segments[2].cue_out == True
assert segments[3].cue_out == True

def test_key_attribute():
obj = m3u8.M3U8(playlists.SIMPLE_PLAYLIST)
Expand Down Expand Up @@ -515,7 +516,7 @@ def test_0_media_sequence_added_to_file():
obj = m3u8.M3U8()
obj.media_sequence = 0
result = obj.dumps()
expected = '#EXTM3U\n#EXT-X-MEDIA-SEQUENCE:0\n'
expected = '#EXTM3U\n'
assert result == expected

def test_none_media_sequence_gracefully_ignored():
Expand Down
12 changes: 12 additions & 0 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ def test_should_parse_variant_playlist():
assert 65000 == playlists_list[-1]['stream_info']['bandwidth']
assert 'mp4a.40.5,avc1.42801e' == playlists_list[-1]['stream_info']['codecs']

def test_should_parse_variant_playlist_with_average_bandwidth():
data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_AVERAGE_BANDWIDTH)
playlists_list = list(data['playlists'])
assert 1280000 == playlists_list[0]['stream_info']['bandwidth']
assert 1252345 == playlists_list[0]['stream_info']['average_bandwidth']
assert 2560000 == playlists_list[1]['stream_info']['bandwidth']
assert 2466570 == playlists_list[1]['stream_info']['average_bandwidth']
assert 7680000 == playlists_list[2]['stream_info']['bandwidth']
assert 7560423 == playlists_list[2]['stream_info']['average_bandwidth']
assert 65000 == playlists_list[3]['stream_info']['bandwidth']
assert 63005 == playlists_list[3]['stream_info']['average_bandwidth']

def test_should_parse_variant_playlist_with_iframe_playlists():
data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_IFRAME_PLAYLISTS)
iframe_playlists = list(data['iframe_playlists'])
Expand Down
35 changes: 35 additions & 0 deletions tests/test_variant_m3u8.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,38 @@ def test_create_a_variant_m3u8_with_two_playlists_and_two_iframe_playlists():
CODECS="avc1.4d001f",URI="video-1200k-iframes.m3u8"
"""
assert expected_content == variant_m3u8.dumps()


def test_variant_playlist_with_average_bandwidth():
variant_m3u8 = m3u8.M3U8()

low_playlist = m3u8.Playlist(
'http://example.com/low.m3u8',
stream_info={'bandwidth': 1280000,
'average_bandwidth': 1257891,
'program_id': 1,
'subtitles': 'subs'},
media=[],
base_uri=None
)
high_playlist = m3u8.Playlist(
'http://example.com/high.m3u8',
stream_info={'bandwidth': 3000000,
'average_bandwidth': 2857123,
'program_id': 1,
'subtitles': 'subs'},
media=[],
base_uri=None
)

variant_m3u8.add_playlist(low_playlist)
variant_m3u8.add_playlist(high_playlist)

expected_content = """\
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1257891
http://example.com/low.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3000000,AVERAGE-BANDWIDTH=2857123
http://example.com/high.m3u8
"""
assert expected_content == variant_m3u8.dumps()

0 comments on commit 707d212

Please sign in to comment.