diff --git a/m3u8/model.py b/m3u8/model.py
index 1e12148..fce4fbf 100644
--- a/m3u8/model.py
+++ b/m3u8/model.py
@@ -510,7 +510,8 @@ class Playlist(BasePathMixin):
             average_bandwidth=stream_info.get('average_bandwidth'),
             program_id=stream_info.get('program_id'),
             resolution=resolution_pair,
-            codecs=stream_info.get('codecs')
+            codecs=stream_info.get('codecs'),
+            frame_rate=stream_info.get('frame_rate')
         )
         self.media = []
         for media_type in ('audio', 'video', 'subtitles'):
@@ -535,6 +536,8 @@ class Playlist(BasePathMixin):
             res = str(self.stream_info.resolution[
                       0]) + 'x' + str(self.stream_info.resolution[1])
             stream_inf.append('RESOLUTION=' + res)
+        if self.stream_info.frame_rate:
+            stream_inf.append('FRAME-RATE=%.5g' % self.stream_info.frame_rate)
         if self.stream_info.codecs:
             stream_inf.append('CODECS=' + quoted(self.stream_info.codecs))
 
@@ -586,7 +589,8 @@ class IFramePlaylist(BasePathMixin):
             average_bandwidth=None,
             program_id=iframe_stream_info.get('program_id'),
             resolution=resolution_pair,
-            codecs=iframe_stream_info.get('codecs')
+            codecs=iframe_stream_info.get('codecs'),
+            frame_rate=None
         )
 
     def __str__(self):
@@ -611,7 +615,7 @@ class IFramePlaylist(BasePathMixin):
 
 StreamInfo = namedtuple(
     'StreamInfo',
-    ['bandwidth', 'closed_captions', 'average_bandwidth', 'program_id', 'resolution', 'codecs', 'audio', 'video', 'subtitles']
+    ['bandwidth', 'closed_captions', 'average_bandwidth', 'program_id', 'resolution', 'codecs', 'audio', 'video', 'subtitles', 'frame_rate']
 )
 
 
diff --git a/m3u8/parser.py b/m3u8/parser.py
index ccd5696..64fbdb8 100644
--- a/m3u8/parser.py
+++ b/m3u8/parser.py
@@ -243,6 +243,7 @@ def _parse_stream_inf(line, data, state):
     atribute_parser["program_id"] = int
     atribute_parser["bandwidth"] = lambda x: int(float(x))
     atribute_parser["average_bandwidth"] = int
+    atribute_parser["frame_rate"] = float
     state['stream_info'] = _parse_attribute_list(protocol.ext_x_stream_inf, line, atribute_parser)
 
 

