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.
- 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
|