video_converter 0.2.13 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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