diff --git a/tests/playlists.py b/tests/playlists.py
index c912a04..44d635e 100755
--- a/tests/playlists.py
+++ b/tests/playlists.py
@@ -707,4 +707,16 @@ CUE_OUT_PLAYLIST_FILENAME = abspath(join(dirname(__file__), 'playlists/cue_out.m
 
 CUE_OUT_PLAYLIST_URI = TEST_HOST + '/path/to/cue_out.m3u8'
 
+VARIANT_PLAYLIST_WITH_FRAME_RATE = '''
+#EXTM3U
+#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1280000,FRAME-RATE=25
+http://example.com/low.m3u8
+#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2560000,FRAME-RATE=50
+http://example.com/mid.m3u8
+#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7680000,FRAME-RATE=60
+http://example.com/hi.m3u8
+#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,FRAME-RATE=12.5,CODECS="mp4a.40.5,avc1.42801e"
+http://example.com/audio-only.m3u8
+'''
+
 del abspath, dirname, join
diff --git a/tests/test_model.py b/tests/test_model.py
index 3225d93..b8bb70d 100755
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -818,6 +818,13 @@ def test_playlist_stream_info_contains_group_id_refs():
         assert pl.stream_info.audio == 'aud'
         assert pl.stream_info.video == 'vid'
 
+def test_should_dump_frame_rate():
+    obj = m3u8.M3U8(playlists.VARIANT_PLAYLIST_WITH_FRAME_RATE)
+    expected = playlists.VARIANT_PLAYLIST_WITH_FRAME_RATE.strip()
+
+    assert expected == obj.dumps().strip()
+
+
 
 # custom asserts
 
diff --git a/tests/test_parser.py b/tests/test_parser.py
index e8b08ef..6f2400e 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -325,4 +325,12 @@ def test_simple_playlist_with_custom_tags():
     assert 5220 == data['targetduration']
     assert 0 == data['media_sequence']
     assert ['http://media.example.com/entire.ts'] == [c['uri'] for c in data['segments']]
-    assert [5220] == [c['duration'] for c in data['segments']]
\ No newline at end of file
+    assert [5220] == [c['duration'] for c in data['segments']]
+
+def test_master_playlist_with_frame_rate():
+    data = m3u8.parse(playlists.VARIANT_PLAYLIST_WITH_FRAME_RATE)
+    playlists_list = list(data['playlists'])
+    assert 25 == playlists_list[0]['stream_info']['frame_rate']
+    assert 50 == playlists_list[1]['stream_info']['frame_rate']
+    assert 60 == playlists_list[2]['stream_info']['frame_rate']
+    assert 12.5 == playlists_list[3]['stream_info']['frame_rate']

Add support for FRAME-RATE tag
Tag `FRAME-RATE` is ignored when parsing and dumping a master playlist.

For example when [master-with-stream-inf-1.m3u8](https://github.com/grafov/m3u8/blob/master/sample-playlists/master-with-stream-inf-1.m3u8), which contains `FRAME-RATE` tag, is loaded:
```
m3u8_obj = m3u8.load('master-with-stream-inf-1.m3u8')
```
And then dumped:
```
print(m3u8_obj.dumps())
```
The `FRAME-RATE` tag is gone:
```
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=300000,AVERAGE-BANDWIDTH=300000,CODECS="avc1.42c015,mp4a.40.2"
chunklist-b300000.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=600000,AVERAGE-BANDWIDTH=600000,CODECS="avc1.42c015,mp4a.40.2"
chunklist-b600000.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=850000,AVERAGE-BANDWIDTH=850000,CODECS="avc1.42c015,mp4a.40.2"
chunklist-b850000.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1000000,AVERAGE-BANDWIDTH=1000000,CODECS="avc1.42c015,mp4a.40.2"
chunklist-b1000000.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1500000,AVERAGE-BANDWIDTH=1500000,CODECS="avc1.42c015,mp4a.40.2"
chunklist-b1500000.m3u8
```

The solution would be probably to extend `stream_info` for `Playlist` class.
tests/test_model.py::test_should_dump_frame_rate tests/test_parser.py::test_master_playlist_with_frame_rate
tests/test_model.py::test_target_duration_attribute tests/test_model.py::test_media_sequence_attribute tests/test_model.py::test_program_date_time_attribute tests/test_model.py::test_program_date_time_attribute_for_each_segment tests/test_model.py::test_program_date_time_attribute_with_discontinuity tests/test_model.py::test_program_date_time_attribute_without_discontinuity tests/test_model.py::test_segment_discontinuity_attribute tests/test_model.py::test_segment_cue_out_attribute tests/test_model.py::test_segment_elemental_scte35_attribute tests/test_model.py::test_segment_envivio_scte35_attribute tests/test_model.py::test_keys_on_clear_playlist tests/test_model.py::test_keys_on_simple_encrypted_playlist tests/test_model.py::test_key_attribute tests/test_model.py::test_key_attribute_on_none tests/test_model.py::test_key_attribute_without_initialization_vector tests/test_model.py::test_segments_attribute tests/test_model.py::test_segments_attribute_without_title tests/test_model.py::test_segments_attribute_without_duration tests/test_model.py::test_segments_attribute_with_byterange tests/test_model.py::test_segment_attribute_with_multiple_keys tests/test_model.py::test_is_variant_attribute tests/test_model.py::test_is_endlist_attribute tests/test_model.py::test_is_i_frames_only_attribute tests/test_model.py::test_playlists_attribute tests/test_model.py::test_playlists_attribute_without_program_id tests/test_model.py::test_playlists_attribute_with_resolution tests/test_model.py::test_iframe_playlists_attribute tests/test_model.py::test_version_attribute tests/test_model.py::test_allow_cache_attribute tests/test_model.py::test_files_attribute_should_list_all_files_including_segments_and_key tests/test_model.py::test_vod_playlist_type_should_be_imported_as_a_simple_attribute tests/test_model.py::test_event_playlist_type_should_be_imported_as_a_simple_attribute tests/test_model.py::test_independent_segments_should_be_true tests/test_model.py::test_independent_segments_should_be_false tests/test_model.py::test_no_playlist_type_leaves_attribute_empty tests/test_model.py::test_dump_playlists_with_resolution tests/test_model.py::test_dump_should_build_file_with_same_content tests/test_model.py::test_dump_should_create_sub_directories tests/test_model.py::test_dump_should_work_for_variant_streams tests/test_model.py::test_dump_should_work_for_variant_playlists_with_iframe_playlists tests/test_model.py::test_dump_should_work_for_iframe_playlists tests/test_model.py::test_dump_should_include_program_date_time tests/test_model.py::test_dump_should_include_segment_level_program_date_time tests/test_model.py::test_dump_should_include_segment_level_program_date_time_without_discontinuity tests/test_model.py::test_dump_should_include_map_attributes tests/test_model.py::test_dump_should_work_for_playlists_using_byteranges tests/test_model.py::test_should_dump_with_endlist_tag tests/test_model.py::test_should_dump_without_endlist_tag tests/test_model.py::test_should_dump_multiple_keys tests/test_model.py::test_should_dump_unencrypted_encrypted_keys_together tests/test_model.py::test_should_dump_complex_unencrypted_encrypted_keys tests/test_model.py::test_should_dump_complex_unencrypted_encrypted_keys_no_uri_attr tests/test_model.py::test_length_segments_by_key tests/test_model.py::test_list_segments_by_key tests/test_model.py::test_replace_segment_key tests/test_model.py::test_should_dump_program_datetime_and_discontinuity tests/test_model.py::test_should_normalize_segments_and_key_urls_if_base_path_passed_to_constructor tests/test_model.py::test_should_normalize_variant_streams_urls_if_base_path_passed_to_constructor tests/test_model.py::test_should_normalize_segments_and_key_urls_if_base_path_attribute_updated tests/test_model.py::test_playlist_type_dumped_to_appropriate_m3u8_field tests/test_model.py::test_empty_playlist_type_is_gracefully_ignored tests/test_model.py::test_none_playlist_type_is_gracefully_ignored tests/test_model.py::test_0_media_sequence_added_to_file tests/test_model.py::test_none_media_sequence_gracefully_ignored tests/test_model.py::test_0_discontinuity_sequence_added_to_file tests/test_model.py::test_none_discontinuity_sequence_gracefully_ignored tests/test_model.py::test_should_correctly_update_base_path_if_its_blank tests/test_model.py::test_m3u8_should_propagate_base_uri_to_segments tests/test_model.py::test_m3u8_should_propagate_base_uri_to_key tests/test_model.py::test_base_path_with_optional_uri_should_do_nothing tests/test_model.py::test_segment_map_uri_attribute tests/test_model.py::test_segment_map_uri_attribute_with_byterange tests/test_model.py::test_start_with_negative_offset tests/test_model.py::test_start_with_precise tests/test_model.py::test_playlist_stream_info_contains_group_id_refs tests/test_parser.py::test_should_parse_simple_playlist_from_string tests/test_parser.py::test_should_parse_non_integer_duration_from_playlist_string tests/test_parser.py::test_should_parse_comma_in_title tests/test_parser.py::test_should_parse_simple_playlist_from_string_with_different_linebreaks tests/test_parser.py::test_should_parse_sliding_window_playlist_from_string tests/test_parser.py::test_should_parse_playlist_with_encripted_segments_from_string tests/test_parser.py::test_should_load_playlist_with_iv_from_string tests/test_parser.py::test_should_add_key_attribute_to_segment_from_playlist tests/test_parser.py::test_should_add_non_key_for_multiple_keys_unencrypted_and_encrypted tests/test_parser.py::test_should_handle_key_method_none_and_no_uri_attr tests/test_parser.py::test_should_parse_title_from_playlist tests/test_parser.py::test_should_parse_variant_playlist tests/test_parser.py::test_should_parse_variant_playlist_with_cc_subtitles_and_audio tests/test_parser.py::test_should_parse_variant_playlist_with_average_bandwidth tests/test_parser.py::test_should_parse_variant_playlist_with_bandwidth_as_float tests/test_parser.py::test_should_parse_variant_playlist_with_iframe_playlists tests/test_parser.py::test_should_parse_variant_playlist_with_alt_iframe_playlists_layout tests/test_parser.py::test_should_parse_iframe_playlist tests/test_parser.py::test_should_parse_playlist_using_byteranges tests/test_parser.py::test_should_parse_endlist_playlist tests/test_parser.py::test_should_parse_ALLOW_CACHE tests/test_parser.py::test_should_parse_VERSION tests/test_parser.py::test_should_parse_program_date_time_from_playlist tests/test_parser.py::test_should_parse_scte35_from_playlist tests/test_parser.py::test_should_parse_envivio_cue_playlist tests/test_parser.py::test_parse_simple_playlist_messy tests/test_parser.py::test_parse_simple_playlist_messy_strict tests/test_parser.py::test_commaless_extinf tests/test_parser.py::test_commaless_extinf_strict tests/test_parser.py::test_should_parse_segment_map_uri tests/test_parser.py::test_should_parse_segment_map_uri_with_byterange tests/test_parser.py::test_should_parse_empty_uri_with_base_path tests/test_parser.py::test_should_parse_start_with_negative_time_offset tests/test_parser.py::test_should_parse_start_with_precise tests/test_parser.py::test_simple_playlist_with_discontinuity_sequence tests/test_parser.py::test_simple_playlist_with_custom_tags