Class: M3U8Generator
- Inherits:
-
Object
- Object
- M3U8Generator
- Includes:
- HLSConstants
- Defined in:
- lib/m3u8_generator.rb
Constant Summary
Constants included from HLSConstants
HLSConstants::EXTINF, HLSConstants::EXTM3U, HLSConstants::EXT_X_ALLOW_CACHE, HLSConstants::EXT_X_CUE_IN, HLSConstants::EXT_X_CUE_OUT, HLSConstants::EXT_X_DISCONTINUITY, HLSConstants::EXT_X_ENDLIST, HLSConstants::EXT_X_FAXS_CM, HLSConstants::EXT_X_KEY, HLSConstants::EXT_X_KEY_ATTRS, HLSConstants::EXT_X_MEDIA, HLSConstants::EXT_X_MEDIA_SEQUENCE, HLSConstants::EXT_X_PLAYLIST_TYPE, HLSConstants::EXT_X_STREAM_INF, HLSConstants::EXT_X_STREAM_INF_ATTRS, HLSConstants::EXT_X_TARGETDURATION, HLSConstants::EXT_X_VERSION, HLSConstants::FIXNUM_MAX, HLSConstants::SUPPORTED_M3U8_VERSIONS
Instance Attribute Summary collapse
-
#is_serving_domain_provider_default ⇒ Object
Returns the value of attribute is_serving_domain_provider_default.
-
#m3u8_serving_domain ⇒ Object
Returns the value of attribute m3u8_serving_domain.
-
#old_serving_domain ⇒ Object
Returns the value of attribute old_serving_domain.
Instance Method Summary collapse
- #append_auth_to_key_url_in_m3u8(original_m3u8_url, authentication_params = {}) ⇒ Object
- #build_bitrate_m3u8(chunks, authentication_params = {}) ⇒ Object
- #build_top_level_m3u8(embed_code, streams, min_bitrate = -1,, max_bitrate = 1000000000, target_bitrate = nil, single_bit_rate = false, authentication_params = {}, captions = nil, enable_resolution_tag = false) ⇒ Object
- #change_sub_m3u8_inside_master_m3u8(original_m3u8_url, sub_m3u8_domain, authentication_params = {}) ⇒ Object
- #shuffle_array_min_before_target_first(array, target) ⇒ Object
- #shuffle_array_with_median_first(array) ⇒ Object
Instance Attribute Details
#is_serving_domain_provider_default ⇒ Object
Returns the value of attribute is_serving_domain_provider_default.
27 28 29 |
# File 'lib/m3u8_generator.rb', line 27 def is_serving_domain_provider_default @is_serving_domain_provider_default end |
#m3u8_serving_domain ⇒ Object
Returns the value of attribute m3u8_serving_domain.
26 27 28 |
# File 'lib/m3u8_generator.rb', line 26 def m3u8_serving_domain @m3u8_serving_domain end |
#old_serving_domain ⇒ Object
Returns the value of attribute old_serving_domain.
25 26 27 |
# File 'lib/m3u8_generator.rb', line 25 def old_serving_domain @old_serving_domain end |
Instance Method Details
#append_auth_to_key_url_in_m3u8(original_m3u8_url, authentication_params = {}) ⇒ Object
157 158 159 160 161 162 163 164 165 166 |
# File 'lib/m3u8_generator.rb', line 157 def append_auth_to_key_url_in_m3u8(original_m3u8_url, authentication_params={}) response = Net::HTTP.get(URI(original_m3u8_url)) hls_manifest = HLSManifest.new(response) hls_manifest.line_items.each do |item| next unless defined?(item.key) key = item.key WarpgateUtils.append_params(key.uri, authentication_params) if key && key.uri end hls_manifest.build end |
#build_bitrate_m3u8(chunks, authentication_params = {}) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/m3u8_generator.rb', line 124 def build_bitrate_m3u8(chunks, authentication_params={}) file_contents = "" max_chunk_length = 0 chunks.each do |chunk| # Chunk Duration file_contents << "#EXTINF:#{chunk[:chunk_length]},\n" max_chunk_length = chunk[:chunk_length] if chunk[:chunk_length] > max_chunk_length # Chunk decryption key url if chunk[:key_url] && !chunk[:key_url].empty? final_auth_url = WarpgateUtils.append_params(chunk[:key_url], authentication_params) file_contents << "#EXT-X-KEY:METHOD=AES-128,URI=\"#{chunk[:key_url]}\"\n" end # Actual Chunk file_contents << "#{chunk[:chunk_url]}\n" end file_contents << "#{EXT_X_ENDLIST}\n" "#EXTM3U\n#EXT-X-TARGETDURATION:#{max_chunk_length}\n#EXT-X-MEDIA-SEQUENCE:0\n" + file_contents end |
#build_top_level_m3u8(embed_code, streams, min_bitrate = -1,, max_bitrate = 1000000000, target_bitrate = nil, single_bit_rate = false, authentication_params = {}, captions = nil, enable_resolution_tag = false) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/m3u8_generator.rb', line 29 def build_top_level_m3u8(, streams, min_bitrate=-1, max_bitrate=1000000000, target_bitrate=nil, single_bit_rate=false, authentication_params={}, =nil, enable_resolution_tag=false) # Check the streams object to verify the right Stream attributes are passed in streams.each do |stream| stream[:average_video_bitrate] stream[:muxing_format] stream[:thrift_path] stream[:audio_bitrate] stream[:video_width] stream[:video_height] stream[:is_encrypted] end file_contents = EXTM3U + "\n" if .each do || file_contents << "#{EXT_X_MEDIA}:TYPE=SUBTITLES,GROUP-ID=\"subs\"," + "NAME=\"#{[:language_name]}\"," + "DEFAULT=#{[:default] ? 'YES' : 'NO'}," + "FORCED=NO," + "AUTOSELECT=#{[:autoselect] ? 'YES' : 'NO'}," + "LANGUAGE=\"#{[:language_code]}\"," + "URI=\"#{[:url]}\"\n" end end # We might have different resolutions per bitrate, but when generating the top level m3u8, we # only care about unique bitrates. unique_bitrates = {} filtered_streams = [] streams.each do |stream| next if stream[:average_video_bitrate] > max_bitrate || stream[:average_video_bitrate] < min_bitrate next if unique_bitrates[stream[:average_video_bitrate]] unique_bitrates[stream[:average_video_bitrate]] = true filtered_streams << stream end # After we filter out streams above max bitrate, let's shuffle the array and put the median first. if(target_bitrate) final_streams = shuffle_array_min_before_target_first(filtered_streams, target_bitrate) else final_streams = shuffle_array_with_median_first(filtered_streams) #if possible, do not let the first stream be audio only. if final_streams != nil && final_streams.length > 1 && final_streams[0][:muxing_format].upcase == 'AAC' final_streams[0], final_streams[1] = final_streams[1], final_streams[0] end end if single_bit_rate final_streams = final_streams[0..0] end # For Adobe Access content, we have to append a link to the key in the manifest streams.each do |stream| if stream[:muxing_format].to_s == "TS_FA" || stream[:muxing_format].to_s == "AAC_FA" file_contents << (EXT_X_FAXS_CM + ":URI=\"#{@m3u8_serving_domain}/#{}/#{}.drmmeta\"\n") break end end # Now build the m3u8 file. final_streams.each do |stream| total_bitrate = stream[:average_video_bitrate] + stream[:audio_bitrate] should_append_resolution = enable_resolution_tag && stream[:muxing_format].upcase != 'AAC' stream_info = "#{EXT_X_STREAM_INF}:PROGRAM-ID=1,BANDWIDTH=#{total_bitrate * 1000}" stream_info += ",RESOLUTION=#{stream[:video_width]}x#{stream[:video_height]}" if should_append_resolution stream_info += ",CODECS=\"mp4a.40.2,mp4a.40.5\"" if stream[:muxing_format].upcase == 'AAC' #add audio stream_info += ",SUBTITLES=\"subs\"" if #add captions group file_contents << stream_info + "\n" stream_url = "" if (@is_serving_domain_provider_default && !stream[:is_encrypted]) || authentication_params['secure_ios_token'] stream_url = "#{@old_serving_domain}/#{}_#{stream[:average_video_bitrate]}.m3u8" else # Prepended embed code is handled by gen_serving_domain stream_url = "#{@m3u8_serving_domain}/#{stream[:thrift_path]}/#{stream[:average_video_bitrate]}_" + "#{stream[:audio_bitrate]}_#{stream[:video_width]}_#{stream[:video_height]}.m3u8" end WarpgateUtils.append_params(stream_url, authentication_params) file_contents << "#{stream_url}\n" end file_contents end |
#change_sub_m3u8_inside_master_m3u8(original_m3u8_url, sub_m3u8_domain, authentication_params = {}) ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/m3u8_generator.rb', line 145 def change_sub_m3u8_inside_master_m3u8(original_m3u8_url, sub_m3u8_domain, authentication_params={}) response = Net::HTTP.get(URI(original_m3u8_url)) hls_manifest = HLSManifest.new(response) hls_manifest.line_items.each do |item| next unless defined?(item.location) encoded_url = Base64.encode64(item.location).gsub("\n", "") new_url = "#{sub_m3u8_domain}?original_url=#{encoded_url}" item.location = WarpgateUtils.append_params(new_url, authentication_params) end hls_manifest.build end |
#shuffle_array_min_before_target_first(array, target) ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/m3u8_generator.rb', line 168 def shuffle_array_min_before_target_first(array, target) return array if array.nil? || array.length < 2 #assume a sorted array, do a binary search for closest min = 0 max = array.length - 1 while min < max do mid = min + (max - min) / 2 array[mid][:average_video_bitrate] < target.to_i ? min = mid + 1 : max = mid end t = array[min][:average_video_bitrate] <= target.to_i ? min : min - 1 t = t < 0 ? 0 : t result = array.clone result.delete_at(t) result.unshift array[t] return result end |
#shuffle_array_with_median_first(array) ⇒ Object
185 186 187 188 189 190 191 192 |
# File 'lib/m3u8_generator.rb', line 185 def shuffle_array_with_median_first(array) return array if array.nil? || array.length < 3 median = array[array.length / 2] result = array.clone result.delete_at(array.length / 2) result.unshift median return result end |