video_converter 0.2.13 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,15 +8,16 @@ require "video_converter/input"
8
8
  require "video_converter/input_array"
9
9
  require "video_converter/output"
10
10
  require "video_converter/output_array"
11
+ require "video_converter/hls"
11
12
  require "fileutils"
12
13
  require "net/http"
13
14
  require "video_screenshoter"
15
+ require "shellwords"
14
16
 
15
17
  module VideoConverter
16
18
  class << self
17
19
  attr_accessor :paral
18
20
  end
19
-
20
21
  self.paral = true
21
22
 
22
23
  def self.new params
@@ -24,7 +25,7 @@ module VideoConverter
24
25
  end
25
26
 
26
27
  def self.find uid
27
- VideoConverter::Process.new uid
28
+ VideoConverter::Process.find uid
28
29
  end
29
30
  end
30
31
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module VideoConverter
4
4
  class Base
5
- attr_accessor :input_array, :output_array, :log, :uid, :clear_tmp
5
+ attr_accessor :input_array, :output_array, :log, :uid, :clear_tmp, :process
6
6
 
7
7
  def initialize params
8
8
  self.uid = params[:uid] || (Socket.gethostname + object_id.to_s)
@@ -19,24 +19,13 @@ module VideoConverter
19
19
  end
20
20
 
21
21
  def run
22
- process = VideoConverter::Process.new(uid)
23
- process.status = 'started'
24
- process.pid = `cat /proc/self/stat`.split[3]
25
- actions = []
26
- actions = [:convert, :segment, :screenshot]
27
- actions << :clear if clear_tmp
28
- actions.each do |action|
22
+ self.process = VideoConverter::Process.new(uid, output_array)
23
+ [:convert, :segment, :screenshot].each do |action|
29
24
  process.status = action.to_s
30
- process.progress = 0
31
- res = send action
32
- if res
33
- process.status = "#{action}_success"
34
- else
35
- process.status = "#{action}_error"
36
- return false
37
- end
25
+ process.status = "#{action}_error" and return false unless send(action)
38
26
  end
39
27
  process.status = 'finished'
28
+ clear if clear_tmp
40
29
  true
41
30
  end
42
31
 
@@ -44,7 +33,7 @@ module VideoConverter
44
33
 
45
34
  def convert
46
35
  params = {}
47
- [:input_array, :output_array, :log].each do |param|
36
+ [:input_array, :output_array, :log, :process].each do |param|
48
37
  params[param] = self.send(param)
49
38
  end
50
39
  Ffmpeg.new(params).run
@@ -73,6 +62,7 @@ module VideoConverter
73
62
  FileUtils.rm(Dir.glob(File.join(output.work_dir, '*.log.mbtree')))
74
63
  FileUtils.rm(File.join(output.work_dir, output.filename.sub(/\.m3u8$/, '.ts'))) if output.type == :segmented
75
64
  end
65
+ FileUtils.rm_r(process.process_dir)
76
66
  true
77
67
  end
78
68
  end
@@ -13,12 +13,23 @@ module VideoConverter
13
13
  def initialize command, params = {}
14
14
  res = command.clone
15
15
  params.each do |param, value|
16
- res.gsub! "%{#{param}}", value.to_s
16
+ value = value.to_s.strip
17
+ res.gsub! "%{#{param}}", if value.empty?
18
+ ''
19
+ elsif matches = value.match(/^([\w-]+)\s+(.+)$/)
20
+ "#{matches[1]} #{escape(matches[2])}"
21
+ else
22
+ escape(value)
23
+ end
17
24
  end
18
25
  self.command = res
19
26
  raise ArgumentError.new("Command is not parsed '#{self.command}'") if self.command.match(/%{[\w\-.]+}/)
20
27
  end
21
28
 
