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.
- data/lib/video_converter.rb +3 -2
- data/lib/video_converter/base.rb +7 -17
- data/lib/video_converter/command.rb +12 -1
- data/lib/video_converter/ffmpeg.rb +41 -12
- data/lib/video_converter/hls.rb +60 -0
- data/lib/video_converter/input.rb +3 -3
- data/lib/video_converter/input_array.rb +1 -1
- data/lib/video_converter/output.rb +8 -2
- data/lib/video_converter/process.rb +61 -11
- data/lib/video_converter/version.rb +1 -1
- data/test/video_converter_test.rb +1 -1
- data/video_converter.gemspec +1 -1
- metadata +7 -6
data/lib/video_converter.rb
CHANGED
@@ -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.
|
28
|
+
VideoConverter::Process.find uid
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
data/lib/video_converter/base.rb
CHANGED
@@ -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
|
-
|
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.
|
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
|
-
|
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
|
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 %{
|
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(
|
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(
|
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.
|
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
|
-
|
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 =>
|
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(
|
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 :
|
8
|
+
attr_accessor :process_dir, :collect_progress_interval
|
9
9
|
end
|
10
|
-
self.
|
10
|
+
self.process_dir = '/tmp/video_converter_process'
|
11
|
+
self.collect_progress_interval = 10
|
11
12
|
|
12
|
-
def
|
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
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
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
|
-
|
29
|
-
|
78
|
+
def progress_dir
|
79
|
+
File.join process_dir, 'progress', status
|
30
80
|
end
|
31
81
|
end
|
32
82
|
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
|
data/video_converter.gemspec
CHANGED
@@ -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.
|
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.
|
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-
|
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.
|
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.
|
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:
|
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:
|
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
|