29
+ def escape value
30
+ Shellwords.escape(value.to_s.gsub(/(?<!\\)(['+])/, '\\\\\1')).gsub("\\\\","\\")
31
+ end
32
+
22
33
  def execute params = {}
23
34
  puts command if params[:verbose] || self.class.verbose
24
35
  if params[:debug] || self.class.debug
@@ -11,39 +11,42 @@ module VideoConverter
11
11
  self.paral = true
12
12
  self.log = '/dev/null'
13
13
 
14
- self.one_pass_command = "%{bin} -i %{input} -y -acodec copy -vcodec %{video_codec} -g 100 -keyint_min 50 -b:v %{video_bitrate}k -bt %{video_bitrate}k -f mp4 %{local_path} 1>%{log} 2>&1 || exit 1"
14
+ self.one_pass_command = "%{bin} -i %{input} -y -acodec copy -vcodec %{video_codec} -g 100 -keyint_min 50 -b:v %{video_bitrate}k -bt %{video_bitrate}k %{vf} %{frame_rate} -progress %{progressfile} -f mp4 %{local_path} 1>%{log} 2>&1 || exit 1"
15
15
 
16
- self.first_pass_command = "%{bin} -i %{input} -y -an -vcodec %{video_codec} -g %{keyframe_interval} -keyint_min 25 -pass 1 -passlogfile %{passlogfile} -b:v 700k -threads %{threads} -f mp4 /dev/null 1>>%{log} 2>&1 || exit 1"
16
+ self.first_pass_command = "%{bin} -i %{input} -y -an -vcodec %{video_codec} -g %{keyframe_interval} -keyint_min 25 -pass 1 -passlogfile %{passlogfile} -progress %{progressfile} -b:v 3000k %{vf} %{frame_rate} -threads %{threads} -f mp4 /dev/null 1>>%{log} 2>&1 || exit 1"
17
17
 
18
- self.second_pass_command = "%{bin} -i %{input} -y -pass 2 -passlogfile %{passlogfile} -c:a %{audio_codec} -b:a %{audio_bitrate}k -c:v %{video_codec} -g %{keyframe_interval} -keyint_min 25 %{frame_rate} -b:v %{video_bitrate}k %{size} -threads %{threads} -f mp4 %{local_path} 1>%{log} 2>&1 || exit 1"
18
+ self.second_pass_command = "%{bin} -i %{input} -y -pass 2 -passlogfile %{passlogfile} -progress %{progressfile} -c:a %{audio_codec} -b:a %{audio_bitrate}k -c:v %{video_codec} -g %{keyframe_interval} -keyint_min 25 %{frame_rate} -b:v %{video_bitrate}k %{vf} -threads %{threads} -f mp4 %{local_path} 1>%{log} 2>&1 || exit 1"
19
19
 
20
- attr_accessor :input_array, :output_array, :one_pass, :paral, :log
20
+ attr_accessor :input_array, :output_array, :one_pass, :paral, :log, :process
21
21
 
22
22
  def initialize params
23
23
  [:input_array, :output_array].each do |param|
24
24
  self.send("#{param}=", params[param]) or raise ArgumentError.new("#{param} is needed")
25
25
  end
26
- [:one_pass, :paral, :log].each do |param|
26
+ [:one_pass, :paral, :log, :process].each do |param|
27
27
  self.send("#{param}=", params[param] ? params[param] : self.class.send(param))
28
28
  end
29
29
  end
30
30
 
31
31
  def run
32
+ progress_thread = Thread.new { collect_progress }
32
33
  res = true
33
34
  input_array.inputs.each do |input|
34
35
  threads = []
35
36
  input.output_groups.each_with_index do |group, group_number|
36
- passlogfile = File.join(File.dirname(group.first.local_path), "#{group_number}.log")
37
+ passlogfile = File.join(group.first.work_dir, "#{group_number}.log")
38
+ progressfile = File.join(process.progress_dir, "#{group_number}.log")
37
39
  one_pass = self.one_pass || group.first.video_codec == 'copy'
38
40
  unless one_pass
39
- first_pass_command = Command.new self.class.first_pass_command, prepare_params(common_params.merge(group.first.to_hash).merge((group.first.playlist.to_hash rescue {})).merge(:passlogfile => passlogfile, :input => input))
41
+ first_pass_command = Command.new self.class.first_pass_command, prepare_params(common_params.merge((group.first.playlist.to_hash rescue {})).merge(group.first.to_hash).merge(:passlogfile => passlogfile, :input => input, :progressfile => progressfile))
40
42
  res &&= first_pass_command.execute
41
43
  end
42
- group.each do |quality|
44
+ group.each_with_index do |quality, quality_number|
45
+ progressfile = File.join(process.progress_dir, "#{group_number}_#{quality_number}.log")
43
46
  if one_pass
44
- quality_command = Command.new self.class.one_pass_command, prepare_params(common_params.merge(quality.to_hash).merge(:passlogfile => passlogfile, :input => input))
47
+ quality_command = Command.new self.class.one_pass_command, prepare_params(common_params.merge(quality.to_hash).merge(:passlogfile => passlogfile, :input => input, :progressfile => progressfile))
45
48
  else
46
- quality_command = Command.new self.class.second_pass_command, prepare_params(common_params.merge(quality.to_hash).merge(:passlogfile => passlogfile, :input => input))
49
+ quality_command = Command.new self.class.second_pass_command, prepare_params(common_params.merge(quality.to_hash).merge(:passlogfile => passlogfile, :input => input, :progressfile => progressfile))
47
50
  end
48
51
  if paral
49
52
  threads << Thread.new { res &&= quality_command.execute }
@@ -54,9 +57,10 @@ module VideoConverter
54
57
  end
55
58
  threads.each { |t| t.join } if paral
56
59
  end
60
+ progress_thread.kill
57
61
  res
58
62
  end
59
-
63
+
60
64
  private
61
65
 
62
66
  def common_params
@@ -64,9 +68,34 @@ module VideoConverter
64
68
  end
65
69
 
66
70
  def prepare_params params
67
- params[:size] = params[:size] ? "-s #{params[:size]}" : ''
71
+ width = params[:width] || params[:size].to_s.match(/^(\d+)x(\d*)$/).to_a[1] || 'trunc(oh*a/2)*2'
72
+ height = params[:height] || params[:size].to_s.match(/^(\d*)x(\d+)$/).to_a[2] || 'trunc(ow/a/2)*2'
73
+ if width.to_s.include?('trunc') && height.to_s.include?('trunc')
74
+ params[:vf] = ''
75
+ else
76
+ params[:vf] = "-vf scale=#{width}:#{height}"
77
+ end
68
78
  params[:frame_rate] = params[:frame_rate] ? "-r #{params[:frame_rate]}" : ''
69
79
  params
70
80
  end
81
+
82
+ def processes_count
83
+ (one_pass ? 0 : input_array.inputs.inject(0) { |sum, i| sum + i.output_groups.count }) +
84
+ input_array.inputs.map { |i| i.output_groups.map { |g| g.count } }.flatten.inject(:+)
85
+ end
86
+
87
+ def collect_progress
88
+ duration = input_array.inputs.first.metadata[:duration_in_ms]
89
+ loop do
90
+ sleep Process.collect_progress_interval
91
+ koefs = []
92
+ Dir.glob(File.join(process.progress_dir, '*.log')).each do |progressfile|
93
+ if matches = `tail -n 9 #{progressfile}`.match(/out_time_ms=(\d+).*?progress=(\w+)/m)
94
+ koefs << (matches[2] == 'end' ? 1 : (matches[1].to_f / 1000 / duration))
95
+ end
96
+ end
97
+ process.collect_progress(koefs.inject { |sum, k| sum + k } / processes_count)
98
+ end
99
+ end
71
100
  end
72
101
  end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ module VideoConverter
4
+ class Hls
5
+ attr_accessor :ffmpeg_bin, :input, :output, :chunks_dir, :replace_in_chunk, :log, :verbose
6
+
7
+ def initialize params
8
+ self.ffmpeg_bin = params[:ffmpeg_bin] || Ffmpeg.bin
9
+ %w(input output).each { |param| self.send("#{param}=", params[param.to_sym]) or raise "#{param} is needed" }
10
+ self.chunks_dir = if params[:chunks_dir]
11
+ params[:chunks_dir]
12
+ elsif !input.match(/^https?:\/\//)
13
+ File.dirname(input)
14
+ end
15
+ self.replace_in_chunk = params[:replace_in_chunk]
16
+ self.log = params[:log] || '/dev/null'
17
+ self.verbose = params[:verbose]
18
+ end
19
+
20
+ def concat
21
+ chunks = parse_playlist rescue []
22
+ raise "Empty or invalid playlist #{input}" if chunks.empty?
23
+ output_dir = File.dirname(output)
24
+ `mkdir -p #{output_dir}` unless Dir.exists?(output_dir)
25
+ concat_file = File.join(output_dir, 'concat.ts')
26
+ `rm #{concat_file}` if File.exists? concat_file
27
+ chunks.each do |chunk|
28
+ local_chunk = if chunks_dir
29
+ File.join(chunks_dir, chunk)
30
+ elsif replace_in_chunk
31
+ chunk.sub(replace_in_chunk.first, replace_in_chunk.last)
32
+ end
33
+ if local_chunk && File.exists?(local_chunk)
34
+ message = "Copy #{local_chunk} to #{concat_file}"
35
+ puts message if verbose
36
+ yield message if block_given?
37
+ `cat #{local_chunk} >> #{concat_file}`
38
+ else
39
+ chunk = File.join(File.dirname(input), chunk) unless chunk.match(/(^https?:\/\/)|(^\/)/)
40
+ message = "Download #{chunk} to #{concat_file}"
41
+ puts message if verbose
42
+ yield message if block_given?
43
+ `cd #{output_dir} && wget #{chunk} 1>>#{log} 2>&1 && cat #{File.basename(chunk)} >> #{concat_file} && rm #{File.basename(chunk)}`
44
+ end
45
+ end
46
+ raise "Cannot download chunks from #{input}" unless File.exists?(concat_file) && File.size(concat_file) > 0
47
+ puts "Convert #{concat_file}" if verbose
48
+ `#{ffmpeg_bin} -i #{concat_file} -vcodec copy -acodec copy -f mpegts pipe:1 2>>/dev/null | #{ffmpeg_bin} -y -i - -acodec copy -vcodec copy -absf aac_adtstoasc -f mp4 #{output} 1>>#{log} 2>&1`
49
+ `rm #{concat_file}`
50
+ output
51
+ end
52
+
53
+ private
54
+
55
+ def parse_playlist
56
+ require 'open-uri'
57
+ open(input) { |f| f.read }.scan(/EXTINF:[\d.]+.*?\n(.*?)\n/).flatten
58
+ end
59
+ end
60
+ end
@@ -18,7 +18,7 @@ module VideoConverter
18
18
  end
19
19
 
20
20
  def to_s
21
- input.gsub(/ /, "\\ ")
21
+ Shellwords.escape(input).gsub("\\\\","\\")
22
22
  end
23
23
 
24
24
  def exists?
@@ -37,7 +37,7 @@ module VideoConverter
37
37
 
38
38
  def metadata
39
39
  metadata = {}
40
- s = `#{Command.new self.class.metadata_command, common_params}`
40
+ s = `#{Command.new self.class.metadata_command, common_params}`.encode!('UTF-8', 'UTF-8', :invalid => :replace)
41
41
  if (m = s.match(/Stream.*?Audio:\s*(\w+).*?(\d+)\s*Hz.*?(\d+)\s*kb\/s$/).to_a).any?
42
42
  metadata[:audio_codec] = m[1]
43
43
  metadata[:audio_sample_rate] = m[2].to_i
@@ -83,7 +83,7 @@ module VideoConverter
83
83
  private
84
84
 
85
85
  def common_params
86
- { :bin => VideoConverter::Ffmpeg.bin, :input => to_s }
86
+ { :bin => VideoConverter::Ffmpeg.bin, :input => input }
87
87
  end
88
88
  end
89
89
  end
@@ -8,7 +8,7 @@ module VideoConverter
8
8
  self.inputs = (inputs.is_a?(Array) ? inputs : [inputs]).map { |input| Input.new(input) }
9
9
  output_array.outputs.each do |output|
10
10
  if [:standard, :segmented].include? output.type
11
- self.inputs[self.inputs.index { |input| input.to_s == output.path.to_s.gsub(/ /, "\\ ") }.to_i].outputs << output
11
+ self.inputs[self.inputs.index { |input| input.to_s == Shellwords.escape(output.path.to_s).gsub("\\\\","\\") }.to_i].outputs << output
12
12
  end
13
13
  end
14
14
  self.inputs.each do |input|
@@ -16,7 +16,7 @@ module VideoConverter
16
16
  self.video_codec = 'libx264'
17
17
  self.audio_codec = 'libfaac'
18
18
 
19
- attr_accessor :type, :url, :base_url, :filename, :format, :video_bitrate, :uid, :streams, :work_dir, :local_path, :playlist, :items, :segment_seconds, :chunks_dir, :audio_bitrate, :keyframe_interval, :threads, :video_codec, :audio_codec, :path, :thumbnails
19
+ attr_accessor :type, :url, :base_url, :filename, :format, :video_bitrate, :uid, :streams, :work_dir, :local_path, :playlist, :items, :segment_seconds, :chunks_dir, :audio_bitrate, :keyframe_interval, :threads, :video_codec, :audio_codec, :path, :thumbnails, :frame_rate, :size, :width, :height
20
20
 
21
21
  def initialize params = {}
22
22
  self.uid = params[:uid].to_s
@@ -59,17 +59,23 @@ module VideoConverter
59
59
 
60
60
  # Frame rate
61
61
  self.keyframe_interval = params[:keyframe_interval].to_i > 0 ? params[:keyframe_interval].to_i : self.class.keyframe_interval
62
+ self.frame_rate = params[:frame_rate].to_i if params[:frame_rate]
62
63
 
63
64
  # Format and codecs
64
65
  self.video_codec = (params[:copy_video] ? 'copy' : params[:video_codec]) || self.class.video_codec
65
66
  self.audio_codec = (params[:copy_audio] ? 'copy' : params[:audio_codec]) || self.class.audio_codec
66
67
 
68
+ # Resolution
69
+ self.size = params[:size]
70
+ self.width = params[:width]
71
+ self.height = params[:height]
72
+
67
73
  #Thumbnails
68
74
  self.thumbnails = params[:thumbnails]
69
75
  end
70
76
 
71
77
  def to_hash
72
- keys = [:video_bitrate, :local_path, :segment_seconds, :chunks_dir, :audio_bitrate, :keyframe_interval, :threads, :video_codec, :audio_codec]
78
+ keys = [:video_bitrate, :local_path, :segment_seconds, :chunks_dir, :audio_bitrate, :keyframe_interval, :frame_rate, :threads, :video_codec, :audio_codec, :size, :width, :height]
73
79
  Hash[*keys.map{ |key| [key, self.send(key)] }.flatten]
74
80
  end
75
81
 
@@ -2,31 +2,81 @@
2
2
 
3
3
  module VideoConverter
4
4
  class Process
5
- attr_accessor :uid, :status, :progress, :pid
5
+ attr_accessor :uid, :status, :progress, :status_progress, :pid, :process_dir, :status_progress_koefs
6
6
 
7
7
  class << self
8
- attr_accessor :path
8
+ attr_accessor :process_dir, :collect_progress_interval
9
9
  end
10
- self.path = 'tmp/processes'
10
+ self.process_dir = '/tmp/video_converter_process'
11
+ self.collect_progress_interval = 10
11
12
 
12
- def initialize uid
13
+ def self.find uid
14
+ if Dir.exists?(File.join(process_dir, uid))
15
+ new uid
16
+ else
17
+ nil
18
+ end
19
+ end
20
+
21
+ def initialize uid, output_array = nil
13
22
  self.uid = uid
14
- Dir.mkdir(self.class.path) unless Dir.exists?(self.class.path)
23
+ self.process_dir = File.join(self.class.process_dir, uid)
24
+
25
+ unless Dir.exists? process_dir
26
+ FileUtils.mkdir_p process_dir
27
+ self.pid = `cat /proc/self/stat`.split[3]
28
+ self.status = 'started'
29
+ self.progress = self.status_progress = 0
30
+ end
31
+
32
+ if output_array
33
+ self.status_progress_koefs = {}
34
+ self.status_progress_koefs[:screenshot] = 0.05 if output_array.outputs.detect { |o| o.thumbnails }
35
+ self.status_progress_koefs[:segment] = 0.1 if output_array.playlists.any?
36
+ self.status_progress_koefs[:convert] = 1 - status_progress_koefs.values.inject(0, :+)
37
+ else
38
+ self.status_progress_koefs = { :screenshot => 0.05, :segment => 0.1, :convert => 0.85 }
39
+ end
15
40
  end
16
41
 
17
- [:status, :progress, :pid].each do |attr|
18
- define_method(attr) { File.open(send("#{attr}_file".to_sym), 'r') { |f| f.read } rescue nil }
19
- define_method("#{attr}=") { |value| File.open(send("#{attr}_file".to_sym), 'w') { |f| f.write value } }
42
+ # attr are saved in local file
43
+ def get_attr attr
44
+ File.open(File.join(process_dir, "#{attr}.txt"), 'r') { |f| f.read } rescue nil
45
+ end
46
+ def set_attr attr, value
47
+ File.open(File.join(process_dir, "#{attr}.txt"), 'w') { |f| f.write value }
48
+ end
49
+
50
+ [:progress, :status_progress, :pid].each do |attr|
51
+ define_method attr do
52
+ get_attr attr
53
+ end
54
+ define_method "#{attr}=" do |value|
55
+ set_attr attr, value
56
+ end
57
+ end
58
+
59
+ def status
60
+ get_attr :status
61
+ end
62
+
63
+ def status= value
64
+ set_attr :status, value
65
+ FileUtils.mkdir_p progress_dir if %w(convert).include?(value.to_s)
66
+ self.progress = self.status_progress = 1 if value.to_s == 'finished'
20
67
  end
21
68
 
22
69
  def stop
23
70
  `pkill -P #{pid}`
24
71
  end
25
72
 
26
- private
73
+ def collect_progress progress
74
+ self.status_progress = progress
75
+ self.progress = progress * status_progress_koefs[status.to_sym].to_f
76
+ end
27
77
 
28
- [:status, :progress, :pid].each do |attr|
29
- define_method("#{attr}_file".to_sym) { File.join self.class.path, "#{uid}_#{attr}" }
78
+ def progress_dir
79
+ File.join process_dir, 'progress', status
30
80
  end
31
81
  end
32
82
  end
@@ -1,3 +1,3 @@
1
1
  module VideoConverter
2
- VERSION = "0.2.13"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -9,7 +9,7 @@ class VideoConverterTest < Test::Unit::TestCase
9
9
 
10
10
  context 'with default type' do
11
11
  setup do
12
- @c = VideoConverter.new('input' => @input_file, 'output' => [{'video_bitrate' => 300, 'filename' => 'tmp/test1.mp4'}, {'video_bitrate' => 700, :filename => 'tmp/test2.mp4'}], 'log' => 'tmp/test.log')
12
+ @c = VideoConverter.new('input' => @input_file, 'output' => [{'video_bitrate' => 300, 'filename' => 'tmp/test1.mp4'}, {'video_bitrate' => 700, :filename => 'tmp/test2.mp4'}], 'log' => 'tmp/test.log', :clear_tmp => false)
13
13
  @res = @c.run
14
14
  end
15
15
  should 'convert files' do
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_runtime_dependency "video_screenshoter", "~> 0.0.6"
21
+ spec.add_runtime_dependency "video_screenshoter", "~> 0.2.1"
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1.3"
24
24
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: video_converter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.13
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-18 00:00:00.000000000 Z
12
+ date: 2013-08-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: video_screenshoter
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 0.0.6
21
+ version: 0.2.1
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 0.0.6
29
+ version: 0.2.1
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: bundler
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -109,6 +109,7 @@ files:
109
109
  - lib/video_converter/base.rb
110
110
  - lib/video_converter/command.rb
111
111
  - lib/video_converter/ffmpeg.rb
112
+ - lib/video_converter/hls.rb
112
113
  - lib/video_converter/input.rb
113
114
  - lib/video_converter/input_array.rb
114
115
  - lib/video_converter/live_segmenter.rb
@@ -136,7 +137,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
137
  version: '0'
137
138
  segments:
138
139
  - 0
139
- hash: 2281938760435681386
140
+ hash: -805925364969050678
140
141
  required_rubygems_version: !ruby/object:Gem::Requirement
141
142
  none: false
142
143
  requirements:
@@ -145,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
146
  version: '0'
146
147
  segments:
147
148
  - 0
148
- hash: 2281938760435681386
149
+ hash: -805925364969050678
149
150
  requirements:
150
151
  - ffmpeg, version 1.2 or greated configured with libx264 and libfaac
151
152
  - live_segmenter to convert to hls